From bd17d4dbd0025908b6f0aa58d74f2bc8cfedb076 Mon Sep 17 00:00:00 2001 From: paolo Date: Sat, 19 Sep 2020 15:20:16 +0000 Subject: [PATCH] Many changes for rk322x target: - Chanaged default x.org configuration to disable glamor - Reintroduce patch to use DRM cursor plane as overlay in rk322x-current and -dev - Updated wifi patches for kernel 5.8.10 - Bumped rk322x to u-boot v2020.07, removed reserved zones from device trees - Updated OPTEE to v3.10, using ddrbin v1.10 - Bumped rk322x-current to kernel 5.8.y - Imported new patches from knaerzche's LibreELEC fork for rk322x-dev (kernel 5.8.y) - Adjusted existing patches to match changes, updated rk322x-dev kernel config file - Add default modprobe conf file for esp8089 to force the crystal frequency to 40Mhz for rk322x targets - Removed ssv6051 firmware packages to move to armbian-firmware repository - Switching ssv6051-wifi.cfg to /lib/firmware for rk322x-legacy - Removed P2P interface for esp8089 driver for rk322x-legacy - Optimized ssv6051 performance: kernel module gains -Os flag, disabled p2p interface, enabled HW crypto for CCMP cipher - Enabled remote control interface, IR GPIO kernel module and HDMI CEC modules --- config/kernel/linux-rk322x-current.config | 289 +- config/kernel/linux-rk322x-dev.config | 5 +- config/kernel/linux-rk322x-legacy.config | 41 +- config/sources/families/rk322x.conf | 16 +- .../rk322x_ddr3_600MHz_ddr2_330MHz_v1.10.bin | Bin 0 -> 9124 bytes packages/blobs/rockchip/rk322x_tee.bin | Bin 347672 -> 291880 bytes packages/blobs/ssv6051/ssv6051-sw.bin | Bin 81176 -> 0 bytes packages/blobs/ssv6051/ssv6051-wifi.cfg | 91 - packages/bsp/rk322x/40-serverflags.conf | 13 +- packages/bsp/rk322x/esp8089.conf | 1 + .../01-linux-0001-rockchip-from-5.9.patch | 3987 +++++++++ .../01-linux-0002-rockchip-from-next.patch | 434 + ...nux-0003-rockchip-from-list.patch.disabled | 2372 ----- ... => 01-linux-0003-rockchip-fromlist.patch} | 1264 ++- ...linux-0004-work-in-progress.patch.disabled | 2864 ------ ...01-linux-0005-for-libreelec.patch.disabled | 1651 ---- .../01-linux-0006-experimental.patch.disabled | 1825 ---- ...a-and-panfrost-for-5.8-plus.patch.disabled | 4172 --------- .../01-linux-0011-v4l2-from-5.9.patch | 1190 +++ ...-linux-0012-v4l2-from-next-from-list.patch | 7852 +++++++++++++++++ ...1-linux-0013-v4l2-from-list.patch.disabled | 319 - ...-0014-v4l2-work-in-progress.patch.disabled | 1525 ---- ...1-linux-0015-fromlist-rga-for-rk322x.patch | 53 - ...ntro-set-of-small-cleanups-and-fixes.patch | 718 -- .../01-linux-0021-drm-from-5.9.patch | 3500 ++++++++ .../01-linux-0022-drm-from-next.patch | 1276 +++ ...linux-1000-clk-rockchip-rk3228-fixup.patch | 98 - ...-linux-1000-export-mm_trace_rss_stat.patch | 12 + ...-1001-clk-rockchip-rk3228-more-fixes.patch | 219 - .../01-linux-1002-arm-dts-rk322x-dts.patch | 1586 ---- .../01-linux-1003-rk322x-hantro.patch | 98 - ...ckchip-rk322x-enhancements-and-fixes.patch | 383 - .../01-linux-2000-rockchip-drm-wip.patch | 5333 +++++++++++ .../01-linux-3000-rockchip-v4l-wip.patch | 4647 ++++++++++ .../01-linux-4000-rockchip-linux-wip.patch | 1692 ++++ .../01-linux-9000-rockchip-linux-le-wip.patch | 912 ++ ...linux-0004-dtsi-adjust-nand-pinctrls.patch | 159 +- .../02-linux-0005-drm-plane-overlay.patch | 66 + .../rk322x-current/board-rk322x-box.patch | 54 +- .../wifi-4003-fix-sha256_state-clashes.patch | 248 + .../wifi-4004-fix-cfg80211-for-5.8.patch | 236 + .../01-linux-0001-rockchip-from-5.9.patch | 3987 +++++++++ .../01-linux-0002-rockchip-from-next.patch | 434 + .../01-linux-0003-rockchip-fromlist.patch | 1956 ++++ .../01-linux-0011-v4l2-from-5.9.patch | 1190 +++ ...-linux-0012-v4l2-from-next-from-list.patch | 7852 +++++++++++++++++ ...015-fromlist-rga-for-rk322x.patch.disabled | 53 - .../01-linux-0021-drm-from-5.9.patch | 3500 ++++++++ .../01-linux-0022-drm-from-next.patch | 1276 +++ ...linux-1000-clk-rockchip-rk3228-fixup.patch | 98 - ...-linux-1000-export-mm_trace_rss_stat.patch | 12 + ...-1001-clk-rockchip-rk3228-more-fixes.patch | 219 - .../01-linux-1002-arm-dts-rk322x-dts.patch | 1586 ---- .../01-linux-1003-rk322x-hantro.patch | 98 - ...ckchip-rk322x-enhancements-and-fixes.patch | 383 - .../01-linux-2000-rockchip-drm-wip.patch | 5333 +++++++++++ .../01-linux-3000-rockchip-v4l-wip.patch | 4647 ++++++++++ .../01-linux-4000-rockchip-linux-wip.patch | 1692 ++++ .../01-linux-9000-rockchip-linux-le-wip.patch | 912 ++ ...linux-0004-dtsi-adjust-nand-pinctrls.patch | 159 +- .../02-linux-0005-drm-plane-overlay.patch | 66 + .../kernel/rk322x-dev/board-rk322x-box.patch | 6 +- .../wifi-4003-fix-sha256_state-clashes.patch | 248 + .../wifi-4004-fix-cfg80211-for-5.8.patch | 236 + .../01-linux-1002-rk322x-dts.patch | 9 +- .../03-001-wifi-esp8089-driver.patch | 4 +- .../03-003-wifi-ssv6051-optimizations.patch | 36 + .../u-boot-rk322x/u-boot-1000-rockchip.patch | 38 - ...ot-1001-rockchip-rmii-integrated-phy.patch | 24 +- .../u-boot-rk322x/u-boot-rk322x-with-spl.bin | 0 70 files changed, 66037 insertions(+), 21218 deletions(-) create mode 100644 packages/blobs/rockchip/rk322x_ddr3_600MHz_ddr2_330MHz_v1.10.bin delete mode 100644 packages/blobs/ssv6051/ssv6051-sw.bin delete mode 100644 packages/blobs/ssv6051/ssv6051-wifi.cfg create mode 100644 packages/bsp/rk322x/esp8089.conf create mode 100644 patch/kernel/rk322x-current/01-linux-0001-rockchip-from-5.9.patch create mode 100644 patch/kernel/rk322x-current/01-linux-0002-rockchip-from-next.patch delete mode 100644 patch/kernel/rk322x-current/01-linux-0003-rockchip-from-list.patch.disabled rename patch/kernel/rk322x-current/{01-linux-0008-fromlist-add-rockchip-nfc-driver.patch.disabled => 01-linux-0003-rockchip-fromlist.patch} (55%) delete mode 100644 patch/kernel/rk322x-current/01-linux-0004-work-in-progress.patch.disabled delete mode 100644 patch/kernel/rk322x-current/01-linux-0005-for-libreelec.patch.disabled delete mode 100644 patch/kernel/rk322x-current/01-linux-0006-experimental.patch.disabled delete mode 100644 patch/kernel/rk322x-current/01-linux-0007-fromlist-drm-lima-and-panfrost-for-5.8-plus.patch.disabled create mode 100644 patch/kernel/rk322x-current/01-linux-0011-v4l2-from-5.9.patch create mode 100644 patch/kernel/rk322x-current/01-linux-0012-v4l2-from-next-from-list.patch delete mode 100644 patch/kernel/rk322x-current/01-linux-0013-v4l2-from-list.patch.disabled delete mode 100644 patch/kernel/rk322x-current/01-linux-0014-v4l2-work-in-progress.patch.disabled delete mode 100644 patch/kernel/rk322x-current/01-linux-0015-fromlist-rga-for-rk322x.patch delete mode 100644 patch/kernel/rk322x-current/01-linux-0015-hantro-set-of-small-cleanups-and-fixes.patch create mode 100644 patch/kernel/rk322x-current/01-linux-0021-drm-from-5.9.patch create mode 100644 patch/kernel/rk322x-current/01-linux-0022-drm-from-next.patch delete mode 100644 patch/kernel/rk322x-current/01-linux-1000-clk-rockchip-rk3228-fixup.patch create mode 100644 patch/kernel/rk322x-current/01-linux-1000-export-mm_trace_rss_stat.patch delete mode 100644 patch/kernel/rk322x-current/01-linux-1001-clk-rockchip-rk3228-more-fixes.patch delete mode 100644 patch/kernel/rk322x-current/01-linux-1002-arm-dts-rk322x-dts.patch delete mode 100644 patch/kernel/rk322x-current/01-linux-1003-rk322x-hantro.patch delete mode 100644 patch/kernel/rk322x-current/01-linux-1004-rockchip-rk322x-enhancements-and-fixes.patch create mode 100644 patch/kernel/rk322x-current/01-linux-2000-rockchip-drm-wip.patch create mode 100644 patch/kernel/rk322x-current/01-linux-3000-rockchip-v4l-wip.patch create mode 100644 patch/kernel/rk322x-current/01-linux-4000-rockchip-linux-wip.patch create mode 100644 patch/kernel/rk322x-current/01-linux-9000-rockchip-linux-le-wip.patch create mode 100644 patch/kernel/rk322x-current/02-linux-0005-drm-plane-overlay.patch create mode 100644 patch/kernel/rk322x-current/wifi-4003-fix-sha256_state-clashes.patch create mode 100644 patch/kernel/rk322x-current/wifi-4004-fix-cfg80211-for-5.8.patch create mode 100644 patch/kernel/rk322x-dev/01-linux-0001-rockchip-from-5.9.patch create mode 100644 patch/kernel/rk322x-dev/01-linux-0002-rockchip-from-next.patch create mode 100644 patch/kernel/rk322x-dev/01-linux-0003-rockchip-fromlist.patch create mode 100644 patch/kernel/rk322x-dev/01-linux-0011-v4l2-from-5.9.patch create mode 100644 patch/kernel/rk322x-dev/01-linux-0012-v4l2-from-next-from-list.patch delete mode 100644 patch/kernel/rk322x-dev/01-linux-0015-fromlist-rga-for-rk322x.patch.disabled create mode 100644 patch/kernel/rk322x-dev/01-linux-0021-drm-from-5.9.patch create mode 100644 patch/kernel/rk322x-dev/01-linux-0022-drm-from-next.patch delete mode 100644 patch/kernel/rk322x-dev/01-linux-1000-clk-rockchip-rk3228-fixup.patch create mode 100644 patch/kernel/rk322x-dev/01-linux-1000-export-mm_trace_rss_stat.patch delete mode 100644 patch/kernel/rk322x-dev/01-linux-1001-clk-rockchip-rk3228-more-fixes.patch delete mode 100644 patch/kernel/rk322x-dev/01-linux-1002-arm-dts-rk322x-dts.patch delete mode 100644 patch/kernel/rk322x-dev/01-linux-1003-rk322x-hantro.patch delete mode 100644 patch/kernel/rk322x-dev/01-linux-1004-rockchip-rk322x-enhancements-and-fixes.patch create mode 100644 patch/kernel/rk322x-dev/01-linux-2000-rockchip-drm-wip.patch create mode 100644 patch/kernel/rk322x-dev/01-linux-3000-rockchip-v4l-wip.patch create mode 100644 patch/kernel/rk322x-dev/01-linux-4000-rockchip-linux-wip.patch create mode 100644 patch/kernel/rk322x-dev/01-linux-9000-rockchip-linux-le-wip.patch create mode 100644 patch/kernel/rk322x-dev/02-linux-0005-drm-plane-overlay.patch create mode 100644 patch/kernel/rk322x-dev/wifi-4003-fix-sha256_state-clashes.patch create mode 100644 patch/kernel/rk322x-dev/wifi-4004-fix-cfg80211-for-5.8.patch create mode 100644 patch/kernel/rk322x-legacy/03-003-wifi-ssv6051-optimizations.patch create mode 100644 patch/u-boot/u-boot-rk322x/u-boot-rk322x-with-spl.bin diff --git a/config/kernel/linux-rk322x-current.config b/config/kernel/linux-rk322x-current.config index 27f995d64..fb2a2b1f4 100644 --- a/config/kernel/linux-rk322x-current.config +++ b/config/kernel/linux-rk322x-current.config @@ -1,16 +1,14 @@ # # Automatically generated file; DO NOT EDIT. -# Linux/arm 5.7.16 Kernel Configuration -# - -# -# Compiler: arm-none-linux-gnueabihf-gcc (GNU Toolchain for the A-profile Architecture 9.2-2019.12 (arm-9.10)) 9.2.1 20191025 +# Linux/arm 5.8.9 Kernel Configuration # +CONFIG_CC_VERSION_TEXT="arm-none-linux-gnueabihf-gcc (GNU Toolchain for the A-profile Architecture 9.2-2019.12 (arm-9.10)) 9.2.1 20191025" CONFIG_CC_IS_GCC=y CONFIG_GCC_VERSION=90201 CONFIG_LD_VERSION=233010000 CONFIG_CLANG_VERSION=0 CONFIG_CC_CAN_LINK=y +CONFIG_CC_CAN_LINK_STATIC=y CONFIG_CC_HAS_ASM_GOTO=y CONFIG_CC_HAS_ASM_INLINE=y CONFIG_IRQ_WORK=y @@ -34,12 +32,14 @@ CONFIG_KERNEL_GZIP=y # CONFIG_KERNEL_XZ is not set # CONFIG_KERNEL_LZO is not set # CONFIG_KERNEL_LZ4 is not set +CONFIG_DEFAULT_INIT="" CONFIG_DEFAULT_HOSTNAME="localhost" CONFIG_SWAP=y CONFIG_SYSVIPC=y CONFIG_SYSVIPC_SYSCTL=y CONFIG_POSIX_MQUEUE=y CONFIG_POSIX_MQUEUE_SYSCTL=y +# CONFIG_WATCH_QUEUE is not set CONFIG_CROSS_MEMORY_ATTACH=y CONFIG_USELIB=y CONFIG_AUDIT=y @@ -110,7 +110,9 @@ CONFIG_PREEMPT_RCU=y # CONFIG_RCU_EXPERT is not set CONFIG_SRCU=y CONFIG_TREE_SRCU=y +CONFIG_TASKS_RCU_GENERIC=y CONFIG_TASKS_RCU=y +CONFIG_TASKS_RUDE_RCU=y CONFIG_RCU_STALL_COMMON=y CONFIG_RCU_NEED_SEGCBLIST=y # end of RCU Subsystem @@ -133,7 +135,6 @@ CONFIG_CGROUPS=y CONFIG_PAGE_COUNTER=y CONFIG_MEMCG=y CONFIG_MEMCG_SWAP=y -CONFIG_MEMCG_SWAP_ENABLED=y CONFIG_MEMCG_KMEM=y CONFIG_BLK_CGROUP=y CONFIG_CGROUP_WRITEBACK=y @@ -318,6 +319,7 @@ CONFIG_ARCH_MULTI_V6_V7=y # CONFIG_ARCH_SIRF is not set # CONFIG_ARCH_QCOM is not set # CONFIG_ARCH_RDA is not set +# CONFIG_ARCH_REALTEK is not set # CONFIG_ARCH_REALVIEW is not set CONFIG_ARCH_ROCKCHIP=y # CONFIG_ARCH_S5PV210 is not set @@ -442,6 +444,9 @@ CONFIG_SCHED_HRTICK=y CONFIG_ARM_PATCH_IDIV=y CONFIG_AEABI=y # CONFIG_OABI_COMPAT is not set +CONFIG_ARCH_SELECT_MEMORY_MODEL=y +CONFIG_ARCH_FLATMEM_ENABLE=y +CONFIG_ARCH_SPARSEMEM_ENABLE=y CONFIG_HAVE_ARCH_PFN_VALID=y CONFIG_HIGHMEM=y # CONFIG_HIGHPTE is not set @@ -503,7 +508,6 @@ CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y # CONFIG_CPUFREQ_DT=m CONFIG_CPUFREQ_DT_PLATDEV=y -# CONFIG_QORIQ_CPUFREQ is not set # end of CPU Frequency scaling # @@ -577,10 +581,11 @@ CONFIG_ARCH_HIBERNATION_POSSIBLE=y # CONFIG_FIRMWARE_MEMMAP is not set # CONFIG_FW_CFG_SYSFS is not set # CONFIG_TRUSTED_FOUNDATIONS is not set -CONFIG_HAVE_ARM_SMCCC=y +# CONFIG_GOOGLE_FIRMWARE is not set CONFIG_ARM_PSCI_FW=y # CONFIG_ARM_PSCI_CHECKER is not set -# CONFIG_GOOGLE_FIRMWARE is not set +CONFIG_HAVE_ARM_SMCCC=y +CONFIG_HAVE_ARM_SMCCC_DISCOVERY=y # # Tegra firmware driver @@ -630,7 +635,6 @@ CONFIG_HAVE_ARCH_THREAD_STRUCT_WHITELIST=y CONFIG_ARCH_32BIT_OFF_T=y CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y CONFIG_HAVE_RSEQ=y -CONFIG_HAVE_CLK=y CONFIG_HAVE_HW_BREAKPOINT=y CONFIG_HAVE_PERF_REGS=y CONFIG_HAVE_PERF_USER_STACK_DUMP=y @@ -705,6 +709,7 @@ CONFIG_BLK_DEV_THROTTLING=y # CONFIG_BLK_CGROUP_IOCOST is not set CONFIG_BLK_DEBUG_FS=y # CONFIG_BLK_SED_OPAL is not set +# CONFIG_BLK_INLINE_ENCRYPTION is not set # # Partition Types @@ -774,6 +779,9 @@ CONFIG_COREDUMP=y # # Memory Management options # +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_FLATMEM_MANUAL=y +# CONFIG_SPARSEMEM_MANUAL is not set CONFIG_FLATMEM=y CONFIG_FLAT_NODE_MEM_MAP=y CONFIG_ARCH_KEEP_MEMBLOCK=y @@ -809,7 +817,7 @@ CONFIG_ZPOOL=y CONFIG_ZBUD=y CONFIG_Z3FOLD=y CONFIG_ZSMALLOC=y -# CONFIG_PGTABLE_MAPPING is not set +# CONFIG_ZSMALLOC_PGTABLE_MAPPING is not set # CONFIG_ZSMALLOC_STAT is not set CONFIG_GENERIC_EARLY_IOREMAP=y CONFIG_IDLE_PAGE_TRACKING=y @@ -843,6 +851,8 @@ CONFIG_XFRM_USER=m # CONFIG_XFRM_SUB_POLICY is not set # CONFIG_XFRM_MIGRATE is not set # CONFIG_XFRM_STATISTICS is not set +CONFIG_XFRM_AH=m +CONFIG_XFRM_ESP=m CONFIG_XFRM_IPCOMP=m CONFIG_NET_KEY=m # CONFIG_NET_KEY_MIGRATE is not set @@ -913,6 +923,7 @@ CONFIG_IPV6_OPTIMISTIC_DAD=y CONFIG_INET6_AH=m CONFIG_INET6_ESP=m CONFIG_INET6_ESP_OFFLOAD=m +# CONFIG_INET6_ESPINTCP is not set CONFIG_INET6_IPCOMP=m CONFIG_IPV6_MIP6=m CONFIG_IPV6_ILA=m @@ -1342,6 +1353,7 @@ CONFIG_MRP=y CONFIG_BRIDGE=y CONFIG_BRIDGE_IGMP_SNOOPING=y CONFIG_BRIDGE_VLAN_FILTERING=y +# CONFIG_BRIDGE_MRP is not set CONFIG_HAVE_NET_DSA=y CONFIG_NET_DSA=m CONFIG_NET_DSA_TAG_8021Q=m @@ -1483,6 +1495,7 @@ CONFIG_NET_ACT_SKBMOD=m CONFIG_NET_ACT_IFE=m CONFIG_NET_ACT_TUNNEL_KEY=m # CONFIG_NET_ACT_CT is not set +# CONFIG_NET_ACT_GATE is not set CONFIG_NET_IFE_SKBMARK=m CONFIG_NET_IFE_SKBPRIO=m CONFIG_NET_IFE_SKBTCINDEX=m @@ -1513,6 +1526,7 @@ CONFIG_NET_NSH=m CONFIG_HSR=m CONFIG_NET_SWITCHDEV=y CONFIG_NET_L3_MASTER_DEV=y +# CONFIG_QRTR is not set # CONFIG_NET_NCSI is not set CONFIG_RPS=y CONFIG_RFS_ACCEL=y @@ -1599,8 +1613,10 @@ CONFIG_BT_HS=y CONFIG_BT_LE=y CONFIG_BT_6LOWPAN=m # CONFIG_BT_LEDS is not set -# CONFIG_BT_SELFTEST is not set +# CONFIG_BT_MSFTEXT is not set CONFIG_BT_DEBUGFS=y +# CONFIG_BT_SELFTEST is not set +# CONFIG_BT_FEATURE_DEBUG is not set # # Bluetooth device drivers @@ -1944,6 +1960,7 @@ CONFIG_DM_CRYPT=y CONFIG_DM_THIN_PROVISIONING=y # CONFIG_DM_CACHE is not set CONFIG_DM_WRITECACHE=m +# CONFIG_DM_EBS is not set # CONFIG_DM_ERA is not set CONFIG_DM_CLONE=m CONFIG_DM_MIRROR=y @@ -2094,6 +2111,7 @@ CONFIG_MDIO_BUS_MUX=m # CONFIG_MDIO_BUS_MUX_MMIOREG is not set CONFIG_MDIO_BUS_MUX_MULTIPLEXER=m # CONFIG_MDIO_HISI_FEMAC is not set +# CONFIG_MDIO_IPQ4019 is not set # CONFIG_MDIO_IPQ8064 is not set CONFIG_MDIO_MSCC_MIIM=m # CONFIG_MDIO_MVUSB is not set @@ -2115,6 +2133,7 @@ CONFIG_BCM7XXX_PHY=m # CONFIG_BCM87XX_PHY is not set CONFIG_BCM_NET_PHYLIB=m # CONFIG_BROADCOM_PHY is not set +# CONFIG_BCM54140_PHY is not set # CONFIG_BCM84881_PHY is not set # CONFIG_CICADA_PHY is not set # CONFIG_CORTINA_PHY is not set @@ -2289,6 +2308,8 @@ CONFIG_MT76x0_COMMON=m CONFIG_MT76x0U=m CONFIG_MT76x2_COMMON=m CONFIG_MT76x2U=m +CONFIG_MT7615_COMMON=m +CONFIG_MT7663U=m CONFIG_WLAN_VENDOR_RALINK=y CONFIG_RT2X00=y CONFIG_RT2500USB=y @@ -2471,6 +2492,7 @@ CONFIG_TOUCHSCREEN_ATMEL_MXT=y # CONFIG_TOUCHSCREEN_BU21013 is not set CONFIG_TOUCHSCREEN_BU21029=m # CONFIG_TOUCHSCREEN_CHIPONE_ICN8318 is not set +# CONFIG_TOUCHSCREEN_CY8CTMA140 is not set # CONFIG_TOUCHSCREEN_CY8CTMG110 is not set # CONFIG_TOUCHSCREEN_CYTTSP_CORE is not set # CONFIG_TOUCHSCREEN_CYTTSP4_CORE is not set @@ -2547,10 +2569,8 @@ CONFIG_INPUT_MISC=y # CONFIG_INPUT_ATMEL_CAPTOUCH is not set # CONFIG_INPUT_BMA150 is not set # CONFIG_INPUT_E3X0_BUTTON is not set -# CONFIG_INPUT_MSM_VIBRATOR is not set CONFIG_INPUT_MAX77650_ONKEY=m # CONFIG_INPUT_MMA8450 is not set -# CONFIG_INPUT_GP2A is not set # CONFIG_INPUT_GPIO_BEEPER is not set # CONFIG_INPUT_GPIO_DECODER is not set CONFIG_INPUT_GPIO_VIBRA=m @@ -2570,6 +2590,7 @@ CONFIG_INPUT_UINPUT=y # CONFIG_INPUT_GPIO_ROTARY_ENCODER is not set # CONFIG_INPUT_ADXL34X is not set # CONFIG_INPUT_IMS_PCU is not set +# CONFIG_INPUT_IQS269A is not set # CONFIG_INPUT_CMA3000 is not set # CONFIG_INPUT_DRV260X_HAPTICS is not set # CONFIG_INPUT_DRV2665_HAPTICS is not set @@ -2686,6 +2707,7 @@ CONFIG_HW_RANDOM=y # CONFIG_HW_RANDOM_TIMERIOMEM is not set CONFIG_HW_RANDOM_VIRTIO=m CONFIG_HW_RANDOM_OPTEE=m +# CONFIG_HW_RANDOM_CCTRNG is not set CONFIG_DEVMEM=y # CONFIG_DEVKMEM is not set # CONFIG_RAW_DRIVER is not set @@ -2798,6 +2820,7 @@ CONFIG_SPI_ROCKCHIP=y # CONFIG_SPI_XCOMM is not set # CONFIG_SPI_XILINX is not set # CONFIG_SPI_ZYNQMP_GQSPI is not set +# CONFIG_SPI_AMD is not set # # SPI Multiplexer support @@ -2811,6 +2834,7 @@ CONFIG_SPI_SPIDEV=y # CONFIG_SPI_LOOPBACK_TEST is not set # CONFIG_SPI_TLE62X0 is not set # CONFIG_SPI_SLAVE is not set +CONFIG_SPI_DYNAMIC=y # CONFIG_SPMI is not set # CONFIG_HSI is not set CONFIG_PPS=y @@ -2842,7 +2866,6 @@ CONFIG_PINMUX=y CONFIG_PINCONF=y CONFIG_GENERIC_PINCONF=y # CONFIG_DEBUG_PINCTRL is not set -# CONFIG_PINCTRL_AMD is not set # CONFIG_PINCTRL_MCP23S08 is not set CONFIG_PINCTRL_ROCKCHIP=y # CONFIG_PINCTRL_SINGLE is not set @@ -2851,7 +2874,6 @@ CONFIG_PINCTRL_ROCKCHIP=y # CONFIG_PINCTRL_RK805 is not set # CONFIG_PINCTRL_OCELOT is not set CONFIG_PINCTRL_MADERA=m -# CONFIG_PINCTRL_EQUILIBRIUM is not set CONFIG_ARCH_HAVE_CUSTOM_GPIO_H=y CONFIG_GPIOLIB=y CONFIG_GPIOLIB_FASTPATH_LIMIT=512 @@ -2923,6 +2945,7 @@ CONFIG_GPIO_MAX77650=m # # end of USB GPIO expanders +# CONFIG_GPIO_AGGREGATOR is not set # CONFIG_GPIO_MOCKUP is not set CONFIG_W1=m CONFIG_W1_CON=y @@ -2985,6 +3008,7 @@ CONFIG_POWER_SUPPLY_HWMON=y # CONFIG_TEST_POWER is not set # CONFIG_CHARGER_ADP5061 is not set # CONFIG_BATTERY_CPCAP is not set +# CONFIG_BATTERY_CW2015 is not set # CONFIG_BATTERY_DS2760 is not set # CONFIG_BATTERY_DS2780 is not set # CONFIG_BATTERY_DS2781 is not set @@ -3013,6 +3037,7 @@ CONFIG_CHARGER_GPIO=m # CONFIG_BATTERY_GAUGE_LTC2941 is not set # CONFIG_CHARGER_RT9455 is not set # CONFIG_CHARGER_UCS1002 is not set +# CONFIG_CHARGER_BD99954 is not set CONFIG_HWMON=y # CONFIG_HWMON_DEBUG_CHIP is not set @@ -3171,7 +3196,6 @@ CONFIG_CPU_FREQ_THERMAL=y # CONFIG_DEVFREQ_THERMAL is not set # CONFIG_THERMAL_EMULATION is not set CONFIG_THERMAL_MMIO=m -# CONFIG_QORIQ_THERMAL is not set CONFIG_ROCKCHIP_THERMAL=m # CONFIG_GENERIC_ADC_THERMAL is not set CONFIG_WATCHDOG=y @@ -3198,6 +3222,7 @@ CONFIG_SOFT_WATCHDOG=m # CONFIG_FTWDT010_WATCHDOG is not set CONFIG_DW_WATCHDOG=m # CONFIG_MAX63XX_WATCHDOG is not set +# CONFIG_ARM_SMC_WATCHDOG is not set # CONFIG_STPMIC1_WATCHDOG is not set # CONFIG_MEN_A21_WDT is not set @@ -3241,8 +3266,10 @@ CONFIG_MFD_MADERA_I2C=m # CONFIG_MFD_DA9063 is not set # CONFIG_MFD_DA9150 is not set # CONFIG_MFD_DLN2 is not set +# CONFIG_MFD_GATEWORKS_GSC is not set # CONFIG_MFD_MC13XXX_SPI is not set # CONFIG_MFD_MC13XXX_I2C is not set +# CONFIG_MFD_MP2629 is not set # CONFIG_MFD_HI6421_PMIC is not set # CONFIG_HTC_PASIC3 is not set # CONFIG_HTC_I2CPLD is not set @@ -3261,6 +3288,7 @@ CONFIG_MFD_MAX77650=m # CONFIG_MFD_MAX8925 is not set # CONFIG_MFD_MAX8997 is not set # CONFIG_MFD_MAX8998 is not set +# CONFIG_MFD_MT6360 is not set # CONFIG_MFD_MT6397 is not set # CONFIG_MFD_MENF21BMC is not set # CONFIG_EZX_PCAP is not set @@ -3355,6 +3383,7 @@ CONFIG_REGULATOR_GPIO=y # CONFIG_REGULATOR_MAX8660 is not set # CONFIG_REGULATOR_MAX8952 is not set # CONFIG_REGULATOR_MAX8973 is not set +# CONFIG_REGULATOR_MAX77826 is not set # CONFIG_REGULATOR_MCP16502 is not set # CONFIG_REGULATOR_MP5416 is not set # CONFIG_REGULATOR_MP8859 is not set @@ -3379,8 +3408,6 @@ CONFIG_REGULATOR_RK808=y # CONFIG_REGULATOR_TPS6524X is not set CONFIG_REGULATOR_TPS6586X=y # CONFIG_REGULATOR_VCTRL is not set -CONFIG_CEC_CORE=y -CONFIG_CEC_NOTIFIER=y CONFIG_RC_CORE=y CONFIG_RC_MAP=y CONFIG_LIRC=y @@ -3415,44 +3442,76 @@ CONFIG_IR_GPIO_CIR=m # CONFIG_IR_SERIAL is not set # CONFIG_IR_SIR is not set # CONFIG_RC_XBOX_DVD is not set +CONFIG_CEC_CORE=y +CONFIG_CEC_NOTIFIER=y +# CONFIG_MEDIA_CEC_RC is not set +# CONFIG_MEDIA_CEC_SUPPORT is not set CONFIG_MEDIA_SUPPORT=y +CONFIG_MEDIA_SUPPORT_FILTER=y +# CONFIG_MEDIA_SUBDRV_AUTOSELECT is not set # -# Multimedia core support +# Media device types # CONFIG_MEDIA_CAMERA_SUPPORT=y CONFIG_MEDIA_ANALOG_TV_SUPPORT=y CONFIG_MEDIA_DIGITAL_TV_SUPPORT=y CONFIG_MEDIA_RADIO_SUPPORT=y CONFIG_MEDIA_SDR_SUPPORT=y -# CONFIG_MEDIA_CEC_SUPPORT is not set -# CONFIG_MEDIA_CEC_RC is not set -CONFIG_MEDIA_CONTROLLER=y -CONFIG_MEDIA_CONTROLLER_DVB=y -CONFIG_MEDIA_CONTROLLER_REQUEST_API=y +CONFIG_MEDIA_PLATFORM_SUPPORT=y +# CONFIG_MEDIA_TEST_SUPPORT is not set +# end of Media device types + CONFIG_VIDEO_DEV=y -CONFIG_VIDEO_V4L2_SUBDEV_API=y +CONFIG_MEDIA_CONTROLLER=y +CONFIG_DVB_CORE=y + +# +# Video4Linux options +# CONFIG_VIDEO_V4L2=y CONFIG_VIDEO_V4L2_I2C=y +CONFIG_VIDEO_V4L2_SUBDEV_API=y # CONFIG_VIDEO_ADV_DEBUG is not set CONFIG_VIDEO_FIXED_MINOR_RANGES=y CONFIG_VIDEO_TUNER=m +CONFIG_V4L2_H264=m CONFIG_V4L2_MEM2MEM_DEV=m CONFIG_V4L2_FWNODE=m CONFIG_VIDEOBUF_GEN=m CONFIG_VIDEOBUF_VMALLOC=m -CONFIG_DVB_CORE=y +# end of Video4Linux options + +# +# Media controller options +# +CONFIG_MEDIA_CONTROLLER_DVB=y +CONFIG_MEDIA_CONTROLLER_REQUEST_API=y + +# +# Please notice that the enabled Media controller Request API is EXPERIMENTAL +# +# end of Media controller options + +# +# Digital TV options +# # CONFIG_DVB_MMAP is not set CONFIG_DVB_NET=y -CONFIG_TTPCI_EEPROM=m CONFIG_DVB_MAX_ADAPTERS=16 CONFIG_DVB_DYNAMIC_MINORS=y # CONFIG_DVB_DEMUX_SECTION_LOSS_LOG is not set # CONFIG_DVB_ULE_DEBUG is not set +# end of Digital TV options # # Media drivers # + +# +# Drivers filtered as selected at 'Filter media drivers' +# +CONFIG_TTPCI_EEPROM=m CONFIG_MEDIA_USB_SUPPORT=y # @@ -3610,32 +3669,6 @@ CONFIG_VIDEO_EM28XX_RC=m CONFIG_USB_AIRSPY=m CONFIG_USB_HACKRF=m CONFIG_USB_MSI2500=m -CONFIG_V4L_PLATFORM_DRIVERS=y -# CONFIG_VIDEO_CADENCE is not set -# CONFIG_VIDEO_ASPEED is not set -CONFIG_VIDEO_MUX=m -CONFIG_VIDEO_XILINX=m -CONFIG_VIDEO_XILINX_TPG=m -CONFIG_VIDEO_XILINX_VTC=m -CONFIG_V4L_MEM2MEM_DRIVERS=y -# CONFIG_VIDEO_MEM2MEM_DEINTERLACE is not set -# CONFIG_VIDEO_SH_VEU is not set -CONFIG_VIDEO_ROCKCHIP_RGA=m -CONFIG_V4L_TEST_DRIVERS=y -# CONFIG_VIDEO_VIMC is not set -CONFIG_VIDEO_VIVID=m -# CONFIG_VIDEO_VIVID_CEC is not set -CONFIG_VIDEO_VIVID_MAX_DEVS=64 -CONFIG_VIDEO_VIM2M=m -CONFIG_VIDEO_VICODEC=m -CONFIG_DVB_PLATFORM_DRIVERS=y -CONFIG_DVB_C8SECTPFE=m -# CONFIG_SDR_PLATFORM_DRIVERS is not set - -# -# Supported MMC/SDIO adapters -# -# CONFIG_SMS_SDIO_DRV is not set # CONFIG_RADIO_ADAPTERS is not set CONFIG_MEDIA_COMMON_OPTIONS=y @@ -3654,19 +3687,32 @@ CONFIG_VIDEOBUF2_DMA_SG=m CONFIG_DVB_B2C2_FLEXCOP=m CONFIG_SMS_SIANO_MDTV=m CONFIG_SMS_SIANO_RC=y -CONFIG_VIDEO_V4L2_TPG=m +CONFIG_V4L_PLATFORM_DRIVERS=y +# CONFIG_VIDEO_CADENCE is not set +# CONFIG_VIDEO_ASPEED is not set +CONFIG_VIDEO_MUX=m +CONFIG_VIDEO_XILINX=m +CONFIG_VIDEO_XILINX_TPG=m +CONFIG_VIDEO_XILINX_VTC=m +CONFIG_V4L_MEM2MEM_DRIVERS=y +# CONFIG_VIDEO_MEM2MEM_DEINTERLACE is not set +CONFIG_VIDEO_ROCKCHIP_RGA=m +CONFIG_DVB_PLATFORM_DRIVERS=y +CONFIG_DVB_C8SECTPFE=m +# CONFIG_SDR_PLATFORM_DRIVERS is not set # -# Media ancillary drivers (tuners, sensors, i2c, spi, frontends) +# MMC/SDIO DVB adapters +# +# CONFIG_SMS_SDIO_DRV is not set +# end of Media drivers + +# +# Media ancillary drivers # -# CONFIG_MEDIA_SUBDRV_AUTOSELECT is not set CONFIG_MEDIA_ATTACH=y CONFIG_VIDEO_IR_I2C=m -# -# I2C Encoders, decoders, sensors and other helper chips -# - # # Audio decoders, processors and mixers # @@ -3686,11 +3732,13 @@ CONFIG_VIDEO_WM8775=m # CONFIG_VIDEO_WM8739 is not set # CONFIG_VIDEO_VP27SMPX is not set # CONFIG_VIDEO_SONY_BTF_MPX is not set +# end of Audio decoders, processors and mixers # # RDS decoders # # CONFIG_VIDEO_SAA6588 is not set +# end of RDS decoders # # Video decoders @@ -3722,6 +3770,7 @@ CONFIG_VIDEO_SAA711X=m # # CONFIG_VIDEO_SAA717X is not set CONFIG_VIDEO_CX25840=m +# end of Video decoders # # Video encoders @@ -3736,6 +3785,35 @@ CONFIG_VIDEO_CX25840=m # CONFIG_VIDEO_AD9389B is not set # CONFIG_VIDEO_AK881X is not set # CONFIG_VIDEO_THS8200 is not set +# end of Video encoders + +# +# Video improvement chips +# +# CONFIG_VIDEO_UPD64031A is not set +# CONFIG_VIDEO_UPD64083 is not set +# end of Video improvement chips + +# +# Audio/Video compression chips +# +# CONFIG_VIDEO_SAA6752HS is not set +# end of Audio/Video compression chips + +# +# SDR tuner chips +# +# CONFIG_SDR_MAX2175 is not set +# end of SDR tuner chips + +# +# Miscellaneous helper chips +# +# CONFIG_VIDEO_THS7303 is not set +# CONFIG_VIDEO_M52790 is not set +# CONFIG_VIDEO_I2C is not set +# CONFIG_VIDEO_ST_MIPID02 is not set +# end of Miscellaneous helper chips # # Camera sensor devices @@ -3752,6 +3830,7 @@ CONFIG_VIDEO_CX25840=m # CONFIG_VIDEO_OV2659 is not set # CONFIG_VIDEO_OV2680 is not set # CONFIG_VIDEO_OV2685 is not set +# CONFIG_VIDEO_OV2740 is not set # CONFIG_VIDEO_OV5640 is not set # CONFIG_VIDEO_OV5645 is not set # CONFIG_VIDEO_OV5647 is not set @@ -3789,6 +3868,7 @@ CONFIG_VIDEO_CX25840=m # CONFIG_VIDEO_SMIAPP is not set # CONFIG_VIDEO_ET8EK8 is not set # CONFIG_VIDEO_S5C73M3 is not set +# end of Camera sensor devices # # Lens drivers @@ -3797,6 +3877,7 @@ CONFIG_VIDEO_CX25840=m # CONFIG_VIDEO_AK7375 is not set # CONFIG_VIDEO_DW9714 is not set # CONFIG_VIDEO_DW9807_VCM is not set +# end of Lens drivers # # Flash devices @@ -3804,31 +3885,7 @@ CONFIG_VIDEO_CX25840=m # CONFIG_VIDEO_ADP1653 is not set # CONFIG_VIDEO_LM3560 is not set # CONFIG_VIDEO_LM3646 is not set - -# -# Video improvement chips -# -# CONFIG_VIDEO_UPD64031A is not set -# CONFIG_VIDEO_UPD64083 is not set - -# -# Audio/Video compression chips -# -# CONFIG_VIDEO_SAA6752HS is not set - -# -# SDR tuner chips -# -# CONFIG_SDR_MAX2175 is not set - -# -# Miscellaneous helper chips -# -# CONFIG_VIDEO_THS7303 is not set -# CONFIG_VIDEO_M52790 is not set -# CONFIG_VIDEO_I2C is not set -# CONFIG_VIDEO_ST_MIPID02 is not set -# end of I2C Encoders, decoders, sensors and other helper chips +# end of Flash devices # # SPI helper chips @@ -4048,12 +4105,8 @@ CONFIG_DVB_AF9033=m # # CONFIG_DVB_CXD2099 is not set # CONFIG_DVB_SP2 is not set - -# -# Tools to develop new frontends -# -# CONFIG_DVB_DUMMY_FE is not set # end of Customise DVB Frontends +# end of Media ancillary drivers # # Graphics support @@ -4147,9 +4200,12 @@ CONFIG_DRM_PANEL_BRIDGE=y # Display Interface Bridges # # CONFIG_DRM_CDNS_DSI is not set +# CONFIG_DRM_CHRONTEL_CH7033 is not set CONFIG_DRM_DISPLAY_CONNECTOR=m +# CONFIG_DRM_ITE_IT66121 is not set # CONFIG_DRM_LVDS_CODEC is not set # CONFIG_DRM_MEGACHIPS_STDPXXXX_GE_B850V3_FW is not set +# CONFIG_DRM_NWL_MIPI_DSI is not set # CONFIG_DRM_NXP_PTN3460 is not set # CONFIG_DRM_PARADE_PS8622 is not set # CONFIG_DRM_PARADE_PS8640 is not set @@ -4435,6 +4491,7 @@ CONFIG_SND_SOC_MAX98090=m CONFIG_SND_SOC_MAX9867=m # CONFIG_SND_SOC_MAX98927 is not set # CONFIG_SND_SOC_MAX98373 is not set +# CONFIG_SND_SOC_MAX98390 is not set # CONFIG_SND_SOC_MAX9860 is not set # CONFIG_SND_SOC_MSM8916_WCD_DIGITAL is not set # CONFIG_SND_SOC_PCM1681 is not set @@ -4509,6 +4566,7 @@ CONFIG_SND_SOC_WM8904=m # CONFIG_SND_SOC_WM8974 is not set # CONFIG_SND_SOC_WM8978 is not set # CONFIG_SND_SOC_WM8985 is not set +# CONFIG_SND_SOC_ZL38060 is not set # CONFIG_SND_SOC_ZX_AUD96P22 is not set CONFIG_SND_SOC_MAX9759=m CONFIG_SND_SOC_MT6351=m @@ -4987,6 +5045,7 @@ CONFIG_LEDS_CLASS=y # LED drivers # # CONFIG_LEDS_AN30259A is not set +# CONFIG_LEDS_AW2013 is not set # CONFIG_LEDS_BCM6328 is not set # CONFIG_LEDS_BCM6358 is not set # CONFIG_LEDS_CPCAP is not set @@ -5223,7 +5282,6 @@ CONFIG_DMABUF_SELFTESTS=m CONFIG_VIRTIO=m # CONFIG_VIRTIO_MENU is not set # CONFIG_VDPA is not set -CONFIG_VHOST_DPN=y CONFIG_VHOST_MENU=y # CONFIG_VHOST_NET is not set # CONFIG_VHOST_CROSS_ENDIAN_LEGACY is not set @@ -5310,6 +5368,7 @@ CONFIG_88EU_AP_MODE=y CONFIG_STAGING_MEDIA=y CONFIG_VIDEO_HANTRO=m CONFIG_VIDEO_HANTRO_ROCKCHIP=y +CONFIG_VIDEO_ROCKCHIP_VDEC=m # # soc_camera sensor drivers @@ -5384,13 +5443,10 @@ CONFIG_HMS_PROFINET=m # CONFIG_MFD_CROS_EC is not set # CONFIG_CHROME_PLATFORMS is not set # CONFIG_MELLANOX_PLATFORM is not set +CONFIG_HAVE_CLK=y CONFIG_CLKDEV_LOOKUP=y CONFIG_HAVE_CLK_PREPARE=y CONFIG_COMMON_CLK=y - -# -# Common Clock Framework -# # CONFIG_CLK_HSDK is not set CONFIG_COMMON_CLK_MAX9485=m CONFIG_COMMON_CLK_RK808=y @@ -5407,8 +5463,6 @@ CONFIG_COMMON_CLK_SI544=m CONFIG_COMMON_CLK_VC5=m # CONFIG_COMMON_CLK_BD718XX is not set # CONFIG_COMMON_CLK_FIXED_MMIO is not set -# end of Common Clock Framework - # CONFIG_HWSPINLOCK is not set # @@ -5619,6 +5673,8 @@ CONFIG_AD7768_1=m # CONFIG_AD7923 is not set # CONFIG_AD7949 is not set # CONFIG_AD799X is not set +# CONFIG_AD9467 is not set +# CONFIG_ADI_AXI_ADC is not set # CONFIG_CC10001_ADC is not set # CONFIG_CPCAP_ADC is not set # CONFIG_ENVELOPE_DETECTOR is not set @@ -5632,6 +5688,7 @@ CONFIG_AD7768_1=m # CONFIG_MAX1027 is not set # CONFIG_MAX11100 is not set # CONFIG_MAX1118 is not set +# CONFIG_MAX1241 is not set # CONFIG_MAX1363 is not set # CONFIG_MAX9611 is not set # CONFIG_MCP320X is not set @@ -5674,6 +5731,7 @@ CONFIG_IIO_RESCALE=m # Chemical Sensors # # CONFIG_ATLAS_PH_SENSOR is not set +# CONFIG_ATLAS_EZO_SENSOR is not set CONFIG_BME680=m CONFIG_BME680_I2C=m CONFIG_BME680_SPI=m @@ -5811,6 +5869,7 @@ CONFIG_SI7020=m # # CONFIG_ADIS16400 is not set CONFIG_ADIS16460=m +# CONFIG_ADIS16475 is not set # CONFIG_ADIS16480 is not set # CONFIG_BMI160_I2C is not set # CONFIG_BMI160_SPI is not set @@ -5976,8 +6035,10 @@ CONFIG_MB1232=m # CONFIG_PING is not set # CONFIG_RFD77402 is not set # CONFIG_SRF04 is not set +# CONFIG_SX9310 is not set # CONFIG_SX9500 is not set # CONFIG_SRF08 is not set +# CONFIG_VCNL3020 is not set # CONFIG_VL53L0X_I2C is not set # end of Proximity and distance sensors @@ -6035,6 +6096,7 @@ CONFIG_GENERIC_PHY=y # CONFIG_PHY_CADENCE_TORRENT is not set # CONFIG_PHY_CADENCE_DPHY is not set # CONFIG_PHY_CADENCE_SIERRA is not set +# CONFIG_PHY_CADENCE_SALVO is not set # CONFIG_PHY_FSL_IMX8MQ_USB is not set # CONFIG_PHY_MIXEL_MIPI_DPHY is not set # CONFIG_PHY_PXA_28NM_HSIC is not set @@ -6051,7 +6113,6 @@ CONFIG_PHY_ROCKCHIP_INNO_USB2=y # CONFIG_PHY_ROCKCHIP_TYPEC is not set CONFIG_PHY_ROCKCHIP_USB=y # CONFIG_PHY_SAMSUNG_USB2 is not set -# CONFIG_PHY_INTEL_EMMC is not set # end of PHY Subsystem # CONFIG_POWERCAP is not set @@ -6114,7 +6175,7 @@ CONFIG_MUX_MMIO=m CONFIG_PM_OPP=y # CONFIG_SIOX is not set # CONFIG_SLIMBUS is not set -CONFIG_INTERCONNECT=m +# CONFIG_INTERCONNECT is not set # CONFIG_COUNTER is not set CONFIG_MOST=m # end of Device Drivers @@ -6307,27 +6368,10 @@ CONFIG_PSTORE_CONSOLE=y # CONFIG_PSTORE_PMSG is not set # CONFIG_PSTORE_FTRACE is not set CONFIG_PSTORE_RAM=y +# CONFIG_PSTORE_BLK is not set # 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=y CONFIG_NFS_V2=y @@ -6448,7 +6492,6 @@ CONFIG_IO_WQ=y CONFIG_KEYS=y # CONFIG_KEYS_REQUEST_CACHE is not set # CONFIG_PERSISTENT_KEYRINGS is not set -# CONFIG_BIG_KEYS is not set # CONFIG_TRUSTED_KEYS is not set # CONFIG_ENCRYPTED_KEYS is not set # CONFIG_KEY_DH_OPERATIONS is not set @@ -6712,6 +6755,7 @@ CONFIG_BINARY_PRINTF=y # CONFIG_RAID6_PQ=y CONFIG_RAID6_PQ_BENCHMARK=y +CONFIG_LINEAR_RANGES=y CONFIG_PACKING=y CONFIG_BITREVERSE=y CONFIG_HAVE_ARCH_BITREVERSE=y @@ -6719,6 +6763,7 @@ CONFIG_GENERIC_STRNCPY_FROM_USER=y CONFIG_GENERIC_STRNLEN_USER=y CONFIG_GENERIC_NET_UTILS=y # CONFIG_CORDIC is not set +# CONFIG_PRIME_NUMBERS is not set CONFIG_RATIONAL=y CONFIG_GENERIC_PCI_IOMAP=y CONFIG_ARCH_USE_CMPXCHG_LOCKREF=y @@ -6835,6 +6880,7 @@ CONFIG_CONSOLE_LOGLEVEL_QUIET=4 CONFIG_MESSAGE_LOGLEVEL_DEFAULT=4 # CONFIG_BOOT_PRINTK_DELAY is not set # CONFIG_DYNAMIC_DEBUG is not set +# CONFIG_DYNAMIC_DEBUG_CORE is not set CONFIG_SYMBOLIC_ERRNAME=y CONFIG_DEBUG_BUGVERBOSE=y # end of printk and dmesg options @@ -6880,6 +6926,7 @@ CONFIG_PAGE_EXTENSION=y # CONFIG_PAGE_POISONING is not set # CONFIG_DEBUG_PAGE_REF is not set # CONFIG_DEBUG_RODATA_TEST is not set +# CONFIG_DEBUG_WX is not set # CONFIG_DEBUG_OBJECTS is not set # CONFIG_SLUB_DEBUG_ON is not set # CONFIG_SLUB_STATS is not set @@ -6894,6 +6941,7 @@ CONFIG_ARCH_HAS_DEBUG_VIRTUAL=y # CONFIG_DEBUG_PER_CPU_MAPS is not set # CONFIG_DEBUG_HIGHMEM is not set CONFIG_CC_HAS_KASAN_GENERIC=y +CONFIG_CC_HAS_WORKING_NOSANITIZE_ADDRESS=y CONFIG_KASAN_STACK=1 # end of Memory Debugging @@ -6996,7 +7044,6 @@ CONFIG_DYNAMIC_FTRACE=y CONFIG_DYNAMIC_FTRACE_WITH_REGS=y # CONFIG_FUNCTION_PROFILER is not set # CONFIG_STACK_TRACER is not set -# CONFIG_PREEMPTIRQ_EVENTS is not set # CONFIG_IRQSOFF_TRACER is not set # CONFIG_PREEMPT_TRACER is not set # CONFIG_SCHED_TRACER is not set @@ -7009,6 +7056,7 @@ CONFIG_BRANCH_PROFILE_NONE=y CONFIG_BLK_DEV_IO_TRACE=y # CONFIG_UPROBE_EVENTS is not set CONFIG_FTRACE_MCOUNT_RECORD=y +# CONFIG_SYNTH_EVENTS is not set # CONFIG_TRACE_EVENT_INJECT is not set # CONFIG_TRACEPOINT_BENCHMARK is not set # CONFIG_RING_BUFFER_BENCHMARK is not set @@ -7025,7 +7073,6 @@ CONFIG_STRICT_DEVMEM=y # arm Debugging # # CONFIG_ARM_PTDUMP_DEBUGFS is not set -# CONFIG_DEBUG_WX is not set CONFIG_UNWINDER_FRAME_POINTER=y # CONFIG_DEBUG_USER is not set # CONFIG_DEBUG_LL is not set diff --git a/config/kernel/linux-rk322x-dev.config b/config/kernel/linux-rk322x-dev.config index 1ad9cfcd9..fb2a2b1f4 100644 --- a/config/kernel/linux-rk322x-dev.config +++ b/config/kernel/linux-rk322x-dev.config @@ -1,6 +1,6 @@ # # Automatically generated file; DO NOT EDIT. -# Linux/arm 5.8.2 Kernel Configuration +# Linux/arm 5.8.9 Kernel Configuration # CONFIG_CC_VERSION_TEXT="arm-none-linux-gnueabihf-gcc (GNU Toolchain for the A-profile Architecture 9.2-2019.12 (arm-9.10)) 9.2.1 20191025" CONFIG_CC_IS_GCC=y @@ -2834,6 +2834,7 @@ CONFIG_SPI_SPIDEV=y # CONFIG_SPI_LOOPBACK_TEST is not set # CONFIG_SPI_TLE62X0 is not set # CONFIG_SPI_SLAVE is not set +CONFIG_SPI_DYNAMIC=y # CONFIG_SPMI is not set # CONFIG_HSI is not set CONFIG_PPS=y @@ -4201,6 +4202,7 @@ CONFIG_DRM_PANEL_BRIDGE=y # CONFIG_DRM_CDNS_DSI is not set # CONFIG_DRM_CHRONTEL_CH7033 is not set CONFIG_DRM_DISPLAY_CONNECTOR=m +# CONFIG_DRM_ITE_IT66121 is not set # CONFIG_DRM_LVDS_CODEC is not set # CONFIG_DRM_MEGACHIPS_STDPXXXX_GE_B850V3_FW is not set # CONFIG_DRM_NWL_MIPI_DSI is not set @@ -5445,6 +5447,7 @@ CONFIG_HAVE_CLK=y CONFIG_CLKDEV_LOOKUP=y CONFIG_HAVE_CLK_PREPARE=y CONFIG_COMMON_CLK=y +# CONFIG_CLK_HSDK is not set CONFIG_COMMON_CLK_MAX9485=m CONFIG_COMMON_CLK_RK808=y # CONFIG_COMMON_CLK_SI5341 is not set diff --git a/config/kernel/linux-rk322x-legacy.config b/config/kernel/linux-rk322x-legacy.config index b0dd4685f..278adc0a4 100644 --- a/config/kernel/linux-rk322x-legacy.config +++ b/config/kernel/linux-rk322x-legacy.config @@ -1925,6 +1925,10 @@ CONFIG_MVL88W8977=m # CONFIG_SSV6051=m # CONFIG_WL_TI is not set +CONFIG_RTL8822BU=m +CONFIG_RTL8821CU=m +CONFIG_88XXAU=m +CONFIG_RTL8192EU=m CONFIG_ZD1211RW=m # CONFIG_ZD1211RW_DEBUG is not set CONFIG_MWIFIEX=y @@ -2814,8 +2818,9 @@ CONFIG_MEDIA_CAMERA_SUPPORT=y CONFIG_MEDIA_DIGITAL_TV_SUPPORT=y # CONFIG_MEDIA_RADIO_SUPPORT is not set # CONFIG_MEDIA_SDR_SUPPORT is not set -# CONFIG_MEDIA_RC_SUPPORT is not set +CONFIG_MEDIA_RC_SUPPORT=y CONFIG_MEDIA_CEC_SUPPORT=y +CONFIG_MEDIA_CEC_RC=y CONFIG_MEDIA_CONTROLLER=y CONFIG_VIDEO_DEV=y CONFIG_VIDEO_V4L2_SUBDEV_API=y @@ -2840,6 +2845,33 @@ CONFIG_DVB_MAX_ADAPTERS=8 # # Media drivers # +CONFIG_RC_CORE=y +CONFIG_RC_MAP=y +# CONFIG_LIRC is not set +CONFIG_RC_DECODERS=y +CONFIG_IR_NEC_DECODER=y +CONFIG_IR_RC5_DECODER=y +CONFIG_IR_RC6_DECODER=y +CONFIG_IR_JVC_DECODER=y +CONFIG_IR_SONY_DECODER=y +CONFIG_IR_SANYO_DECODER=y +CONFIG_IR_SHARP_DECODER=y +CONFIG_IR_MCE_KBD_DECODER=y +CONFIG_IR_XMP_DECODER=y +# CONFIG_IR_IMON_DECODER is not set +CONFIG_RC_DEVICES=y +# CONFIG_RC_ATI_REMOTE is not set +# CONFIG_IR_HIX5HD2 is not set +# CONFIG_IR_IMON is not set +# CONFIG_IR_MCEUSB is not set +# CONFIG_IR_REDRAT3 is not set +# CONFIG_IR_STREAMZAP is not set +# CONFIG_IR_IGORPLUGUSB is not set +# CONFIG_IR_IGUANA is not set +# CONFIG_IR_TTUSBIR is not set +# CONFIG_RC_LOOPBACK is not set +CONFIG_IR_GPIO_CIR=m +# CONFIG_IR_SERIAL is not set CONFIG_MEDIA_USB_SUPPORT=y # @@ -2861,10 +2893,14 @@ CONFIG_USB_VIDEO_CLASS=y # CONFIG_VIDEO_AU0828=m CONFIG_VIDEO_AU0828_V4L2=y +# CONFIG_VIDEO_AU0828_RC is not set +# CONFIG_VIDEO_CX231XX is not set +# CONFIG_VIDEO_TM6000 is not set # # Digital TV USB devices # +# CONFIG_DVB_USB is not set CONFIG_DVB_USB_V2=y CONFIG_DVB_USB_AF9015=m CONFIG_DVB_USB_AF9035=m @@ -2874,6 +2910,7 @@ CONFIG_DVB_USB_AZ6007=m CONFIG_DVB_USB_CE6230=m CONFIG_DVB_USB_EC168=m CONFIG_DVB_USB_GL861=m +# CONFIG_DVB_USB_LME2510 is not set CONFIG_DVB_USB_MXL111SF=m CONFIG_DVB_USB_RTL28XXU=m CONFIG_DVB_USB_DVBSKY=m @@ -2926,6 +2963,7 @@ CONFIG_DVB_B2C2_FLEXCOP=m # # CONFIG_MEDIA_SUBDRV_AUTOSELECT is not set CONFIG_MEDIA_ATTACH=y +CONFIG_VIDEO_IR_I2C=y # # I2C Encoders, decoders, sensors and other helper chips @@ -3801,6 +3839,7 @@ CONFIG_HID_PICOLCD=m CONFIG_HID_PICOLCD_FB=y CONFIG_HID_PICOLCD_BACKLIGHT=y CONFIG_HID_PICOLCD_LEDS=y +# CONFIG_HID_PICOLCD_CIR is not set CONFIG_HID_PLANTRONICS=m CONFIG_HID_PRIMAX=m CONFIG_HID_ROCCAT=m diff --git a/config/sources/families/rk322x.conf b/config/sources/families/rk322x.conf index 91c6cf472..df304d3df 100644 --- a/config/sources/families/rk322x.conf +++ b/config/sources/families/rk322x.conf @@ -3,7 +3,7 @@ BOOTENV_FILE='rk322x.txt' OVERLAY_PREFIX='rk322x' UBOOT_TARGET_MAP="all u-boot.itb;;u-boot-rk322x-with-spl.bin" BOOTDELAY=0 -BOOTBRANCH='tag:v2020.04' +BOOTBRANCH='tag:v2020.07' ARCH=armhf SERIALCON=ttyS2 @@ -19,7 +19,7 @@ case $BRANCH in current) - KERNELBRANCH='branch:linux-5.7.y' + KERNELBRANCH='branch:linux-5.8.y' AUFS=no ;; @@ -57,7 +57,7 @@ uboot_custom_postprocess() # tools/mkimage -n rk322x -T rksd -d tpl/u-boot-tpl.bin u-boot-rk322x-with-spl.bin # - tools/mkimage -n rk322x -T rksd -d $SRC/packages/blobs/rockchip/rk322x_ddr2_300_ddr3_600_v1.09.bin u-boot-rk322x-with-spl.bin + tools/mkimage -n rk322x -T rksd -d $SRC/packages/blobs/rockchip/rk322x_ddr3_600MHz_ddr2_330MHz_v1.10.bin u-boot-rk322x-with-spl.bin cat spl/u-boot-spl.bin >> u-boot-rk322x-with-spl.bin dd if=u-boot.itb of=u-boot-rk322x-with-spl.bin seek=$((0x200 - 0x40)) conv=notrunc @@ -97,13 +97,9 @@ family_tweaks_bsp() cp $SRC/packages/bsp/rockchip/asound.conf $destination/etc/ cp $SRC/packages/bsp/rockchip/89-pulseaudio-usb.rules $destination/etc/udev/rules.d - # For rk322x boards copy ssv6051 wifi firmware files to /etc/firmware - # We don't want to copy it into /lib/firmware to not interfere with armbian - # firmware deb package, so for now put them in a separate position - mkdir -p $destination/etc/firmware - cp $SRC/packages/blobs/ssv6051/ssv6051-wifi.cfg $destination/etc/firmware - cp $SRC/packages/blobs/ssv6051/ssv6051-sw.bin $destination/etc/firmware - echo "options ssv6051 stacfgpath=/etc/firmware/ssv6051-wifi.cfg cfgfirmwarepath=/etc/firmware/" > $destination/etc/modprobe.d/ssv6051.conf + # esp8089 wifi driver modprobe default configuration options + mkdir -p $destination/etc/modprobe.d + cp $SRC/packages/bsp/rk322x/esp8089.conf $destination/etc/modprobe.d/esp8089.conf # Board selection script install -m 755 $SRC/packages/bsp/rk322x/rk322x-config $destination/usr/local/bin diff --git a/packages/blobs/rockchip/rk322x_ddr3_600MHz_ddr2_330MHz_v1.10.bin b/packages/blobs/rockchip/rk322x_ddr3_600MHz_ddr2_330MHz_v1.10.bin new file mode 100644 index 0000000000000000000000000000000000000000..fbc4e34b7a9796679a647894784ba341b2feb8de GIT binary patch literal 9124 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 X6bL9%qD)AIDmCgfXc7@K=70YHUNu3R literal 347672 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%0D7HtS<%#{%(w%yX!nWKdG&GXvUjW< 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 KxNfUe 00:33:33:33:33:33 -# 1. => Always random -# 2. => First random and write to file[Default path mac_output_path] -# -############################################################ -ignore_efuse_mac = 0 -#mac_address_path = /xxxx/xxxx -mac_address_mode = 2 -mac_output_path = /data/wifimac - -################################################## -# Hardware setting -# -#volt regulator(DCDC-0 LDO-1) -# -################################################## -xtal_clock = 24 -volt_regulator = 1 - -################################################## -# Default channel after wifi on -# value range: [1 ~ 14] -################################################## -def_chan = 6 -################################################## -# Hardware Capability Settings: -################################################## -hw_cap_ht = on -hw_cap_gf = off -hw_cap_2ghz = on -hw_cap_5ghz = off -hw_cap_security = on -hw_cap_sgi_20 = on -hw_cap_sgi_40 = off -hw_cap_ap = on -hw_cap_p2p = on -hw_cap_ampdu_rx = on -hw_cap_ampdu_tx = on -use_wpa2_only = 1 -################################################## -# TX power level setting [0-14] -# The larger the number the smaller the TX power -# 0 - The maximum power -# 1 level = -0.5db -# -# 6051Z .. 4 or 4 -# 6051Q .. 2 or 5 -# 6051P .. 0 or 0 -# -################################################## -#wifi_tx_gain_level_b = 2 -#wifi_tx_gain_level_gn = 5 -################################################ -# Signal strength control -# rssi control -#rssi_ctl = 10 - - -################################################## -# Import extenal configuration(UP to 64 groups) -# example: -# register = CE010010:91919191 -# register = 00CC0010:00091919 -################################################## diff --git a/packages/bsp/rk322x/40-serverflags.conf b/packages/bsp/rk322x/40-serverflags.conf index e40e146a0..735a8a141 100644 --- a/packages/bsp/rk322x/40-serverflags.conf +++ b/packages/bsp/rk322x/40-serverflags.conf @@ -1,10 +1,13 @@ Section "ServerFlags" - Option "AutoAddGPU" "off" + Option "AutoAddGPU" "off" + Option "Debug" "dmabuf_capable" EndSection -Section "Device" - Identifier "meson" - Driver "modesetting" - Option "kmsdev" "/dev/dri/card0" +Section "OutputClass" + Identifier "Lima" + Driver "modesetting" + MatchDriver "rockchip" + Option "AccelMethod" "none" + Option "PrimaryGPU" "true" EndSection diff --git a/packages/bsp/rk322x/esp8089.conf b/packages/bsp/rk322x/esp8089.conf new file mode 100644 index 000000000..c43b297c2 --- /dev/null +++ b/packages/bsp/rk322x/esp8089.conf @@ -0,0 +1 @@ +options esp8089 crystal_26M_en=0 diff --git a/patch/kernel/rk322x-current/01-linux-0001-rockchip-from-5.9.patch b/patch/kernel/rk322x-current/01-linux-0001-rockchip-from-5.9.patch new file mode 100644 index 000000000..d8845599b --- /dev/null +++ b/patch/kernel/rk322x-current/01-linux-0001-rockchip-from-5.9.patch @@ -0,0 +1,3987 @@ +From df792eba98fd6a729c254623ea28968f642efd1e Mon Sep 17 00:00:00 2001 +From: Tobias Schramm +Date: Thu, 28 May 2020 19:25:50 +0200 +Subject: [PATCH] arm64: dts: rockchip: add fuel gauge to Pinebook Pro dts + +This commit adds cw2015 fuel gauge and battery to the Pinebook Pro dts. + +Signed-off-by: Tobias Schramm +Link: https://lore.kernel.org/r/20200528172550.2324722-2-t.schramm@manjaro.org +Signed-off-by: Heiko Stuebner +(cherry picked from commit c7c4d698cd2882c4d095aeed43bbad6fc990e998) +--- + .../boot/dts/rockchip/rk3399-pinebook-pro.dts | 25 +++++++++++++++++++ + 1 file changed, 25 insertions(+) + +diff --git a/arch/arm64/boot/dts/rockchip/rk3399-pinebook-pro.dts b/arch/arm64/boot/dts/rockchip/rk3399-pinebook-pro.dts +index cb0245d2226d..8f5b2df01560 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3399-pinebook-pro.dts ++++ b/arch/arm64/boot/dts/rockchip/rk3399-pinebook-pro.dts +@@ -28,6 +28,13 @@ backlight: edp-backlight { + pwms = <&pwm0 0 740740 0>; + }; + ++ bat: battery { ++ compatible = "simple-battery"; ++ charge-full-design-microamp-hours = <9800000>; ++ voltage-max-design-microvolt = <4350000>; ++ voltage-min-design-microvolt = <3000000>; ++ }; ++ + edp_panel: edp-panel { + compatible = "boe,nv140fhmn49"; + backlight = <&backlight>; +@@ -741,6 +748,24 @@ usbc_dp: endpoint { + }; + }; + }; ++ ++ cw2015@62 { ++ compatible = "cellwise,cw2015"; ++ reg = <0x62>; ++ cellwise,battery-profile = /bits/ 8 < ++ 0x17 0x67 0x80 0x73 0x6E 0x6C 0x6B 0x63 ++ 0x77 0x51 0x5C 0x58 0x50 0x4C 0x48 0x36 ++ 0x15 0x0C 0x0C 0x19 0x5B 0x7D 0x6F 0x69 ++ 0x69 0x5B 0x0C 0x29 0x20 0x40 0x52 0x59 ++ 0x57 0x56 0x54 0x4F 0x3B 0x1F 0x7F 0x17 ++ 0x06 0x1A 0x30 0x5A 0x85 0x93 0x96 0x2D ++ 0x48 0x77 0x9C 0xB3 0x80 0x52 0x94 0xCB ++ 0x2F 0x00 0x64 0xA5 0xB5 0x11 0xF0 0x11 ++ >; ++ cellwise,monitor-interval-ms = <5000>; ++ monitored-battery = <&bat>; ++ power-supplies = <&mains_charger>, <&fusb0>; ++ }; + }; + + &i2s1 { + +From 279f038076d9ccc8a78c938eaf8008ff626ccb10 Mon Sep 17 00:00:00 2001 +From: Peter Geis +Date: Sun, 14 Jun 2020 14:29:51 +0000 +Subject: [PATCH] arm64: dts: rockchip: set rockpro64 usbc dr_mode as host + +The usb-c port on the rockpro64 does not detect devices reliably when in otg mode. +Setting the mode to "host" allows the port to work reliably. +This aligns with the pinebook-pro configuration. + +Signed-off-by: Peter Geis +Link: https://lore.kernel.org/r/20200614142950.1120694-1-pgwipeout@gmail.com +Signed-off-by: Heiko Stuebner +(cherry picked from commit 75152d66315521a48c4997305f4e01c5f139e160) +--- + arch/arm64/boot/dts/rockchip/rk3399-rockpro64.dtsi | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/rockchip/rk3399-rockpro64.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-rockpro64.dtsi +index 6788ab28f89a..3456ee97c288 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3399-rockpro64.dtsi ++++ b/arch/arm64/boot/dts/rockchip/rk3399-rockpro64.dtsi +@@ -795,7 +795,7 @@ &usbdrd3_0 { + + &usbdrd_dwc3_0 { + status = "okay"; +- dr_mode = "otg"; ++ dr_mode = "host"; + }; + + &usbdrd3_1 { + +From f739ccdaa19eac37af51d49e2d56e84b0bf62bfa Mon Sep 17 00:00:00 2001 +From: Johan Jonker +Date: Sun, 24 May 2020 18:06:36 +0200 +Subject: [PATCH] arm64: dts: rockchip: rename label and nodename pinctrl + subnodes that end with gpio + +A test with the command below gives for example this error: + +arch/arm64/boot/dts/rockchip/rk3326-odroid-go2.dt.yaml: +tsadc: tsadc-otp-gpio: +{'phandle': [[90]], 'rockchip,pins': [[0, 6, 0, 123]]} +is not of type 'array' + +'gpio' is a sort of reserved nodename and should not be used +for pinctrl in combination with 'rockchip,pins', so change +nodes that end with 'gpio' to end with 'pin' or 'pins'. + +make ARCH=arm64 dtbs_check +DT_SCHEMA_FILES=~/.local/lib/python3.5/site-packages/ +dtschema/schemas/gpio/gpio.yaml + +Signed-off-by: Johan Jonker +Link: https://lore.kernel.org/r/20200524160636.16547-2-jbx6244@gmail.com +Signed-off-by: Heiko Stuebner +(cherry picked from commit 2bc65fef4fe424f5f8295175f1b42f8b94c6df01) +--- + arch/arm64/boot/dts/rockchip/px30.dtsi | 6 +- + arch/arm64/boot/dts/rockchip/rk3308.dtsi | 6 +- + arch/arm64/boot/dts/rockchip/rk3328-evb.dts | 2 +- + .../arm64/boot/dts/rockchip/rk3328-roc-cc.dts | 2 +- + .../arm64/boot/dts/rockchip/rk3328-rock64.dts | 2 +- + arch/arm64/boot/dts/rockchip/rk3328.dtsi | 24 +++--- + .../boot/dts/rockchip/rk3368-lion-haikou.dts | 2 +- + arch/arm64/boot/dts/rockchip/rk3368.dtsi | 6 +- + .../boot/dts/rockchip/rk3399-firefly.dts | 4 +- + .../boot/dts/rockchip/rk3399-gru-scarlet.dtsi | 2 +- + arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi | 4 +- + .../boot/dts/rockchip/rk3399-hugsun-x99.dts | 8 +- + .../boot/dts/rockchip/rk3399-leez-p710.dts | 8 +- + .../boot/dts/rockchip/rk3399-pinebook-pro.dts | 74 +++++++++---------- + .../boot/dts/rockchip/rk3399-roc-pc.dtsi | 8 +- + .../boot/dts/rockchip/rk3399-rock-pi-4.dts | 8 +- + .../boot/dts/rockchip/rk3399-rock960.dtsi | 4 +- + .../boot/dts/rockchip/rk3399-rockpro64.dtsi | 8 +- + .../boot/dts/rockchip/rk3399-sapphire.dtsi | 4 +- + arch/arm64/boot/dts/rockchip/rk3399.dtsi | 6 +- + 20 files changed, 94 insertions(+), 94 deletions(-) + +diff --git a/arch/arm64/boot/dts/rockchip/px30.dtsi b/arch/arm64/boot/dts/rockchip/px30.dtsi +index a6b8427156d5..e9bb2b97ae55 100644 +--- a/arch/arm64/boot/dts/rockchip/px30.dtsi ++++ b/arch/arm64/boot/dts/rockchip/px30.dtsi +@@ -733,9 +733,9 @@ tsadc: tsadc@ff280000 { + rockchip,grf = <&grf>; + rockchip,hw-tshut-temp = <120000>; + pinctrl-names = "init", "default", "sleep"; +- pinctrl-0 = <&tsadc_otp_gpio>; ++ pinctrl-0 = <&tsadc_otp_pin>; + pinctrl-1 = <&tsadc_otp_out>; +- pinctrl-2 = <&tsadc_otp_gpio>; ++ pinctrl-2 = <&tsadc_otp_pin>; + #thermal-sensor-cells = <1>; + status = "disabled"; + }; +@@ -1373,7 +1373,7 @@ i2c3_xfer: i2c3-xfer { + }; + + tsadc { +- tsadc_otp_gpio: tsadc-otp-gpio { ++ tsadc_otp_pin: tsadc-otp-pin { + rockchip,pins = + <0 RK_PA6 RK_FUNC_GPIO &pcfg_pull_none>; + }; +diff --git a/arch/arm64/boot/dts/rockchip/rk3308.dtsi b/arch/arm64/boot/dts/rockchip/rk3308.dtsi +index ac7f694079d0..ba1c71568164 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3308.dtsi ++++ b/arch/arm64/boot/dts/rockchip/rk3308.dtsi +@@ -1629,7 +1629,7 @@ spi2_mosi: spi2-mosi { + }; + + tsadc { +- tsadc_otp_gpio: tsadc-otp-gpio { ++ tsadc_otp_pin: tsadc-otp-pin { + rockchip,pins = + <0 RK_PB2 0 &pcfg_pull_none>; + }; +@@ -1657,7 +1657,7 @@ uart0_rts: uart0-rts { + <2 RK_PA3 1 &pcfg_pull_none>; + }; + +- uart0_rts_gpio: uart0-rts-gpio { ++ uart0_rts_pin: uart0-rts-pin { + rockchip,pins = + <2 RK_PA3 0 &pcfg_pull_none>; + }; +@@ -1730,7 +1730,7 @@ uart4_rts: uart4-rts { + <4 RK_PA7 1 &pcfg_pull_none>; + }; + +- uart4_rts_gpio: uart4-rts-gpio { ++ uart4_rts_pin: uart4-rts-pin { + rockchip,pins = + <4 RK_PA7 0 &pcfg_pull_none>; + }; +diff --git a/arch/arm64/boot/dts/rockchip/rk3328-evb.dts b/arch/arm64/boot/dts/rockchip/rk3328-evb.dts +index ac29c2744d08..1969dab84138 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3328-evb.dts ++++ b/arch/arm64/boot/dts/rockchip/rk3328-evb.dts +@@ -41,7 +41,7 @@ vcc_sd: sdmmc-regulator { + compatible = "regulator-fixed"; + gpio = <&gpio0 30 GPIO_ACTIVE_LOW>; + pinctrl-names = "default"; +- pinctrl-0 = <&sdmmc0m1_gpio>; ++ pinctrl-0 = <&sdmmc0m1_pin>; + regulator-name = "vcc_sd"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; +diff --git a/arch/arm64/boot/dts/rockchip/rk3328-roc-cc.dts b/arch/arm64/boot/dts/rockchip/rk3328-roc-cc.dts +index 34db48c274e5..b70ffb1c6a63 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3328-roc-cc.dts ++++ b/arch/arm64/boot/dts/rockchip/rk3328-roc-cc.dts +@@ -34,7 +34,7 @@ vcc_sd: sdmmc-regulator { + compatible = "regulator-fixed"; + gpio = <&gpio0 RK_PD6 GPIO_ACTIVE_LOW>; + pinctrl-names = "default"; +- pinctrl-0 = <&sdmmc0m1_gpio>; ++ pinctrl-0 = <&sdmmc0m1_pin>; + regulator-boot-on; + regulator-name = "vcc_sd"; + regulator-min-microvolt = <3300000>; +diff --git a/arch/arm64/boot/dts/rockchip/rk3328-rock64.dts b/arch/arm64/boot/dts/rockchip/rk3328-rock64.dts +index 6e09c223ed57..86cfb5c50a94 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3328-rock64.dts ++++ b/arch/arm64/boot/dts/rockchip/rk3328-rock64.dts +@@ -25,7 +25,7 @@ vcc_sd: sdmmc-regulator { + compatible = "regulator-fixed"; + gpio = <&gpio0 RK_PD6 GPIO_ACTIVE_LOW>; + pinctrl-names = "default"; +- pinctrl-0 = <&sdmmc0m1_gpio>; ++ pinctrl-0 = <&sdmmc0m1_pin>; + regulator-name = "vcc_sd"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; +diff --git a/arch/arm64/boot/dts/rockchip/rk3328.dtsi b/arch/arm64/boot/dts/rockchip/rk3328.dtsi +index d399883d4b75..72e655020560 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3328.dtsi ++++ b/arch/arm64/boot/dts/rockchip/rk3328.dtsi +@@ -552,9 +552,9 @@ tsadc: tsadc@ff250000 { + clocks = <&cru SCLK_TSADC>, <&cru PCLK_TSADC>; + clock-names = "tsadc", "apb_pclk"; + pinctrl-names = "init", "default", "sleep"; +- pinctrl-0 = <&otp_gpio>; ++ pinctrl-0 = <&otp_pin>; + pinctrl-1 = <&otp_out>; +- pinctrl-2 = <&otp_gpio>; ++ pinctrl-2 = <&otp_pin>; + resets = <&cru SRST_TSADC>; + reset-names = "tsadc-apb"; + rockchip,grf = <&grf>; +@@ -1154,7 +1154,7 @@ i2c3_xfer: i2c3-xfer { + rockchip,pins = <0 RK_PA5 2 &pcfg_pull_none>, + <0 RK_PA6 2 &pcfg_pull_none>; + }; +- i2c3_gpio: i2c3-gpio { ++ i2c3_pins: i2c3-pins { + rockchip,pins = + <0 RK_PA5 RK_FUNC_GPIO &pcfg_pull_none>, + <0 RK_PA6 RK_FUNC_GPIO &pcfg_pull_none>; +@@ -1225,7 +1225,7 @@ pdmm0_fsync_sleep: pdmm0-fsync-sleep { + }; + + tsadc { +- otp_gpio: otp-gpio { ++ otp_pin: otp-pin { + rockchip,pins = <2 RK_PB5 RK_FUNC_GPIO &pcfg_pull_none>; + }; + +@@ -1248,7 +1248,7 @@ uart0_rts: uart0-rts { + rockchip,pins = <1 RK_PB2 1 &pcfg_pull_none>; + }; + +- uart0_rts_gpio: uart0-rts-gpio { ++ uart0_rts_pin: uart0-rts-pin { + rockchip,pins = <1 RK_PB2 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; +@@ -1267,7 +1267,7 @@ uart1_rts: uart1-rts { + rockchip,pins = <3 RK_PA5 4 &pcfg_pull_none>; + }; + +- uart1_rts_gpio: uart1-rts-gpio { ++ uart1_rts_pin: uart1-rts-pin { + rockchip,pins = <3 RK_PA5 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; +@@ -1493,7 +1493,7 @@ sdmmc0m0_pwren: sdmmc0m0-pwren { + rockchip,pins = <2 RK_PA7 1 &pcfg_pull_up_4ma>; + }; + +- sdmmc0m0_gpio: sdmmc0m0-gpio { ++ sdmmc0m0_pin: sdmmc0m0-pin { + rockchip,pins = <2 RK_PA7 RK_FUNC_GPIO &pcfg_pull_up_4ma>; + }; + }; +@@ -1503,7 +1503,7 @@ sdmmc0m1_pwren: sdmmc0m1-pwren { + rockchip,pins = <0 RK_PD6 3 &pcfg_pull_up_4ma>; + }; + +- sdmmc0m1_gpio: sdmmc0m1-gpio { ++ sdmmc0m1_pin: sdmmc0m1-pin { + rockchip,pins = <0 RK_PD6 RK_FUNC_GPIO &pcfg_pull_up_4ma>; + }; + }; +@@ -1536,7 +1536,7 @@ sdmmc0_bus4: sdmmc0-bus4 { + <1 RK_PA3 1 &pcfg_pull_up_8ma>; + }; + +- sdmmc0_gpio: sdmmc0-gpio { ++ sdmmc0_pins: sdmmc0-pins { + rockchip,pins = + <1 RK_PA6 RK_FUNC_GPIO &pcfg_pull_up_4ma>, + <1 RK_PA4 RK_FUNC_GPIO &pcfg_pull_up_4ma>, +@@ -1578,7 +1578,7 @@ sdmmc0ext_bus4: sdmmc0ext-bus4 { + <3 RK_PA7 3 &pcfg_pull_up_4ma>; + }; + +- sdmmc0ext_gpio: sdmmc0ext-gpio { ++ sdmmc0ext_pins: sdmmc0ext-pins { + rockchip,pins = + <3 RK_PA0 RK_FUNC_GPIO &pcfg_pull_up_4ma>, + <3 RK_PA1 RK_FUNC_GPIO &pcfg_pull_up_4ma>, +@@ -1623,7 +1623,7 @@ sdmmc1_bus4: sdmmc1-bus4 { + <1 RK_PC1 1 &pcfg_pull_up_8ma>; + }; + +- sdmmc1_gpio: sdmmc1-gpio { ++ sdmmc1_pins: sdmmc1-pins { + rockchip,pins = + <1 RK_PB4 RK_FUNC_GPIO &pcfg_pull_up_4ma>, + <1 RK_PB5 RK_FUNC_GPIO &pcfg_pull_up_4ma>, +@@ -1817,7 +1817,7 @@ tsadc_pin { + tsadc_int: tsadc-int { + rockchip,pins = <2 RK_PB5 2 &pcfg_pull_none>; + }; +- tsadc_gpio: tsadc-gpio { ++ tsadc_pin: tsadc-pin { + rockchip,pins = <2 RK_PB5 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; +diff --git a/arch/arm64/boot/dts/rockchip/rk3368-lion-haikou.dts b/arch/arm64/boot/dts/rockchip/rk3368-lion-haikou.dts +index cbde279ae81d..dbd2caba322f 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3368-lion-haikou.dts ++++ b/arch/arm64/boot/dts/rockchip/rk3368-lion-haikou.dts +@@ -125,7 +125,7 @@ led_sd_haikou: led-sd-gpio { + }; + + sdmmc { +- sdmmc_cd_gpio: sdmmc-cd-gpio { ++ sdmmc_cd_pin: sdmmc-cd-pin { + rockchip,pins = + <2 RK_PB3 RK_FUNC_GPIO &pcfg_pull_none>; + }; +diff --git a/arch/arm64/boot/dts/rockchip/rk3368.dtsi b/arch/arm64/boot/dts/rockchip/rk3368.dtsi +index 1ebb0eef42da..5d25a9d04051 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3368.dtsi ++++ b/arch/arm64/boot/dts/rockchip/rk3368.dtsi +@@ -483,9 +483,9 @@ tsadc: tsadc@ff280000 { + resets = <&cru SRST_TSADC>; + reset-names = "tsadc-apb"; + pinctrl-names = "init", "default", "sleep"; +- pinctrl-0 = <&otp_gpio>; ++ pinctrl-0 = <&otp_pin>; + pinctrl-1 = <&otp_out>; +- pinctrl-2 = <&otp_gpio>; ++ pinctrl-2 = <&otp_pin>; + #thermal-sensor-cells = <1>; + rockchip,hw-tshut-temp = <95000>; + status = "disabled"; +@@ -1145,7 +1145,7 @@ spi2_tx: spi2-tx { + }; + + tsadc { +- otp_gpio: otp-gpio { ++ otp_pin: otp-pin { + rockchip,pins = <0 RK_PA3 RK_FUNC_GPIO &pcfg_pull_none>; + }; + +diff --git a/arch/arm64/boot/dts/rockchip/rk3399-firefly.dts b/arch/arm64/boot/dts/rockchip/rk3399-firefly.dts +index 20b5599f5e78..6db18808b9c5 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3399-firefly.dts ++++ b/arch/arm64/boot/dts/rockchip/rk3399-firefly.dts +@@ -589,11 +589,11 @@ pcie_3g_drv: pcie-3g-drv { + }; + + pmic { +- vsel1_gpio: vsel1-gpio { ++ vsel1_pin: vsel1-pin { + rockchip,pins = <1 RK_PC2 RK_FUNC_GPIO &pcfg_pull_down>; + }; + +- vsel2_gpio: vsel2-gpio { ++ vsel2_pin: vsel2-pin { + rockchip,pins = <1 RK_PB6 RK_FUNC_GPIO &pcfg_pull_down>; + }; + }; +diff --git a/arch/arm64/boot/dts/rockchip/rk3399-gru-scarlet.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-gru-scarlet.dtsi +index 4373ed732af7..60cd1c18cd4e 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3399-gru-scarlet.dtsi ++++ b/arch/arm64/boot/dts/rockchip/rk3399-gru-scarlet.dtsi +@@ -499,7 +499,7 @@ &i2s0_8ch_bus { + }; + + /* there is no external pull up, so need to set this pin pull up */ +-&sdmmc_cd_gpio { ++&sdmmc_cd_pin { + rockchip,pins = <1 RK_PB3 RK_FUNC_GPIO &pcfg_pull_up>; + }; + +diff --git a/arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi +index 2f3997740068..32dcaf210085 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi ++++ b/arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi +@@ -516,7 +516,7 @@ &sdmmc { + * configured as SDMMC and not JTAG. + */ + pinctrl-names = "default"; +- pinctrl-0 = <&sdmmc_clk &sdmmc_cmd &sdmmc_cd &sdmmc_cd_gpio ++ pinctrl-0 = <&sdmmc_clk &sdmmc_cmd &sdmmc_cd &sdmmc_cd_pin + &sdmmc_bus4>; + + bus-width = <4>; +@@ -767,7 +767,7 @@ sdmmc_cd: sdmmc-cd { + }; + + /* This is where we actually hook up CD; has external pull */ +- sdmmc_cd_gpio: sdmmc-cd-gpio { ++ sdmmc_cd_pin: sdmmc-cd-pin { + rockchip,pins = <4 RK_PD0 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; +diff --git a/arch/arm64/boot/dts/rockchip/rk3399-hugsun-x99.dts b/arch/arm64/boot/dts/rockchip/rk3399-hugsun-x99.dts +index bf87fa32d3b1..341d074ed996 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3399-hugsun-x99.dts ++++ b/arch/arm64/boot/dts/rockchip/rk3399-hugsun-x99.dts +@@ -205,7 +205,7 @@ vdd_cpu_b: syr827@40 { + compatible = "silergy,syr827"; + reg = <0x40>; + regulator-compatible = "fan53555-reg"; +- pinctrl-0 = <&vsel1_gpio>; ++ pinctrl-0 = <&vsel1_pin>; + regulator-name = "vdd_cpu_b"; + regulator-min-microvolt = <712500>; + regulator-max-microvolt = <1500000>; +@@ -223,7 +223,7 @@ vdd_gpu: syr828@41 { + compatible = "silergy,syr828"; + reg = <0x41>; + regulator-compatible = "fan53555-reg"; +- pinctrl-0 = <&vsel2_gpio>; ++ pinctrl-0 = <&vsel2_pin>; + regulator-name = "vdd_gpu"; + regulator-min-microvolt = <712500>; + regulator-max-microvolt = <1500000>; +@@ -521,12 +521,12 @@ pmic_int_l: pmic-int-l { + <1 RK_PC5 RK_FUNC_GPIO &pcfg_pull_up>; + }; + +- vsel1_gpio: vsel1-gpio { ++ vsel1_pin: vsel1-pin { + rockchip,pins = + <1 RK_PC1 RK_FUNC_GPIO &pcfg_pull_down>; + }; + +- vsel2_gpio: vsel2-gpio { ++ vsel2_pin: vsel2-pin { + rockchip,pins = + <1 RK_PB6 RK_FUNC_GPIO &pcfg_pull_down>; + }; +diff --git a/arch/arm64/boot/dts/rockchip/rk3399-leez-p710.dts b/arch/arm64/boot/dts/rockchip/rk3399-leez-p710.dts +index 73be38a53796..1fa80ac15464 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3399-leez-p710.dts ++++ b/arch/arm64/boot/dts/rockchip/rk3399-leez-p710.dts +@@ -341,7 +341,7 @@ vdd_cpu_b: regulator@40 { + reg = <0x40>; + fcs,suspend-voltage-selector = <1>; + pinctrl-names = "default"; +- pinctrl-0 = <&vsel1_gpio>; ++ pinctrl-0 = <&vsel1_pin>; + regulator-name = "vdd_cpu_b"; + regulator-min-microvolt = <712500>; + regulator-max-microvolt = <1500000>; +@@ -360,7 +360,7 @@ vdd_gpu: regulator@41 { + reg = <0x41>; + fcs,suspend-voltage-selector = <1>; + pinctrl-names = "default"; +- pinctrl-0 = <&vsel2_gpio>; ++ pinctrl-0 = <&vsel2_pin>; + regulator-name = "vdd_gpu"; + regulator-min-microvolt = <712500>; + regulator-max-microvolt = <1500000>; +@@ -447,11 +447,11 @@ pmic_int_l: pmic-int-l { + rockchip,pins = <1 RK_PC5 RK_FUNC_GPIO &pcfg_pull_up>; + }; + +- vsel1_gpio: vsel1-gpio { ++ vsel1_pin: vsel1-pin { + rockchip,pins = <1 RK_PC1 RK_FUNC_GPIO &pcfg_pull_down>; + }; + +- vsel2_gpio: vsel2-gpio { ++ vsel2_pin: vsel2-pin { + rockchip,pins = <1 RK_PB6 RK_FUNC_GPIO &pcfg_pull_down>; + }; + }; +diff --git a/arch/arm64/boot/dts/rockchip/rk3399-pinebook-pro.dts b/arch/arm64/boot/dts/rockchip/rk3399-pinebook-pro.dts +index 8f5b2df01560..06d48338c836 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3399-pinebook-pro.dts ++++ b/arch/arm64/boot/dts/rockchip/rk3399-pinebook-pro.dts +@@ -40,7 +40,7 @@ edp_panel: edp-panel { + backlight = <&backlight>; + enable-gpios = <&gpio1 RK_PA0 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; +- pinctrl-0 = <&panel_en_gpio>; ++ pinctrl-0 = <&panel_en_pin>; + power-supply = <&vcc3v3_panel>; + + ports { +@@ -67,7 +67,7 @@ panel_in_edp: endpoint@0 { + gpio-key-lid { + compatible = "gpio-keys"; + pinctrl-names = "default"; +- pinctrl-0 = <&lidbtn_gpio>; ++ pinctrl-0 = <&lidbtn_pin>; + + lid { + debounce-interval = <20>; +@@ -83,7 +83,7 @@ lid { + gpio-key-power { + compatible = "gpio-keys"; + pinctrl-names = "default"; +- pinctrl-0 = <&pwrbtn_gpio>; ++ pinctrl-0 = <&pwrbtn_pin>; + + power { + debounce-interval = <20>; +@@ -124,7 +124,7 @@ sdio_pwrseq: sdio-pwrseq { + clocks = <&rk808 1>; + clock-names = "ext_clock"; + pinctrl-names = "default"; +- pinctrl-0 = <&wifi_enable_h_gpio>; ++ pinctrl-0 = <&wifi_enable_h_pin>; + post-power-on-delay-ms = <100>; + power-off-delay-us = <500000>; + +@@ -136,7 +136,7 @@ sdio_pwrseq: sdio-pwrseq { + es8316-sound { + compatible = "simple-audio-card"; + pinctrl-names = "default"; +- pinctrl-0 = <&hp_det_gpio>; ++ pinctrl-0 = <&hp_det_pin>; + simple-audio-card,name = "rockchip,es8316-codec"; + simple-audio-card,format = "i2s"; + simple-audio-card,mclk-fs = <256>; +@@ -220,7 +220,7 @@ vcc5v0_usb: pa_5v: vcc5v0-usb-regulator { + enable-active-high; + gpio = <&gpio1 RK_PB5 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; +- pinctrl-0 = <&pwr_5v_gpio>; ++ pinctrl-0 = <&pwr_5v_pin>; + regulator-name = "vcc5v0_usb"; + regulator-always-on; + regulator-min-microvolt = <5000000>; +@@ -277,7 +277,7 @@ vcc3v0_sd: vcc3v0-sd { + enable-active-high; + gpio = <&gpio0 RK_PA1 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; +- pinctrl-0 = <&sdmmc0_pwr_h_gpio>; ++ pinctrl-0 = <&sdmmc0_pwr_h_pin>; + regulator-name = "vcc3v0_sd"; + regulator-always-on; + regulator-min-microvolt = <3000000>; +@@ -295,7 +295,7 @@ vcc3v3_panel: vcc3v3-panel { + enable-active-high; + gpio = <&gpio1 RK_PC6 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; +- pinctrl-0 = <&lcdvcc_en_gpio>; ++ pinctrl-0 = <&lcdvcc_en_pin>; + regulator-name = "vcc3v3_panel"; + regulator-always-on; + regulator-min-microvolt = <3300000>; +@@ -324,7 +324,7 @@ vcc5v0_otg: vcc5v0-otg { + enable-active-high; + gpio = <&gpio4 RK_PD2 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; +- pinctrl-0 = <&vcc5v0_host_en_gpio>; ++ pinctrl-0 = <&vcc5v0_host_en_pin>; + regulator-name = "vcc5v0_otg"; + regulator-always-on; + regulator-min-microvolt = <5000000>; +@@ -343,7 +343,7 @@ vbus_5vout: vbus_typec: vbus-5vout { + enable-active-high; + gpio = <&gpio1 RK_PA3 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; +- pinctrl-0 = <&vcc5v0_typec0_en_gpio>; ++ pinctrl-0 = <&vcc5v0_typec0_en_pin>; + regulator-name = "vbus_5vout"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; +@@ -375,7 +375,7 @@ mains_charger: dc-charger { + + /* Also triggered by USB charger */ + pinctrl-names = "default"; +- pinctrl-0 = <&dc_det_gpio>; ++ pinctrl-0 = <&dc_det_pin>; + }; + }; + +@@ -454,7 +454,7 @@ rk808: pmic@1b { + interrupt-parent = <&gpio3>; + interrupts = <10 IRQ_TYPE_LEVEL_LOW>; + pinctrl-names = "default"; +- pinctrl-0 = <&pmic_int_l_gpio>; ++ pinctrl-0 = <&pmic_int_l_pin>; + rockchip,system-power-controller; + wakeup-source; + +@@ -634,7 +634,7 @@ vdd_cpu_b: regulator@40 { + reg = <0x40>; + fcs,suspend-voltage-selector = <1>; + pinctrl-names = "default"; +- pinctrl-0 = <&vsel1_gpio>; ++ pinctrl-0 = <&vsel1_pin>; + regulator-name = "vdd_cpu_b"; + regulator-always-on; + regulator-boot-on; +@@ -653,7 +653,7 @@ vdd_gpu: regulator@41 { + reg = <0x41>; + fcs,suspend-voltage-selector = <1>; + pinctrl-names = "default"; +- pinctrl-0 = <&vsel2_gpio>; ++ pinctrl-0 = <&vsel2_pin>; + regulator-name = "vdd_gpu"; + regulator-always-on; + regulator-boot-on; +@@ -700,7 +700,7 @@ fusb0: fusb30x@22 { + interrupt-parent = <&gpio1>; + interrupts = ; + pinctrl-names = "default"; +- pinctrl-0 = <&fusb0_int_gpio>; ++ pinctrl-0 = <&fusb0_int_pin>; + vbus-supply = <&vbus_typec>; + + connector { +@@ -770,7 +770,7 @@ cw2015@62 { + + &i2s1 { + pinctrl-names = "default"; +- pinctrl-0 = <&i2s_8ch_mclk_gpio>, <&i2s1_2ch_bus>; ++ pinctrl-0 = <&i2s_8ch_mclk_pin>, <&i2s1_2ch_bus>; + rockchip,capture-channels = <8>; + rockchip,playback-channels = <8>; + status = "okay"; +@@ -802,49 +802,49 @@ &pcie0 { + + &pinctrl { + buttons { +- pwrbtn_gpio: pwrbtn-gpio { ++ pwrbtn_pin: pwrbtn-pin { + rockchip,pins = <0 RK_PA5 RK_FUNC_GPIO &pcfg_pull_up>; + }; + +- lidbtn_gpio: lidbtn-gpio { ++ lidbtn_pin: lidbtn-pin { + rockchip,pins = <1 RK_PA1 RK_FUNC_GPIO &pcfg_pull_up>; + }; + }; + + dc-charger { +- dc_det_gpio: dc-det-gpio { ++ dc_det_pin: dc-det-pin { + rockchip,pins = <4 RK_PD0 RK_FUNC_GPIO &pcfg_pull_up>; + }; + }; + + es8316 { +- hp_det_gpio: hp-det-gpio { ++ hp_det_pin: hp-det-pin { + rockchip,pins = <0 RK_PB0 RK_FUNC_GPIO &pcfg_pull_up>; + }; + }; + + fusb302x { +- fusb0_int_gpio: fusb0-int-gpio { ++ fusb0_int_pin: fusb0-int-pin { + rockchip,pins = <1 RK_PA2 RK_FUNC_GPIO &pcfg_pull_up>; + }; + }; + + i2s1 { +- i2s_8ch_mclk_gpio: i2s-8ch-mclk-gpio { ++ i2s_8ch_mclk_pin: i2s-8ch-mclk-pin { + rockchip,pins = <4 RK_PA0 1 &pcfg_pull_none>; + }; + }; + + lcd-panel { +- lcdvcc_en_gpio: lcdvcc-en-gpio { ++ lcdvcc_en_pin: lcdvcc-en-pin { + rockchip,pins = <1 RK_PC6 RK_FUNC_GPIO &pcfg_pull_none>; + }; + +- panel_en_gpio: panel-en-gpio { ++ panel_en_pin: panel-en-pin { + rockchip,pins = <1 RK_PA0 RK_FUNC_GPIO &pcfg_pull_none>; + }; + +- lcd_panel_reset_gpio: lcd-panel-reset-gpio { ++ lcd_panel_reset_pin: lcd-panel-reset-pin { + rockchip,pins = <4 RK_PD6 RK_FUNC_GPIO &pcfg_pull_up>; + }; + }; +@@ -860,58 +860,58 @@ slp_led_pin: slp-led-pin { + }; + + pmic { +- pmic_int_l_gpio: pmic-int-l-gpio { ++ pmic_int_l_pin: pmic-int-l-pin { + rockchip,pins = <3 RK_PB2 RK_FUNC_GPIO &pcfg_pull_up>; + }; + +- vsel1_gpio: vsel1-gpio { ++ vsel1_pin: vsel1-pin { + rockchip,pins = <1 RK_PC1 RK_FUNC_GPIO &pcfg_pull_down>; + }; + +- vsel2_gpio: vsel2-gpio { ++ vsel2_pin: vsel2-pin { + rockchip,pins = <1 RK_PB6 RK_FUNC_GPIO &pcfg_pull_down>; + }; + }; + + sdcard { +- sdmmc0_pwr_h_gpio: sdmmc0-pwr-h-gpio { ++ sdmmc0_pwr_h_pin: sdmmc0-pwr-h-pin { + rockchip,pins = <0 RK_PA1 RK_FUNC_GPIO &pcfg_pull_none>; + }; + + }; + + sdio-pwrseq { +- wifi_enable_h_gpio: wifi-enable-h-gpio { ++ wifi_enable_h_pin: wifi-enable-h-pin { + rockchip,pins = <0 RK_PB2 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + + usb-typec { +- vcc5v0_typec0_en_gpio: vcc5v0-typec0-en-gpio { ++ vcc5v0_typec0_en_pin: vcc5v0-typec0-en-pin { + rockchip,pins = <1 RK_PA3 RK_FUNC_GPIO &pcfg_pull_up>; + }; + }; + + usb2 { +- pwr_5v_gpio: pwr-5v-gpio { ++ pwr_5v_pin: pwr-5v-pin { + rockchip,pins = <1 RK_PB5 RK_FUNC_GPIO &pcfg_pull_none>; + }; + +- vcc5v0_host_en_gpio: vcc5v0-host-en-gpio { ++ vcc5v0_host_en_pin: vcc5v0-host-en-pin { + rockchip,pins = <4 RK_PD2 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + + wireless-bluetooth { +- bt_wake_gpio: bt-wake-gpio { ++ bt_wake_pin: bt-wake-pin { + rockchip,pins = <2 RK_PD3 RK_FUNC_GPIO &pcfg_pull_none>; + }; + +- bt_host_wake_gpio: bt-host-wake-gpio { ++ bt_host_wake_pin: bt-host-wake-pin { + rockchip,pins = <0 RK_PA4 RK_FUNC_GPIO &pcfg_pull_none>; + }; + +- bt_reset_gpio: bt-reset-gpio { ++ bt_reset_pin: bt-reset-pin { + rockchip,pins = <0 RK_PB1 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; +@@ -1059,7 +1059,7 @@ bluetooth { + host-wakeup-gpios = <&gpio0 RK_PA4 GPIO_ACTIVE_HIGH>; + max-speed = <1500000>; + pinctrl-names = "default"; +- pinctrl-0 = <&bt_host_wake_gpio &bt_wake_gpio &bt_reset_gpio>; ++ pinctrl-0 = <&bt_host_wake_pin &bt_wake_pin &bt_reset_pin>; + shutdown-gpios = <&gpio0 RK_PB1 GPIO_ACTIVE_HIGH>; + vbat-supply = <&wifi_bat>; + vddio-supply = <&vcc_wl>; +diff --git a/arch/arm64/boot/dts/rockchip/rk3399-roc-pc.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-roc-pc.dtsi +index 9f225e9c3d54..59b89d6ccdef 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3399-roc-pc.dtsi ++++ b/arch/arm64/boot/dts/rockchip/rk3399-roc-pc.dtsi +@@ -456,7 +456,7 @@ vdd_cpu_b: regulator@40 { + reg = <0x40>; + fcs,suspend-voltage-selector = <1>; + pinctrl-names = "default"; +- pinctrl-0 = <&vsel1_gpio>; ++ pinctrl-0 = <&vsel1_pin>; + regulator-name = "vdd_cpu_b"; + regulator-min-microvolt = <712500>; + regulator-max-microvolt = <1500000>; +@@ -475,7 +475,7 @@ vdd_gpu: regulator@41 { + reg = <0x41>; + fcs,suspend-voltage-selector = <1>; + pinctrl-names = "default"; +- pinctrl-0 = <&vsel2_gpio>; ++ pinctrl-0 = <&vsel2_pin>; + regulator-name = "vdd_gpu"; + regulator-min-microvolt = <712500>; + regulator-max-microvolt = <1500000>; +@@ -609,11 +609,11 @@ yellow_led_gpio: yellow_led-gpio { + }; + + pmic { +- vsel1_gpio: vsel1-gpio { ++ vsel1_pin: vsel1-pin { + rockchip,pins = <1 RK_PC2 RK_FUNC_GPIO &pcfg_pull_down>; + }; + +- vsel2_gpio: vsel2-gpio { ++ vsel2_pin: vsel2-pin { + rockchip,pins = <1 RK_PB6 RK_FUNC_GPIO &pcfg_pull_down>; + }; + }; +diff --git a/arch/arm64/boot/dts/rockchip/rk3399-rock-pi-4.dts b/arch/arm64/boot/dts/rockchip/rk3399-rock-pi-4.dts +index 3923ec01ef66..60f98a3e19d8 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3399-rock-pi-4.dts ++++ b/arch/arm64/boot/dts/rockchip/rk3399-rock-pi-4.dts +@@ -390,7 +390,7 @@ vdd_cpu_b: regulator@40 { + reg = <0x40>; + fcs,suspend-voltage-selector = <1>; + pinctrl-names = "default"; +- pinctrl-0 = <&vsel1_gpio>; ++ pinctrl-0 = <&vsel1_pin>; + regulator-name = "vdd_cpu_b"; + regulator-min-microvolt = <712500>; + regulator-max-microvolt = <1500000>; +@@ -409,7 +409,7 @@ vdd_gpu: regulator@41 { + reg = <0x41>; + fcs,suspend-voltage-selector = <1>; + pinctrl-names = "default"; +- pinctrl-0 = <&vsel2_gpio>; ++ pinctrl-0 = <&vsel2_pin>; + regulator-name = "vdd_gpu"; + regulator-min-microvolt = <712500>; + regulator-max-microvolt = <1500000>; +@@ -532,11 +532,11 @@ pmic_int_l: pmic-int-l { + rockchip,pins = <1 RK_PC5 RK_FUNC_GPIO &pcfg_pull_up>; + }; + +- vsel1_gpio: vsel1-gpio { ++ vsel1_pin: vsel1-pin { + rockchip,pins = <1 RK_PC1 RK_FUNC_GPIO &pcfg_pull_down>; + }; + +- vsel2_gpio: vsel2-gpio { ++ vsel2_pin: vsel2-pin { + rockchip,pins = <1 RK_PB6 RK_FUNC_GPIO &pcfg_pull_down>; + }; + }; +diff --git a/arch/arm64/boot/dts/rockchip/rk3399-rock960.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-rock960.dtsi +index ba7c75c9f2a1..5e3ac589bc54 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3399-rock960.dtsi ++++ b/arch/arm64/boot/dts/rockchip/rk3399-rock960.dtsi +@@ -470,12 +470,12 @@ pmic_int_l: pmic-int-l { + <1 RK_PC5 RK_FUNC_GPIO &pcfg_pull_up>; + }; + +- vsel1_gpio: vsel1-gpio { ++ vsel1_pin: vsel1-pin { + rockchip,pins = + <1 RK_PC1 RK_FUNC_GPIO &pcfg_pull_down>; + }; + +- vsel2_gpio: vsel2-gpio { ++ vsel2_pin: vsel2-pin { + rockchip,pins = + <1 RK_PB6 RK_FUNC_GPIO &pcfg_pull_down>; + }; +diff --git a/arch/arm64/boot/dts/rockchip/rk3399-rockpro64.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-rockpro64.dtsi +index 3456ee97c288..c84cad16118a 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3399-rockpro64.dtsi ++++ b/arch/arm64/boot/dts/rockchip/rk3399-rockpro64.dtsi +@@ -445,7 +445,7 @@ vdd_cpu_b: regulator@40 { + reg = <0x40>; + fcs,suspend-voltage-selector = <1>; + pinctrl-names = "default"; +- pinctrl-0 = <&vsel1_gpio>; ++ pinctrl-0 = <&vsel1_pin>; + regulator-name = "vdd_cpu_b"; + regulator-min-microvolt = <712500>; + regulator-max-microvolt = <1500000>; +@@ -464,7 +464,7 @@ vdd_gpu: regulator@41 { + reg = <0x41>; + fcs,suspend-voltage-selector = <1>; + pinctrl-names = "default"; +- pinctrl-0 = <&vsel2_gpio>; ++ pinctrl-0 = <&vsel2_pin>; + regulator-name = "vdd_gpu"; + regulator-min-microvolt = <712500>; + regulator-max-microvolt = <1500000>; +@@ -612,11 +612,11 @@ pmic_int_l: pmic-int-l { + rockchip,pins = <3 RK_PB2 RK_FUNC_GPIO &pcfg_pull_up>; + }; + +- vsel1_gpio: vsel1-gpio { ++ vsel1_pin: vsel1-pin { + rockchip,pins = <1 RK_PC1 RK_FUNC_GPIO &pcfg_pull_down>; + }; + +- vsel2_gpio: vsel2-gpio { ++ vsel2_pin: vsel2-pin { + rockchip,pins = <1 RK_PB6 RK_FUNC_GPIO &pcfg_pull_down>; + }; + }; +diff --git a/arch/arm64/boot/dts/rockchip/rk3399-sapphire.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-sapphire.dtsi +index 1bc1579674e5..701a567d7638 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3399-sapphire.dtsi ++++ b/arch/arm64/boot/dts/rockchip/rk3399-sapphire.dtsi +@@ -481,11 +481,11 @@ pmic_int_l: pmic-int-l { + <1 RK_PC5 RK_FUNC_GPIO &pcfg_pull_up>; + }; + +- vsel1_gpio: vsel1-gpio { ++ vsel1_pin: vsel1-pin { + rockchip,pins = <1 RK_PC1 RK_FUNC_GPIO &pcfg_pull_down>; + }; + +- vsel2_gpio: vsel2-gpio { ++ vsel2_pin: vsel2-pin { + rockchip,pins = <1 RK_PB6 RK_FUNC_GPIO &pcfg_pull_down>; + }; + }; +diff --git a/arch/arm64/boot/dts/rockchip/rk3399.dtsi b/arch/arm64/boot/dts/rockchip/rk3399.dtsi +index 2581e9cc7a1d..781b5c2cdb4d 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3399.dtsi ++++ b/arch/arm64/boot/dts/rockchip/rk3399.dtsi +@@ -845,9 +845,9 @@ tsadc: tsadc@ff260000 { + rockchip,grf = <&grf>; + rockchip,hw-tshut-temp = <95000>; + pinctrl-names = "init", "default", "sleep"; +- pinctrl-0 = <&otp_gpio>; ++ pinctrl-0 = <&otp_pin>; + pinctrl-1 = <&otp_out>; +- pinctrl-2 = <&otp_gpio>; ++ pinctrl-2 = <&otp_pin>; + #thermal-sensor-cells = <1>; + status = "disabled"; + }; +@@ -2485,7 +2485,7 @@ test_clkout2: test-clkout2 { + }; + + tsadc { +- otp_gpio: otp-gpio { ++ otp_pin: otp-pin { + rockchip,pins = <1 RK_PA6 RK_FUNC_GPIO &pcfg_pull_none>; + }; + + +From b73a18f9f69f893cb7ae0155770d4eac8cc9874f Mon Sep 17 00:00:00 2001 +From: Johan Jonker +Date: Fri, 22 May 2020 17:46:57 +0200 +Subject: [PATCH] arm64: dts: rockchip: rename and label gpio-led subnodes part + 2 + +Current dts files with 'gpio-led' nodes were manually verified. +In order to automate this process leds-gpio.txt +has been converted to yaml. With this conversion a check +for pattern properties was added. In part 2 rename and label +gpio-led subnodes that passed the regex, but still don't have +the preferred form. Any pin subnode that ends with '-gpio' +in the pinctrl node generates a warning. + +Fix with help of the following rules: + +1: Add nodename in the preferred form. + +2: Always add a label that ends with '_led' to prevent conflicts + with other labels such as 'power' and 'mmc' + +3: If leds need pinctrl add a label that ends with '_led_pin' + also to prevent conflicts with other labels. + +patternProperties: + # The first form is preferred, but fall back to just 'led' + # anywhere in the node name to at least catch some child nodes. + "(^led-[0-9a-f]$|led)": + +make ARCH=arm64 dtbs_check +DT_SCHEMA_FILES=Documentation/devicetree/bindings/leds/ +leds-gpio.yaml + +make ARCH=arm64 dtbs_check +DT_SCHEMA_FILES=~/.local/lib/python3.5/site-packages/dtschema/ +schemas/gpio/gpio.yaml + +Signed-off-by: Johan Jonker +Link: https://lore.kernel.org/r/20200522154657.9472-1-jbx6244@gmail.com +Signed-off-by: Heiko Stuebner +(cherry picked from commit 6dd5e12c0b9bba40b3947ac1a9fd2f992585b5c6) +--- + .../arm64/boot/dts/rockchip/rk3368-lion-haikou.dts | 6 +++--- + arch/arm64/boot/dts/rockchip/rk3368-lion.dtsi | 8 ++++---- + .../boot/dts/rockchip/rk3399-khadas-edge.dtsi | 10 +++++----- + arch/arm64/boot/dts/rockchip/rk3399-nanopi4.dtsi | 6 +++--- + .../arm64/boot/dts/rockchip/rk3399-puma-haikou.dts | 6 +++--- + arch/arm64/boot/dts/rockchip/rk3399-puma.dtsi | 6 +++--- + arch/arm64/boot/dts/rockchip/rk3399-roc-pc.dtsi | 14 +++++++------- + arch/arm64/boot/dts/rockchip/rk3399-rockpro64.dtsi | 10 +++++----- + 8 files changed, 33 insertions(+), 33 deletions(-) + +diff --git a/arch/arm64/boot/dts/rockchip/rk3368-lion-haikou.dts b/arch/arm64/boot/dts/rockchip/rk3368-lion-haikou.dts +index dbd2caba322f..7fcb1eacea8a 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3368-lion-haikou.dts ++++ b/arch/arm64/boot/dts/rockchip/rk3368-lion-haikou.dts +@@ -25,9 +25,9 @@ eeprom: eeprom@50 { + }; + + leds { +- pinctrl-0 = <&led_pins_module>, <&led_sd_haikou>; ++ pinctrl-0 = <&module_led_pins>, <&sd_card_led_pin>; + +- sd-card-led { ++ sd_card_led: led-3 { + label = "sd_card_led"; + gpios = <&gpio0 RK_PD2 GPIO_ACTIVE_HIGH>; + linux,default-trigger = "mmc0"; +@@ -118,7 +118,7 @@ haikou_pin_hog: haikou-pin-hog { + }; + + leds { +- led_sd_haikou: led-sd-gpio { ++ sd_card_led_pin: sd-card-led-pin { + rockchip,pins = + <0 RK_PD2 RK_FUNC_GPIO &pcfg_pull_none>; + }; +diff --git a/arch/arm64/boot/dts/rockchip/rk3368-lion.dtsi b/arch/arm64/boot/dts/rockchip/rk3368-lion.dtsi +index 216aafd90e7f..24d28be4736c 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3368-lion.dtsi ++++ b/arch/arm64/boot/dts/rockchip/rk3368-lion.dtsi +@@ -76,16 +76,16 @@ i2c@1 { + leds { + compatible = "gpio-leds"; + pinctrl-names = "default"; +- pinctrl-0 = <&led_pins_module>; ++ pinctrl-0 = <&module_led_pins>; + +- module_led1 { ++ module_led1: led-1 { + label = "module_led1"; + gpios = <&gpio2 RK_PB5 GPIO_ACTIVE_HIGH>; + linux,default-trigger = "heartbeat"; + panic-indicator; + }; + +- module_led2 { ++ module_led2: led-2 { + label = "module_led2"; + gpios = <&gpio3 RK_PA3 GPIO_ACTIVE_HIGH>; + default-state = "off"; +@@ -270,7 +270,7 @@ &i2c2 { + + &pinctrl { + leds { +- led_pins_module: led-module-gpio { ++ module_led_pins: module-led-pins { + rockchip,pins = + <2 RK_PB5 RK_FUNC_GPIO &pcfg_pull_none>, + <3 RK_PA3 RK_FUNC_GPIO &pcfg_pull_none>; +diff --git a/arch/arm64/boot/dts/rockchip/rk3399-khadas-edge.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-khadas-edge.dtsi +index e87a04477440..e36837c04dc7 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3399-khadas-edge.dtsi ++++ b/arch/arm64/boot/dts/rockchip/rk3399-khadas-edge.dtsi +@@ -141,15 +141,15 @@ power { + leds { + compatible = "gpio-leds"; + pinctrl-names = "default"; +- pinctrl-0 = <&sys_led_gpio>, <&user_led_gpio>; ++ pinctrl-0 = <&sys_led_pin>, <&user_led_pin>; + +- sys-led { ++ sys_led: led-0 { + label = "sys_led"; + linux,default-trigger = "heartbeat"; + gpios = <&gpio0 RK_PA6 GPIO_ACTIVE_HIGH>; + }; + +- user-led { ++ user_led: led-1 { + label = "user_led"; + default-state = "off"; + gpios = <&gpio4 RK_PD0 GPIO_ACTIVE_HIGH>; +@@ -586,11 +586,11 @@ pwrbtn: pwrbtn { + }; + + leds { +- sys_led_gpio: sys_led-gpio { ++ sys_led_pin: sys-led-pin { + rockchip,pins = <0 RK_PA6 RK_FUNC_GPIO &pcfg_pull_none>; + }; + +- user_led_gpio: user_led-gpio { ++ user_led_pin: user-led-pin { + rockchip,pins = <4 RK_PD0 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; +diff --git a/arch/arm64/boot/dts/rockchip/rk3399-nanopi4.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-nanopi4.dtsi +index 1d246c2caa3c..76a8b40a93c6 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3399-nanopi4.dtsi ++++ b/arch/arm64/boot/dts/rockchip/rk3399-nanopi4.dtsi +@@ -117,9 +117,9 @@ power { + leds: gpio-leds { + compatible = "gpio-leds"; + pinctrl-names = "default"; +- pinctrl-0 = <&leds_gpio>; ++ pinctrl-0 = <&status_led_pin>; + +- status { ++ status_led: led-0 { + gpios = <&gpio0 RK_PB5 GPIO_ACTIVE_HIGH>; + label = "status_led"; + linux,default-trigger = "heartbeat"; +@@ -520,7 +520,7 @@ fusb0_int: fusb0-int { + }; + + gpio-leds { +- leds_gpio: leds-gpio { ++ status_led_pin: status-led-pin { + rockchip,pins = <0 RK_PB5 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; +diff --git a/arch/arm64/boot/dts/rockchip/rk3399-puma-haikou.dts b/arch/arm64/boot/dts/rockchip/rk3399-puma-haikou.dts +index d80d6b726820..a8d363568fd6 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3399-puma-haikou.dts ++++ b/arch/arm64/boot/dts/rockchip/rk3399-puma-haikou.dts +@@ -15,9 +15,9 @@ chosen { + }; + + leds { +- pinctrl-0 = <&led_pin_module>, <&led_sd_haikou>; ++ pinctrl-0 = <&module_led_pin>, <&sd_card_led_pin>; + +- sd-card-led { ++ sd_card_led: led-1 { + label = "sd_card_led"; + gpios = <&gpio1 RK_PA2 GPIO_ACTIVE_HIGH>; + linux,default-trigger = "mmc0"; +@@ -179,7 +179,7 @@ haikou_pin_hog: haikou-pin-hog { + }; + + leds { +- led_sd_haikou: led-sd-gpio { ++ sd_card_led_pin: sd-card-led-pin { + rockchip,pins = + <1 RK_PA2 RK_FUNC_GPIO &pcfg_pull_none>; + }; +diff --git a/arch/arm64/boot/dts/rockchip/rk3399-puma.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-puma.dtsi +index 72c06abd27ea..4660416c8f38 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3399-puma.dtsi ++++ b/arch/arm64/boot/dts/rockchip/rk3399-puma.dtsi +@@ -11,9 +11,9 @@ / { + leds { + compatible = "gpio-leds"; + pinctrl-names = "default"; +- pinctrl-0 = <&led_pin_module>; ++ pinctrl-0 = <&module_led_pin>; + +- module-led { ++ module_led: led-0 { + label = "module_led"; + gpios = <&gpio2 RK_PD1 GPIO_ACTIVE_HIGH>; + linux,default-trigger = "heartbeat"; +@@ -450,7 +450,7 @@ i2c8_xfer_a: i2c8-xfer { + }; + + leds { +- led_pin_module: led-module-gpio { ++ module_led_pin: module-led-pin { + rockchip,pins = + <2 RK_PD1 RK_FUNC_GPIO &pcfg_pull_none>; + }; +diff --git a/arch/arm64/boot/dts/rockchip/rk3399-roc-pc.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-roc-pc.dtsi +index 59b89d6ccdef..b85ec31cd283 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3399-roc-pc.dtsi ++++ b/arch/arm64/boot/dts/rockchip/rk3399-roc-pc.dtsi +@@ -61,23 +61,23 @@ power { + leds { + compatible = "gpio-leds"; + pinctrl-names = "default"; +- pinctrl-0 = <&work_led_gpio>, <&diy_led_gpio>, <&yellow_led_gpio>; ++ pinctrl-0 = <&work_led_pin>, <&diy_led_pin>, <&yellow_led_pin>; + +- work-led { ++ work_led: led-0 { + label = "green:work"; + gpios = <&gpio2 RK_PD3 GPIO_ACTIVE_HIGH>; + default-state = "on"; + linux,default-trigger = "heartbeat"; + }; + +- diy-led { ++ diy_led: led-1 { + label = "red:diy"; + gpios = <&gpio0 RK_PB5 GPIO_ACTIVE_HIGH>; + default-state = "off"; + linux,default-trigger = "mmc1"; + }; + +- yellow-led { ++ yellow_led: led-2 { + label = "yellow:yellow-led"; + gpios = <&gpio0 RK_PA2 GPIO_ACTIVE_HIGH>; + default-state = "off"; +@@ -595,15 +595,15 @@ lcd_panel_reset: lcd-panel-reset { + }; + + leds { +- diy_led_gpio: diy_led-gpio { ++ diy_led_pin: diy-led-pin { + rockchip,pins = <0 RK_PB5 RK_FUNC_GPIO &pcfg_pull_none>; + }; + +- work_led_gpio: work_led-gpio { ++ work_led_pin: work-led-pin { + rockchip,pins = <2 RK_PD3 RK_FUNC_GPIO &pcfg_pull_none>; + }; + +- yellow_led_gpio: yellow_led-gpio { ++ yellow_led_pin: yellow-led-pin { + rockchip,pins = <0 RK_PA2 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; +diff --git a/arch/arm64/boot/dts/rockchip/rk3399-rockpro64.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-rockpro64.dtsi +index c84cad16118a..6e553ff47534 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3399-rockpro64.dtsi ++++ b/arch/arm64/boot/dts/rockchip/rk3399-rockpro64.dtsi +@@ -39,15 +39,15 @@ power { + leds { + compatible = "gpio-leds"; + pinctrl-names = "default"; +- pinctrl-0 = <&work_led_gpio>, <&diy_led_gpio>; ++ pinctrl-0 = <&work_led_pin>, <&diy_led_pin>; + +- work-led { ++ work_led: led-0 { + label = "work"; + default-state = "on"; + gpios = <&gpio0 RK_PB3 GPIO_ACTIVE_HIGH>; + }; + +- diy-led { ++ diy_led: led-1 { + label = "diy"; + default-state = "off"; + gpios = <&gpio0 RK_PA2 GPIO_ACTIVE_HIGH>; +@@ -588,11 +588,11 @@ fusb0_int: fusb0-int { + }; + + leds { +- work_led_gpio: work_led-gpio { ++ work_led_pin: work-led-pin { + rockchip,pins = <0 RK_PB3 RK_FUNC_GPIO &pcfg_pull_none>; + }; + +- diy_led_gpio: diy_led-gpio { ++ diy_led_pin: diy-led-pin { + rockchip,pins = <0 RK_PA2 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + +From c40071fd1c70da63fdd7cc308114b34623d7eb91 Mon Sep 17 00:00:00 2001 +From: Johan Jonker +Date: Sun, 24 May 2020 18:06:35 +0200 +Subject: [PATCH] ARM: dts: rockchip: rename label and nodename pinctrl + subnodes that end with gpio + +A test with the command below gives for example this error: + +arch/arm/boot/dts/rk3288-tinker.dt.yaml: tsadc: otp-gpio: +{'phandle': [[54]], 'rockchip,pins': [[0, 10, 0, 118]]} +is not of type 'array' + +'gpio' is a sort of reserved nodename and should not be used +for pinctrl in combination with 'rockchip,pins', so change +nodes that end with 'gpio' to end with 'pin' or 'pins'. + +make ARCH=arm dtbs_check +DT_SCHEMA_FILES=~/.local/lib/python3.5/site-packages/ +dtschema/schemas/gpio/gpio.yaml + +Signed-off-by: Johan Jonker +Link: https://lore.kernel.org/r/20200524160636.16547-1-jbx6244@gmail.com +Signed-off-by: Heiko Stuebner +(cherry picked from commit fff987e7328951f7d6fb2d0545de8635ceafa89f) +--- + arch/arm/boot/dts/rk322x.dtsi | 6 +++--- + arch/arm/boot/dts/rk3288-veyron-jaq.dts | 2 +- + arch/arm/boot/dts/rk3288-veyron-jerry.dts | 2 +- + arch/arm/boot/dts/rk3288-veyron-mighty.dts | 6 +++--- + arch/arm/boot/dts/rk3288-veyron-minnie.dts | 2 +- + arch/arm/boot/dts/rk3288-veyron-pinky.dts | 6 +++--- + arch/arm/boot/dts/rk3288-veyron-sdmmc.dtsi | 2 +- + arch/arm/boot/dts/rk3288-veyron-speedy.dts | 2 +- + arch/arm/boot/dts/rk3288.dtsi | 6 +++--- + arch/arm/boot/dts/rv1108.dtsi | 12 ++++++------ + 10 files changed, 23 insertions(+), 23 deletions(-) + +diff --git a/arch/arm/boot/dts/rk322x.dtsi b/arch/arm/boot/dts/rk322x.dtsi +index b0fd92befdeb..3236abb0aba9 100644 +--- a/arch/arm/boot/dts/rk322x.dtsi ++++ b/arch/arm/boot/dts/rk322x.dtsi +@@ -520,9 +520,9 @@ tsadc: tsadc@11150000 { + resets = <&cru SRST_TSADC>; + reset-names = "tsadc-apb"; + pinctrl-names = "init", "default", "sleep"; +- pinctrl-0 = <&otp_gpio>; ++ pinctrl-0 = <&otp_pin>; + pinctrl-1 = <&otp_out>; +- pinctrl-2 = <&otp_gpio>; ++ pinctrl-2 = <&otp_pin>; + #thermal-sensor-cells = <0>; + rockchip,hw-tshut-temp = <95000>; + status = "disabled"; +@@ -1111,7 +1111,7 @@ spdif_tx: spdif-tx { + }; + + tsadc { +- otp_gpio: otp-gpio { ++ otp_pin: otp-pin { + rockchip,pins = <0 RK_PD0 RK_FUNC_GPIO &pcfg_pull_none>; + }; + +diff --git a/arch/arm/boot/dts/rk3288-veyron-jaq.dts b/arch/arm/boot/dts/rk3288-veyron-jaq.dts +index 171ba6185b6d..8efba9deae3c 100644 +--- a/arch/arm/boot/dts/rk3288-veyron-jaq.dts ++++ b/arch/arm/boot/dts/rk3288-veyron-jaq.dts +@@ -47,7 +47,7 @@ regulator-state-mem { + &sdmmc { + disable-wp; + pinctrl-names = "default"; +- pinctrl-0 = <&sdmmc_clk &sdmmc_cmd &sdmmc_cd_disabled &sdmmc_cd_gpio ++ pinctrl-0 = <&sdmmc_clk &sdmmc_cmd &sdmmc_cd_disabled &sdmmc_cd_pin + &sdmmc_bus4>; + }; + +diff --git a/arch/arm/boot/dts/rk3288-veyron-jerry.dts b/arch/arm/boot/dts/rk3288-veyron-jerry.dts +index 66f00d28801a..2c916c50dda5 100644 +--- a/arch/arm/boot/dts/rk3288-veyron-jerry.dts ++++ b/arch/arm/boot/dts/rk3288-veyron-jerry.dts +@@ -192,7 +192,7 @@ mwifiex: wifi@1 { + &sdmmc { + disable-wp; + pinctrl-names = "default"; +- pinctrl-0 = <&sdmmc_clk &sdmmc_cmd &sdmmc_cd_disabled &sdmmc_cd_gpio ++ pinctrl-0 = <&sdmmc_clk &sdmmc_cmd &sdmmc_cd_disabled &sdmmc_cd_pin + &sdmmc_bus4>; + }; + +diff --git a/arch/arm/boot/dts/rk3288-veyron-mighty.dts b/arch/arm/boot/dts/rk3288-veyron-mighty.dts +index 27fbc07476d2..fa695a88f236 100644 +--- a/arch/arm/boot/dts/rk3288-veyron-mighty.dts ++++ b/arch/arm/boot/dts/rk3288-veyron-mighty.dts +@@ -18,8 +18,8 @@ / { + }; + + &sdmmc { +- pinctrl-0 = <&sdmmc_clk &sdmmc_cmd &sdmmc_cd_disabled &sdmmc_cd_gpio +- &sdmmc_wp_gpio &sdmmc_bus4>; ++ pinctrl-0 = <&sdmmc_clk &sdmmc_cmd &sdmmc_cd_disabled &sdmmc_cd_pin ++ &sdmmc_wp_pin &sdmmc_bus4>; + wp-gpios = <&gpio7 10 GPIO_ACTIVE_HIGH>; + + /delete-property/ disable-wp; +@@ -27,7 +27,7 @@ &sdmmc { + + &pinctrl { + sdmmc { +- sdmmc_wp_gpio: sdmmc-wp-gpio { ++ sdmmc_wp_pin: sdmmc-wp-pin { + rockchip,pins = <7 RK_PB2 RK_FUNC_GPIO &pcfg_pull_up>; + }; + }; +diff --git a/arch/arm/boot/dts/rk3288-veyron-minnie.dts b/arch/arm/boot/dts/rk3288-veyron-minnie.dts +index 383fad1a88a1..f8b69e0a16a0 100644 +--- a/arch/arm/boot/dts/rk3288-veyron-minnie.dts ++++ b/arch/arm/boot/dts/rk3288-veyron-minnie.dts +@@ -114,7 +114,7 @@ regulator-state-mem { + &sdmmc { + disable-wp; + pinctrl-names = "default"; +- pinctrl-0 = <&sdmmc_clk &sdmmc_cmd &sdmmc_cd_disabled &sdmmc_cd_gpio ++ pinctrl-0 = <&sdmmc_clk &sdmmc_cmd &sdmmc_cd_disabled &sdmmc_cd_pin + &sdmmc_bus4>; + }; + +diff --git a/arch/arm/boot/dts/rk3288-veyron-pinky.dts b/arch/arm/boot/dts/rk3288-veyron-pinky.dts +index 71e6629cc208..4e9fdb0f722d 100644 +--- a/arch/arm/boot/dts/rk3288-veyron-pinky.dts ++++ b/arch/arm/boot/dts/rk3288-veyron-pinky.dts +@@ -105,7 +105,7 @@ emmc_reset: emmc-reset { + }; + + sdmmc { +- sdmmc_wp_gpio: sdmmc-wp-gpio { ++ sdmmc_wp_pin: sdmmc-wp-pin { + rockchip,pins = <7 RK_PB2 RK_FUNC_GPIO &pcfg_pull_up>; + }; + }; +@@ -126,8 +126,8 @@ regulator-state-mem { + + &sdmmc { + pinctrl-names = "default"; +- pinctrl-0 = <&sdmmc_clk &sdmmc_cmd &sdmmc_cd_disabled &sdmmc_cd_gpio +- &sdmmc_wp_gpio &sdmmc_bus4>; ++ pinctrl-0 = <&sdmmc_clk &sdmmc_cmd &sdmmc_cd_disabled &sdmmc_cd_pin ++ &sdmmc_wp_pin &sdmmc_bus4>; + wp-gpios = <&gpio7 RK_PB2 GPIO_ACTIVE_HIGH>; + }; + +diff --git a/arch/arm/boot/dts/rk3288-veyron-sdmmc.dtsi b/arch/arm/boot/dts/rk3288-veyron-sdmmc.dtsi +index fe950f9863e8..27fb06ce907e 100644 +--- a/arch/arm/boot/dts/rk3288-veyron-sdmmc.dtsi ++++ b/arch/arm/boot/dts/rk3288-veyron-sdmmc.dtsi +@@ -41,7 +41,7 @@ sdmmc_cd_disabled: sdmmc-cd-disabled { + }; + + /* This is where we actually hook up CD */ +- sdmmc_cd_gpio: sdmmc-cd-gpio { ++ sdmmc_cd_pin: sdmmc-cd-pin { + rockchip,pins = <7 RK_PA5 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; +diff --git a/arch/arm/boot/dts/rk3288-veyron-speedy.dts b/arch/arm/boot/dts/rk3288-veyron-speedy.dts +index e354c61a45e7..4a3ea934d03e 100644 +--- a/arch/arm/boot/dts/rk3288-veyron-speedy.dts ++++ b/arch/arm/boot/dts/rk3288-veyron-speedy.dts +@@ -54,7 +54,7 @@ &rk808 { + &sdmmc { + disable-wp; + pinctrl-names = "default"; +- pinctrl-0 = <&sdmmc_clk &sdmmc_cmd &sdmmc_cd_disabled &sdmmc_cd_gpio ++ pinctrl-0 = <&sdmmc_clk &sdmmc_cmd &sdmmc_cd_disabled &sdmmc_cd_pin + &sdmmc_bus4>; + }; + +diff --git a/arch/arm/boot/dts/rk3288.dtsi b/arch/arm/boot/dts/rk3288.dtsi +index 2e1edd85f04a..84d59469035e 100644 +--- a/arch/arm/boot/dts/rk3288.dtsi ++++ b/arch/arm/boot/dts/rk3288.dtsi +@@ -574,9 +574,9 @@ tsadc: tsadc@ff280000 { + resets = <&cru SRST_TSADC>; + reset-names = "tsadc-apb"; + pinctrl-names = "init", "default", "sleep"; +- pinctrl-0 = <&otp_gpio>; ++ pinctrl-0 = <&otp_pin>; + pinctrl-1 = <&otp_out>; +- pinctrl-2 = <&otp_gpio>; ++ pinctrl-2 = <&otp_pin>; + #thermal-sensor-cells = <1>; + rockchip,grf = <&grf>; + rockchip,hw-tshut-temp = <95000>; +@@ -1929,7 +1929,7 @@ uart4_rts: uart4-rts { + }; + + tsadc { +- otp_gpio: otp-gpio { ++ otp_pin: otp-pin { + rockchip,pins = <0 RK_PB2 RK_FUNC_GPIO &pcfg_pull_none>; + }; + +diff --git a/arch/arm/boot/dts/rv1108.dtsi b/arch/arm/boot/dts/rv1108.dtsi +index f9cfe2c80791..a5d130bd0547 100644 +--- a/arch/arm/boot/dts/rv1108.dtsi ++++ b/arch/arm/boot/dts/rv1108.dtsi +@@ -351,9 +351,9 @@ tsadc: tsadc@10370000 { + clocks = <&cru SCLK_TSADC>, <&cru PCLK_TSADC>; + clock-names = "tsadc", "apb_pclk"; + pinctrl-names = "init", "default", "sleep"; +- pinctrl-0 = <&otp_gpio>; ++ pinctrl-0 = <&otp_pin>; + pinctrl-1 = <&otp_out>; +- pinctrl-2 = <&otp_gpio>; ++ pinctrl-2 = <&otp_pin>; + resets = <&cru SRST_TSADC>; + reset-names = "tsadc-apb"; + rockchip,hw-tshut-temp = <120000>; +@@ -728,7 +728,7 @@ i2c2m1_xfer: i2c2m1-xfer { + <0 RK_PC6 3 &pcfg_pull_none>; + }; + +- i2c2m1_gpio: i2c2m1-gpio { ++ i2c2m1_pins: i2c2m1-pins { + rockchip,pins = <0 RK_PC2 RK_FUNC_GPIO &pcfg_pull_none>, + <0 RK_PC6 RK_FUNC_GPIO &pcfg_pull_none>; + }; +@@ -740,7 +740,7 @@ i2c2m05v_xfer: i2c2m05v-xfer { + <1 RK_PD4 2 &pcfg_pull_none>; + }; + +- i2c2m05v_gpio: i2c2m05v-gpio { ++ i2c2m05v_pins: i2c2m05v-pins { + rockchip,pins = <1 RK_PD5 RK_FUNC_GPIO &pcfg_pull_none>, + <1 RK_PD4 RK_FUNC_GPIO &pcfg_pull_none>; + }; +@@ -867,7 +867,7 @@ otp_out: otp-out { + rockchip,pins = <0 RK_PB7 1 &pcfg_pull_none>; + }; + +- otp_gpio: otp-gpio { ++ otp_pin: otp-pin { + rockchip,pins = <0 RK_PB7 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; +@@ -886,7 +886,7 @@ uart0_rts: uart0-rts { + rockchip,pins = <3 RK_PA3 1 &pcfg_pull_none>; + }; + +- uart0_rts_gpio: uart0-rts-gpio { ++ uart0_rts_pin: uart0-rts-pin { + rockchip,pins = <3 RK_PA3 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + +From c07b527960a7909caa8adb15247362f2319f1653 Mon Sep 17 00:00:00 2001 +From: Abhishek Pandit-Subedi +Date: Fri, 12 Jun 2020 13:02:48 -0700 +Subject: [PATCH] ARM: dts: rockchip: Add marvell BT irq config + +Veyron Jaq and Mighty both use the Marvel 8897 WiFi+BT chip. Add wakeup +and pinctrl block to devicetree so the btmrvl driver can correctly +configure the wakeup interrupt. + +Signed-off-by: Abhishek Pandit-Subedi +Reviewed-by: Douglas Anderson +Link: https://lore.kernel.org/r/20200612130219.v2.1.I66864be898aa835ccb66b6cd5220d0b082338a81@changeid +Signed-off-by: Heiko Stuebner +(cherry picked from commit 6c2b99a2e7a073575b4ee91abf7d16470991c1f4) +--- + arch/arm/boot/dts/rk3288-veyron-jaq.dts | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +diff --git a/arch/arm/boot/dts/rk3288-veyron-jaq.dts b/arch/arm/boot/dts/rk3288-veyron-jaq.dts +index 8efba9deae3c..af77ab20586d 100644 +--- a/arch/arm/boot/dts/rk3288-veyron-jaq.dts ++++ b/arch/arm/boot/dts/rk3288-veyron-jaq.dts +@@ -44,6 +44,21 @@ regulator-state-mem { + }; + }; + ++&sdio0 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ btmrvl: btmrvl@2 { ++ compatible = "marvell,sd8897-bt"; ++ reg = <2>; ++ interrupt-parent = <&gpio4>; ++ interrupts = ; ++ marvell,wakeup-pin = /bits/ 16 <13>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&bt_host_wake_l>; ++ }; ++}; ++ + &sdmmc { + disable-wp; + pinctrl-names = "default"; + +From f0ee8fdc42d8bb5a2cb126df71302324fb23866b Mon Sep 17 00:00:00 2001 +From: Sugar Zhang +Date: Thu, 4 Jun 2020 09:36:38 +0800 +Subject: [PATCH] dmaengine: pl330: Make sure the debug is idle before doing + DMAGO + +According to the datasheet of pl330: + +Example 2-1 Using DMAGO with the debug instruction registers + +1. Create a program for the DMA channel +2. Store the program in a region of system memory +3. Poll the DBGSTATUS Register to ensure that the debug is idle +4. Write to the DBGINST0 Register +5. Write to the DBGINST1 Register +6. Write zero to the DBGCMD Register + +so, we should make sure the debug is idle before step 4/5/6, not +only step 6. if not, there maybe a risk that fail to write DBGINST0/1. + +Signed-off-by: Sugar Zhang +Link: https://lore.kernel.org/r/1591234598-78919-1-git-send-email-sugar.zhang@rock-chips.com +Signed-off-by: Vinod Koul +(cherry picked from commit d12ea5591eddf625b7707c018b72e46e8674c3c2) +--- + drivers/dma/pl330.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c +index 88b884cbb7c1..6a158eef6b8a 100644 +--- a/drivers/dma/pl330.c ++++ b/drivers/dma/pl330.c +@@ -885,6 +885,12 @@ static inline void _execute_DBGINSN(struct pl330_thread *thrd, + void __iomem *regs = thrd->dmac->base; + u32 val; + ++ /* If timed out due to halted state-machine */ ++ if (_until_dmac_idle(thrd)) { ++ dev_err(thrd->dmac->ddma.dev, "DMAC halted!\n"); ++ return; ++ } ++ + val = (insn[0] << 16) | (insn[1] << 24); + if (!as_manager) { + val |= (1 << 0); +@@ -895,12 +901,6 @@ static inline void _execute_DBGINSN(struct pl330_thread *thrd, + val = le32_to_cpu(*((__le32 *)&insn[2])); + writel(val, regs + DBGINST1); + +- /* If timed out due to halted state-machine */ +- if (_until_dmac_idle(thrd)) { +- dev_err(thrd->dmac->ddma.dev, "DMAC halted!\n"); +- return; +- } +- + /* Get going */ + writel(0, regs + DBGCMD); + } + +From e5214dd97994bfdb32dcae94e03f18a794c43947 Mon Sep 17 00:00:00 2001 +From: Shunqian Zheng +Date: Fri, 3 Apr 2020 13:15:37 -0300 +Subject: [PATCH] arm64: dts: rockchip: add rx0 mipi-phy for rk3399 + +Designware MIPI D-PHY, used for ISP0 in rk3399. + +Verified with: +make ARCH=arm64 dtbs_check DT_SCHEMA_FILES=Documentation/devicetree/bindings/phy/rockchip-mipi-dphy-rx0.yaml + +Signed-off-by: Shunqian Zheng +Signed-off-by: Jacob Chen +Signed-off-by: Helen Koike +Link: https://lore.kernel.org/r/20200403161538.1375908-9-helen.koike@collabora.com +Signed-off-by: Heiko Stuebner +(cherry picked from commit e4bfde13e323f9ee5f2f38aa5cac0676dd656f8e) +--- + arch/arm64/boot/dts/rockchip/rk3399.dtsi | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/arch/arm64/boot/dts/rockchip/rk3399.dtsi b/arch/arm64/boot/dts/rockchip/rk3399.dtsi +index 781b5c2cdb4d..f2ef0d8ba54b 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3399.dtsi ++++ b/arch/arm64/boot/dts/rockchip/rk3399.dtsi +@@ -1397,6 +1397,17 @@ io_domains: io-domains { + status = "disabled"; + }; + ++ mipi_dphy_rx0: mipi-dphy-rx0 { ++ compatible = "rockchip,rk3399-mipi-dphy-rx0"; ++ clocks = <&cru SCLK_MIPIDPHY_REF>, ++ <&cru SCLK_DPHY_RX0_CFG>, ++ <&cru PCLK_VIO_GRF>; ++ clock-names = "dphy-ref", "dphy-cfg", "grf"; ++ power-domains = <&power RK3399_PD_VIO>; ++ #phy-cells = <0>; ++ status = "disabled"; ++ }; ++ + u2phy0: usb2-phy@e450 { + compatible = "rockchip,rk3399-usb2phy"; + reg = <0xe450 0x10>; + +From d2266424a494804c6709ea8231fc44e1ca376138 Mon Sep 17 00:00:00 2001 +From: Pierre-Louis Bossart +Date: Tue, 7 Jul 2020 14:06:10 -0500 +Subject: [PATCH] ASoC: codecs: es8316: fix 'defined but not used' warning + +Fix W=1 warning + +sound/soc/codecs/es8316.c:842:36: warning: 'es8316_acpi_match' defined +but not used [-Wunused-const-variable=] + 842 | static const struct acpi_device_id es8316_acpi_match[] = { + | ^~~~~~~~~~~~~~~~~ + +Signed-off-by: Pierre-Louis Bossart +Link: https://lore.kernel.org/r/20200707190612.97799-12-pierre-louis.bossart@linux.intel.com +Signed-off-by: Mark Brown +(cherry picked from commit 07ac670981fc5932ca3799ce7d96431d80afce0e) +--- + sound/soc/codecs/es8316.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/sound/soc/codecs/es8316.c b/sound/soc/codecs/es8316.c +index 36eef1fb3d18..70af35c5f727 100644 +--- a/sound/soc/codecs/es8316.c ++++ b/sound/soc/codecs/es8316.c +@@ -839,11 +839,13 @@ static const struct of_device_id es8316_of_match[] = { + }; + MODULE_DEVICE_TABLE(of, es8316_of_match); + ++#ifdef CONFIG_ACPI + static const struct acpi_device_id es8316_acpi_match[] = { + {"ESSX8316", 0}, + {}, + }; + MODULE_DEVICE_TABLE(acpi, es8316_acpi_match); ++#endif + + static struct i2c_driver es8316_i2c_driver = { + .driver = { + +From 2a38a809f8b033a5ddae29b81fb1209a897689f5 Mon Sep 17 00:00:00 2001 +From: Vinod Koul +Date: Wed, 8 Jul 2020 18:58:07 +0530 +Subject: [PATCH] phy: rockchip-typec: use correct format for structure + description + +We get warning with W=1 build: +drivers/phy/rockchip/phy-rockchip-typec.c:360: warning: cannot +understand function prototype: 'struct rockchip_usb3phy_port_cfg ' + +The 'struct rockchip_usb3phy_port_cfg ' is commented properly but uses +wrong format, so fix that up + +Link: https://lore.kernel.org/r/20200708132809.265967-4-vkoul@kernel.org +Signed-off-by: Vinod Koul +(cherry picked from commit 72fbf95f36218ec2a901e0eb7c3aa0bea6f1f396) +--- + drivers/phy/rockchip/phy-rockchip-typec.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/phy/rockchip/phy-rockchip-typec.c b/drivers/phy/rockchip/phy-rockchip-typec.c +index 24563160197f..70a31251b202 100644 +--- a/drivers/phy/rockchip/phy-rockchip-typec.c ++++ b/drivers/phy/rockchip/phy-rockchip-typec.c +@@ -347,7 +347,7 @@ struct usb3phy_reg { + }; + + /** +- * struct rockchip_usb3phy_port_cfg: usb3-phy port configuration. ++ * struct rockchip_usb3phy_port_cfg - usb3-phy port configuration. + * @reg: the base address for usb3-phy config. + * @typec_conn_dir: the register of type-c connector direction. + * @usb3tousb2_en: the register of type-c force usb2 to usb2 enable. + +From 4210b54dbec5ef3259494989feab48ffde364bb2 Mon Sep 17 00:00:00 2001 +From: Sugar Zhang +Date: Mon, 13 Jul 2020 18:26:00 +0800 +Subject: [PATCH] ASoC: rockchip: spdif: Handle clk by pm runtime + +This patch handle the clk by pm runtime mechanism to simplify +the clk management. + +Signed-off-by: Sugar Zhang +Link: https://lore.kernel.org/r/1594635960-67855-1-git-send-email-sugar.zhang@rock-chips.com +Signed-off-by: Mark Brown +(cherry picked from commit f50d67f9eff62f8078fe6e98ede3f4fb1defc361) +--- + sound/soc/rockchip/rockchip_spdif.c | 59 +++++++++-------------------- + 1 file changed, 17 insertions(+), 42 deletions(-) + +diff --git a/sound/soc/rockchip/rockchip_spdif.c b/sound/soc/rockchip/rockchip_spdif.c +index 6635145a26c4..674810851fbc 100644 +--- a/sound/soc/rockchip/rockchip_spdif.c ++++ b/sound/soc/rockchip/rockchip_spdif.c +@@ -306,44 +306,22 @@ static int rk_spdif_probe(struct platform_device *pdev) + return -ENOMEM; + + spdif->hclk = devm_clk_get(&pdev->dev, "hclk"); +- if (IS_ERR(spdif->hclk)) { +- dev_err(&pdev->dev, "Can't retrieve rk_spdif bus clock\n"); ++ if (IS_ERR(spdif->hclk)) + return PTR_ERR(spdif->hclk); +- } +- ret = clk_prepare_enable(spdif->hclk); +- if (ret) { +- dev_err(spdif->dev, "hclock enable failed %d\n", ret); +- return ret; +- } + + spdif->mclk = devm_clk_get(&pdev->dev, "mclk"); +- if (IS_ERR(spdif->mclk)) { +- dev_err(&pdev->dev, "Can't retrieve rk_spdif master clock\n"); +- ret = PTR_ERR(spdif->mclk); +- goto err_disable_hclk; +- } +- +- ret = clk_prepare_enable(spdif->mclk); +- if (ret) { +- dev_err(spdif->dev, "clock enable failed %d\n", ret); +- goto err_disable_clocks; +- } ++ if (IS_ERR(spdif->mclk)) ++ return PTR_ERR(spdif->mclk); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + regs = devm_ioremap_resource(&pdev->dev, res); +- if (IS_ERR(regs)) { +- ret = PTR_ERR(regs); +- goto err_disable_clocks; +- } ++ if (IS_ERR(regs)) ++ return PTR_ERR(regs); + + spdif->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "hclk", regs, + &rk_spdif_regmap_config); +- if (IS_ERR(spdif->regmap)) { +- dev_err(&pdev->dev, +- "Failed to initialise managed register map\n"); +- ret = PTR_ERR(spdif->regmap); +- goto err_disable_clocks; +- } ++ if (IS_ERR(spdif->regmap)) ++ return PTR_ERR(spdif->regmap); + + spdif->playback_dma_data.addr = res->start + SPDIF_SMPDR; + spdif->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; +@@ -352,47 +330,44 @@ static int rk_spdif_probe(struct platform_device *pdev) + spdif->dev = &pdev->dev; + dev_set_drvdata(&pdev->dev, spdif); + +- pm_runtime_set_active(&pdev->dev); + pm_runtime_enable(&pdev->dev); +- pm_request_idle(&pdev->dev); ++ if (!pm_runtime_enabled(&pdev->dev)) { ++ ret = rk_spdif_runtime_resume(&pdev->dev); ++ if (ret) ++ goto err_pm_runtime; ++ } + + ret = devm_snd_soc_register_component(&pdev->dev, + &rk_spdif_component, + &rk_spdif_dai, 1); + if (ret) { + dev_err(&pdev->dev, "Could not register DAI\n"); +- goto err_pm_runtime; ++ goto err_pm_suspend; + } + + ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0); + if (ret) { + dev_err(&pdev->dev, "Could not register PCM\n"); +- goto err_pm_runtime; ++ goto err_pm_suspend; + } + + return 0; + ++err_pm_suspend: ++ if (!pm_runtime_status_suspended(&pdev->dev)) ++ rk_spdif_runtime_suspend(&pdev->dev); + err_pm_runtime: + pm_runtime_disable(&pdev->dev); +-err_disable_clocks: +- clk_disable_unprepare(spdif->mclk); +-err_disable_hclk: +- clk_disable_unprepare(spdif->hclk); + + return ret; + } + + static int rk_spdif_remove(struct platform_device *pdev) + { +- struct rk_spdif_dev *spdif = dev_get_drvdata(&pdev->dev); +- + pm_runtime_disable(&pdev->dev); + if (!pm_runtime_status_suspended(&pdev->dev)) + rk_spdif_runtime_suspend(&pdev->dev); + +- clk_disable_unprepare(spdif->mclk); +- clk_disable_unprepare(spdif->hclk); +- + return 0; + } + + +From 6af0776af231629c2331f81faa2fdb311cf3ed44 Mon Sep 17 00:00:00 2001 +From: Katsuhiro Suzuki +Date: Tue, 14 Jul 2020 16:32:47 +0900 +Subject: [PATCH] ASoC: convert rk3328 codec binding to yaml + +This patch converts Rockchip rk3328 audio codec binding to DT schema. +And adds description about "mclk" clock and fixes some errors in +original example. + +Signed-off-by: Katsuhiro Suzuki +Reviewed-by: Rob Herring +Link: https://lore.kernel.org/r/20200714073247.172859-1-katsuhiro@katsuster.net +Signed-off-by: Mark Brown +(cherry picked from commit 3f6597ad2f9ed8ed89dbd2a9ec0b0c892774f9d2) +--- + .../bindings/sound/rockchip,rk3328-codec.txt | 28 -------- + .../bindings/sound/rockchip,rk3328-codec.yaml | 69 +++++++++++++++++++ + 2 files changed, 69 insertions(+), 28 deletions(-) + delete mode 100644 Documentation/devicetree/bindings/sound/rockchip,rk3328-codec.txt + create mode 100644 Documentation/devicetree/bindings/sound/rockchip,rk3328-codec.yaml + +diff --git a/Documentation/devicetree/bindings/sound/rockchip,rk3328-codec.txt b/Documentation/devicetree/bindings/sound/rockchip,rk3328-codec.txt +deleted file mode 100644 +index 1ecd75d2032a..000000000000 +--- a/Documentation/devicetree/bindings/sound/rockchip,rk3328-codec.txt ++++ /dev/null +@@ -1,28 +0,0 @@ +-* Rockchip Rk3328 internal codec +- +-Required properties: +- +-- compatible: "rockchip,rk3328-codec" +-- reg: physical base address of the controller and length of memory mapped +- region. +-- rockchip,grf: the phandle of the syscon node for GRF register. +-- clocks: a list of phandle + clock-specifer pairs, one for each entry in clock-names. +-- clock-names: should be "pclk". +-- spk-depop-time-ms: speak depop time msec. +- +-Optional properties: +- +-- mute-gpios: GPIO specifier for external line driver control (typically the +- dedicated GPIO_MUTE pin) +- +-Example for rk3328 internal codec: +- +-codec: codec@ff410000 { +- compatible = "rockchip,rk3328-codec"; +- reg = <0x0 0xff410000 0x0 0x1000>; +- rockchip,grf = <&grf>; +- clocks = <&cru PCLK_ACODEC>; +- clock-names = "pclk"; +- mute-gpios = <&grf_gpio 0 GPIO_ACTIVE_LOW>; +- spk-depop-time-ms = 100; +-}; +diff --git a/Documentation/devicetree/bindings/sound/rockchip,rk3328-codec.yaml b/Documentation/devicetree/bindings/sound/rockchip,rk3328-codec.yaml +new file mode 100644 +index 000000000000..5b85ad5e4834 +--- /dev/null ++++ b/Documentation/devicetree/bindings/sound/rockchip,rk3328-codec.yaml +@@ -0,0 +1,69 @@ ++# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/sound/rockchip,rk3328-codec.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: Rockchip rk3328 internal codec ++ ++maintainers: ++ - Heiko Stuebner ++ ++properties: ++ compatible: ++ const: rockchip,rk3328-codec ++ ++ reg: ++ maxItems: 1 ++ ++ clocks: ++ items: ++ - description: clock for audio codec ++ - description: clock for I2S master clock ++ ++ clock-names: ++ items: ++ - const: pclk ++ - const: mclk ++ ++ rockchip,grf: ++ $ref: /schemas/types.yaml#/definitions/phandle ++ description: ++ The phandle of the syscon node for the GRF register. ++ ++ spk-depop-time-ms: ++ default: 200 ++ description: ++ Speaker depop time in msec. ++ ++ mute-gpios: ++ maxItems: 1 ++ description: ++ GPIO specifier for external line driver control (typically the ++ dedicated GPIO_MUTE pin) ++ ++ "#sound-dai-cells": ++ const: 0 ++ ++required: ++ - compatible ++ - reg ++ - clocks ++ - clock-names ++ - rockchip,grf ++ - "#sound-dai-cells" ++ ++examples: ++ - | ++ #include ++ #include ++ codec: codec@ff410000 { ++ compatible = "rockchip,rk3328-codec"; ++ reg = <0xff410000 0x1000>; ++ clocks = <&cru PCLK_ACODECPHY>, <&cru SCLK_I2S1>; ++ clock-names = "pclk", "mclk"; ++ rockchip,grf = <&grf>; ++ mute-gpios = <&grf_gpio 0 GPIO_ACTIVE_LOW>; ++ spk-depop-time-ms = <100>; ++ #sound-dai-cells = <0>; ++ }; + +From 6917bb6287536dbdd26511d0ba6e6b82bc0f5d86 Mon Sep 17 00:00:00 2001 +From: Sugar Zhang +Date: Mon, 29 Jun 2020 22:05:42 +0800 +Subject: [PATCH] dmaengine: pl330: Remove the burst limit for quirk + 'NO-FLUSHP' + +There is no reason to limit the performance on the 'NO-FLUSHP' SoCs, +because 'FLUSHP' instruction is broken on these platforms, so remove +the limit to improve the efficiency. + +Signed-off-by: Sugar Zhang +Link: https://lore.kernel.org/r/1593439555-68130-2-git-send-email-sugar.zhang@rock-chips.com +Signed-off-by: Vinod Koul +(cherry picked from commit 05611a93b8ffa3fe7d2eb43dd6c11e37ead5908a) +--- + drivers/dma/pl330.c | 10 ++-------- + 1 file changed, 2 insertions(+), 8 deletions(-) + +diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c +index 6a158eef6b8a..7686292bc1db 100644 +--- a/drivers/dma/pl330.c ++++ b/drivers/dma/pl330.c +@@ -1183,9 +1183,6 @@ static inline int _ldst_peripheral(struct pl330_dmac *pl330, + { + int off = 0; + +- if (pl330->quirks & PL330_QUIRK_BROKEN_NO_FLUSHP) +- cond = BURST; +- + /* + * do FLUSHP at beginning to clear any stale dma requests before the + * first WFP. +@@ -2221,9 +2218,7 @@ static bool pl330_prep_slave_fifo(struct dma_pl330_chan *pch, + + static int fixup_burst_len(int max_burst_len, int quirks) + { +- if (quirks & PL330_QUIRK_BROKEN_NO_FLUSHP) +- return 1; +- else if (max_burst_len > PL330_MAX_BURST) ++ if (max_burst_len > PL330_MAX_BURST) + return PL330_MAX_BURST; + else if (max_burst_len < 1) + return 1; +@@ -3128,8 +3123,7 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id) + pd->dst_addr_widths = PL330_DMA_BUSWIDTHS; + pd->directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV); + pd->residue_granularity = DMA_RESIDUE_GRANULARITY_BURST; +- pd->max_burst = ((pl330->quirks & PL330_QUIRK_BROKEN_NO_FLUSHP) ? +- 1 : PL330_MAX_BURST); ++ pd->max_burst = PL330_MAX_BURST; + + ret = dma_async_device_register(pd); + if (ret) { + +From cb00fa158b947abf47ce2f256139a849b3bc8f2e Mon Sep 17 00:00:00 2001 +From: Sugar Zhang +Date: Mon, 29 Jun 2020 22:05:43 +0800 +Subject: [PATCH] dmaengine: pl330: Improve transfer efficiency for the dregs + +Only the unaligned burst transfers have the dregs. +so, still use BURST transfer with a reduced size +for better performance. + +Signed-off-by: Sugar Zhang +Link: https://lore.kernel.org/r/1593439555-68130-3-git-send-email-sugar.zhang@rock-chips.com +Signed-off-by: Vinod Koul +(cherry picked from commit 3e7f0bd872087bf4653eeee9a83050f91baae907) +--- + drivers/dma/pl330.c | 32 +++++++++++++++++++++----------- + 1 file changed, 21 insertions(+), 11 deletions(-) + +diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c +index 7686292bc1db..f1f0176c6c05 100644 +--- a/drivers/dma/pl330.c ++++ b/drivers/dma/pl330.c +@@ -1228,8 +1228,9 @@ static int _bursts(struct pl330_dmac *pl330, unsigned dry_run, u8 buf[], + } + + /* +- * transfer dregs with single transfers to peripheral, or a reduced size burst +- * for mem-to-mem. ++ * only the unaligned burst transfers have the dregs. ++ * so, still transfer dregs with a reduced size burst ++ * for mem-to-mem, mem-to-dev or dev-to-mem. + */ + static int _dregs(struct pl330_dmac *pl330, unsigned int dry_run, u8 buf[], + const struct _xfer_spec *pxs, int transfer_length) +@@ -1240,22 +1241,31 @@ static int _dregs(struct pl330_dmac *pl330, unsigned int dry_run, u8 buf[], + if (transfer_length == 0) + return off; + ++ /* ++ * dregs_len = (total bytes - BURST_TO_BYTE(bursts, ccr)) / ++ * BRST_SIZE(ccr) ++ * the dregs len must be smaller than burst len, ++ * so, for higher efficiency, we can modify CCR ++ * to use a reduced size burst len for the dregs. ++ */ ++ dregs_ccr = pxs->ccr; ++ dregs_ccr &= ~((0xf << CC_SRCBRSTLEN_SHFT) | ++ (0xf << CC_DSTBRSTLEN_SHFT)); ++ dregs_ccr |= (((transfer_length - 1) & 0xf) << ++ CC_SRCBRSTLEN_SHFT); ++ dregs_ccr |= (((transfer_length - 1) & 0xf) << ++ CC_DSTBRSTLEN_SHFT); ++ + switch (pxs->desc->rqtype) { + case DMA_MEM_TO_DEV: + /* fall through */ + case DMA_DEV_TO_MEM: +- off += _ldst_peripheral(pl330, dry_run, &buf[off], pxs, +- transfer_length, SINGLE); ++ off += _emit_MOV(dry_run, &buf[off], CCR, dregs_ccr); ++ off += _ldst_peripheral(pl330, dry_run, &buf[off], pxs, 1, ++ BURST); + break; + + case DMA_MEM_TO_MEM: +- dregs_ccr = pxs->ccr; +- dregs_ccr &= ~((0xf << CC_SRCBRSTLEN_SHFT) | +- (0xf << CC_DSTBRSTLEN_SHFT)); +- dregs_ccr |= (((transfer_length - 1) & 0xf) << +- CC_SRCBRSTLEN_SHFT); +- dregs_ccr |= (((transfer_length - 1) & 0xf) << +- CC_DSTBRSTLEN_SHFT); + off += _emit_MOV(dry_run, &buf[off], CCR, dregs_ccr); + off += _ldst_memtomem(dry_run, &buf[off], pxs, 1); + break; + +From 73de2b83dab82d5b7ad55360f14b1aa35e55eb8f Mon Sep 17 00:00:00 2001 +From: Sugar Zhang +Date: Mon, 29 Jun 2020 22:05:45 +0800 +Subject: [PATCH] dmaengine: pl330: Add quirk 'arm,pl330-periph-burst' + +This patch adds the qurik to use burst transfers only +for pl330 controller, even for request with a length of 1. + +Although, the correct way should be: if the peripheral request +length is 1, the peripheral should use SINGLE request, and then +notify the dmac using SINGLE mode by src/dst_maxburst with 1. + +For example, on the Rockchip SoCs, all the peripherals can use +SINGLE or BURST request by setting GRF registers. it is possible +that if these peripheral drivers are used only for Rockchip SoCs. +Unfortunately, it's not, such as dw uart, which is used so widely, +and we can't set src/dst_maxburst according to the SoCs' specific +to compatible with all the other SoCs. + +So, for convenience, all the peripherals are set as BURST request +by default on the Rockchip SoCs. even for request with a length of 1. +the current pl330 driver will perform SINGLE transfer if the client's +maxburst is 1, which still should be working according to chapter 2.6.6 +of datasheet which describe how DMAC performs SINGLE transfers for +a BURST request. Unfortunately, it's broken on the Rockchip SoCs, +which support only matching transfers, such as BURST transfer for +BURST request, SINGLE transfer for SINGLE request. + +Finally, we add the quirk to specify pl330 to use burst transfers only. + +Signed-off-by: Sugar Zhang +Link: https://lore.kernel.org/r/1593439555-68130-5-git-send-email-sugar.zhang@rock-chips.com +Signed-off-by: Vinod Koul +(cherry picked from commit 5fb9e3a3423313fe6169d5069e471bfdab6e0b79) +--- + drivers/dma/pl330.c | 10 +++++++++- + 1 file changed, 9 insertions(+), 1 deletion(-) + +diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c +index f1f0176c6c05..3be8d462eab4 100644 +--- a/drivers/dma/pl330.c ++++ b/drivers/dma/pl330.c +@@ -33,7 +33,8 @@ + #define PL330_MAX_PERI 32 + #define PL330_MAX_BURST 16 + +-#define PL330_QUIRK_BROKEN_NO_FLUSHP BIT(0) ++#define PL330_QUIRK_BROKEN_NO_FLUSHP BIT(0) ++#define PL330_QUIRK_PERIPH_BURST BIT(1) + + enum pl330_cachectrl { + CCTRL0, /* Noncacheable and nonbufferable */ +@@ -509,6 +510,10 @@ static struct pl330_of_quirks { + { + .quirk = "arm,pl330-broken-no-flushp", + .id = PL330_QUIRK_BROKEN_NO_FLUSHP, ++ }, ++ { ++ .quirk = "arm,pl330-periph-burst", ++ .id = PL330_QUIRK_PERIPH_BURST, + } + }; + +@@ -1206,6 +1211,9 @@ static int _bursts(struct pl330_dmac *pl330, unsigned dry_run, u8 buf[], + int off = 0; + enum pl330_cond cond = BRST_LEN(pxs->ccr) > 1 ? BURST : SINGLE; + ++ if (pl330->quirks & PL330_QUIRK_PERIPH_BURST) ++ cond = BURST; ++ + switch (pxs->desc->rqtype) { + case DMA_MEM_TO_DEV: + /* fall through */ + +From e02c5f202e532c3107f055ff4938852675c9effd Mon Sep 17 00:00:00 2001 +From: Lee Jones +Date: Tue, 14 Jul 2020 12:15:34 +0100 +Subject: [PATCH] dmaengine: pl330: Demote obvious misuse of kerneldoc to + standard comment block + +No 'struct' title is provided. Nor are any attribute descriptions. + +Fixes the following W=1 kernel build warning(s): + + drivers/dma/pl330.c:295: warning: cannot understand function prototype: 'struct pl330_reqcfg ' + +Signed-off-by: Lee Jones +Cc: Philipp Zabel +Cc: Jaswinder Singh +Link: https://lore.kernel.org/r/20200714111546.1755231-6-lee.jones@linaro.org +Signed-off-by: Vinod Koul +(cherry picked from commit f9e036df575d8efce6fd469acd9df3148c2adf6e) +--- + drivers/dma/pl330.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c +index 3be8d462eab4..2c508ee672b9 100644 +--- a/drivers/dma/pl330.c ++++ b/drivers/dma/pl330.c +@@ -285,7 +285,7 @@ struct pl330_config { + u32 irq_ns; + }; + +-/** ++/* + * Request Configuration. + * The PL330 core does not modify this and uses the last + * working configuration if the request doesn't provide any. + +From 90e0dc93ec0461e912927d1667f31be40a277954 Mon Sep 17 00:00:00 2001 +From: Kuninori Morimoto +Date: Thu, 9 Jul 2020 10:55:36 +0900 +Subject: [PATCH] ASoC: hdmi-codec: return -ENOTSUPP for digital_mute + +snd_soc_dai_digital_mute() will return -ENOTSUPP if driver doesn't +support mute. +In hdmi-codec case, hdmi_codec_digital_mute() will be used for it, +and each driver has .digital_mute() callback. +hdmi_codec_digital_mute() want to return -ENOTSUPP to follow it. + +Signed-off-by: Kuninori Morimoto +Link: https://lore.kernel.org/r/87fta1xxjc.wl-kuninori.morimoto.gx@renesas.com +Signed-off-by: Mark Brown +(cherry picked from commit e07e49c0d1e3693facf588142c4cbde45904b3f8) +--- + sound/soc/codecs/hdmi-codec.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c +index f005751da2cc..926ab447a96b 100644 +--- a/sound/soc/codecs/hdmi-codec.c ++++ b/sound/soc/codecs/hdmi-codec.c +@@ -566,7 +566,7 @@ static int hdmi_codec_digital_mute(struct snd_soc_dai *dai, int mute) + return hcp->hcd.ops->digital_mute(dai->dev->parent, + hcp->hcd.data, mute); + +- return 0; ++ return -ENOTSUPP; + } + + static const struct snd_soc_dai_ops hdmi_codec_i2s_dai_ops = { + +From f7c70c0be79698095f473dc90a266d98a4a5d12d Mon Sep 17 00:00:00 2001 +From: Johan Jonker +Date: Wed, 15 Jul 2020 09:09:54 +0200 +Subject: [PATCH] arm64: dts: rockchip: remove bus-width from mmc nodes in px30 + dts files + +'bus-width' has been added to px30.dtsi mmc nodes, so now it can be +removed from the dts files that include it. + +Signed-off-by: Johan Jonker +Link: https://lore.kernel.org/r/20200715070954.1992-1-jbx6244@gmail.com +Signed-off-by: Heiko Stuebner +(cherry picked from commit e7e46a1f6b755248058db531b1cff3b0cc580650) +--- + arch/arm64/boot/dts/rockchip/px30-evb.dts | 3 --- + arch/arm64/boot/dts/rockchip/rk3326-odroid-go2.dts | 1 - + 2 files changed, 4 deletions(-) + +diff --git a/arch/arm64/boot/dts/rockchip/px30-evb.dts b/arch/arm64/boot/dts/rockchip/px30-evb.dts +index 0a680257d9c2..5fe905fae9a8 100644 +--- a/arch/arm64/boot/dts/rockchip/px30-evb.dts ++++ b/arch/arm64/boot/dts/rockchip/px30-evb.dts +@@ -145,7 +145,6 @@ &dsi_dphy { + }; + + &emmc { +- bus-width = <8>; + cap-mmc-highspeed; + mmc-hs200-1_8v; + non-removable; +@@ -499,7 +498,6 @@ &saradc { + }; + + &sdmmc { +- bus-width = <4>; + cap-mmc-highspeed; + cap-sd-highspeed; + card-detect-delay = <800>; +@@ -513,7 +511,6 @@ &sdmmc { + }; + + &sdio { +- bus-width = <4>; + cap-sd-highspeed; + keep-power-in-suspend; + non-removable; +diff --git a/arch/arm64/boot/dts/rockchip/rk3326-odroid-go2.dts b/arch/arm64/boot/dts/rockchip/rk3326-odroid-go2.dts +index b3a8f936578f..35bd6b904b9c 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3326-odroid-go2.dts ++++ b/arch/arm64/boot/dts/rockchip/rk3326-odroid-go2.dts +@@ -445,7 +445,6 @@ &saradc { + }; + + &sdmmc { +- bus-width = <4>; + cap-sd-highspeed; + card-detect-delay = <200>; + cd-gpios = <&gpio0 RK_PA3 GPIO_ACTIVE_LOW>; /*[> CD GPIO <]*/ + +From 3abee17c54e34c806bacab0a257b88ea3d75ab80 Mon Sep 17 00:00:00 2001 +From: Sugar Zhang +Date: Mon, 29 Jun 2020 22:12:11 +0800 +Subject: [PATCH] arm64: dts: rockchip: Add 'arm,pl330-periph-burst' for dmac + +This patch Add the quirk to specify to use burst transfer +for better compatible and higher performance. + +Signed-off-by: Sugar Zhang + +Link: https://lore.kernel.org/r/1593439935-68540-1-git-send-email-sugar.zhang@rock-chips.com +Signed-off-by: Heiko Stuebner +(cherry picked from commit 505af9184ec0a0222bb883486137fac32731e01d) +--- + arch/arm64/boot/dts/rockchip/px30.dtsi | 1 + + arch/arm64/boot/dts/rockchip/rk3308.dtsi | 2 ++ + arch/arm64/boot/dts/rockchip/rk3328.dtsi | 1 + + arch/arm64/boot/dts/rockchip/rk3368.dtsi | 2 ++ + arch/arm64/boot/dts/rockchip/rk3399.dtsi | 2 ++ + 5 files changed, 8 insertions(+) + +diff --git a/arch/arm64/boot/dts/rockchip/px30.dtsi b/arch/arm64/boot/dts/rockchip/px30.dtsi +index e9bb2b97ae55..2695ea8cda14 100644 +--- a/arch/arm64/boot/dts/rockchip/px30.dtsi ++++ b/arch/arm64/boot/dts/rockchip/px30.dtsi +@@ -714,6 +714,7 @@ dmac: dmac@ff240000 { + reg = <0x0 0xff240000 0x0 0x4000>; + interrupts = , + ; ++ arm,pl330-periph-burst; + clocks = <&cru ACLK_DMAC>; + clock-names = "apb_pclk"; + #dma-cells = <1>; +diff --git a/arch/arm64/boot/dts/rockchip/rk3308.dtsi b/arch/arm64/boot/dts/rockchip/rk3308.dtsi +index ba1c71568164..e8b754d415d8 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3308.dtsi ++++ b/arch/arm64/boot/dts/rockchip/rk3308.dtsi +@@ -524,6 +524,7 @@ dmac0: dma-controller@ff2c0000 { + reg = <0x0 0xff2c0000 0x0 0x4000>; + interrupts = , + ; ++ arm,pl330-periph-burst; + clocks = <&cru ACLK_DMAC0>; + clock-names = "apb_pclk"; + #dma-cells = <1>; +@@ -534,6 +535,7 @@ dmac1: dma-controller@ff2d0000 { + reg = <0x0 0xff2d0000 0x0 0x4000>; + interrupts = , + ; ++ arm,pl330-periph-burst; + clocks = <&cru ACLK_DMAC1>; + clock-names = "apb_pclk"; + #dma-cells = <1>; +diff --git a/arch/arm64/boot/dts/rockchip/rk3328.dtsi b/arch/arm64/boot/dts/rockchip/rk3328.dtsi +index 72e655020560..bbdb19a3e85d 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3328.dtsi ++++ b/arch/arm64/boot/dts/rockchip/rk3328.dtsi +@@ -153,6 +153,7 @@ dmac: dmac@ff1f0000 { + reg = <0x0 0xff1f0000 0x0 0x4000>; + interrupts = , + ; ++ arm,pl330-periph-burst; + clocks = <&cru ACLK_DMAC>; + clock-names = "apb_pclk"; + #dma-cells = <1>; +diff --git a/arch/arm64/boot/dts/rockchip/rk3368.dtsi b/arch/arm64/boot/dts/rockchip/rk3368.dtsi +index 5d25a9d04051..3746f23dc3df 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3368.dtsi ++++ b/arch/arm64/boot/dts/rockchip/rk3368.dtsi +@@ -149,6 +149,7 @@ dmac_peri: dma-controller@ff250000 { + ; + #dma-cells = <1>; + arm,pl330-broken-no-flushp; ++ arm,pl330-periph-burst; + clocks = <&cru ACLK_DMAC_PERI>; + clock-names = "apb_pclk"; + }; +@@ -160,6 +161,7 @@ dmac_bus: dma-controller@ff600000 { + ; + #dma-cells = <1>; + arm,pl330-broken-no-flushp; ++ arm,pl330-periph-burst; + clocks = <&cru ACLK_DMAC_BUS>; + clock-names = "apb_pclk"; + }; +diff --git a/arch/arm64/boot/dts/rockchip/rk3399.dtsi b/arch/arm64/boot/dts/rockchip/rk3399.dtsi +index f2ef0d8ba54b..ada724b12f01 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3399.dtsi ++++ b/arch/arm64/boot/dts/rockchip/rk3399.dtsi +@@ -209,6 +209,7 @@ dmac_bus: dma-controller@ff6d0000 { + interrupts = , + ; + #dma-cells = <1>; ++ arm,pl330-periph-burst; + clocks = <&cru ACLK_DMAC0_PERILP>; + clock-names = "apb_pclk"; + }; +@@ -219,6 +220,7 @@ dmac_peri: dma-controller@ff6e0000 { + interrupts = , + ; + #dma-cells = <1>; ++ arm,pl330-periph-burst; + clocks = <&cru ACLK_DMAC1_PERILP>; + clock-names = "apb_pclk"; + }; + +From 932b4a4d3d1ea833e2ac81c122879e4671ee2429 Mon Sep 17 00:00:00 2001 +From: Sugar Zhang +Date: Mon, 29 Jun 2020 22:10:57 +0800 +Subject: [PATCH] ARM: dts: rockchip: Add 'arm,pl330-periph-burst' for dmac + +This patch Add the quirk to specify to use burst transfer +for better compatible and higher performance. + +Signed-off-by: Sugar Zhang + +Link: https://lore.kernel.org/r/1593439866-68459-1-git-send-email-sugar.zhang@rock-chips.com +Signed-off-by: Heiko Stuebner +(cherry picked from commit fb082df317823463eaf09ac88de19fb3319e4f58) +--- + arch/arm/boot/dts/rk3036.dtsi | 1 + + arch/arm/boot/dts/rk322x.dtsi | 1 + + arch/arm/boot/dts/rk3288.dtsi | 3 +++ + arch/arm/boot/dts/rk3xxx.dtsi | 3 +++ + arch/arm/boot/dts/rv1108.dtsi | 1 + + 5 files changed, 9 insertions(+) + +diff --git a/arch/arm/boot/dts/rk3036.dtsi b/arch/arm/boot/dts/rk3036.dtsi +index d9a0c9a29b68..093567022386 100644 +--- a/arch/arm/boot/dts/rk3036.dtsi ++++ b/arch/arm/boot/dts/rk3036.dtsi +@@ -67,6 +67,7 @@ pdma: pdma@20078000 { + ; + #dma-cells = <1>; + arm,pl330-broken-no-flushp; ++ arm,pl330-periph-burst; + clocks = <&cru ACLK_DMAC2>; + clock-names = "apb_pclk"; + }; +diff --git a/arch/arm/boot/dts/rk322x.dtsi b/arch/arm/boot/dts/rk322x.dtsi +index 3236abb0aba9..48e6e8d44a1a 100644 +--- a/arch/arm/boot/dts/rk322x.dtsi ++++ b/arch/arm/boot/dts/rk322x.dtsi +@@ -107,6 +107,7 @@ pdma: pdma@110f0000 { + interrupts = , + ; + #dma-cells = <1>; ++ arm,pl330-periph-burst; + clocks = <&cru ACLK_DMAC>; + clock-names = "apb_pclk"; + }; +diff --git a/arch/arm/boot/dts/rk3288.dtsi b/arch/arm/boot/dts/rk3288.dtsi +index 84d59469035e..9fa11b9f4522 100644 +--- a/arch/arm/boot/dts/rk3288.dtsi ++++ b/arch/arm/boot/dts/rk3288.dtsi +@@ -167,6 +167,7 @@ dmac_peri: dma-controller@ff250000 { + ; + #dma-cells = <1>; + arm,pl330-broken-no-flushp; ++ arm,pl330-periph-burst; + clocks = <&cru ACLK_DMAC2>; + clock-names = "apb_pclk"; + }; +@@ -178,6 +179,7 @@ dmac_bus_ns: dma-controller@ff600000 { + ; + #dma-cells = <1>; + arm,pl330-broken-no-flushp; ++ arm,pl330-periph-burst; + clocks = <&cru ACLK_DMAC1>; + clock-names = "apb_pclk"; + status = "disabled"; +@@ -190,6 +192,7 @@ dmac_bus_s: dma-controller@ffb20000 { + ; + #dma-cells = <1>; + arm,pl330-broken-no-flushp; ++ arm,pl330-periph-burst; + clocks = <&cru ACLK_DMAC1>; + clock-names = "apb_pclk"; + }; +diff --git a/arch/arm/boot/dts/rk3xxx.dtsi b/arch/arm/boot/dts/rk3xxx.dtsi +index d929b60517ab..859a7477909f 100644 +--- a/arch/arm/boot/dts/rk3xxx.dtsi ++++ b/arch/arm/boot/dts/rk3xxx.dtsi +@@ -45,6 +45,7 @@ dmac1_s: dma-controller@20018000 { + ; + #dma-cells = <1>; + arm,pl330-broken-no-flushp; ++ arm,pl330-periph-burst; + clocks = <&cru ACLK_DMA1>; + clock-names = "apb_pclk"; + }; +@@ -56,6 +57,7 @@ dmac1_ns: dma-controller@2001c000 { + ; + #dma-cells = <1>; + arm,pl330-broken-no-flushp; ++ arm,pl330-periph-burst; + clocks = <&cru ACLK_DMA1>; + clock-names = "apb_pclk"; + status = "disabled"; +@@ -68,6 +70,7 @@ dmac2: dma-controller@20078000 { + ; + #dma-cells = <1>; + arm,pl330-broken-no-flushp; ++ arm,pl330-periph-burst; + clocks = <&cru ACLK_DMA2>; + clock-names = "apb_pclk"; + }; +diff --git a/arch/arm/boot/dts/rv1108.dtsi b/arch/arm/boot/dts/rv1108.dtsi +index a5d130bd0547..a1a08cb9364e 100644 +--- a/arch/arm/boot/dts/rv1108.dtsi ++++ b/arch/arm/boot/dts/rv1108.dtsi +@@ -97,6 +97,7 @@ pdma: pdma@102a0000 { + interrupts = ; + #dma-cells = <1>; + arm,pl330-broken-no-flushp; ++ arm,pl330-periph-burst; + clocks = <&cru ACLK_DMAC>; + clock-names = "apb_pclk"; + }; + +From ea1abccee16e018a29011224d0e7b5392d818e70 Mon Sep 17 00:00:00 2001 +From: Jagan Teki +Date: Wed, 15 Jul 2020 14:04:12 +0530 +Subject: [PATCH] ARM: dts: rockchip: dalang-carrier: Move i2c nodes into SOM + +I2C nodes and associated slave devices defined in Carrier board +are specific to rk3399pro vmrac SOM. + +So, move them into SOM dtsi. + +Signed-off-by: Jagan Teki +Link: https://lore.kernel.org/r/20200715083418.112003-2-jagan@amarulasolutions.com +Signed-off-by: Heiko Stuebner +(cherry picked from commit c2f343510d99ab53b46bdfeb184cb48f622e6943) +--- + .../dts/rockchip-radxa-dalang-carrier.dtsi | 32 ------------------- + .../dts/rockchip/rk3399pro-vmarc-som.dtsi | 29 +++++++++++++++++ + 2 files changed, 29 insertions(+), 32 deletions(-) + +diff --git a/arch/arm/boot/dts/rockchip-radxa-dalang-carrier.dtsi b/arch/arm/boot/dts/rockchip-radxa-dalang-carrier.dtsi +index df3712aedf8a..176b53b8e41a 100644 +--- a/arch/arm/boot/dts/rockchip-radxa-dalang-carrier.dtsi ++++ b/arch/arm/boot/dts/rockchip-radxa-dalang-carrier.dtsi +@@ -17,29 +17,6 @@ &gmac { + status = "okay"; + }; + +-&i2c1 { +- status = "okay"; +- i2c-scl-rising-time-ns = <140>; +- i2c-scl-falling-time-ns = <30>; +-}; +- +-&i2c2 { +- status = "okay"; +- clock-frequency = <400000>; +- +- hym8563: hym8563@51 { +- compatible = "haoyu,hym8563"; +- reg = <0x51>; +- #clock-cells = <0>; +- clock-frequency = <32768>; +- clock-output-names = "hym8563"; +- pinctrl-names = "default"; +- pinctrl-0 = <&hym8563_int>; +- interrupt-parent = <&gpio4>; +- interrupts = <30 IRQ_TYPE_LEVEL_LOW>; +- }; +-}; +- + &pwm0 { + status = "okay"; + }; +@@ -70,12 +47,3 @@ &uart0 { + &uart2 { + status = "okay"; + }; +- +-&pinctrl { +- hym8563 { +- hym8563_int: hym8563-int { +- rockchip,pins = +- <4 RK_PD6 0 &pcfg_pull_up>; +- }; +- }; +-}; +diff --git a/arch/arm64/boot/dts/rockchip/rk3399pro-vmarc-som.dtsi b/arch/arm64/boot/dts/rockchip/rk3399pro-vmarc-som.dtsi +index 0a516334f15f..e11538171e67 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3399pro-vmarc-som.dtsi ++++ b/arch/arm64/boot/dts/rockchip/rk3399pro-vmarc-som.dtsi +@@ -297,6 +297,29 @@ regulator-state-mem { + }; + }; + ++&i2c1 { ++ i2c-scl-falling-time-ns = <30>; ++ i2c-scl-rising-time-ns = <140>; ++ status = "okay"; ++}; ++ ++&i2c2 { ++ clock-frequency = <400000>; ++ status = "okay"; ++ ++ hym8563: hym8563@51 { ++ compatible = "haoyu,hym8563"; ++ reg = <0x51>; ++ #clock-cells = <0>; ++ clock-frequency = <32768>; ++ clock-output-names = "hym8563"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&hym8563_int>; ++ interrupt-parent = <&gpio4>; ++ interrupts = ; ++ }; ++}; ++ + &io_domains { + status = "okay"; + bt656-supply = <&vcca_1v8>; +@@ -324,6 +347,12 @@ &tsadc { + }; + + &pinctrl { ++ hym8563 { ++ hym8563_int: hym8563-int { ++ rockchip,pins = <4 RK_PD6 0 &pcfg_pull_up>; ++ }; ++ }; ++ + pmic { + pmic_int_l: pmic-int-l { + rockchip,pins = + +From 2e13dc44e6d147dad03cc7f4024ec9152f329fa9 Mon Sep 17 00:00:00 2001 +From: Jagan Teki +Date: Wed, 15 Jul 2020 14:04:13 +0530 +Subject: [PATCH] arm64: dts: rk3399pro: vmarc-som: Fix sorting nodes, + properties + +Fix node, properties sorting on RockPI N10 board dts(i) files. + +Signed-off-by: Jagan Teki +Link: https://lore.kernel.org/r/20200715083418.112003-3-jagan@amarulasolutions.com +Signed-off-by: Heiko Stuebner +(cherry picked from commit 3047b384a74090f09b994298eb5c40986275233a) +--- + .../dts/rockchip/rk3399pro-rock-pi-n10.dts | 2 +- + .../dts/rockchip/rk3399pro-vmarc-som.dtsi | 35 +++++++++---------- + 2 files changed, 18 insertions(+), 19 deletions(-) + +diff --git a/arch/arm64/boot/dts/rockchip/rk3399pro-rock-pi-n10.dts b/arch/arm64/boot/dts/rockchip/rk3399pro-rock-pi-n10.dts +index a1783e7f769a..539f4005386d 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3399pro-rock-pi-n10.dts ++++ b/arch/arm64/boot/dts/rockchip/rk3399pro-rock-pi-n10.dts +@@ -8,8 +8,8 @@ + /dts-v1/; + #include "rk3399.dtsi" + #include "rk3399-opp.dtsi" +-#include "rk3399pro-vmarc-som.dtsi" + #include ++#include "rk3399pro-vmarc-som.dtsi" + + / { + model = "Radxa ROCK Pi N10"; +diff --git a/arch/arm64/boot/dts/rockchip/rk3399pro-vmarc-som.dtsi b/arch/arm64/boot/dts/rockchip/rk3399pro-vmarc-som.dtsi +index e11538171e67..121a430d6a70 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3399pro-vmarc-som.dtsi ++++ b/arch/arm64/boot/dts/rockchip/rk3399pro-vmarc-som.dtsi +@@ -76,8 +76,8 @@ &gmac { + + &i2c0 { + clock-frequency = <400000>; +- i2c-scl-rising-time-ns = <180>; + i2c-scl-falling-time-ns = <30>; ++ i2c-scl-rising-time-ns = <180>; + status = "okay"; + + rk809: pmic@20 { +@@ -323,8 +323,22 @@ hym8563: hym8563@51 { + &io_domains { + status = "okay"; + bt656-supply = <&vcca_1v8>; +- sdmmc-supply = <&vccio_sd>; + gpio1830-supply = <&vccio_3v0>; ++ sdmmc-supply = <&vccio_sd>; ++}; ++ ++&pinctrl { ++ hym8563 { ++ hym8563_int: hym8563-int { ++ rockchip,pins = <4 RK_PD6 0 &pcfg_pull_up>; ++ }; ++ }; ++ ++ pmic { ++ pmic_int_l: pmic-int-l { ++ rockchip,pins = <1 RK_PC2 0 &pcfg_pull_up>; ++ }; ++ }; + }; + + &pmu_io_domains { +@@ -341,22 +355,7 @@ &sdhci { + }; + + &tsadc { +- status = "okay"; + rockchip,hw-tshut-mode = <1>; + rockchip,hw-tshut-polarity = <1>; +-}; +- +-&pinctrl { +- hym8563 { +- hym8563_int: hym8563-int { +- rockchip,pins = <4 RK_PD6 0 &pcfg_pull_up>; +- }; +- }; +- +- pmic { +- pmic_int_l: pmic-int-l { +- rockchip,pins = +- <1 RK_PC2 0 &pcfg_pull_up>; +- }; +- }; ++ status = "okay"; + }; + +From 4617f4569e155d9512cdfa8defdea925cd30b9e4 Mon Sep 17 00:00:00 2001 +From: Jagan Teki +Date: Wed, 15 Jul 2020 14:04:14 +0530 +Subject: [PATCH] arm64: dts: rk3399pro: vmarc-som: Move supply regulators into + Carrier + +Supply regulators are common across different variants of vmarc SOM's +since the Type C power controller IC is part of the carrier board. + +So, move the supply regulators into carrier board dtsi. + +Signed-off-by: Jagan Teki +Link: https://lore.kernel.org/r/20200715083418.112003-4-jagan@amarulasolutions.com +Signed-off-by: Heiko Stuebner +(cherry picked from commit 4a3ca113c0f3a2ce33e51fc6a48a121b2d707d4f) +--- + .../dts/rockchip-radxa-dalang-carrier.dtsi | 19 +++++++++++++++++++ + .../dts/rockchip/rk3399pro-vmarc-som.dtsi | 19 ------------------- + 2 files changed, 19 insertions(+), 19 deletions(-) + +diff --git a/arch/arm/boot/dts/rockchip-radxa-dalang-carrier.dtsi b/arch/arm/boot/dts/rockchip-radxa-dalang-carrier.dtsi +index 176b53b8e41a..00b200a62263 100644 +--- a/arch/arm/boot/dts/rockchip-radxa-dalang-carrier.dtsi ++++ b/arch/arm/boot/dts/rockchip-radxa-dalang-carrier.dtsi +@@ -11,6 +11,25 @@ / { + chosen { + stdout-path = "serial2:1500000n8"; + }; ++ ++ vcc12v_dcin: vcc12v-dcin-regulator { ++ compatible = "regulator-fixed"; ++ regulator-name = "vcc12v_dcin"; ++ regulator-always-on; ++ regulator-boot-on; ++ regulator-min-microvolt = <12000000>; ++ regulator-max-microvolt = <12000000>; ++ }; ++ ++ vcc5v0_sys: vcc5v0-sys-regulator { ++ compatible = "regulator-fixed"; ++ regulator-name = "vcc5v0_sys"; ++ regulator-always-on; ++ regulator-boot-on; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; ++ vin-supply = <&vcc12v_dcin>; ++ }; + }; + + &gmac { +diff --git a/arch/arm64/boot/dts/rockchip/rk3399pro-vmarc-som.dtsi b/arch/arm64/boot/dts/rockchip/rk3399pro-vmarc-som.dtsi +index 121a430d6a70..d8fa8127d9dc 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3399pro-vmarc-som.dtsi ++++ b/arch/arm64/boot/dts/rockchip/rk3399pro-vmarc-som.dtsi +@@ -18,25 +18,6 @@ clkin_gmac: external-gmac-clock { + clock-output-names = "clkin_gmac"; + #clock-cells = <0>; + }; +- +- vcc12v_dcin: vcc12v-dcin-regulator { +- compatible = "regulator-fixed"; +- regulator-name = "vcc12v_dcin"; +- regulator-always-on; +- regulator-boot-on; +- regulator-min-microvolt = <12000000>; +- regulator-max-microvolt = <12000000>; +- }; +- +- vcc5v0_sys: vcc5v0-sys-regulator { +- compatible = "regulator-fixed"; +- regulator-name = "vcc5v0_sys"; +- regulator-always-on; +- regulator-boot-on; +- regulator-min-microvolt = <5000000>; +- regulator-max-microvolt = <5000000>; +- vin-supply = <&vcc12v_dcin>; +- }; + }; + + &cpu_l0 { + +From 772d02fccf2734a12aaaf22398aa70986a2868c7 Mon Sep 17 00:00:00 2001 +From: Jagan Teki +Date: Wed, 15 Jul 2020 14:04:15 +0530 +Subject: [PATCH] arm64: dts: rk3399pro: vmarc-som: Move common properties into + Carrier + +Some of gmac, sdmmc node properties are common across rk3288 and +rk3399pro SOM's so move them into Carrier dtsi. + +Chosen node is specific to rk3399pro configure SBC, so move it into +RockPI N10 dts. + +Signed-off-by: Jagan Teki +Link: https://lore.kernel.org/r/20200715083418.112003-5-jagan@amarulasolutions.com +Signed-off-by: Heiko Stuebner +(cherry picked from commit a66bd94d0eac017e4846658750acaca2937555bb) +--- + .../dts/rockchip-radxa-dalang-carrier.dtsi | 18 ++++++++++++---- + .../dts/rockchip/rk3399pro-rock-pi-n10.dts | 4 ++++ + .../dts/rockchip/rk3399pro-vmarc-som.dtsi | 21 +++++-------------- + 3 files changed, 23 insertions(+), 20 deletions(-) + +diff --git a/arch/arm/boot/dts/rockchip-radxa-dalang-carrier.dtsi b/arch/arm/boot/dts/rockchip-radxa-dalang-carrier.dtsi +index 00b200a62263..450e5bb5af0b 100644 +--- a/arch/arm/boot/dts/rockchip-radxa-dalang-carrier.dtsi ++++ b/arch/arm/boot/dts/rockchip-radxa-dalang-carrier.dtsi +@@ -8,8 +8,11 @@ + #include + + / { +- chosen { +- stdout-path = "serial2:1500000n8"; ++ clkin_gmac: external-gmac-clock { ++ compatible = "fixed-clock"; ++ clock-frequency = <125000000>; ++ clock-output-names = "clkin_gmac"; ++ #clock-cells = <0>; + }; + + vcc12v_dcin: vcc12v-dcin-regulator { +@@ -33,6 +36,15 @@ vcc5v0_sys: vcc5v0-sys-regulator { + }; + + &gmac { ++ assigned-clock-parents = <&clkin_gmac>; ++ clock_in_out = "input"; ++ phy-mode = "rgmii"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&rgmii_pins>; ++ snps,reset-active-low; ++ snps,reset-delays-us = <0 10000 50000>; ++ tx_delay = <0x28>; ++ rx_delay = <0x11>; + status = "okay"; + }; + +@@ -48,10 +60,8 @@ &sdmmc { + bus-width = <4>; + cap-mmc-highspeed; + cap-sd-highspeed; +- cd-gpios = <&gpio0 RK_PA7 GPIO_ACTIVE_LOW>; + disable-wp; + vqmmc-supply = <&vccio_sd>; +- max-frequency = <150000000>; + pinctrl-names = "default"; + pinctrl-0 = <&sdmmc_clk &sdmmc_cmd &sdmmc_cd &sdmmc_bus4>; + status = "okay"; +diff --git a/arch/arm64/boot/dts/rockchip/rk3399pro-rock-pi-n10.dts b/arch/arm64/boot/dts/rockchip/rk3399pro-rock-pi-n10.dts +index 539f4005386d..369de5dc0ebd 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3399pro-rock-pi-n10.dts ++++ b/arch/arm64/boot/dts/rockchip/rk3399pro-rock-pi-n10.dts +@@ -15,4 +15,8 @@ / { + model = "Radxa ROCK Pi N10"; + compatible = "radxa,rockpi-n10", "vamrs,rk3399pro-vmarc-som", + "rockchip,rk3399pro"; ++ ++ chosen { ++ stdout-path = "serial2:1500000n8"; ++ }; + }; +diff --git a/arch/arm64/boot/dts/rockchip/rk3399pro-vmarc-som.dtsi b/arch/arm64/boot/dts/rockchip/rk3399pro-vmarc-som.dtsi +index d8fa8127d9dc..37ed95d5f7e9 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3399pro-vmarc-som.dtsi ++++ b/arch/arm64/boot/dts/rockchip/rk3399pro-vmarc-som.dtsi +@@ -11,13 +11,6 @@ + + / { + compatible = "vamrs,rk3399pro-vmarc-som", "rockchip,rk3399pro"; +- +- clkin_gmac: external-gmac-clock { +- compatible = "fixed-clock"; +- clock-frequency = <125000000>; +- clock-output-names = "clkin_gmac"; +- #clock-cells = <0>; +- }; + }; + + &cpu_l0 { +@@ -42,17 +35,8 @@ &emmc_phy { + + &gmac { + assigned-clocks = <&cru SCLK_RMII_SRC>; +- assigned-clock-parents = <&clkin_gmac>; +- clock_in_out = "input"; + phy-supply = <&vcc_lan>; +- phy-mode = "rgmii"; +- pinctrl-names = "default"; +- pinctrl-0 = <&rgmii_pins>; + snps,reset-gpio = <&gpio3 RK_PB7 GPIO_ACTIVE_LOW>; +- snps,reset-active-low; +- snps,reset-delays-us = <0 10000 50000>; +- tx_delay = <0x28>; +- rx_delay = <0x11>; + }; + + &i2c0 { +@@ -335,6 +319,11 @@ &sdhci { + status = "okay"; + }; + ++&sdmmc { ++ cd-gpios = <&gpio0 RK_PA7 GPIO_ACTIVE_LOW>; ++ max-frequency = <150000000>; ++}; ++ + &tsadc { + rockchip,hw-tshut-mode = <1>; + rockchip,hw-tshut-polarity = <1>; + +From 916191ead33a0ce0baec3a3cadb386c12d9a1b99 Mon Sep 17 00:00:00 2001 +From: Jagan Teki +Date: Wed, 15 Jul 2020 14:04:16 +0530 +Subject: [PATCH] dt-bindings: arm: rockchip: Add Rock Pi N8 binding + +Rock Pi N8 is a Rockchip RK3288 based SBC, which has +- VMARC RK3288 SOM (as per SMARC standard) from Vamrs. +- Compatible carrier board from Radxa. + +VMARC RK3288 SOM need to mount on top of dalang carrier +board for making Rock PI N8 SBC. + +Add dt-bindings for it. + +Signed-off-by: Jagan Teki +Reviewed-by: Rob Herring +Link: https://lore.kernel.org/r/20200715083418.112003-6-jagan@amarulasolutions.com +Signed-off-by: Heiko Stuebner +(cherry picked from commit 09ee4794270f0010c6397163f033f883f5bff1aa) +--- + Documentation/devicetree/bindings/arm/rockchip.yaml | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/Documentation/devicetree/bindings/arm/rockchip.yaml b/Documentation/devicetree/bindings/arm/rockchip.yaml +index d4a4045092df..db2e35796795 100644 +--- a/Documentation/devicetree/bindings/arm/rockchip.yaml ++++ b/Documentation/devicetree/bindings/arm/rockchip.yaml +@@ -435,6 +435,12 @@ properties: + - const: radxa,rockpi4 + - const: rockchip,rk3399 + ++ - description: Radxa ROCK Pi N8 ++ items: ++ - const: radxa,rockpi-n8 ++ - const: vamrs,rk3288-vmarc-som ++ - const: rockchip,rk3288 ++ + - description: Radxa ROCK Pi N10 + items: + - const: radxa,rockpi-n10 + +From 2a5e46160a746adc9a7b9b952e2000060d6da48a Mon Sep 17 00:00:00 2001 +From: Jagan Teki +Date: Wed, 15 Jul 2020 14:04:17 +0530 +Subject: [PATCH] ARM: dts: rockchip: Add VMARC RK3288 SOM initial support + +VMARC RK3288 SOM is a standard SMARC SOM design with +Rockchip RK3288 SoC, which is designed by Vamrs. + +Specification: +- Rockchip RK3288 +- PMIC: RK808 +- eMMC: 16GB/32GB/64GB +- SD slot +- 2xUSB-2.0, 1xUSB3.0 +- USB-C for power supply +- Ethernet +- HDMI, MIPI-DSI/CSI, eDP + +Add initial support for VMARC RK3288 SOM, this would use +with associated carrier board. + +Signed-off-by: Jagan Teki +Link: https://lore.kernel.org/r/20200715083418.112003-7-jagan@amarulasolutions.com +Signed-off-by: Heiko Stuebner +(cherry picked from commit b8c564d4fa76b1314a10585eea8e97b8c621a77a) +--- + arch/arm/boot/dts/rk3288-vmarc-som.dtsi | 270 ++++++++++++++++++++++++ + 1 file changed, 270 insertions(+) + create mode 100644 arch/arm/boot/dts/rk3288-vmarc-som.dtsi + +diff --git a/arch/arm/boot/dts/rk3288-vmarc-som.dtsi b/arch/arm/boot/dts/rk3288-vmarc-som.dtsi +new file mode 100644 +index 000000000000..cd61b6230f0d +--- /dev/null ++++ b/arch/arm/boot/dts/rk3288-vmarc-som.dtsi +@@ -0,0 +1,270 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR MIT) ++/* ++ * Copyright (c) 2019 Fuzhou Rockchip Electronics Co., Ltd ++ * Copyright (c) 2019 Vamrs Limited ++ * Copyright (c) 2019 Amarula Solutions(India) ++ */ ++ ++#include ++#include ++ ++/ { ++ compatible = "vamrs,rk3288-vmarc-som", "rockchip,rk3288"; ++ ++ vccio_flash: vccio-flash-regulator { ++ compatible = "regulator-fixed"; ++ regulator-name = "vccio_flash"; ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <1800000>; ++ vin-supply = <&vcc_io>; ++ }; ++}; ++ ++&emmc { ++ bus-width = <8>; ++ cap-mmc-highspeed; ++ disable-wp; ++ non-removable; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&emmc_clk &emmc_cmd &emmc_pwr &emmc_bus8>; ++ vmmc-supply = <&vcc_io>; ++ vqmmc-supply = <&vccio_flash>; ++ status = "okay"; ++}; ++ ++&gmac { ++ assigned-clocks = <&cru SCLK_MAC>; ++ phy-supply = <&vcc_io>; ++ snps,reset-gpio = <&gpio4 RK_PA7 GPIO_ACTIVE_HIGH>; ++}; ++ ++&i2c0 { ++ clock-frequency = <400000>; ++ status = "okay"; ++ ++ rk808: pmic@1b { ++ compatible = "rockchip,rk808"; ++ reg = <0x1b>; ++ interrupt-parent = <&gpio0>; ++ interrupts = ; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pmic_int &global_pwroff>; ++ rockchip,system-power-controller; ++ wakeup-source; ++ #clock-cells = <1>; ++ clock-output-names = "rk808-clkout1", "rk808-clkout2"; ++ ++ vcc1-supply = <&vcc5v0_sys>; ++ vcc2-supply = <&vcc5v0_sys>; ++ vcc3-supply = <&vcc5v0_sys>; ++ vcc4-supply = <&vcc5v0_sys>; ++ vcc6-supply = <&vcc5v0_sys>; ++ vcc7-supply = <&vcc5v0_sys>; ++ vcc8-supply = <&vcc_io>; ++ vcc9-supply = <&vcc_io>; ++ vcc10-supply = <&vcc5v0_sys>; ++ vcc11-supply = <&vcc5v0_sys>; ++ vcc12-supply = <&vcc_io>; ++ vddio-supply = <&vcc_io>; ++ ++ regulators { ++ vdd_cpu: DCDC_REG1 { ++ regulator-name = "vdd_arm"; ++ regulator-always-on; ++ regulator-boot-on; ++ regulator-min-microvolt = <750000>; ++ regulator-max-microvolt = <1400000>; ++ regulator-state-mem { ++ regulator-off-in-suspend; ++ }; ++ }; ++ ++ vdd_gpu: DCDC_REG2 { ++ regulator-name = "vdd_gpu"; ++ regulator-always-on; ++ regulator-boot-on; ++ regulator-min-microvolt = <850000>; ++ regulator-max-microvolt = <1250000>; ++ regulator-ramp-delay = <6000>; ++ regulator-state-mem { ++ regulator-off-in-suspend; ++ }; ++ }; ++ ++ vcc_ddr: DCDC_REG3 { ++ regulator-name = "vcc_ddr"; ++ regulator-always-on; ++ regulator-boot-on; ++ regulator-state-mem { ++ regulator-on-in-suspend; ++ }; ++ }; ++ ++ vcc_io: DCDC_REG4 { ++ regulator-name = "vcc_io"; ++ regulator-always-on; ++ regulator-boot-on; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-state-mem { ++ regulator-on-in-suspend; ++ regulator-suspend-microvolt = <3300000>; ++ }; ++ }; ++ ++ vcc_tp: LDO_REG1 { ++ regulator-name = "vcc_tp"; ++ regulator-always-on; ++ regulator-boot-on; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-state-mem { ++ regulator-off-in-suspend; ++ }; ++ }; ++ ++ vcca_codec: LDO_REG2 { ++ regulator-name = "vcca_codec"; ++ regulator-always-on; ++ regulator-boot-on; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-state-mem { ++ regulator-on-in-suspend; ++ regulator-suspend-microvolt = <3300000>; ++ }; ++ }; ++ ++ vdd_10: LDO_REG3 { ++ regulator-name = "vdd_10"; ++ regulator-always-on; ++ regulator-boot-on; ++ regulator-min-microvolt = <1000000>; ++ regulator-max-microvolt = <1000000>; ++ regulator-state-mem { ++ regulator-on-in-suspend; ++ regulator-suspend-microvolt = <1000000>; ++ }; ++ }; ++ ++ vcc_wl: LDO_REG4 { ++ regulator-name = "vcc_wl"; ++ regulator-always-on; ++ regulator-boot-on; ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <1800000>; ++ regulator-state-mem { ++ regulator-on-in-suspend; ++ }; ++ }; ++ ++ vccio_sd: LDO_REG5 { ++ regulator-name = "vccio_sd"; ++ regulator-always-on; ++ regulator-boot-on; ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-state-mem { ++ regulator-on-in-suspend; ++ regulator-suspend-microvolt = <3300000>; ++ }; ++ }; ++ ++ vdd10_lcd: LDO_REG6 { ++ regulator-name = "vdd10_lcd"; ++ regulator-always-on; ++ regulator-boot-on; ++ regulator-min-microvolt = <1000000>; ++ regulator-max-microvolt = <1000000>; ++ regulator-state-mem { ++ regulator-off-in-suspend; ++ }; ++ }; ++ ++ vcc_18: LDO_REG7 { ++ regulator-name = "vcc_18"; ++ regulator-always-on; ++ regulator-boot-on; ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <1800000>; ++ regulator-state-mem { ++ regulator-on-in-suspend; ++ regulator-suspend-microvolt = <1800000>; ++ }; ++ }; ++ ++ vcc18_lcd: LDO_REG8 { ++ regulator-name = "vcc18_lcd"; ++ regulator-always-on; ++ regulator-boot-on; ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <1800000>; ++ regulator-state-mem { ++ regulator-off-in-suspend; ++ }; ++ }; ++ ++ vcc_sd: SWITCH_REG1 { ++ regulator-name = "vcc_sd"; ++ regulator-always-on; ++ regulator-boot-on; ++ regulator-state-mem { ++ regulator-off-in-suspend; ++ }; ++ }; ++ ++ vcc_lcd: SWITCH_REG2 { ++ regulator-name = "vcc_lcd"; ++ regulator-always-on; ++ regulator-boot-on; ++ regulator-state-mem { ++ regulator-off-in-suspend; ++ }; ++ }; ++ }; ++ }; ++}; ++ ++&io_domains { ++ bb-supply = <&vcc_io>; ++ flash0-supply = <&vccio_flash>; ++ gpio1830-supply = <&vcc_18>; ++ gpio30-supply = <&vcc_io>; ++ sdcard-supply = <&vccio_sd>; ++ status = "okay"; ++}; ++ ++&pinctrl { ++ pcfg_pull_none_drv_8ma: pcfg-pull-none-drv-8ma { ++ drive-strength = <8>; ++ }; ++ ++ pcfg_pull_up_drv_8ma: pcfg-pull-up-drv-8ma { ++ bias-pull-up; ++ drive-strength = <8>; ++ }; ++ ++ pmic { ++ pmic_int: pmic-int { ++ rockchip,pins = <0 RK_PA4 RK_FUNC_GPIO &pcfg_pull_up>; ++ }; ++ }; ++ ++ sdmmc { ++ sdmmc_bus4: sdmmc-bus4 { ++ rockchip,pins = ++ <6 RK_PC0 1 &pcfg_pull_up_drv_8ma>, ++ <6 RK_PC1 1 &pcfg_pull_up_drv_8ma>, ++ <6 RK_PC2 1 &pcfg_pull_up_drv_8ma>, ++ <6 RK_PC3 1 &pcfg_pull_up_drv_8ma>; ++ }; ++ ++ sdmmc_clk: sdmmc-clk { ++ rockchip,pins = <6 RK_PC4 1 &pcfg_pull_none_drv_8ma>; ++ }; ++ ++ sdmmc_cmd: sdmmc-cmd { ++ rockchip,pins = <6 RK_PC5 1 &pcfg_pull_up_drv_8ma>; ++ }; ++ }; ++}; + +From 10ff584a4e12d06e7f041b37f806bd6ffac91f94 Mon Sep 17 00:00:00 2001 +From: Michael Trimarchi +Date: Tue, 7 Jul 2020 12:12:14 +0200 +Subject: [PATCH] ARM: dts: rockchip: Fix VBUS on rk3288-vyasa + +Connect the voltage regulator of vbus to the otg connector. +Depending on the current mode this is enabled (in "host" mode") +or disabled (in "peripheral" mode). The regulator must be updated +if the controller is configured in "otg" mode and the status changes +between "host" and "peripheral". + +Signed-off-by: Michael Trimarchi +Link: https://lore.kernel.org/r/20200707101214.2301768-1-michael@amarulasolutions.com +Signed-off-by: Heiko Stuebner +(cherry picked from commit 719646b76a41b8a482f8701825b635e9710ab329) +--- + arch/arm/boot/dts/rk3288-vyasa.dts | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/arch/arm/boot/dts/rk3288-vyasa.dts b/arch/arm/boot/dts/rk3288-vyasa.dts +index 385dd59393e1..1a20854a1317 100644 +--- a/arch/arm/boot/dts/rk3288-vyasa.dts ++++ b/arch/arm/boot/dts/rk3288-vyasa.dts +@@ -99,8 +99,6 @@ vusb1_5v: vusb1-5v { + pinctrl-0 = <&otg_vbus_drv>; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; +- regulator-always-on; +- regulator-boot-on; + vin-supply = <&vsus_5v>; + }; + +@@ -416,6 +414,7 @@ &usb_host1 { + }; + + &usb_otg { ++ vbus-supply = <&vusb1_5v>; + status = "okay"; + }; + + +From 8635890fdcf41e911c4e3dd5213f3ff891513cab Mon Sep 17 00:00:00 2001 +From: Jagan Teki +Date: Mon, 20 Jul 2020 16:28:46 +0530 +Subject: [PATCH] ARM: dts: rockchip: Add usb host0 ohci node for rk3288 + +rk3288 and rk3288w have a usb host0 ohci controller. + +Although rk3288 ohci doesn't actually work on hardware, but +rk3288w ohci can work well. + +So add usb host0 ohci node in rk3288 dtsi and boards +can then enable it if supported. + +Signed-off-by: Jagan Teki +Cc: William Wu +Link: https://lore.kernel.org/r/20200720105846.367776-1-jagan@amarulasolutions.com +Signed-off-by: Heiko Stuebner +(cherry picked from commit 82540defdd9cfc491f564ffb8d01911966636bc7) +--- + arch/arm/boot/dts/rk3288.dtsi | 11 ++++++++++- + 1 file changed, 10 insertions(+), 1 deletion(-) + +diff --git a/arch/arm/boot/dts/rk3288.dtsi b/arch/arm/boot/dts/rk3288.dtsi +index 9fa11b9f4522..68d5a58cfe88 100644 +--- a/arch/arm/boot/dts/rk3288.dtsi ++++ b/arch/arm/boot/dts/rk3288.dtsi +@@ -616,7 +616,16 @@ usb_host0_ehci: usb@ff500000 { + status = "disabled"; + }; + +- /* NOTE: ohci@ff520000 doesn't actually work on hardware */ ++ /* NOTE: doesn't work on RK3288, but was fixed on RK3288W */ ++ usb_host0_ohci: usb@ff520000 { ++ compatible = "generic-ohci"; ++ reg = <0x0 0xff520000 0x0 0x100>; ++ interrupts = ; ++ clocks = <&cru HCLK_USBHOST0>; ++ phys = <&usbphy1>; ++ phy-names = "usb"; ++ status = "disabled"; ++ }; + + usb_host1: usb@ff540000 { + compatible = "rockchip,rk3288-usb", "rockchip,rk3066-usb", + +From cb343a78f51f82997bce9de813c1035f15010e38 Mon Sep 17 00:00:00 2001 +From: Jagan Teki +Date: Mon, 20 Jul 2020 16:32:28 +0530 +Subject: [PATCH] ARM: dts: rockchip: Add USB for RockPI N8/N10 + +Radxa dalang carrier board has 2x USB 2.0 and 1x USB 3.0 +ports. + +This patch adds support to enable all these USB ports for +N10 and N8 combinations SBCs. + +Note that the USB 3.0 port on RockPI N8 combination works +as USB 2.0 OTG since it is driven from RK3288. + +Signed-off-by: Jagan Teki +Link: https://lore.kernel.org/r/20200720110230.367985-1-jagan@amarulasolutions.com +Signed-off-by: Heiko Stuebner +(cherry picked from commit 417b188a985d3557b0ecb5623b27bd9843f03aec) +--- + arch/arm/boot/dts/rk3288-vmarc-som.dtsi | 42 ++++++++++ + .../dts/rockchip-radxa-dalang-carrier.dtsi | 18 +++++ + .../dts/rockchip/rk3399pro-vmarc-som.dtsi | 78 +++++++++++++++++++ + 3 files changed, 138 insertions(+) + +diff --git a/arch/arm/boot/dts/rk3288-vmarc-som.dtsi b/arch/arm/boot/dts/rk3288-vmarc-som.dtsi +index cd61b6230f0d..78164d117248 100644 +--- a/arch/arm/boot/dts/rk3288-vmarc-som.dtsi ++++ b/arch/arm/boot/dts/rk3288-vmarc-som.dtsi +@@ -267,4 +267,46 @@ sdmmc_cmd: sdmmc-cmd { + rockchip,pins = <6 RK_PC5 1 &pcfg_pull_up_drv_8ma>; + }; + }; ++ ++ vbus_host { ++ usb1_en_oc: usb1-en-oc { ++ rockchip,pins = <0 RK_PC1 RK_FUNC_GPIO &pcfg_pull_up>; ++ }; ++ }; ++ ++ vbus_typec { ++ usb0_en_oc: usb0-en-oc { ++ rockchip,pins = <0 RK_PB5 RK_FUNC_GPIO &pcfg_pull_up>; ++ }; ++ }; ++}; ++ ++&usbphy { ++ status = "okay"; ++}; ++ ++&usb_host0_ehci { ++ status = "okay"; ++}; ++ ++&usb_host0_ohci { ++ status = "okay"; ++}; ++ ++&usb_host1 { ++ status = "okay"; ++}; ++ ++&usb_otg { ++ status = "okay"; ++}; ++ ++&vbus_host { ++ enable-active-high; ++ gpio = <&gpio0 RK_PC1 GPIO_ACTIVE_HIGH>; /* USB1_EN_OC# */ ++}; ++ ++&vbus_typec { ++ enable-active-high; ++ gpio = <&gpio0 RK_PB5 GPIO_ACTIVE_HIGH>; /* USB0_EN_OC# */ + }; +diff --git a/arch/arm/boot/dts/rockchip-radxa-dalang-carrier.dtsi b/arch/arm/boot/dts/rockchip-radxa-dalang-carrier.dtsi +index 450e5bb5af0b..d2b6ead148a2 100644 +--- a/arch/arm/boot/dts/rockchip-radxa-dalang-carrier.dtsi ++++ b/arch/arm/boot/dts/rockchip-radxa-dalang-carrier.dtsi +@@ -33,6 +33,24 @@ vcc5v0_sys: vcc5v0-sys-regulator { + regulator-max-microvolt = <5000000>; + vin-supply = <&vcc12v_dcin>; + }; ++ ++ vbus_host: vbus-host { ++ compatible = "regulator-fixed"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&usb1_en_oc>; ++ regulator-name = "vbus_host"; /* HOST-5V */ ++ regulator-always-on; ++ vin-supply = <&vcc5v0_sys>; ++ }; ++ ++ vbus_typec: vbus-typec { ++ compatible = "regulator-fixed"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&usb0_en_oc>; ++ regulator-name = "vbus_typec"; ++ regulator-always-on; ++ vin-supply = <&vcc5v0_sys>; ++ }; + }; + + &gmac { +diff --git a/arch/arm64/boot/dts/rockchip/rk3399pro-vmarc-som.dtsi b/arch/arm64/boot/dts/rockchip/rk3399pro-vmarc-som.dtsi +index 37ed95d5f7e9..111d6cf9a4e6 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3399pro-vmarc-som.dtsi ++++ b/arch/arm64/boot/dts/rockchip/rk3399pro-vmarc-som.dtsi +@@ -304,6 +304,18 @@ pmic_int_l: pmic-int-l { + rockchip,pins = <1 RK_PC2 0 &pcfg_pull_up>; + }; + }; ++ ++ vbus_host { ++ usb1_en_oc: usb1-en-oc { ++ rockchip,pins = <4 RK_PD1 RK_FUNC_GPIO &pcfg_pull_up>; ++ }; ++ }; ++ ++ vbus_typec { ++ usb0_en_oc: usb0-en-oc { ++ rockchip,pins = <4 RK_PD2 RK_FUNC_GPIO &pcfg_pull_up>; ++ }; ++ }; + }; + + &pmu_io_domains { +@@ -324,8 +336,74 @@ &sdmmc { + max-frequency = <150000000>; + }; + ++&tcphy0 { ++ status = "okay"; ++}; ++ + &tsadc { + rockchip,hw-tshut-mode = <1>; + rockchip,hw-tshut-polarity = <1>; + status = "okay"; + }; ++ ++&u2phy0 { ++ status = "okay"; ++ ++ u2phy0_otg: otg-port { ++ phy-supply = <&vbus_typec>; ++ status = "okay"; ++ }; ++ ++ u2phy0_host: host-port { ++ phy-supply = <&vbus_host>; ++ status = "okay"; ++ }; ++}; ++ ++ ++&u2phy1 { ++ status = "okay"; ++ ++ u2phy1_host: host-port { ++ phy-supply = <&vbus_host>; ++ status = "okay"; ++ }; ++}; ++ ++&usb_host0_ehci { ++ status = "okay"; ++}; ++ ++&usb_host0_ohci { ++ status = "okay"; ++}; ++ ++&usb_host1_ehci { ++ status = "okay"; ++}; ++ ++&usb_host1_ohci { ++ status = "okay"; ++}; ++ ++&usbdrd3_0 { ++ status = "okay"; ++}; ++ ++&usbdrd_dwc3_0 { ++ status = "okay"; ++}; ++ ++&vbus_host { ++ enable-active-high; ++ gpio = <&gpio4 RK_PD1 GPIO_ACTIVE_HIGH>; /* USB1_EN_OC# */ ++ pinctrl-names = "default"; ++ pinctrl-0 = <&usb1_en_oc>; ++}; ++ ++&vbus_typec { ++ enable-active-high; ++ gpio = <&gpio4 RK_PD2 GPIO_ACTIVE_HIGH>; /* USB0_EN_OC# */ ++ pinctrl-names = "default"; ++ pinctrl-0 = <&usb0_en_oc>; ++}; + +From 3137628a7366f1fc30748b59254d6b25c2c86efd Mon Sep 17 00:00:00 2001 +From: Jagan Teki +Date: Mon, 20 Jul 2020 16:32:29 +0530 +Subject: [PATCH] ARM: dts: rockchip: Add HDMI out for RockPI N8/N10 + +This patch adds support to enable HDMI out for +N10 and N8 combinations SBCs. + +Signed-off-by: Jagan Teki +Signed-off-by: Suniel Mahesh +Link: https://lore.kernel.org/r/20200720110230.367985-2-jagan@amarulasolutions.com +Signed-off-by: Heiko Stuebner +(cherry picked from commit d0cb2f30e7c033f0a8bbe98ec73dbc1db4788942) +--- + arch/arm/boot/dts/rk3288-vmarc-som.dtsi | 10 ++++++++++ + .../dts/rockchip-radxa-dalang-carrier.dtsi | 20 +++++++++++++++++++ + .../dts/rockchip/rk3399pro-vmarc-som.dtsi | 12 +++++++++++ + 3 files changed, 42 insertions(+) + +diff --git a/arch/arm/boot/dts/rk3288-vmarc-som.dtsi b/arch/arm/boot/dts/rk3288-vmarc-som.dtsi +index 78164d117248..4a373f5aa600 100644 +--- a/arch/arm/boot/dts/rk3288-vmarc-som.dtsi ++++ b/arch/arm/boot/dts/rk3288-vmarc-som.dtsi +@@ -38,6 +38,12 @@ &gmac { + snps,reset-gpio = <&gpio4 RK_PA7 GPIO_ACTIVE_HIGH>; + }; + ++&hdmi { ++ ddc-i2c-bus = <&i2c5>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&hdmi_cec_c0>; ++}; ++ + &i2c0 { + clock-frequency = <400000>; + status = "okay"; +@@ -225,6 +231,10 @@ regulator-state-mem { + }; + }; + ++&i2c5 { ++ status = "okay"; ++}; ++ + &io_domains { + bb-supply = <&vcc_io>; + flash0-supply = <&vccio_flash>; +diff --git a/arch/arm/boot/dts/rockchip-radxa-dalang-carrier.dtsi b/arch/arm/boot/dts/rockchip-radxa-dalang-carrier.dtsi +index d2b6ead148a2..26b53eac4706 100644 +--- a/arch/arm/boot/dts/rockchip-radxa-dalang-carrier.dtsi ++++ b/arch/arm/boot/dts/rockchip-radxa-dalang-carrier.dtsi +@@ -66,6 +66,10 @@ &gmac { + status = "okay"; + }; + ++&hdmi { ++ status = "okay"; ++}; ++ + &pwm0 { + status = "okay"; + }; +@@ -94,3 +98,19 @@ &uart0 { + &uart2 { + status = "okay"; + }; ++ ++&vopb { ++ status = "okay"; ++}; ++ ++&vopb_mmu { ++ status = "okay"; ++}; ++ ++&vopl { ++ status = "okay"; ++}; ++ ++&vopl_mmu { ++ status = "okay"; ++}; +diff --git a/arch/arm64/boot/dts/rockchip/rk3399pro-vmarc-som.dtsi b/arch/arm64/boot/dts/rockchip/rk3399pro-vmarc-som.dtsi +index 111d6cf9a4e6..ebccc4a153a2 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3399pro-vmarc-som.dtsi ++++ b/arch/arm64/boot/dts/rockchip/rk3399pro-vmarc-som.dtsi +@@ -39,6 +39,12 @@ &gmac { + snps,reset-gpio = <&gpio3 RK_PB7 GPIO_ACTIVE_LOW>; + }; + ++&hdmi { ++ ddc-i2c-bus = <&i2c3>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&hdmi_cec>; ++}; ++ + &i2c0 { + clock-frequency = <400000>; + i2c-scl-falling-time-ns = <30>; +@@ -285,6 +291,12 @@ hym8563: hym8563@51 { + }; + }; + ++&i2c3 { ++ i2c-scl-rising-time-ns = <450>; ++ i2c-scl-falling-time-ns = <15>; ++ status = "okay"; ++}; ++ + &io_domains { + status = "okay"; + bt656-supply = <&vcca_1v8>; + +From 0d5ba09fbbd6b8a5d9fc7df9d3f760842549c07f Mon Sep 17 00:00:00 2001 +From: Jagan Teki +Date: Mon, 20 Jul 2020 16:32:30 +0530 +Subject: [PATCH] arm64: dts: rockchip: Add PCIe for RockPI N10 + +This patch adds support to enable PCIe for RockPI N10. + +Signed-off-by: Jagan Teki +Link: https://lore.kernel.org/r/20200720110230.367985-3-jagan@amarulasolutions.com +Signed-off-by: Heiko Stuebner +(cherry picked from commit 93ca8ac2e8fcea6feb02a40edd2334144b62fc6e) +--- + .../dts/rockchip/rk3399pro-vmarc-som.dtsi | 40 ++++++++++++++++++- + 1 file changed, 38 insertions(+), 2 deletions(-) + +diff --git a/arch/arm64/boot/dts/rockchip/rk3399pro-vmarc-som.dtsi b/arch/arm64/boot/dts/rockchip/rk3399pro-vmarc-som.dtsi +index ebccc4a153a2..5d087be04af8 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3399pro-vmarc-som.dtsi ++++ b/arch/arm64/boot/dts/rockchip/rk3399pro-vmarc-som.dtsi +@@ -11,6 +11,18 @@ + + / { + compatible = "vamrs,rk3399pro-vmarc-som", "rockchip,rk3399pro"; ++ ++ vcc3v3_pcie: vcc-pcie-regulator { ++ compatible = "regulator-fixed"; ++ enable-active-high; ++ gpio = <&gpio4 RK_PD4 GPIO_ACTIVE_HIGH>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pcie_pwr>; ++ regulator-name = "vcc3v3_pcie"; ++ regulator-always-on; ++ regulator-boot-on; ++ vin-supply = <&vcc5v0_sys>; ++ }; + }; + + &cpu_l0 { +@@ -142,7 +154,8 @@ vcca_0v9: LDO_REG1 { + regulator-min-microvolt = <900000>; + regulator-max-microvolt = <900000>; + regulator-state-mem { +- regulator-off-in-suspend; ++ regulator-on-in-suspend; ++ regulator-suspend-microvolt = <900000>; + }; + }; + +@@ -177,7 +190,8 @@ vcca_1v8: LDO_REG4 { + regulator-min-microvolt = <1850000>; + regulator-max-microvolt = <1850000>; + regulator-state-mem { +- regulator-off-in-suspend; ++ regulator-on-in-suspend; ++ regulator-suspend-microvolt = <1850000>; + }; + }; + +@@ -304,6 +318,22 @@ &io_domains { + sdmmc-supply = <&vccio_sd>; + }; + ++&pcie_phy { ++ status = "okay"; ++}; ++ ++&pcie0 { ++ ep-gpios = <&gpio0 RK_PB4 GPIO_ACTIVE_HIGH>; ++ max-link-speed = <2>; ++ num-lanes = <4>; ++ pinctrl-0 = <&pcie_clkreqnb_cpm>; ++ pinctrl-names = "default"; ++ vpcie0v9-supply = <&vcca_0v9>; /* VCC_0V9_S0 */ ++ vpcie1v8-supply = <&vcca_1v8>; /* VCC_1V8_S0 */ ++ vpcie3v3-supply = <&vcc3v3_pcie>; ++ status = "okay"; ++}; ++ + &pinctrl { + hym8563 { + hym8563_int: hym8563-int { +@@ -311,6 +341,12 @@ hym8563_int: hym8563-int { + }; + }; + ++ pcie { ++ pcie_pwr: pcie-pwr { ++ rockchip,pins = <4 RK_PD4 RK_FUNC_GPIO &pcfg_pull_up>; ++ }; ++ }; ++ + pmic { + pmic_int_l: pmic-int-l { + rockchip,pins = <1 RK_PC2 0 &pcfg_pull_up>; + +From ec258d2b9150088af58b6935bbf3c6c3618ea8f7 Mon Sep 17 00:00:00 2001 +From: Katsuhiro Suzuki +Date: Sat, 25 Jul 2020 00:59:33 +0900 +Subject: [PATCH] ASoC: convert Everest ES8316 binding to yaml + +This patch converts Everest Semiconductor ES8316 low power audio +CODEC binding to DT schema. + +Signed-off-by: Katsuhiro Suzuki +Reviewed-by: Rob Herring +Link: https://lore.kernel.org/r/20200724155933.1040501-1-katsuhiro@katsuster.net +Signed-off-by: Mark Brown +(cherry picked from commit 92e67a9c4f206dc9c859c405e67448a8be59ac5d) +--- + .../bindings/sound/everest,es8316.txt | 23 --------- + .../bindings/sound/everest,es8316.yaml | 50 +++++++++++++++++++ + 2 files changed, 50 insertions(+), 23 deletions(-) + delete mode 100644 Documentation/devicetree/bindings/sound/everest,es8316.txt + create mode 100644 Documentation/devicetree/bindings/sound/everest,es8316.yaml + +diff --git a/Documentation/devicetree/bindings/sound/everest,es8316.txt b/Documentation/devicetree/bindings/sound/everest,es8316.txt +deleted file mode 100644 +index 1bf03c5f2af4..000000000000 +--- a/Documentation/devicetree/bindings/sound/everest,es8316.txt ++++ /dev/null +@@ -1,23 +0,0 @@ +-Everest ES8316 audio CODEC +- +-This device supports both I2C and SPI. +- +-Required properties: +- +- - compatible : should be "everest,es8316" +- - reg : the I2C address of the device for I2C +- +-Optional properties: +- +- - clocks : a list of phandle, should contain entries for clock-names +- - clock-names : should include as follows: +- "mclk" : master clock (MCLK) of the device +- +-Example: +- +-es8316: codec@11 { +- compatible = "everest,es8316"; +- reg = <0x11>; +- clocks = <&clks 10>; +- clock-names = "mclk"; +-}; +diff --git a/Documentation/devicetree/bindings/sound/everest,es8316.yaml b/Documentation/devicetree/bindings/sound/everest,es8316.yaml +new file mode 100644 +index 000000000000..3b752bba748b +--- /dev/null ++++ b/Documentation/devicetree/bindings/sound/everest,es8316.yaml +@@ -0,0 +1,50 @@ ++# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/sound/everest,es8316.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: Everest ES8316 audio CODEC ++ ++maintainers: ++ - Daniel Drake ++ - Katsuhiro Suzuki ++ ++properties: ++ compatible: ++ const: everest,es8316 ++ ++ reg: ++ maxItems: 1 ++ ++ clocks: ++ items: ++ - description: clock for master clock (MCLK) ++ ++ clock-names: ++ items: ++ - const: mclk ++ ++ "#sound-dai-cells": ++ const: 0 ++ ++required: ++ - compatible ++ - reg ++ - "#sound-dai-cells" ++ ++additionalProperties: false ++ ++examples: ++ - | ++ i2c0 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ es8316: codec@11 { ++ compatible = "everest,es8316"; ++ reg = <0x11>; ++ clocks = <&clks 10>; ++ clock-names = "mclk"; ++ #sound-dai-cells = <0>; ++ }; ++ }; + +From f5b60a176251d6e0d1716bbe62a5697a80d38089 Mon Sep 17 00:00:00 2001 +From: Alper Nebi Yasak +Date: Tue, 21 Jul 2020 21:27:10 +0300 +Subject: [PATCH] ASoC: rk3399_gru_sound: Add DAPM pins, kcontrols for jack + detection + +PulseAudio (and perhaps other userspace utilities) can not detect any +jack for rk3399_gru_sound as the driver doesn't expose related Jack +kcontrols. + +This patch adds two DAPM pins to the headset jack, where the +snd_soc_card_jack_new() call automatically creates "Headphones Jack" and +"Headset Mic Jack" kcontrols from them. + +With an appropriate ALSA UCM config specifying JackControl fields for +the "Headphones" and "Headset" (mic) devices, PulseAudio can detect +plug/unplug events for both of them after this patch. + +Signed-off-by: Alper Nebi Yasak +Link: https://lore.kernel.org/r/20200721182709.6895-1-alpernebiyasak@gmail.com +Signed-off-by: Mark Brown +(cherry picked from commit d0508b4f16049a658d68a7c276ba08296c5a76bc) +--- + sound/soc/rockchip/rk3399_gru_sound.c | 17 ++++++++++++++++- + 1 file changed, 16 insertions(+), 1 deletion(-) + +diff --git a/sound/soc/rockchip/rk3399_gru_sound.c b/sound/soc/rockchip/rk3399_gru_sound.c +index 9539b0d024fe..3e45179638ca 100644 +--- a/sound/soc/rockchip/rk3399_gru_sound.c ++++ b/sound/soc/rockchip/rk3399_gru_sound.c +@@ -32,6 +32,19 @@ static unsigned int dmic_wakeup_delay; + + static struct snd_soc_jack rockchip_sound_jack; + ++/* Headset jack detection DAPM pins */ ++static struct snd_soc_jack_pin rockchip_sound_jack_pins[] = { ++ { ++ .pin = "Headphones", ++ .mask = SND_JACK_HEADPHONE, ++ }, ++ { ++ .pin = "Headset Mic", ++ .mask = SND_JACK_MICROPHONE, ++ }, ++ ++}; ++ + static const struct snd_soc_dapm_widget rockchip_dapm_widgets[] = { + SND_SOC_DAPM_HP("Headphones", NULL), + SND_SOC_DAPM_SPK("Speakers", NULL), +@@ -176,7 +189,9 @@ static int rockchip_sound_da7219_init(struct snd_soc_pcm_runtime *rtd) + SND_JACK_HEADSET | SND_JACK_LINEOUT | + SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3, +- &rockchip_sound_jack, NULL, 0); ++ &rockchip_sound_jack, ++ rockchip_sound_jack_pins, ++ ARRAY_SIZE(rockchip_sound_jack_pins)); + + if (ret) { + dev_err(rtd->card->dev, "New Headset Jack failed! (%d)\n", ret); diff --git a/patch/kernel/rk322x-current/01-linux-0002-rockchip-from-next.patch b/patch/kernel/rk322x-current/01-linux-0002-rockchip-from-next.patch new file mode 100644 index 000000000..a20e585c6 --- /dev/null +++ b/patch/kernel/rk322x-current/01-linux-0002-rockchip-from-next.patch @@ -0,0 +1,434 @@ +From 9d29c5e2f20a44575a5a0e483319682d62daa4b3 Mon Sep 17 00:00:00 2001 +From: Heiko Stuebner +Date: Wed, 29 Jan 2020 17:38:19 +0100 +Subject: [PATCH] clk: rockchip: convert rk3399 pll type to use + readl_relaxed_poll_timeout + +Instead of open coding the polling of the lock status, use the handy +readl_relaxed_poll_timeout for this. As the pll locking is normally +blazingly fast and we don't want to incur additional delays, we're +not doing any sleeps similar to for example the imx clk-pllv4 +and define a very safe but still short timeout of 1ms. + +Suggested-by: Stephen Boyd +Signed-off-by: Heiko Stuebner +Reviewed-by: Stephen Boyd +Link: https://lore.kernel.org/r/20200129163821.1547295-1-heiko@sntech.de +(cherry picked from commit bf4237a188f872e535de8cbfc7903c1387b83b01) +--- + drivers/clk/rockchip/clk-pll.c | 23 ++++++++++++----------- + 1 file changed, 12 insertions(+), 11 deletions(-) + +diff --git a/drivers/clk/rockchip/clk-pll.c b/drivers/clk/rockchip/clk-pll.c +index 10560d963baf..28b04aad31ad 100644 +--- a/drivers/clk/rockchip/clk-pll.c ++++ b/drivers/clk/rockchip/clk-pll.c +@@ -589,19 +589,20 @@ static const struct clk_ops rockchip_rk3066_pll_clk_ops = { + static int rockchip_rk3399_pll_wait_lock(struct rockchip_clk_pll *pll) + { + u32 pllcon; +- int delay = 24000000; ++ int ret; + +- /* poll check the lock status in rk3399 xPLLCON2 */ +- while (delay > 0) { +- pllcon = readl_relaxed(pll->reg_base + RK3399_PLLCON(2)); +- if (pllcon & RK3399_PLLCON2_LOCK_STATUS) +- return 0; ++ /* ++ * Lock time typical 250, max 500 input clock cycles @24MHz ++ * So define a very safe maximum of 1000us, meaning 24000 cycles. ++ */ ++ ret = readl_relaxed_poll_timeout(pll->reg_base + RK3399_PLLCON(2), ++ pllcon, ++ pllcon & RK3399_PLLCON2_LOCK_STATUS, ++ 0, 1000); ++ if (ret) ++ pr_err("%s: timeout waiting for pll to lock\n", __func__); + +- delay--; +- } +- +- pr_err("%s: timeout waiting for pll to lock\n", __func__); +- return -ETIMEDOUT; ++ return ret; + } + + static void rockchip_rk3399_pll_get_params(struct rockchip_clk_pll *pll, + +From afe54d66a661ce9d99250431f1371e46f9b6d8a5 Mon Sep 17 00:00:00 2001 +From: Heiko Stuebner +Date: Wed, 29 Jan 2020 17:38:20 +0100 +Subject: [PATCH] clk: rockchip: convert basic pll lock_wait to use + regmap_read_poll_timeout + +Instead of open coding the polling of the lock status, use the +handy regmap_read_poll_timeout for this. As the pll locking is +normally blazingly fast and we don't want to incur additional +delays, we're not doing any sleeps similar to for example the imx +clk-pllv4 and define a very safe but still short timeout of 1ms. + +Suggested-by: Stephen Boyd +Signed-off-by: Heiko Stuebner +Reviewed-by: Stephen Boyd +Link: https://lore.kernel.org/r/20200129163821.1547295-2-heiko@sntech.de +(cherry picked from commit 3507df1a4615113ae6509e0f14f6546f0d1c84b4) +--- + drivers/clk/rockchip/clk-pll.c | 21 ++++++--------------- + 1 file changed, 6 insertions(+), 15 deletions(-) + +diff --git a/drivers/clk/rockchip/clk-pll.c b/drivers/clk/rockchip/clk-pll.c +index 28b04aad31ad..945f8b2cacc1 100644 +--- a/drivers/clk/rockchip/clk-pll.c ++++ b/drivers/clk/rockchip/clk-pll.c +@@ -86,23 +86,14 @@ static int rockchip_pll_wait_lock(struct rockchip_clk_pll *pll) + { + struct regmap *grf = pll->ctx->grf; + unsigned int val; +- int delay = 24000000, ret; +- +- while (delay > 0) { +- ret = regmap_read(grf, pll->lock_offset, &val); +- if (ret) { +- pr_err("%s: failed to read pll lock status: %d\n", +- __func__, ret); +- return ret; +- } ++ int ret; + +- if (val & BIT(pll->lock_shift)) +- return 0; +- delay--; +- } ++ ret = regmap_read_poll_timeout(grf, pll->lock_offset, val, ++ val & BIT(pll->lock_shift), 0, 1000); ++ if (ret) ++ pr_err("%s: timeout waiting for pll to lock\n", __func__); + +- pr_err("%s: timeout waiting for pll to lock\n", __func__); +- return -ETIMEDOUT; ++ return ret; + } + + /** + +From 9a37c781854b2cc475aced9045ba8c35b6838f3a Mon Sep 17 00:00:00 2001 +From: Heiko Stuebner +Date: Wed, 29 Jan 2020 17:38:21 +0100 +Subject: [PATCH] clk: rockchip: convert rk3036 pll type to use internal lock + status + +The rk3036 pll type exposes its lock status in both its pllcon registers +as well as the General Register Files. To remove one dependency convert +it to the "internal" lock status, similar to how rk3399 handles it. + +Signed-off-by: Heiko Stuebner +Reviewed-by: Stephen Boyd +Link: https://lore.kernel.org/r/20200129163821.1547295-3-heiko@sntech.de +(cherry picked from commit 7f6ffbb885d147557bdca471c37b7b1204005798) +--- + drivers/clk/rockchip/clk-pll.c | 26 +++++++++++++++++++++++--- + 1 file changed, 23 insertions(+), 3 deletions(-) + +diff --git a/drivers/clk/rockchip/clk-pll.c b/drivers/clk/rockchip/clk-pll.c +index 945f8b2cacc1..4c6c9167ef50 100644 +--- a/drivers/clk/rockchip/clk-pll.c ++++ b/drivers/clk/rockchip/clk-pll.c +@@ -12,6 +12,7 @@ + #include + #include + #include ++#include + #include + #include + #include "clk.h" +@@ -109,12 +110,31 @@ static int rockchip_pll_wait_lock(struct rockchip_clk_pll *pll) + #define RK3036_PLLCON1_REFDIV_SHIFT 0 + #define RK3036_PLLCON1_POSTDIV2_MASK 0x7 + #define RK3036_PLLCON1_POSTDIV2_SHIFT 6 ++#define RK3036_PLLCON1_LOCK_STATUS BIT(10) + #define RK3036_PLLCON1_DSMPD_MASK 0x1 + #define RK3036_PLLCON1_DSMPD_SHIFT 12 ++#define RK3036_PLLCON1_PWRDOWN BIT(13) + #define RK3036_PLLCON2_FRAC_MASK 0xffffff + #define RK3036_PLLCON2_FRAC_SHIFT 0 + +-#define RK3036_PLLCON1_PWRDOWN (1 << 13) ++static int rockchip_rk3036_pll_wait_lock(struct rockchip_clk_pll *pll) ++{ ++ u32 pllcon; ++ int ret; ++ ++ /* ++ * Lock time typical 250, max 500 input clock cycles @24MHz ++ * So define a very safe maximum of 1000us, meaning 24000 cycles. ++ */ ++ ret = readl_relaxed_poll_timeout(pll->reg_base + RK3036_PLLCON(1), ++ pllcon, ++ pllcon & RK3036_PLLCON1_LOCK_STATUS, ++ 0, 1000); ++ if (ret) ++ pr_err("%s: timeout waiting for pll to lock\n", __func__); ++ ++ return ret; ++} + + static void rockchip_rk3036_pll_get_params(struct rockchip_clk_pll *pll, + struct rockchip_pll_rate_table *rate) +@@ -212,7 +232,7 @@ static int rockchip_rk3036_pll_set_params(struct rockchip_clk_pll *pll, + writel_relaxed(pllcon, pll->reg_base + RK3036_PLLCON(2)); + + /* wait for the pll to lock */ +- ret = rockchip_pll_wait_lock(pll); ++ ret = rockchip_rk3036_pll_wait_lock(pll); + if (ret) { + pr_warn("%s: pll update unsuccessful, trying to restore old params\n", + __func__); +@@ -251,7 +271,7 @@ static int rockchip_rk3036_pll_enable(struct clk_hw *hw) + + writel(HIWORD_UPDATE(0, RK3036_PLLCON1_PWRDOWN, 0), + pll->reg_base + RK3036_PLLCON(1)); +- rockchip_pll_wait_lock(pll); ++ rockchip_rk3036_pll_wait_lock(pll); + + return 0; + } + +From 4e8605e139b42a4b239339fc54016ef2d0704908 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Myl=C3=A8ne=20Josserand?= +Date: Tue, 2 Jun 2020 10:06:43 +0200 +Subject: [PATCH] clk: rockchip: Handle clock tree for rk3288w variant +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The revision rk3288w has a different clock tree about "hclk_vio" +clock, according to the BSP kernel code. + +This patch handles this difference by detecting which device-tree +we are using. If it is a "rockchip,rk3288-cru", let's register +the clock tree as it was before. If the device-tree node is +"rockchip,rk3288w-cru", we will apply the difference with this +version of this SoC. + +Noticed that this new device-tree compatible must be handled in +bootloader such as u-boot. + +Signed-off-by: Mylène Josserand +Link: https://lore.kernel.org/r/20200602080644.11333-2-mylene.josserand@collabora.com +Signed-off-by: Heiko Stuebner +(cherry picked from commit 1627f683636df70fb25358b0a7b39a24e8fce5bf) +--- + drivers/clk/rockchip/clk-rk3288.c | 20 ++++++++++++++++++-- + 1 file changed, 18 insertions(+), 2 deletions(-) + +diff --git a/drivers/clk/rockchip/clk-rk3288.c b/drivers/clk/rockchip/clk-rk3288.c +index cc2a177bbdbf..204976e2d0cb 100644 +--- a/drivers/clk/rockchip/clk-rk3288.c ++++ b/drivers/clk/rockchip/clk-rk3288.c +@@ -425,8 +425,6 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = { + COMPOSITE(0, "aclk_vio0", mux_pll_src_cpll_gpll_usb480m_p, CLK_IGNORE_UNUSED, + RK3288_CLKSEL_CON(31), 6, 2, MFLAGS, 0, 5, DFLAGS, + RK3288_CLKGATE_CON(3), 0, GFLAGS), +- DIV(0, "hclk_vio", "aclk_vio0", 0, +- RK3288_CLKSEL_CON(28), 8, 5, DFLAGS), + COMPOSITE(0, "aclk_vio1", mux_pll_src_cpll_gpll_usb480m_p, CLK_IGNORE_UNUSED, + RK3288_CLKSEL_CON(31), 14, 2, MFLAGS, 8, 5, DFLAGS, + RK3288_CLKGATE_CON(3), 2, GFLAGS), +@@ -819,6 +817,16 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = { + INVERTER(0, "pclk_isp", "pclk_isp_in", RK3288_CLKSEL_CON(29), 3, IFLAGS), + }; + ++static struct rockchip_clk_branch rk3288w_hclkvio_branch[] __initdata = { ++ DIV(0, "hclk_vio", "aclk_vio1", 0, ++ RK3288_CLKSEL_CON(28), 8, 5, DFLAGS), ++}; ++ ++static struct rockchip_clk_branch rk3288_hclkvio_branch[] __initdata = { ++ DIV(0, "hclk_vio", "aclk_vio0", 0, ++ RK3288_CLKSEL_CON(28), 8, 5, DFLAGS), ++}; ++ + static const char *const rk3288_critical_clocks[] __initconst = { + "aclk_cpu", + "aclk_peri", +@@ -936,6 +944,14 @@ static void __init rk3288_clk_init(struct device_node *np) + RK3288_GRF_SOC_STATUS1); + rockchip_clk_register_branches(ctx, rk3288_clk_branches, + ARRAY_SIZE(rk3288_clk_branches)); ++ ++ if (of_device_is_compatible(np, "rockchip,rk3288w-cru")) ++ rockchip_clk_register_branches(ctx, rk3288w_hclkvio_branch, ++ ARRAY_SIZE(rk3288w_hclkvio_branch)); ++ else ++ rockchip_clk_register_branches(ctx, rk3288_hclkvio_branch, ++ ARRAY_SIZE(rk3288_hclkvio_branch)); ++ + rockchip_clk_protect_critical(rk3288_critical_clocks, + ARRAY_SIZE(rk3288_critical_clocks)); + + +From cac2ef41ac59ff839b73fea934e8ffd161d406f2 Mon Sep 17 00:00:00 2001 +From: Heiko Stuebner +Date: Fri, 3 Jul 2020 17:49:48 +0200 +Subject: [PATCH] clk: rockchip: use separate compatibles for rk3288w-cru + +Commit 1627f683636d ("clk: rockchip: Handle clock tree for rk3288w variant") +added the check for rk3288w-specific clock-tree changes but in turn would +require a double-compatible due to re-using the main rockchip,rk3288-cru +compatible as entry point. + +The binding change actually describes the compatibles as one or the other +so adapt the code accordingly and add a real second entry-point for the +clock controller. + +Signed-off-by: Heiko Stuebner +Reviewed-by: Ezequiel Garcia +Reviewed-by: Jagan Teki +Tested-by: Jagan Teki # rock-pi-n8 +Link: https://lore.kernel.org/r/20200703154948.260369-1-heiko@sntech.de +(cherry picked from commit 0a7f99aad259d223ce69c03e792c7e2bfcf8c2c6) +--- + drivers/clk/rockchip/clk-rk3288.c | 21 +++++++++++++++++++-- + 1 file changed, 19 insertions(+), 2 deletions(-) + +diff --git a/drivers/clk/rockchip/clk-rk3288.c b/drivers/clk/rockchip/clk-rk3288.c +index 204976e2d0cb..93c794695c46 100644 +--- a/drivers/clk/rockchip/clk-rk3288.c ++++ b/drivers/clk/rockchip/clk-rk3288.c +@@ -15,6 +15,11 @@ + #define RK3288_GRF_SOC_CON(x) (0x244 + x * 4) + #define RK3288_GRF_SOC_STATUS1 0x284 + ++enum rk3288_variant { ++ RK3288_CRU, ++ RK3288W_CRU, ++}; ++ + enum rk3288_plls { + apll, dpll, cpll, gpll, npll, + }; +@@ -922,7 +927,8 @@ static struct syscore_ops rk3288_clk_syscore_ops = { + .resume = rk3288_clk_resume, + }; + +-static void __init rk3288_clk_init(struct device_node *np) ++static void __init rk3288_common_init(struct device_node *np, ++ enum rk3288_variant soc) + { + struct rockchip_clk_provider *ctx; + +@@ -945,7 +951,7 @@ static void __init rk3288_clk_init(struct device_node *np) + rockchip_clk_register_branches(ctx, rk3288_clk_branches, + ARRAY_SIZE(rk3288_clk_branches)); + +- if (of_device_is_compatible(np, "rockchip,rk3288w-cru")) ++ if (soc == RK3288W_CRU) + rockchip_clk_register_branches(ctx, rk3288w_hclkvio_branch, + ARRAY_SIZE(rk3288w_hclkvio_branch)); + else +@@ -970,4 +976,15 @@ static void __init rk3288_clk_init(struct device_node *np) + + rockchip_clk_of_add_provider(np, ctx); + } ++ ++static void __init rk3288_clk_init(struct device_node *np) ++{ ++ rk3288_common_init(np, RK3288_CRU); ++} + CLK_OF_DECLARE(rk3288_cru, "rockchip,rk3288-cru", rk3288_clk_init); ++ ++static void __init rk3288w_clk_init(struct device_node *np) ++{ ++ rk3288_common_init(np, RK3288W_CRU); ++} ++CLK_OF_DECLARE(rk3288w_cru, "rockchip,rk3288w-cru", rk3288w_clk_init); + +From b80ef30ce22bba6a4bdf9f0aaa9376b6fea24249 Mon Sep 17 00:00:00 2001 +From: Robin Murphy +Date: Thu, 18 Jun 2020 18:56:29 +0100 +Subject: [PATCH] clk: rockchip: Revert "fix wrong mmc sample phase shift for + rk3328" + +This reverts commit 82f4b67f018c88a7cc9337f0067ed3d6ec352648. + +According to a subsequent revert in the vendor kernel, the original +change was based on unclear documentation and was in fact incorrect. + +Emprically, my board's HS200 eMMC at 200MHZ apparently gets lucky with a +phase where this had no impact, but limiting max-frequency to 150MHz to +match the nominal capability of the I/O pins made it virtually unusable, +constantly throwing errors and retuning. With this revert, it starts +behaving perfectly at 150MHz too. + +Fixes: 82f4b67f018c ("clk: rockchip: fix wrong mmc sample phase shift for rk3328") +Signed-off-by: Robin Murphy +Reviewed-by: Shawn Lin +Link: https://lore.kernel.org/r/c80eb52e34c03f817586b6b7912fbd4e31be9079.1589475794.git.robin.murphy@arm.com +Signed-off-by: Heiko Stuebner +(cherry picked from commit 465931e70881476a210d44705102ef8b6ee6cdb0) +--- + drivers/clk/rockchip/clk-rk3328.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/clk/rockchip/clk-rk3328.c b/drivers/clk/rockchip/clk-rk3328.c +index c186a1985bf4..2429b7c2a8b3 100644 +--- a/drivers/clk/rockchip/clk-rk3328.c ++++ b/drivers/clk/rockchip/clk-rk3328.c +@@ -808,22 +808,22 @@ static struct rockchip_clk_branch rk3328_clk_branches[] __initdata = { + MMC(SCLK_SDMMC_DRV, "sdmmc_drv", "clk_sdmmc", + RK3328_SDMMC_CON0, 1), + MMC(SCLK_SDMMC_SAMPLE, "sdmmc_sample", "clk_sdmmc", +- RK3328_SDMMC_CON1, 0), ++ RK3328_SDMMC_CON1, 1), + + MMC(SCLK_SDIO_DRV, "sdio_drv", "clk_sdio", + RK3328_SDIO_CON0, 1), + MMC(SCLK_SDIO_SAMPLE, "sdio_sample", "clk_sdio", +- RK3328_SDIO_CON1, 0), ++ RK3328_SDIO_CON1, 1), + + MMC(SCLK_EMMC_DRV, "emmc_drv", "clk_emmc", + RK3328_EMMC_CON0, 1), + MMC(SCLK_EMMC_SAMPLE, "emmc_sample", "clk_emmc", +- RK3328_EMMC_CON1, 0), ++ RK3328_EMMC_CON1, 1), + + MMC(SCLK_SDMMC_EXT_DRV, "sdmmc_ext_drv", "clk_sdmmc_ext", + RK3328_SDMMC_EXT_CON0, 1), + MMC(SCLK_SDMMC_EXT_SAMPLE, "sdmmc_ext_sample", "clk_sdmmc_ext", +- RK3328_SDMMC_EXT_CON1, 0), ++ RK3328_SDMMC_EXT_CON1, 1), + }; + + static const char *const rk3328_critical_clocks[] __initconst = { + +From 21710a18bfba0cf0993a1ef700f03f540d2648ed Mon Sep 17 00:00:00 2001 +From: Alex Bee +Date: Wed, 22 Jul 2020 18:18:20 +0200 +Subject: [PATCH] clk: rockchip: add sclk_mac_lbtest to rk3188_critical_clocks + +Since the loopbacktest clock is not exported and is not touched in the +driver, it has to be added to rk3188_critical_clocks to be protected from +being disabled and in order to get the emac working. + +Signed-off-by: Alex Bee +Link: https://lore.kernel.org/r/20200722161820.5316-1-knaerzche@gmail.com +Signed-off-by: Heiko Stuebner +(cherry picked from commit ef990bcad58cf1d13c5a49191a2c2342eb8d6709) +--- + drivers/clk/rockchip/clk-rk3188.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/clk/rockchip/clk-rk3188.c b/drivers/clk/rockchip/clk-rk3188.c +index 77aebfb1d6d5..730020fcc7fe 100644 +--- a/drivers/clk/rockchip/clk-rk3188.c ++++ b/drivers/clk/rockchip/clk-rk3188.c +@@ -751,6 +751,7 @@ static const char *const rk3188_critical_clocks[] __initconst = { + "pclk_peri", + "hclk_cpubus", + "hclk_vio_bus", ++ "sclk_mac_lbtest", + }; + + static struct rockchip_clk_provider *__init rk3188_common_clk_init(struct device_node *np) diff --git a/patch/kernel/rk322x-current/01-linux-0003-rockchip-from-list.patch.disabled b/patch/kernel/rk322x-current/01-linux-0003-rockchip-from-list.patch.disabled deleted file mode 100644 index 179cc5018..000000000 --- a/patch/kernel/rk322x-current/01-linux-0003-rockchip-from-list.patch.disabled +++ /dev/null @@ -1,2372 +0,0 @@ -diff --git a/drivers/media/rc/keymaps/Makefile b/drivers/media/rc/keymaps/Makefile -index aaa1bf81d00d..c903112fc0c1 100644 ---- a/drivers/media/rc/keymaps/Makefile -+++ b/drivers/media/rc/keymaps/Makefile -@@ -79,6 +79,7 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \ - rc-npgtech.o \ - rc-odroid.o \ - rc-pctv-sedna.o \ -+ rc-pine64.o \ - rc-pinnacle-color.o \ - rc-pinnacle-grey.o \ - rc-pinnacle-pctv-hd.o \ -diff --git a/drivers/media/rc/keymaps/rc-pine64.c b/drivers/media/rc/keymaps/rc-pine64.c -new file mode 100644 -index 000000000000..94e5624f63f4 ---- /dev/null -+++ b/drivers/media/rc/keymaps/rc-pine64.c -@@ -0,0 +1,59 @@ -+// SPDX-License-Identifier: GPL-2.0+ -+// Keytable for Pine64 IR Remote Controller -+// Copyright (c) 2017 Jonas Karlman -+ -+#include -+#include -+ -+static struct rc_map_table pine64[] = { -+ { 0x404000, KEY_NUMERIC_0 }, -+ { 0x404001, KEY_NUMERIC_1 }, -+ { 0x404002, KEY_NUMERIC_2 }, -+ { 0x404003, KEY_NUMERIC_3 }, -+ { 0x404004, KEY_NUMERIC_4 }, -+ { 0x404005, KEY_NUMERIC_5 }, -+ { 0x404006, KEY_NUMERIC_6 }, -+ { 0x404007, KEY_NUMERIC_7 }, -+ { 0x404008, KEY_NUMERIC_8 }, -+ { 0x404009, KEY_NUMERIC_9 }, -+ { 0x40400a, KEY_MUTE }, -+ { 0x40400b, KEY_UP }, -+ { 0x40400c, KEY_BACKSPACE }, -+ { 0x40400d, KEY_OK }, -+ { 0x40400e, KEY_DOWN }, -+ { 0x404010, KEY_LEFT }, -+ { 0x404011, KEY_RIGHT }, -+ { 0x404017, KEY_VOLUMEDOWN }, -+ { 0x404018, KEY_VOLUMEUP }, -+ { 0x40401a, KEY_HOME }, -+ { 0x40401d, KEY_MENU }, -+ { 0x40401f, KEY_WWW }, -+ { 0x404045, KEY_BACK }, -+ { 0x404047, KEY_CONTEXT_MENU }, -+ { 0x40404d, KEY_POWER }, -+}; -+ -+static struct rc_map_list pine64_map = { -+ .map = { -+ .scan = pine64, -+ .size = ARRAY_SIZE(pine64), -+ .rc_proto = RC_PROTO_NECX, -+ .name = RC_MAP_PINE64, -+ } -+}; -+ -+static int __init init_rc_map_pine64(void) -+{ -+ return rc_map_register(&pine64_map); -+} -+ -+static void __exit exit_rc_map_pine64(void) -+{ -+ rc_map_unregister(&pine64_map); -+} -+ -+module_init(init_rc_map_pine64) -+module_exit(exit_rc_map_pine64) -+ -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("Jonas Karlman"); -diff --git a/include/media/rc-map.h b/include/media/rc-map.h -index d22810dcd85c..bd1f4f4347d5 100644 ---- a/include/media/rc-map.h -+++ b/include/media/rc-map.h -@@ -233,6 +233,7 @@ struct rc_map *rc_map_get(const char *name); - #define RC_MAP_NPGTECH "rc-npgtech" - #define RC_MAP_ODROID "rc-odroid" - #define RC_MAP_PCTV_SEDNA "rc-pctv-sedna" -+#define RC_MAP_PINE64 "rc-pine64" - #define RC_MAP_PINNACLE_COLOR "rc-pinnacle-color" - #define RC_MAP_PINNACLE_GREY "rc-pinnacle-grey" - #define RC_MAP_PINNACLE_PCTV_HD "rc-pinnacle-pctv-hd" --- -2.17.1 - - -From 64be34f37bf89d457bc4352f8f8c663a30464a40 Mon Sep 17 00:00:00 2001 -From: Jonas Karlman -Date: Wed, 7 Aug 2019 15:11:23 +0000 -Subject: [PATCH] ASoC: hdmi-codec: reorder channel allocation list - -Wrong channel allocation is selected by hdmi_codec_get_ch_alloc_table_idx(). - -E.g when ELD reports FL|FR|LFE|FC|RL|RR or FL|FR|LFE|FC|RL|RR|RC|RLC|RRC - -ca_id 0x01 with speaker mask FL|FR|LFE gets selected instead of -ca_id 0x03 with speaker mask FL|FR|LFE|FC for 4 channels - -and - -ca_id 0x04 with speaker mask FL|FR|RC gets selected instead of -ca_id 0x0b with speaker mask FL|FR|LFE|FC|RL|RR for 6 channels - -Fix this by reorder the channel allocation list with -most specific speaker mask at the top. - -Signed-off-by: Jonas Karlman ---- - sound/soc/codecs/hdmi-codec.c | 115 ++++++++++++++++------------------ - 1 file changed, 53 insertions(+), 62 deletions(-) - -diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c -index f005751da2cc..437759e5f459 100644 ---- a/sound/soc/codecs/hdmi-codec.c -+++ b/sound/soc/codecs/hdmi-codec.c -@@ -189,84 +189,75 @@ static const struct snd_pcm_chmap_elem hdmi_codec_8ch_chmaps[] = { - /* - * hdmi_codec_channel_alloc: speaker configuration available for CEA - * -- * This is an ordered list that must match with hdmi_codec_8ch_chmaps struct -+ * This is an ordered list where ca_id must exist in hdmi_codec_8ch_chmaps - * The preceding ones have better chances to be selected by - * hdmi_codec_get_ch_alloc_table_idx(). - */ - static const struct hdmi_codec_cea_spk_alloc hdmi_codec_channel_alloc[] = { - { .ca_id = 0x00, .n_ch = 2, -- .mask = FL | FR}, -- /* 2.1 */ -- { .ca_id = 0x01, .n_ch = 4, -- .mask = FL | FR | LFE}, -- /* Dolby Surround */ -+ .mask = FL | FR }, -+ { .ca_id = 0x03, .n_ch = 4, -+ .mask = FL | FR | LFE | FC }, - { .ca_id = 0x02, .n_ch = 4, - .mask = FL | FR | FC }, -- /* surround51 */ -+ { .ca_id = 0x01, .n_ch = 4, -+ .mask = FL | FR | LFE }, - { .ca_id = 0x0b, .n_ch = 6, -- .mask = FL | FR | LFE | FC | RL | RR}, -- /* surround40 */ -- { .ca_id = 0x08, .n_ch = 6, -- .mask = FL | FR | RL | RR }, -- /* surround41 */ -- { .ca_id = 0x09, .n_ch = 6, -- .mask = FL | FR | LFE | RL | RR }, -- /* surround50 */ -+ .mask = FL | FR | LFE | FC | RL | RR }, - { .ca_id = 0x0a, .n_ch = 6, - .mask = FL | FR | FC | RL | RR }, -- /* 6.1 */ -- { .ca_id = 0x0f, .n_ch = 8, -- .mask = FL | FR | LFE | FC | RL | RR | RC }, -- /* surround71 */ -+ { .ca_id = 0x09, .n_ch = 6, -+ .mask = FL | FR | LFE | RL | RR }, -+ { .ca_id = 0x08, .n_ch = 6, -+ .mask = FL | FR | RL | RR }, -+ { .ca_id = 0x07, .n_ch = 6, -+ .mask = FL | FR | LFE | FC | RC }, -+ { .ca_id = 0x06, .n_ch = 6, -+ .mask = FL | FR | FC | RC }, -+ { .ca_id = 0x05, .n_ch = 6, -+ .mask = FL | FR | LFE | RC }, -+ { .ca_id = 0x04, .n_ch = 6, -+ .mask = FL | FR | RC }, - { .ca_id = 0x13, .n_ch = 8, - .mask = FL | FR | LFE | FC | RL | RR | RLC | RRC }, -- /* others */ -- { .ca_id = 0x03, .n_ch = 8, -- .mask = FL | FR | LFE | FC }, -- { .ca_id = 0x04, .n_ch = 8, -- .mask = FL | FR | RC}, -- { .ca_id = 0x05, .n_ch = 8, -- .mask = FL | FR | LFE | RC }, -- { .ca_id = 0x06, .n_ch = 8, -- .mask = FL | FR | FC | RC }, -- { .ca_id = 0x07, .n_ch = 8, -- .mask = FL | FR | LFE | FC | RC }, -- { .ca_id = 0x0c, .n_ch = 8, -- .mask = FL | FR | RC | RL | RR }, -- { .ca_id = 0x0d, .n_ch = 8, -- .mask = FL | FR | LFE | RL | RR | RC }, -- { .ca_id = 0x0e, .n_ch = 8, -- .mask = FL | FR | FC | RL | RR | RC }, -- { .ca_id = 0x10, .n_ch = 8, -- .mask = FL | FR | RL | RR | RLC | RRC }, -- { .ca_id = 0x11, .n_ch = 8, -- .mask = FL | FR | LFE | RL | RR | RLC | RRC }, -+ { .ca_id = 0x1f, .n_ch = 8, -+ .mask = FL | FR | LFE | FC | RL | RR | FLC | FRC }, - { .ca_id = 0x12, .n_ch = 8, - .mask = FL | FR | FC | RL | RR | RLC | RRC }, -- { .ca_id = 0x14, .n_ch = 8, -- .mask = FL | FR | FLC | FRC }, -- { .ca_id = 0x15, .n_ch = 8, -- .mask = FL | FR | LFE | FLC | FRC }, -- { .ca_id = 0x16, .n_ch = 8, -- .mask = FL | FR | FC | FLC | FRC }, -- { .ca_id = 0x17, .n_ch = 8, -- .mask = FL | FR | LFE | FC | FLC | FRC }, -- { .ca_id = 0x18, .n_ch = 8, -- .mask = FL | FR | RC | FLC | FRC }, -- { .ca_id = 0x19, .n_ch = 8, -- .mask = FL | FR | LFE | RC | FLC | FRC }, -- { .ca_id = 0x1a, .n_ch = 8, -- .mask = FL | FR | RC | FC | FLC | FRC }, -- { .ca_id = 0x1b, .n_ch = 8, -- .mask = FL | FR | LFE | RC | FC | FLC | FRC }, -- { .ca_id = 0x1c, .n_ch = 8, -- .mask = FL | FR | RL | RR | FLC | FRC }, -- { .ca_id = 0x1d, .n_ch = 8, -- .mask = FL | FR | LFE | RL | RR | FLC | FRC }, - { .ca_id = 0x1e, .n_ch = 8, - .mask = FL | FR | FC | RL | RR | FLC | FRC }, -- { .ca_id = 0x1f, .n_ch = 8, -- .mask = FL | FR | LFE | FC | RL | RR | FLC | FRC }, -+ { .ca_id = 0x11, .n_ch = 8, -+ .mask = FL | FR | LFE | RL | RR | RLC | RRC }, -+ { .ca_id = 0x1d, .n_ch = 8, -+ .mask = FL | FR | LFE | RL | RR | FLC | FRC }, -+ { .ca_id = 0x10, .n_ch = 8, -+ .mask = FL | FR | RL | RR | RLC | RRC }, -+ { .ca_id = 0x1c, .n_ch = 8, -+ .mask = FL | FR | RL | RR | FLC | FRC }, -+ { .ca_id = 0x0f, .n_ch = 8, -+ .mask = FL | FR | LFE | FC | RL | RR | RC }, -+ { .ca_id = 0x1b, .n_ch = 8, -+ .mask = FL | FR | LFE | RC | FC | FLC | FRC }, -+ { .ca_id = 0x0e, .n_ch = 8, -+ .mask = FL | FR | FC | RL | RR | RC }, -+ { .ca_id = 0x1a, .n_ch = 8, -+ .mask = FL | FR | RC | FC | FLC | FRC }, -+ { .ca_id = 0x0d, .n_ch = 8, -+ .mask = FL | FR | LFE | RL | RR | RC }, -+ { .ca_id = 0x19, .n_ch = 8, -+ .mask = FL | FR | LFE | RC | FLC | FRC }, -+ { .ca_id = 0x0c, .n_ch = 8, -+ .mask = FL | FR | RC | RL | RR }, -+ { .ca_id = 0x18, .n_ch = 8, -+ .mask = FL | FR | RC | FLC | FRC }, -+ { .ca_id = 0x17, .n_ch = 8, -+ .mask = FL | FR | LFE | FC | FLC | FRC }, -+ { .ca_id = 0x16, .n_ch = 8, -+ .mask = FL | FR | FC | FLC | FRC }, -+ { .ca_id = 0x15, .n_ch = 8, -+ .mask = FL | FR | LFE | FLC | FRC }, -+ { .ca_id = 0x14, .n_ch = 8, -+ .mask = FL | FR | FLC | FRC }, - }; - - struct hdmi_codec_priv { --- -2.17.1 - - -From 5e626ea314cb0b25dc7a58e72908b1f91e762dfc Mon Sep 17 00:00:00 2001 -From: Jonas Karlman -Date: Tue, 1 Oct 2019 20:52:42 +0000 -Subject: [PATCH] media: cec-adap: add debounce support when setting an invalid - phys addr - -When EDID is refreshed, HDMI cable is unplugged/replugged or -an AVR is power cycled the CEC phys addr gets invalidated. - -This can cause some disruption of CEC communication when -adapter is being reconfigured. - -Add a debounce module option that can be used to debounce setting -an invalid phys addr. Default is not to use debouncing. - -Using a configured debounce of e.g. 5000 ms, cec reconfiguring -could be avoided when AVR was power cycled on my setup. - -Power off AVR (default cec.debounce=0): -[ 101.536866] cec-dw_hdmi: new physical address f.f.f.f -[ 102.495686] cec-dw_hdmi: new physical address 2.1.0.0 -[ 102.495913] cec-dw_hdmi: physical address: 2.1.0.0, claim 1 logical addresses -[ 102.628574] cec-dw_hdmi: config: la 1 pa 2.1.0.0 -[ 105.130115] cec-dw_hdmi: new physical address f.f.f.f -[ 106.979705] cec-dw_hdmi: new physical address 2.1.0.0 -[ 106.979872] cec-dw_hdmi: physical address: 2.1.0.0, claim 1 logical addresses -[ 107.112399] cec-dw_hdmi: config: la 1 pa 2.1.0.0 -[ 108.979408] cec-dw_hdmi: reported physical address 2.0.0.0 for logical address 5 -[ 109.205386] cec-dw_hdmi: reported physical address 2.0.0.0 for logical address 11 - -Power on AVR (default cec.debounce=0): -[ 158.398447] cec-dw_hdmi: new physical address f.f.f.f -[ 161.977714] cec-dw_hdmi: new physical address 2.1.0.0 -[ 161.978766] cec-dw_hdmi: physical address: 2.1.0.0, claim 1 logical addresses -[ 162.115624] cec-dw_hdmi: config: la 1 pa 2.1.0.0 -[ 162.402750] cec-dw_hdmi: new physical address f.f.f.f -[ 162.403389] cec-dw_hdmi: cec_transmit_msg_fh: adapter is unconfigured -[ 162.886757] cec-dw_hdmi: new physical address 2.1.0.0 -[ 162.886964] cec-dw_hdmi: physical address: 2.1.0.0, claim 1 logical addresses -[ 163.510725] cec-dw_hdmi: config: la 1 pa 2.1.0.0 -[ 173.034200] cec-dw_hdmi: message 10 89 02 05 timed out - -Power off AVR (cec.debounce=5000): -[ 251.720471] cec-dw_hdmi: reported physical address 2.0.0.0 for logical address 5 -[ 251.922432] cec-dw_hdmi: reported physical address 2.0.0.0 for logical address 11 - -Power on AVR (cec.debounce=5000): -[ 291.154262] cec-dw_hdmi: reported physical address 2.0.0.0 for logical address 5 -[ 291.296199] cec-dw_hdmi: reported physical address 2.0.0.0 for logical address 11 - -Signed-off-by: Jonas Karlman ---- - Documentation/media/uapi/cec/cec-intro.rst | 8 ++++++++ - drivers/media/cec/cec-adap.c | 9 ++++++++- - drivers/media/cec/cec-core.c | 18 ++++++++++++++++++ - drivers/media/cec/cec-priv.h | 1 + - include/media/cec.h | 2 ++ - 5 files changed, 37 insertions(+), 1 deletion(-) - -diff --git a/Documentation/media/uapi/cec/cec-intro.rst b/Documentation/media/uapi/cec/cec-intro.rst -index 05088fcefe81..9bfd11ef987b 100644 ---- a/Documentation/media/uapi/cec/cec-intro.rst -+++ b/Documentation/media/uapi/cec/cec-intro.rst -@@ -47,3 +47,11 @@ provides three tools to handle CEC: - determine how compliant the CEC implementation is. - - - cec-follower: emulates a CEC follower. -+ -+Debouncing -+---------- -+ -+The ``debounce_ms`` option is a module parameter that can be used to enabled -+debouncing of setting invalid physical address. -+ -+FIXME: Make a section "1.1 Debouncing" that explains this module option. -diff --git a/drivers/media/cec/cec-adap.c b/drivers/media/cec/cec-adap.c -index 6c95dc471d4c..c483e847db95 100644 ---- a/drivers/media/cec/cec-adap.c -+++ b/drivers/media/cec/cec-adap.c -@@ -1609,8 +1609,15 @@ void cec_s_phys_addr(struct cec_adapter *adap, u16 phys_addr, bool block) - if (IS_ERR_OR_NULL(adap)) - return; - -+ cancel_delayed_work_sync(&adap->debounce_work); -+ - mutex_lock(&adap->lock); -- __cec_s_phys_addr(adap, phys_addr, block); -+ if (cec_debounce_ms > 0 && !block && -+ phys_addr == CEC_PHYS_ADDR_INVALID && adap->phys_addr != phys_addr) -+ schedule_delayed_work(&adap->debounce_work, -+ msecs_to_jiffies(cec_debounce_ms)); -+ else -+ __cec_s_phys_addr(adap, phys_addr, block); - mutex_unlock(&adap->lock); - } - EXPORT_SYMBOL_GPL(cec_s_phys_addr); -diff --git a/drivers/media/cec/cec-core.c b/drivers/media/cec/cec-core.c -index 0c52e1bb3910..cd71d77c057c 100644 ---- a/drivers/media/cec/cec-core.c -+++ b/drivers/media/cec/cec-core.c -@@ -28,6 +28,10 @@ static bool debug_phys_addr; - module_param(debug_phys_addr, bool, 0644); - MODULE_PARM_DESC(debug_phys_addr, "add CEC_CAP_PHYS_ADDR if set"); - -+int cec_debounce_ms; -+module_param_named(debounce_ms, cec_debounce_ms, int, 0644); -+MODULE_PARM_DESC(debounce_ms, "invalid physical address debounce time in ms"); -+ - static dev_t cec_dev_t; - - /* Active devices */ -@@ -174,6 +178,8 @@ static void cec_devnode_unregister(struct cec_adapter *adap) - devnode->unregistered = true; - mutex_unlock(&devnode->lock); - -+ cancel_delayed_work_sync(&adap->debounce_work); -+ - mutex_lock(&adap->lock); - __cec_s_phys_addr(adap, CEC_PHYS_ADDR_INVALID, false); - __cec_s_log_addrs(adap, NULL, false); -@@ -232,6 +238,17 @@ static const struct file_operations cec_error_inj_fops = { - }; - #endif - -+static void cec_s_phys_addr_debounce(struct work_struct *work) -+{ -+ struct delayed_work *delayed_work = to_delayed_work(work); -+ struct cec_adapter *adap = -+ container_of(delayed_work, struct cec_adapter, debounce_work); -+ -+ mutex_lock(&adap->lock); -+ __cec_s_phys_addr(adap, CEC_PHYS_ADDR_INVALID, false); -+ mutex_unlock(&adap->lock); -+} -+ - struct cec_adapter *cec_allocate_adapter(const struct cec_adap_ops *ops, - void *priv, const char *name, u32 caps, - u8 available_las) -@@ -270,6 +287,7 @@ struct cec_adapter *cec_allocate_adapter(const struct cec_adap_ops *ops, - INIT_LIST_HEAD(&adap->transmit_queue); - INIT_LIST_HEAD(&adap->wait_queue); - init_waitqueue_head(&adap->kthread_waitq); -+ INIT_DELAYED_WORK(&adap->debounce_work, cec_s_phys_addr_debounce); - - /* adap->devnode initialization */ - INIT_LIST_HEAD(&adap->devnode.fhs); -diff --git a/drivers/media/cec/cec-priv.h b/drivers/media/cec/cec-priv.h -index 9bbd05053d42..d479dbd50528 100644 ---- a/drivers/media/cec/cec-priv.h -+++ b/drivers/media/cec/cec-priv.h -@@ -27,6 +27,7 @@ static inline bool msg_is_raw(const struct cec_msg *msg) - - /* cec-core.c */ - extern int cec_debug; -+extern int cec_debounce_ms; - int cec_get_device(struct cec_devnode *devnode); - void cec_put_device(struct cec_devnode *devnode); - -diff --git a/include/media/cec.h b/include/media/cec.h -index 972bc8cd4384..5befad3a6a0f 100644 ---- a/include/media/cec.h -+++ b/include/media/cec.h -@@ -164,6 +164,8 @@ struct cec_adapter { - wait_queue_head_t kthread_waitq; - wait_queue_head_t waitq; - -+ struct delayed_work debounce_work; -+ - const struct cec_adap_ops *ops; - void *priv; - u32 capabilities; --- -2.17.1 - - -From e7067ef6d71c5686c082f37f8e54454d499124a8 Mon Sep 17 00:00:00 2001 -From: Boris Brezillon -Date: Thu, 19 Dec 2019 11:11:48 +0100 -Subject: [PATCH] drm/bridge: Add a drm_bridge_state object - -One of the last remaining objects to not have its atomic state. - -This is being motivated by our attempt to support runtime bus-format -negotiation between elements of the bridge chain. -This patch just paves the road for such a feature by adding a new -drm_bridge_state object inheriting from drm_private_obj so we can -re-use some of the existing state initialization/tracking logic. - -Signed-off-by: Boris Brezillon -Reviewed-by: Neil Armstrong -Reviewed-by: Laurent Pinchart -Signed-off-by: Neil Armstrong ---- - drivers/gpu/drm/drm_atomic.c | 39 +++++++ - drivers/gpu/drm/drm_atomic_helper.c | 20 ++++ - drivers/gpu/drm/drm_bridge.c | 169 +++++++++++++++++++++++++++- - include/drm/drm_atomic.h | 3 + - include/drm/drm_bridge.h | 120 ++++++++++++++++++++ - 5 files changed, 345 insertions(+), 6 deletions(-) - -diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c -index d33691512a8e..bf1b9c37d515 100644 ---- a/drivers/gpu/drm/drm_atomic.c -+++ b/drivers/gpu/drm/drm_atomic.c -@@ -30,6 +30,7 @@ - - #include - #include -+#include - #include - #include - #include -@@ -1017,6 +1018,44 @@ static void drm_atomic_connector_print_state(struct drm_printer *p, - connector->funcs->atomic_print_state(p, state); - } - -+/** -+ * drm_atomic_add_encoder_bridges - add bridges attached to an encoder -+ * @state: atomic state -+ * @encoder: DRM encoder -+ * -+ * This function adds all bridges attached to @encoder. This is needed to add -+ * bridge states to @state and make them available when -+ * &bridge_funcs.atomic_{check,pre_enable,enable,disable_post_disable}() are -+ * called -+ * -+ * Returns: -+ * 0 on success or can fail with -EDEADLK or -ENOMEM. When the error is EDEADLK -+ * then the w/w mutex code has detected a deadlock and the entire atomic -+ * sequence must be restarted. All other errors are fatal. -+ */ -+int -+drm_atomic_add_encoder_bridges(struct drm_atomic_state *state, -+ struct drm_encoder *encoder) -+{ -+ struct drm_bridge_state *bridge_state; -+ struct drm_bridge *bridge; -+ -+ if (!encoder) -+ return 0; -+ -+ DRM_DEBUG_ATOMIC("Adding all bridges for [encoder:%d:%s] to %p\n", -+ encoder->base.id, encoder->name, state); -+ -+ drm_for_each_bridge_in_chain(encoder, bridge) { -+ bridge_state = drm_atomic_get_bridge_state(state, bridge); -+ if (IS_ERR(bridge_state)) -+ return PTR_ERR(bridge_state); -+ } -+ -+ return 0; -+} -+EXPORT_SYMBOL(drm_atomic_add_encoder_bridges); -+ - /** - * drm_atomic_add_affected_connectors - add connectors for CRTC - * @state: atomic state -diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c -index 4511c2e07bb9..ad8eae98d9e8 100644 ---- a/drivers/gpu/drm/drm_atomic_helper.c -+++ b/drivers/gpu/drm/drm_atomic_helper.c -@@ -730,6 +730,26 @@ drm_atomic_helper_check_modeset(struct drm_device *dev, - return ret; - } - -+ /* -+ * Iterate over all connectors again, and add all affected bridges to -+ * the state. -+ */ -+ for_each_oldnew_connector_in_state(state, connector, -+ old_connector_state, -+ new_connector_state, i) { -+ struct drm_encoder *encoder; -+ -+ encoder = old_connector_state->best_encoder; -+ ret = drm_atomic_add_encoder_bridges(state, encoder); -+ if (ret) -+ return ret; -+ -+ encoder = new_connector_state->best_encoder; -+ ret = drm_atomic_add_encoder_bridges(state, encoder); -+ if (ret) -+ return ret; -+ } -+ - ret = mode_valid(state); - if (ret) - return ret; -diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c -index c2cf0c90fa26..a3921b45f044 100644 ---- a/drivers/gpu/drm/drm_bridge.c -+++ b/drivers/gpu/drm/drm_bridge.c -@@ -25,6 +25,7 @@ - #include - #include - -+#include - #include - #include - -@@ -89,6 +90,38 @@ void drm_bridge_remove(struct drm_bridge *bridge) - } - EXPORT_SYMBOL(drm_bridge_remove); - -+static struct drm_private_state * -+drm_bridge_atomic_duplicate_priv_state(struct drm_private_obj *obj) -+{ -+ struct drm_bridge *bridge = drm_priv_to_bridge(obj); -+ struct drm_bridge_state *state; -+ -+ if (bridge->funcs->atomic_duplicate_state) -+ state = bridge->funcs->atomic_duplicate_state(bridge); -+ else -+ state = drm_atomic_helper_bridge_duplicate_state(bridge); -+ -+ return state ? &state->base : NULL; -+} -+ -+static void -+drm_bridge_atomic_destroy_priv_state(struct drm_private_obj *obj, -+ struct drm_private_state *s) -+{ -+ struct drm_bridge_state *state = drm_priv_to_bridge_state(s); -+ struct drm_bridge *bridge = drm_priv_to_bridge(obj); -+ -+ if (bridge->funcs->atomic_destroy_state) -+ bridge->funcs->atomic_destroy_state(bridge, state); -+ else -+ drm_atomic_helper_bridge_destroy_state(bridge, state); -+} -+ -+static const struct drm_private_state_funcs drm_bridge_priv_state_funcs = { -+ .atomic_duplicate_state = drm_bridge_atomic_duplicate_priv_state, -+ .atomic_destroy_state = drm_bridge_atomic_destroy_priv_state, -+}; -+ - /** - * drm_bridge_attach - attach the bridge to an encoder's chain - * -@@ -114,6 +147,7 @@ EXPORT_SYMBOL(drm_bridge_remove); - int drm_bridge_attach(struct drm_encoder *encoder, struct drm_bridge *bridge, - struct drm_bridge *previous) - { -+ struct drm_bridge_state *state; - int ret; - - if (!encoder || !bridge) -@@ -135,15 +169,35 @@ int drm_bridge_attach(struct drm_encoder *encoder, struct drm_bridge *bridge, - - if (bridge->funcs->attach) { - ret = bridge->funcs->attach(bridge); -- if (ret < 0) { -- list_del(&bridge->chain_node); -- bridge->dev = NULL; -- bridge->encoder = NULL; -- return ret; -- } -+ if (ret < 0) -+ goto err_reset_bridge; -+ } -+ -+ if (bridge->funcs->atomic_reset) -+ state = bridge->funcs->atomic_reset(bridge); -+ else -+ state = drm_atomic_helper_bridge_reset(bridge); -+ -+ if (IS_ERR(state)) { -+ ret = PTR_ERR(state); -+ goto err_detach_bridge; - } - -+ drm_atomic_private_obj_init(bridge->dev, &bridge->base, -+ &state->base, -+ &drm_bridge_priv_state_funcs); -+ - return 0; -+ -+err_detach_bridge: -+ if (bridge->funcs->detach) -+ bridge->funcs->detach(bridge); -+ -+err_reset_bridge: -+ bridge->dev = NULL; -+ bridge->encoder = NULL; -+ list_del(&bridge->chain_node); -+ return ret; - } - EXPORT_SYMBOL(drm_bridge_attach); - -@@ -155,6 +209,8 @@ void drm_bridge_detach(struct drm_bridge *bridge) - if (WARN_ON(!bridge->dev)) - return; - -+ drm_atomic_private_obj_fini(&bridge->base); -+ - if (bridge->funcs->detach) - bridge->funcs->detach(bridge); - -@@ -516,6 +572,107 @@ void drm_atomic_bridge_chain_enable(struct drm_bridge *bridge, - } - EXPORT_SYMBOL(drm_atomic_bridge_chain_enable); - -+/** -+ * drm_atomic_helper_bridge_destroy_state() - Default destroy state helper -+ * @bridge: the bridge this state refers to -+ * @state: state object to destroy -+ * -+ * Just a simple kfree() for now. -+ */ -+void drm_atomic_helper_bridge_destroy_state(struct drm_bridge *bridge, -+ struct drm_bridge_state *state) -+{ -+ kfree(state); -+} -+EXPORT_SYMBOL(drm_atomic_helper_bridge_destroy_state); -+ -+/** -+ * __drm_atomic_helper_bridge_reset() - Initialize a bridge state to its -+ * default -+ * @bridge: the bridge this state is refers to -+ * @state: bridge state to initialize -+ * -+ * Initialize the bridge state to default values. This is meant to be* called -+ * by the bridge &drm_plane_funcs.reset hook for bridges that subclass the -+ * bridge state. -+ */ -+void __drm_atomic_helper_bridge_reset(struct drm_bridge *bridge, -+ struct drm_bridge_state *state) -+{ -+ memset(state, 0, sizeof(*state)); -+ state->bridge = bridge; -+} -+EXPORT_SYMBOL(__drm_atomic_helper_bridge_reset); -+ -+/** -+ * drm_atomic_helper_bridge_reset() - default &drm_plane_funcs.reset hook for -+ * bridges -+ * @bridge: the bridge to reset state on -+ * -+ * Resets the atomic state for @bridge by freeing the state pointer (which -+ * might be NULL, e.g. at driver load time) and allocating a new empty state -+ * object. -+ * -+ * RETURNS: -+ * A valid drm_bridge_state object in case of success, an ERR_PTR() -+ * giving the reaon of the failure otherwise. -+ */ -+struct drm_bridge_state * -+drm_atomic_helper_bridge_reset(struct drm_bridge *bridge) -+{ -+ struct drm_bridge_state *bridge_state; -+ -+ bridge_state = kzalloc(sizeof(*bridge_state), GFP_KERNEL); -+ if (!bridge_state) -+ return ERR_PTR(-ENOMEM); -+ -+ __drm_atomic_helper_bridge_reset(bridge, bridge_state); -+ return bridge_state; -+} -+EXPORT_SYMBOL(drm_atomic_helper_bridge_reset); -+ -+/** -+ * __drm_atomic_helper_bridge_duplicate_state() - Copy atomic bridge state -+ * @bridge: bridge object -+ * @state: atomic bridge state -+ * -+ * Copies atomic state from a bridge's current state and resets inferred values. -+ * This is useful for drivers that subclass the bridge state. -+ */ -+void __drm_atomic_helper_bridge_duplicate_state(struct drm_bridge *bridge, -+ struct drm_bridge_state *state) -+{ -+ __drm_atomic_helper_private_obj_duplicate_state(&bridge->base, -+ &state->base); -+ state->bridge = bridge; -+} -+EXPORT_SYMBOL(__drm_atomic_helper_bridge_duplicate_state); -+ -+/** -+ * drm_atomic_helper_duplicate_bridge_state() - Default duplicate state helper -+ * @bridge: bridge containing the state to duplicate -+ * -+ * Default implementation of &drm_bridge_funcs.atomic_duplicate(). -+ * -+ * RETURNS: -+ * a valid state object or NULL if the allocation fails. -+ */ -+struct drm_bridge_state * -+drm_atomic_helper_bridge_duplicate_state(struct drm_bridge *bridge) -+{ -+ struct drm_bridge_state *new; -+ -+ if (WARN_ON(!bridge->base.state)) -+ return NULL; -+ -+ new = kzalloc(sizeof(*new), GFP_KERNEL); -+ if (new) -+ __drm_atomic_helper_bridge_duplicate_state(bridge, new); -+ -+ return new; -+} -+EXPORT_SYMBOL(drm_atomic_helper_bridge_duplicate_state); -+ - #ifdef CONFIG_OF - /** - * of_drm_find_bridge - find the bridge corresponding to the device node in -diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h -index 951dfb15c27b..ccce65e14917 100644 ---- a/include/drm/drm_atomic.h -+++ b/include/drm/drm_atomic.h -@@ -669,6 +669,9 @@ __drm_atomic_get_current_plane_state(struct drm_atomic_state *state, - return plane->state; - } - -+int __must_check -+drm_atomic_add_encoder_bridges(struct drm_atomic_state *state, -+ struct drm_encoder *encoder); - int __must_check - drm_atomic_add_affected_connectors(struct drm_atomic_state *state, - struct drm_crtc *crtc); -diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h -index 694e153a7531..8a926c1a08db 100644 ---- a/include/drm/drm_bridge.h -+++ b/include/drm/drm_bridge.h -@@ -25,6 +25,8 @@ - - #include - #include -+ -+#include - #include - #include - #include -@@ -33,6 +35,23 @@ struct drm_bridge; - struct drm_bridge_timings; - struct drm_panel; - -+/** -+ * struct drm_bridge_state - Atomic bridge state object -+ * @base: inherit from &drm_private_state -+ * @bridge: the bridge this state refers to -+ */ -+struct drm_bridge_state { -+ struct drm_private_state base; -+ -+ struct drm_bridge *bridge; -+}; -+ -+static inline struct drm_bridge_state * -+drm_priv_to_bridge_state(struct drm_private_state *priv) -+{ -+ return container_of(priv, struct drm_bridge_state, base); -+} -+ - /** - * struct drm_bridge_funcs - drm_bridge control functions - */ -@@ -338,6 +357,49 @@ struct drm_bridge_funcs { - */ - void (*atomic_post_disable)(struct drm_bridge *bridge, - struct drm_atomic_state *old_state); -+ -+ /** -+ * @atomic_duplicate_state: -+ * -+ * Duplicate the current bridge state object (which is guaranteed to be -+ * non-NULL). -+ * -+ * The atomic_duplicate_state() is optional. When not implemented the -+ * core allocates a drm_bridge_state object and calls -+ * &__drm_atomic_helper_bridge_duplicate_state() to initialize it. -+ * -+ * RETURNS: -+ * A valid drm_bridge_state object or NULL if the allocation fails. -+ */ -+ struct drm_bridge_state *(*atomic_duplicate_state)(struct drm_bridge *bridge); -+ -+ /** -+ * @atomic_destroy_state: -+ * -+ * Destroy a bridge state object previously allocated by -+ * &drm_bridge_funcs.atomic_duplicate_state(). -+ * -+ * The atomic_destroy_state hook is optional. When not implemented the -+ * core calls kfree() on the state. -+ */ -+ void (*atomic_destroy_state)(struct drm_bridge *bridge, -+ struct drm_bridge_state *state); -+ -+ /** -+ * @atomic_reset: -+ * -+ * Reset the bridge to a predefined state (or retrieve its current -+ * state) and return a &drm_bridge_state object matching this state. -+ * This function is called at attach time. -+ * -+ * The atomic_reset hook is optional. When not implemented the core -+ * allocates a new state and calls &__drm_atomic_helper_bridge_reset(). -+ * -+ * RETURNS: -+ * A valid drm_bridge_state object in case of success, an ERR_PTR() -+ * giving the reason of the failure otherwise. -+ */ -+ struct drm_bridge_state *(*atomic_reset)(struct drm_bridge *bridge); - }; - - /** -@@ -380,6 +442,8 @@ struct drm_bridge_timings { - * struct drm_bridge - central DRM bridge control structure - */ - struct drm_bridge { -+ /** @base: inherit from &drm_private_object */ -+ struct drm_private_obj base; - /** @dev: DRM device this bridge belongs to */ - struct drm_device *dev; - /** @encoder: encoder to which this bridge is connected */ -@@ -404,6 +468,12 @@ struct drm_bridge { - void *driver_private; - }; - -+static inline struct drm_bridge * -+drm_priv_to_bridge(struct drm_private_obj *priv) -+{ -+ return container_of(priv, struct drm_bridge, base); -+} -+ - void drm_bridge_add(struct drm_bridge *bridge); - void drm_bridge_remove(struct drm_bridge *bridge); - struct drm_bridge *of_drm_find_bridge(struct device_node *np); -@@ -491,6 +561,56 @@ void drm_atomic_bridge_chain_pre_enable(struct drm_bridge *bridge, - void drm_atomic_bridge_chain_enable(struct drm_bridge *bridge, - struct drm_atomic_state *state); - -+void __drm_atomic_helper_bridge_reset(struct drm_bridge *bridge, -+ struct drm_bridge_state *state); -+void drm_atomic_helper_bridge_destroy_state(struct drm_bridge *bridge, -+ struct drm_bridge_state *state); -+struct drm_bridge_state * -+drm_atomic_helper_bridge_reset(struct drm_bridge *bridge); -+void __drm_atomic_helper_bridge_duplicate_state(struct drm_bridge *bridge, -+ struct drm_bridge_state *new); -+struct drm_bridge_state * -+drm_atomic_helper_bridge_duplicate_state(struct drm_bridge *bridge); -+ -+static inline struct drm_bridge_state * -+drm_atomic_get_bridge_state(struct drm_atomic_state *state, -+ struct drm_bridge *bridge) -+{ -+ struct drm_private_state *obj_state; -+ -+ obj_state = drm_atomic_get_private_obj_state(state, &bridge->base); -+ if (IS_ERR(obj_state)) -+ return ERR_CAST(obj_state); -+ -+ return drm_priv_to_bridge_state(obj_state); -+} -+ -+static inline struct drm_bridge_state * -+drm_atomic_get_old_bridge_state(struct drm_atomic_state *state, -+ struct drm_bridge *bridge) -+{ -+ struct drm_private_state *obj_state; -+ -+ obj_state = drm_atomic_get_old_private_obj_state(state, &bridge->base); -+ if (!obj_state) -+ return NULL; -+ -+ return drm_priv_to_bridge_state(obj_state); -+} -+ -+static inline struct drm_bridge_state * -+drm_atomic_get_new_bridge_state(struct drm_atomic_state *state, -+ struct drm_bridge *bridge) -+{ -+ struct drm_private_state *obj_state; -+ -+ obj_state = drm_atomic_get_new_private_obj_state(state, &bridge->base); -+ if (!obj_state) -+ return NULL; -+ -+ return drm_priv_to_bridge_state(obj_state); -+} -+ - #ifdef CONFIG_DRM_PANEL_BRIDGE - struct drm_bridge *drm_panel_bridge_add(struct drm_panel *panel); - struct drm_bridge *drm_panel_bridge_add_typed(struct drm_panel *panel, --- -2.17.1 - - -From 7b00bdecec40941c08461791cdc3ebfe766ffb15 Mon Sep 17 00:00:00 2001 -From: Boris Brezillon -Date: Thu, 19 Dec 2019 11:11:49 +0100 -Subject: [PATCH] drm/bridge: Patch atomic hooks to take a drm_bridge_state - -This way the drm_bridge_funcs interface is consistent with the rest of -the subsystem. - -The only driver implementing those hooks (analogix DP) is patched too. - -Signed-off-by: Boris Brezillon -Reviewed-by: Laurent Pinchart -Signed-off-by: Neil Armstrong ---- - .../drm/bridge/analogix/analogix_dp_core.c | 41 +++++++------ - drivers/gpu/drm/drm_bridge.c | 61 +++++++++++++++---- - include/drm/drm_bridge.h | 8 +-- - 3 files changed, 77 insertions(+), 33 deletions(-) - -diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c -index 6effe532f820..6fab71985cd4 100644 ---- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c -+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c -@@ -1289,19 +1289,21 @@ struct drm_crtc *analogix_dp_get_new_crtc(struct analogix_dp_device *dp, - return conn_state->crtc; - } - --static void analogix_dp_bridge_atomic_pre_enable(struct drm_bridge *bridge, -- struct drm_atomic_state *state) -+static void -+analogix_dp_bridge_atomic_pre_enable(struct drm_bridge *bridge, -+ struct drm_bridge_state *old_bridge_state) - { -+ struct drm_atomic_state *old_state = old_bridge_state->base.state; - struct analogix_dp_device *dp = bridge->driver_private; - struct drm_crtc *crtc; - struct drm_crtc_state *old_crtc_state; - int ret; - -- crtc = analogix_dp_get_new_crtc(dp, state); -+ crtc = analogix_dp_get_new_crtc(dp, old_state); - if (!crtc) - return; - -- old_crtc_state = drm_atomic_get_old_crtc_state(state, crtc); -+ old_crtc_state = drm_atomic_get_old_crtc_state(old_state, crtc); - /* Don't touch the panel if we're coming back from PSR */ - if (old_crtc_state && old_crtc_state->self_refresh_active) - return; -@@ -1366,20 +1368,22 @@ static int analogix_dp_set_bridge(struct analogix_dp_device *dp) - return ret; - } - --static void analogix_dp_bridge_atomic_enable(struct drm_bridge *bridge, -- struct drm_atomic_state *state) -+static void -+analogix_dp_bridge_atomic_enable(struct drm_bridge *bridge, -+ struct drm_bridge_state *old_bridge_state) - { -+ struct drm_atomic_state *old_state = old_bridge_state->base.state; - struct analogix_dp_device *dp = bridge->driver_private; - struct drm_crtc *crtc; - struct drm_crtc_state *old_crtc_state; - int timeout_loop = 0; - int ret; - -- crtc = analogix_dp_get_new_crtc(dp, state); -+ crtc = analogix_dp_get_new_crtc(dp, old_state); - if (!crtc) - return; - -- old_crtc_state = drm_atomic_get_old_crtc_state(state, crtc); -+ old_crtc_state = drm_atomic_get_old_crtc_state(old_state, crtc); - /* Not a full enable, just disable PSR and continue */ - if (old_crtc_state && old_crtc_state->self_refresh_active) { - ret = analogix_dp_disable_psr(dp); -@@ -1440,18 +1444,20 @@ static void analogix_dp_bridge_disable(struct drm_bridge *bridge) - dp->dpms_mode = DRM_MODE_DPMS_OFF; - } - --static void analogix_dp_bridge_atomic_disable(struct drm_bridge *bridge, -- struct drm_atomic_state *state) -+static void -+analogix_dp_bridge_atomic_disable(struct drm_bridge *bridge, -+ struct drm_bridge_state *old_bridge_state) - { -+ struct drm_atomic_state *old_state = old_bridge_state->base.state; - struct analogix_dp_device *dp = bridge->driver_private; - struct drm_crtc *crtc; - struct drm_crtc_state *new_crtc_state = NULL; - -- crtc = analogix_dp_get_new_crtc(dp, state); -+ crtc = analogix_dp_get_new_crtc(dp, old_state); - if (!crtc) - goto out; - -- new_crtc_state = drm_atomic_get_new_crtc_state(state, crtc); -+ new_crtc_state = drm_atomic_get_new_crtc_state(old_state, crtc); - if (!new_crtc_state) - goto out; - -@@ -1463,20 +1469,21 @@ static void analogix_dp_bridge_atomic_disable(struct drm_bridge *bridge, - analogix_dp_bridge_disable(bridge); - } - --static --void analogix_dp_bridge_atomic_post_disable(struct drm_bridge *bridge, -- struct drm_atomic_state *state) -+static void -+analogix_dp_bridge_atomic_post_disable(struct drm_bridge *bridge, -+ struct drm_bridge_state *old_bridge_state) - { -+ struct drm_atomic_state *old_state = old_bridge_state->base.state; - struct analogix_dp_device *dp = bridge->driver_private; - struct drm_crtc *crtc; - struct drm_crtc_state *new_crtc_state; - int ret; - -- crtc = analogix_dp_get_new_crtc(dp, state); -+ crtc = analogix_dp_get_new_crtc(dp, old_state); - if (!crtc) - return; - -- new_crtc_state = drm_atomic_get_new_crtc_state(state, crtc); -+ new_crtc_state = drm_atomic_get_new_crtc_state(old_state, crtc); - if (!new_crtc_state || !new_crtc_state->self_refresh_active) - return; - -diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c -index a3921b45f044..6bdc4ab789c9 100644 ---- a/drivers/gpu/drm/drm_bridge.c -+++ b/drivers/gpu/drm/drm_bridge.c -@@ -465,10 +465,19 @@ void drm_atomic_bridge_chain_disable(struct drm_bridge *bridge, - - encoder = bridge->encoder; - list_for_each_entry_reverse(iter, &encoder->bridge_chain, chain_node) { -- if (iter->funcs->atomic_disable) -- iter->funcs->atomic_disable(iter, old_state); -- else if (iter->funcs->disable) -+ if (iter->funcs->atomic_disable) { -+ struct drm_bridge_state *old_bridge_state; -+ -+ old_bridge_state = -+ drm_atomic_get_old_bridge_state(old_state, -+ iter); -+ if (WARN_ON(!old_bridge_state)) -+ return; -+ -+ iter->funcs->atomic_disable(iter, old_bridge_state); -+ } else if (iter->funcs->disable) { - iter->funcs->disable(iter); -+ } - - if (iter == bridge) - break; -@@ -499,10 +508,20 @@ void drm_atomic_bridge_chain_post_disable(struct drm_bridge *bridge, - - encoder = bridge->encoder; - list_for_each_entry_from(bridge, &encoder->bridge_chain, chain_node) { -- if (bridge->funcs->atomic_post_disable) -- bridge->funcs->atomic_post_disable(bridge, old_state); -- else if (bridge->funcs->post_disable) -+ if (bridge->funcs->atomic_post_disable) { -+ struct drm_bridge_state *old_bridge_state; -+ -+ old_bridge_state = -+ drm_atomic_get_old_bridge_state(old_state, -+ bridge); -+ if (WARN_ON(!old_bridge_state)) -+ return; -+ -+ bridge->funcs->atomic_post_disable(bridge, -+ old_bridge_state); -+ } else if (bridge->funcs->post_disable) { - bridge->funcs->post_disable(bridge); -+ } - } - } - EXPORT_SYMBOL(drm_atomic_bridge_chain_post_disable); -@@ -531,10 +550,19 @@ void drm_atomic_bridge_chain_pre_enable(struct drm_bridge *bridge, - - encoder = bridge->encoder; - list_for_each_entry_reverse(iter, &encoder->bridge_chain, chain_node) { -- if (iter->funcs->atomic_pre_enable) -- iter->funcs->atomic_pre_enable(iter, old_state); -- else if (iter->funcs->pre_enable) -+ if (iter->funcs->atomic_pre_enable) { -+ struct drm_bridge_state *old_bridge_state; -+ -+ old_bridge_state = -+ drm_atomic_get_old_bridge_state(old_state, -+ iter); -+ if (WARN_ON(!old_bridge_state)) -+ return; -+ -+ iter->funcs->atomic_pre_enable(iter, old_bridge_state); -+ } else if (iter->funcs->pre_enable) { - iter->funcs->pre_enable(iter); -+ } - - if (iter == bridge) - break; -@@ -564,10 +592,19 @@ void drm_atomic_bridge_chain_enable(struct drm_bridge *bridge, - - encoder = bridge->encoder; - list_for_each_entry_from(bridge, &encoder->bridge_chain, chain_node) { -- if (bridge->funcs->atomic_enable) -- bridge->funcs->atomic_enable(bridge, old_state); -- else if (bridge->funcs->enable) -+ if (bridge->funcs->atomic_enable) { -+ struct drm_bridge_state *old_bridge_state; -+ -+ old_bridge_state = -+ drm_atomic_get_old_bridge_state(old_state, -+ bridge); -+ if (WARN_ON(!old_bridge_state)) -+ return; -+ -+ bridge->funcs->atomic_enable(bridge, old_bridge_state); -+ } else if (bridge->funcs->enable) { - bridge->funcs->enable(bridge); -+ } - } - } - EXPORT_SYMBOL(drm_atomic_bridge_chain_enable); -diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h -index 8a926c1a08db..0331e330635b 100644 ---- a/include/drm/drm_bridge.h -+++ b/include/drm/drm_bridge.h -@@ -282,7 +282,7 @@ struct drm_bridge_funcs { - * The @atomic_pre_enable callback is optional. - */ - void (*atomic_pre_enable)(struct drm_bridge *bridge, -- struct drm_atomic_state *old_state); -+ struct drm_bridge_state *old_bridge_state); - - /** - * @atomic_enable: -@@ -307,7 +307,7 @@ struct drm_bridge_funcs { - * The @atomic_enable callback is optional. - */ - void (*atomic_enable)(struct drm_bridge *bridge, -- struct drm_atomic_state *old_state); -+ struct drm_bridge_state *old_bridge_state); - /** - * @atomic_disable: - * -@@ -330,7 +330,7 @@ struct drm_bridge_funcs { - * The @atomic_disable callback is optional. - */ - void (*atomic_disable)(struct drm_bridge *bridge, -- struct drm_atomic_state *old_state); -+ struct drm_bridge_state *old_bridge_state); - - /** - * @atomic_post_disable: -@@ -356,7 +356,7 @@ struct drm_bridge_funcs { - * The @atomic_post_disable callback is optional. - */ - void (*atomic_post_disable)(struct drm_bridge *bridge, -- struct drm_atomic_state *old_state); -+ struct drm_bridge_state *old_bridge_state); - - /** - * @atomic_duplicate_state: --- -2.17.1 - - -From 7891bb247f22d65b57b84efb5cadaae13114236b Mon Sep 17 00:00:00 2001 -From: Boris Brezillon -Date: Thu, 19 Dec 2019 11:11:50 +0100 -Subject: [PATCH] drm/bridge: Add an ->atomic_check() hook - -So that bridge drivers have a way to check/reject an atomic operation. -The drm_atomic_bridge_chain_check() (which is just a wrapper around -the ->atomic_check() hook) is called in place of -drm_bridge_chain_mode_fixup() (when ->atomic_check() is not implemented, -the core falls back on ->mode_fixup(), so the behavior should stay -the same for existing bridge drivers). - -Signed-off-by: Boris Brezillon -Reviewed-by: Neil Armstrong -Reviewed-by: Laurent Pinchart -Signed-off-by: Neil Armstrong ---- - drivers/gpu/drm/drm_atomic_helper.c | 12 +++--- - drivers/gpu/drm/drm_bridge.c | 62 +++++++++++++++++++++++++++++ - include/drm/drm_bridge.h | 29 +++++++++++++- - 3 files changed, 96 insertions(+), 7 deletions(-) - -diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c -index ad8eae98d9e8..afe14f72a824 100644 ---- a/drivers/gpu/drm/drm_atomic_helper.c -+++ b/drivers/gpu/drm/drm_atomic_helper.c -@@ -437,12 +437,12 @@ mode_fixup(struct drm_atomic_state *state) - funcs = encoder->helper_private; - - bridge = drm_bridge_chain_get_first_bridge(encoder); -- ret = drm_bridge_chain_mode_fixup(bridge, -- &new_crtc_state->mode, -- &new_crtc_state->adjusted_mode); -- if (!ret) { -- DRM_DEBUG_ATOMIC("Bridge fixup failed\n"); -- return -EINVAL; -+ ret = drm_atomic_bridge_chain_check(bridge, -+ new_crtc_state, -+ new_conn_state); -+ if (ret) { -+ DRM_DEBUG_ATOMIC("Bridge atomic check failed\n"); -+ return ret; - } - - if (funcs && funcs->atomic_check) { -diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c -index 6bdc4ab789c9..442804598f60 100644 ---- a/drivers/gpu/drm/drm_bridge.c -+++ b/drivers/gpu/drm/drm_bridge.c -@@ -609,6 +609,68 @@ void drm_atomic_bridge_chain_enable(struct drm_bridge *bridge, - } - EXPORT_SYMBOL(drm_atomic_bridge_chain_enable); - -+static int drm_atomic_bridge_check(struct drm_bridge *bridge, -+ struct drm_crtc_state *crtc_state, -+ struct drm_connector_state *conn_state) -+{ -+ if (bridge->funcs->atomic_check) { -+ struct drm_bridge_state *bridge_state; -+ int ret; -+ -+ bridge_state = drm_atomic_get_new_bridge_state(crtc_state->state, -+ bridge); -+ if (WARN_ON(!bridge_state)) -+ return -EINVAL; -+ -+ ret = bridge->funcs->atomic_check(bridge, bridge_state, -+ crtc_state, conn_state); -+ if (ret) -+ return ret; -+ } else if (bridge->funcs->mode_fixup) { -+ if (!bridge->funcs->mode_fixup(bridge, &crtc_state->mode, -+ &crtc_state->adjusted_mode)) -+ return -EINVAL; -+ } -+ -+ return 0; -+} -+ -+/** -+ * drm_atomic_bridge_chain_check() - Do an atomic check on the bridge chain -+ * @bridge: bridge control structure -+ * @crtc_state: new CRTC state -+ * @conn_state: new connector state -+ * -+ * Calls &drm_bridge_funcs.atomic_check() (falls back on -+ * &drm_bridge_funcs.mode_fixup()) op for all the bridges in the encoder chain, -+ * starting from the last bridge to the first. These are called before calling -+ * &drm_encoder_helper_funcs.atomic_check() -+ * -+ * RETURNS: -+ * 0 on success, a negative error code on failure -+ */ -+int drm_atomic_bridge_chain_check(struct drm_bridge *bridge, -+ struct drm_crtc_state *crtc_state, -+ struct drm_connector_state *conn_state) -+{ -+ struct drm_encoder *encoder = bridge->encoder; -+ struct drm_bridge *iter; -+ -+ list_for_each_entry_reverse(iter, &encoder->bridge_chain, chain_node) { -+ int ret; -+ -+ ret = drm_atomic_bridge_check(iter, crtc_state, conn_state); -+ if (ret) -+ return ret; -+ -+ if (iter == bridge) -+ break; -+ } -+ -+ return 0; -+} -+EXPORT_SYMBOL(drm_atomic_bridge_chain_check); -+ - /** - * drm_atomic_helper_bridge_destroy_state() - Default destroy state helper - * @bridge: the bridge this state refers to -diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h -index 0331e330635b..269f0d1da339 100644 ---- a/include/drm/drm_bridge.h -+++ b/include/drm/drm_bridge.h -@@ -128,7 +128,9 @@ struct drm_bridge_funcs { - * this function passes all other callbacks must succeed for this - * configuration. - * -- * The @mode_fixup callback is optional. -+ * The mode_fixup callback is optional. &drm_bridge_funcs.mode_fixup() -+ * is not called when &drm_bridge_funcs.atomic_check() is implemented, -+ * so only one of them should be provided. - * - * NOTE: - * -@@ -385,6 +387,28 @@ struct drm_bridge_funcs { - void (*atomic_destroy_state)(struct drm_bridge *bridge, - struct drm_bridge_state *state); - -+ /** -+ * @atomic_check: -+ * -+ * This method is responsible for checking bridge state correctness. -+ * It can also check the state of the surrounding components in chain -+ * to make sure the whole pipeline can work properly. -+ * -+ * &drm_bridge_funcs.atomic_check() hooks are called in reverse -+ * order (from the last to the first bridge). -+ * -+ * This method is optional. &drm_bridge_funcs.mode_fixup() is not -+ * called when &drm_bridge_funcs.atomic_check() is implemented, so only -+ * one of them should be provided. -+ * -+ * RETURNS: -+ * zero if the check passed, a negative error code otherwise. -+ */ -+ int (*atomic_check)(struct drm_bridge *bridge, -+ struct drm_bridge_state *bridge_state, -+ struct drm_crtc_state *crtc_state, -+ struct drm_connector_state *conn_state); -+ - /** - * @atomic_reset: - * -@@ -552,6 +576,9 @@ void drm_bridge_chain_mode_set(struct drm_bridge *bridge, - void drm_bridge_chain_pre_enable(struct drm_bridge *bridge); - void drm_bridge_chain_enable(struct drm_bridge *bridge); - -+int drm_atomic_bridge_chain_check(struct drm_bridge *bridge, -+ struct drm_crtc_state *crtc_state, -+ struct drm_connector_state *conn_state); - void drm_atomic_bridge_chain_disable(struct drm_bridge *bridge, - struct drm_atomic_state *state); - void drm_atomic_bridge_chain_post_disable(struct drm_bridge *bridge, --- -2.17.1 - - -From 08c9023ffcdae0022fe84dac4e12efc6f989c6c8 Mon Sep 17 00:00:00 2001 -From: Boris Brezillon -Date: Thu, 19 Dec 2019 11:11:51 +0100 -Subject: [PATCH] drm/bridge: Add the necessary bits to support bus format - negotiation - -drm_bridge_state is extended to describe the input and output bus -configurations. These bus configurations are exposed through the -drm_bus_cfg struct which encodes the configuration of a physical -bus between two components in an output pipeline, usually between -two bridges, an encoder and a bridge, or a bridge and a connector. - -The bus configuration is stored in drm_bridge_state separately for -the input and output buses, as seen from the point of view of each -bridge. The bus configuration of a bridge output is usually identical -to the configuration of the next bridge's input, but may differ if -the signals are modified between the two bridges, for instance by an -inverter on the board. The input and output configurations of a -bridge may differ if the bridge modifies the signals internally, -for instance by performing format conversion, or*modifying signals -polarities. - -Bus format negotiation is automated by the core, drivers just have -to implement the ->atomic_get_{output,input}_bus_fmts() hooks if they -want to take part to this negotiation. Negotiation happens in reverse -order, starting from the last element of the chain (the one directly -connected to the display) up to the first element of the chain (the one -connected to the encoder). -During this negotiation all supported formats are tested until we find -one that works, meaning that the formats array should be in decreasing -preference order (assuming the driver has a preference order). - -Note that the bus format negotiation works even if some elements in the -chain don't implement the ->atomic_get_{output,input}_bus_fmts() hooks. -In that case, the core advertises only MEDIA_BUS_FMT_FIXED and lets -the previous bridge element decide what to do (most of the time, bridge -drivers will pick a default bus format or extract this piece of -information from somewhere else, like a FW property). - -Signed-off-by: Boris Brezillon -Signed-off-by: Neil Armstrong ---- - drivers/gpu/drm/drm_bridge.c | 267 ++++++++++++++++++++++++++++++++++- - include/drm/drm_bridge.h | 124 ++++++++++++++++ - 2 files changed, 390 insertions(+), 1 deletion(-) - -diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c -index 442804598f60..9cc4b0181f85 100644 ---- a/drivers/gpu/drm/drm_bridge.c -+++ b/drivers/gpu/drm/drm_bridge.c -@@ -635,13 +635,261 @@ static int drm_atomic_bridge_check(struct drm_bridge *bridge, - return 0; - } - -+/** -+ * drm_atomic_helper_bridge_propagate_bus_fmt() - Propagate output format to -+ * the input end of a bridge -+ * @bridge: bridge control structure -+ * @bridge_state: new bridge state -+ * @crtc_state: new CRTC state -+ * @conn_state: new connector state -+ * @output_fmt: tested output bus format -+ * @num_input_fmts: will contain the size of the returned array -+ * -+ * This helper is a pluggable implementation of the -+ * &drm_bridge_funcs.atomic_get_input_bus_fmts operation for bridges that don't -+ * modify the bus configuration between their input and their output. It -+ * returns an array of input formats with a single element set to @output_fmt. -+ * -+ * RETURNS: -+ * a valid format array of size @num_input_fmts, or NULL if the allocation -+ * failed -+ */ -+u32 * -+drm_atomic_helper_bridge_propagate_bus_fmt(struct drm_bridge *bridge, -+ struct drm_bridge_state *bridge_state, -+ struct drm_crtc_state *crtc_state, -+ struct drm_connector_state *conn_state, -+ u32 output_fmt, -+ unsigned int *num_input_fmts) -+{ -+ u32 *input_fmts; -+ -+ input_fmts = kzalloc(sizeof(*input_fmts), GFP_KERNEL); -+ if (!input_fmts) { -+ *num_input_fmts = 0; -+ return NULL; -+ } -+ -+ *num_input_fmts = 1; -+ input_fmts[0] = output_fmt; -+ return input_fmts; -+} -+EXPORT_SYMBOL(drm_atomic_helper_bridge_propagate_bus_fmt); -+ -+static int select_bus_fmt_recursive(struct drm_bridge *first_bridge, -+ struct drm_bridge *cur_bridge, -+ struct drm_crtc_state *crtc_state, -+ struct drm_connector_state *conn_state, -+ u32 out_bus_fmt) -+{ -+ struct drm_bridge_state *cur_state; -+ unsigned int num_in_bus_fmts, i; -+ struct drm_bridge *prev_bridge; -+ u32 *in_bus_fmts; -+ int ret; -+ -+ prev_bridge = drm_bridge_get_prev_bridge(cur_bridge); -+ cur_state = drm_atomic_get_new_bridge_state(crtc_state->state, -+ cur_bridge); -+ if (WARN_ON(!cur_state)) -+ return -EINVAL; -+ -+ /* -+ * If bus format negotiation is not supported by this bridge, let's -+ * pass MEDIA_BUS_FMT_FIXED to the previous bridge in the chain and -+ * hope that it can handle this situation gracefully (by providing -+ * appropriate default values). -+ */ -+ if (!cur_bridge->funcs->atomic_get_input_bus_fmts) { -+ if (cur_bridge != first_bridge) { -+ ret = select_bus_fmt_recursive(first_bridge, -+ prev_bridge, crtc_state, -+ conn_state, -+ MEDIA_BUS_FMT_FIXED); -+ if (ret) -+ return ret; -+ } -+ -+ cur_state->input_bus_cfg.format = MEDIA_BUS_FMT_FIXED; -+ cur_state->output_bus_cfg.format = out_bus_fmt; -+ return 0; -+ } -+ -+ in_bus_fmts = cur_bridge->funcs->atomic_get_input_bus_fmts(cur_bridge, -+ cur_state, -+ crtc_state, -+ conn_state, -+ out_bus_fmt, -+ &num_in_bus_fmts); -+ if (!num_in_bus_fmts) -+ return -ENOTSUPP; -+ else if (!in_bus_fmts) -+ return -ENOMEM; -+ -+ if (first_bridge == cur_bridge) { -+ cur_state->input_bus_cfg.format = in_bus_fmts[0]; -+ cur_state->output_bus_cfg.format = out_bus_fmt; -+ kfree(in_bus_fmts); -+ return 0; -+ } -+ -+ for (i = 0; i < num_in_bus_fmts; i++) { -+ ret = select_bus_fmt_recursive(first_bridge, prev_bridge, -+ crtc_state, conn_state, -+ in_bus_fmts[i]); -+ if (ret != -ENOTSUPP) -+ break; -+ } -+ -+ if (!ret) { -+ cur_state->input_bus_cfg.format = in_bus_fmts[i]; -+ cur_state->output_bus_cfg.format = out_bus_fmt; -+ } -+ -+ kfree(in_bus_fmts); -+ return ret; -+} -+ -+/* -+ * This function is called by &drm_atomic_bridge_chain_check() just before -+ * calling &drm_bridge_funcs.atomic_check() on all elements of the chain. -+ * It performs bus format negotiation between bridge elements. The negotiation -+ * happens in reverse order, starting from the last element in the chain up to -+ * @bridge. -+ * -+ * Negotiation starts by retrieving supported output bus formats on the last -+ * bridge element and testing them one by one. The test is recursive, meaning -+ * that for each tested output format, the whole chain will be walked backward, -+ * and each element will have to choose an input bus format that can be -+ * transcoded to the requested output format. When a bridge element does not -+ * support transcoding into a specific output format -ENOTSUPP is returned and -+ * the next bridge element will have to try a different format. If none of the -+ * combinations worked, -ENOTSUPP is returned and the atomic modeset will fail. -+ * -+ * This implementation is relying on -+ * &drm_bridge_funcs.atomic_get_output_bus_fmts() and -+ * &drm_bridge_funcs.atomic_get_input_bus_fmts() to gather supported -+ * input/output formats. -+ * -+ * When &drm_bridge_funcs.atomic_get_output_bus_fmts() is not implemented by -+ * the last element of the chain, &drm_atomic_bridge_chain_select_bus_fmts() -+ * tries a single format: &drm_connector.display_info.bus_formats[0] if -+ * available, MEDIA_BUS_FMT_FIXED otherwise. -+ * -+ * When &drm_bridge_funcs.atomic_get_input_bus_fmts() is not implemented, -+ * &drm_atomic_bridge_chain_select_bus_fmts() skips the negotiation on the -+ * bridge element that lacks this hook and asks the previous element in the -+ * chain to try MEDIA_BUS_FMT_FIXED. It's up to bridge drivers to decide what -+ * to do in that case (fail if they want to enforce bus format negotiation, or -+ * provide a reasonable default if they need to support pipelines where not -+ * all elements support bus format negotiation). -+ */ -+static int -+drm_atomic_bridge_chain_select_bus_fmts(struct drm_bridge *bridge, -+ struct drm_crtc_state *crtc_state, -+ struct drm_connector_state *conn_state) -+{ -+ struct drm_connector *conn = conn_state->connector; -+ struct drm_encoder *encoder = bridge->encoder; -+ struct drm_bridge_state *last_bridge_state; -+ unsigned int i, num_out_bus_fmts; -+ struct drm_bridge *last_bridge; -+ u32 *out_bus_fmts; -+ int ret = 0; -+ -+ last_bridge = list_last_entry(&encoder->bridge_chain, -+ struct drm_bridge, chain_node); -+ last_bridge_state = drm_atomic_get_new_bridge_state(crtc_state->state, -+ last_bridge); -+ if (WARN_ON(!last_bridge_state)) -+ return -EINVAL; -+ -+ if (last_bridge->funcs->atomic_get_output_bus_fmts) { -+ const struct drm_bridge_funcs *funcs = last_bridge->funcs; -+ -+ out_bus_fmts = funcs->atomic_get_output_bus_fmts(last_bridge, -+ last_bridge_state, -+ crtc_state, -+ conn_state, -+ &num_out_bus_fmts); -+ if (!num_out_bus_fmts) -+ return -ENOTSUPP; -+ else if (!out_bus_fmts) -+ return -ENOMEM; -+ } else { -+ num_out_bus_fmts = 1; -+ out_bus_fmts = kmalloc(sizeof(*out_bus_fmts), GFP_KERNEL); -+ if (!out_bus_fmts) -+ return -ENOMEM; -+ -+ if (conn->display_info.num_bus_formats && -+ conn->display_info.bus_formats) -+ out_bus_fmts[0] = conn->display_info.bus_formats[0]; -+ else -+ out_bus_fmts[0] = MEDIA_BUS_FMT_FIXED; -+ } -+ -+ for (i = 0; i < num_out_bus_fmts; i++) { -+ ret = select_bus_fmt_recursive(bridge, last_bridge, crtc_state, -+ conn_state, out_bus_fmts[i]); -+ if (ret != -ENOTSUPP) -+ break; -+ } -+ -+ kfree(out_bus_fmts); -+ -+ return ret; -+} -+ -+static void -+drm_atomic_bridge_propagate_bus_flags(struct drm_bridge *bridge, -+ struct drm_connector *conn, -+ struct drm_atomic_state *state) -+{ -+ struct drm_bridge_state *bridge_state, *next_bridge_state; -+ struct drm_bridge *next_bridge; -+ u32 output_flags; -+ -+ bridge_state = drm_atomic_get_new_bridge_state(state, bridge); -+ next_bridge = drm_bridge_get_next_bridge(bridge); -+ -+ /* -+ * Let's try to apply the most common case here, that is, propagate -+ * display_info flags for the last bridge, and propagate the input -+ * flags of the next bridge element to the output end of the current -+ * bridge when the bridge is not the last one. -+ * There are exceptions to this rule, like when signal inversion is -+ * happening at the board level, but that's something drivers can deal -+ * with from their &drm_bridge_funcs.atomic_check() implementation by -+ * simply overriding the flags value we've set here. -+ */ -+ if (!next_bridge) { -+ output_flags = conn->display_info.bus_flags; -+ } else { -+ next_bridge_state = drm_atomic_get_new_bridge_state(state, -+ next_bridge); -+ output_flags = next_bridge_state->input_bus_cfg.flags; -+ } -+ -+ bridge_state->output_bus_cfg.flags = output_flags; -+ -+ /* -+ * Propage the output flags to the input end of the bridge. Again, it's -+ * not necessarily what all bridges want, but that's what most of them -+ * do, and by doing that by default we avoid forcing drivers to -+ * duplicate the "dummy propagation" logic. -+ */ -+ bridge_state->input_bus_cfg.flags = output_flags; -+} -+ - /** - * drm_atomic_bridge_chain_check() - Do an atomic check on the bridge chain - * @bridge: bridge control structure - * @crtc_state: new CRTC state - * @conn_state: new connector state - * -- * Calls &drm_bridge_funcs.atomic_check() (falls back on -+ * First trigger a bus format negotiation before calling -+ * &drm_bridge_funcs.atomic_check() (falls back on - * &drm_bridge_funcs.mode_fixup()) op for all the bridges in the encoder chain, - * starting from the last bridge to the first. These are called before calling - * &drm_encoder_helper_funcs.atomic_check() -@@ -653,12 +901,29 @@ int drm_atomic_bridge_chain_check(struct drm_bridge *bridge, - struct drm_crtc_state *crtc_state, - struct drm_connector_state *conn_state) - { -+ struct drm_connector *conn = conn_state->connector; - struct drm_encoder *encoder = bridge->encoder; - struct drm_bridge *iter; -+ int ret; -+ -+ ret = drm_atomic_bridge_chain_select_bus_fmts(bridge, crtc_state, -+ conn_state); -+ if (ret) -+ return ret; - - list_for_each_entry_reverse(iter, &encoder->bridge_chain, chain_node) { - int ret; - -+ /* -+ * Bus flags are propagated by default. If a bridge needs to -+ * tweak the input bus flags for any reason, it should happen -+ * in its &drm_bridge_funcs.atomic_check() implementation such -+ * that preceding bridges in the chain can propagate the new -+ * bus flags. -+ */ -+ drm_atomic_bridge_propagate_bus_flags(iter, conn, -+ crtc_state->state); -+ - ret = drm_atomic_bridge_check(iter, crtc_state, conn_state); - if (ret) - return ret; -diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h -index 269f0d1da339..192227f03d4b 100644 ---- a/include/drm/drm_bridge.h -+++ b/include/drm/drm_bridge.h -@@ -35,6 +35,38 @@ struct drm_bridge; - struct drm_bridge_timings; - struct drm_panel; - -+/** -+ * struct drm_bus_cfg - bus configuration -+ * -+ * This structure stores the configuration of a physical bus between two -+ * components in an output pipeline, usually between two bridges, an encoder -+ * and a bridge, or a bridge and a connector. -+ * -+ * The bus configuration is stored in &drm_bridge_state separately for the -+ * input and output buses, as seen from the point of view of each bridge. The -+ * bus configuration of a bridge output is usually identical to the -+ * configuration of the next bridge's input, but may differ if the signals are -+ * modified between the two bridges, for instance by an inverter on the board. -+ * The input and output configurations of a bridge may differ if the bridge -+ * modifies the signals internally, for instance by performing format -+ * conversion, or modifying signals polarities. -+ */ -+struct drm_bus_cfg { -+ /** -+ * @fmt: format used on this bus (one of the MEDIA_BUS_FMT_* format) -+ * -+ * This field should not be directly modified by drivers -+ * (&drm_atomic_bridge_chain_select_bus_fmts() takes care of the bus -+ * format negotiation). -+ */ -+ u32 format; -+ -+ /** -+ * @flags: DRM_BUS_* flags used on this bus -+ */ -+ u32 flags; -+}; -+ - /** - * struct drm_bridge_state - Atomic bridge state object - * @base: inherit from &drm_private_state -@@ -44,6 +76,16 @@ struct drm_bridge_state { - struct drm_private_state base; - - struct drm_bridge *bridge; -+ -+ /** -+ * @input_bus_cfg: input bus configuration -+ */ -+ struct drm_bus_cfg input_bus_cfg; -+ -+ /** -+ * @output_bus_cfg: input bus configuration -+ */ -+ struct drm_bus_cfg output_bus_cfg; - }; - - static inline struct drm_bridge_state * -@@ -387,6 +429,72 @@ struct drm_bridge_funcs { - void (*atomic_destroy_state)(struct drm_bridge *bridge, - struct drm_bridge_state *state); - -+ /** -+ * @atomic_get_output_bus_fmts: -+ * -+ * Return the supported bus formats on the output end of a bridge. -+ * The returned array must be allocated with kmalloc() and will be -+ * freed by the caller. If the allocation fails, NULL should be -+ * returned. num_output_fmts must be set to the returned array size. -+ * Formats listed in the returned array should be listed in decreasing -+ * preference order (the core will try all formats until it finds one -+ * that works). -+ * -+ * This method is only called on the last element of the bridge chain -+ * as part of the bus format negotiation process that happens in -+ * &drm_atomic_bridge_chain_select_bus_fmts(). -+ * This method is optional. When not implemented, the core will -+ * fall back to &drm_connector.display_info.bus_formats[0] if -+ * &drm_connector.display_info.num_bus_formats > 0, -+ * or to MEDIA_BUS_FMT_FIXED otherwise. -+ */ -+ u32 *(*atomic_get_output_bus_fmts)(struct drm_bridge *bridge, -+ struct drm_bridge_state *bridge_state, -+ struct drm_crtc_state *crtc_state, -+ struct drm_connector_state *conn_state, -+ unsigned int *num_output_fmts); -+ -+ /** -+ * @atomic_get_input_bus_fmts: -+ * -+ * Return the supported bus formats on the input end of a bridge for -+ * a specific output bus format. -+ * -+ * The returned array must be allocated with kmalloc() and will be -+ * freed by the caller. If the allocation fails, NULL should be -+ * returned. num_output_fmts must be set to the returned array size. -+ * Formats listed in the returned array should be listed in decreasing -+ * preference order (the core will try all formats until it finds one -+ * that works). When the format is not supported NULL should be -+ * returned and *num_output_fmts should be set to 0. -+ * -+ * This method is called on all elements of the bridge chain as part of -+ * the bus format negotiation process that happens in -+ * &drm_atomic_bridge_chain_select_bus_fmts(). -+ * This method is optional. When not implemented, the core will bypass -+ * bus format negotiation on this element of the bridge without -+ * failing, and the previous element in the chain will be passed -+ * MEDIA_BUS_FMT_FIXED as its output bus format. -+ * -+ * Bridge drivers that need to support being linked to bridges that are -+ * not supporting bus format negotiation should handle the -+ * output_fmt == MEDIA_BUS_FMT_FIXED case appropriately, by selecting a -+ * sensible default value or extracting this information from somewhere -+ * else (FW property, &drm_display_mode, &drm_display_info, ...) -+ * -+ * Note: Even if input format selection on the first bridge has no -+ * impact on the negotiation process (bus format negotiation stops once -+ * we reach the first element of the chain), drivers are expected to -+ * return accurate input formats as the input format may be used to -+ * configure the CRTC output appropriately. -+ */ -+ u32 *(*atomic_get_input_bus_fmts)(struct drm_bridge *bridge, -+ struct drm_bridge_state *bridge_state, -+ struct drm_crtc_state *crtc_state, -+ struct drm_connector_state *conn_state, -+ u32 output_fmt, -+ unsigned int *num_input_fmts); -+ - /** - * @atomic_check: - * -@@ -401,6 +509,14 @@ struct drm_bridge_funcs { - * called when &drm_bridge_funcs.atomic_check() is implemented, so only - * one of them should be provided. - * -+ * If drivers need to tweak &drm_bridge_state.input_bus_cfg.flags or -+ * &drm_bridge_state.output_bus_cfg.flags it should should happen in -+ * this function. By default the &drm_bridge_state.output_bus_cfg.flags -+ * field is set to the next bridge -+ * &drm_bridge_state.input_bus_cfg.flags value or -+ * &drm_connector.display_info.bus_flags if the bridge is the last -+ * element in the chain. -+ * - * RETURNS: - * zero if the check passed, a negative error code otherwise. - */ -@@ -588,6 +704,14 @@ void drm_atomic_bridge_chain_pre_enable(struct drm_bridge *bridge, - void drm_atomic_bridge_chain_enable(struct drm_bridge *bridge, - struct drm_atomic_state *state); - -+u32 * -+drm_atomic_helper_bridge_propagate_bus_fmt(struct drm_bridge *bridge, -+ struct drm_bridge_state *bridge_state, -+ struct drm_crtc_state *crtc_state, -+ struct drm_connector_state *conn_state, -+ u32 output_fmt, -+ unsigned int *num_input_fmts); -+ - void __drm_atomic_helper_bridge_reset(struct drm_bridge *bridge, - struct drm_bridge_state *state); - void drm_atomic_helper_bridge_destroy_state(struct drm_bridge *bridge, --- -2.17.1 - - -From 152ee505b889cb0f5bc3ad4af82b43a8f4f6562b Mon Sep 17 00:00:00 2001 -From: Jonas Karlman -Date: Wed, 18 Dec 2019 16:46:28 +0100 -Subject: [PATCH] drm/bridge: dw-hdmi: set mtmdsclock for deep color - -Configure the correct mtmdsclock for deep colors to prepare support -for 10, 12 & 16bit output. - -Signed-off-by: Jonas Karlman -Signed-off-by: Neil Armstrong ---- - drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 17 +++++++++++++++++ - 1 file changed, 17 insertions(+) - -diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c -index 24965e53d351..b8b91d28f398 100644 ---- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c -+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c -@@ -1824,9 +1824,26 @@ static void hdmi_av_composer(struct dw_hdmi *hdmi, - - dev_dbg(hdmi->dev, "final pixclk = %d\n", vmode->mpixelclock); - -+ if (!hdmi_bus_fmt_is_yuv422(hdmi->hdmi_data.enc_out_bus_format)) { -+ switch (hdmi_bus_fmt_color_depth( -+ hdmi->hdmi_data.enc_out_bus_format)) { -+ case 16: -+ vmode->mtmdsclock = (u64)vmode->mpixelclock * 2; -+ break; -+ case 12: -+ vmode->mtmdsclock = (u64)vmode->mpixelclock * 3 / 2; -+ break; -+ case 10: -+ vmode->mtmdsclock = (u64)vmode->mpixelclock * 5 / 4; -+ break; -+ } -+ } -+ - if (hdmi_bus_fmt_is_yuv420(hdmi->hdmi_data.enc_out_bus_format)) - vmode->mtmdsclock /= 2; - -+ dev_dbg(hdmi->dev, "final tmdsclk = %d\n", vmode->mtmdsclock); -+ - /* Set up HDMI_FC_INVIDCONF */ - inv_val = (hdmi->hdmi_data.hdcp_enable || - (dw_hdmi_support_scdc(hdmi) && --- -2.17.1 - - -From 7cc0932dda90b853ff45cbe43688d5888a81d0b7 Mon Sep 17 00:00:00 2001 -From: Jonas Karlman -Date: Wed, 18 Dec 2019 16:46:29 +0100 -Subject: [PATCH] drm/bridge: dw-hdmi: add max bpc connector property - -Add the max_bpc property to the dw-hdmi connector to prepare support -for 10, 12 & 16bit output support. - -Signed-off-by: Jonas Karlman -Signed-off-by: Neil Armstrong ---- - drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c -index b8b91d28f398..8da173798ed4 100644 ---- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c -+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c -@@ -2412,6 +2412,10 @@ static int dw_hdmi_bridge_attach(struct drm_bridge *bridge) - DRM_MODE_CONNECTOR_HDMIA, - hdmi->ddc); - -+ drm_atomic_helper_connector_reset(connector); -+ -+ drm_connector_attach_max_bpc_property(connector, 8, 16); -+ - if (hdmi->version >= 0x200a && hdmi->plat_data->use_drm_infoframe) - drm_object_attach_property(&connector->base, - connector->dev->mode_config.hdr_output_metadata_property, 0); --- -2.17.1 - - -From d38c69cb5bb12563a7a533ae5eb75453e736f85b Mon Sep 17 00:00:00 2001 -From: Neil Armstrong -Date: Wed, 18 Dec 2019 16:46:30 +0100 -Subject: [PATCH] drm/bridge: synopsys: dw-hdmi: add bus format negociation - -Add the atomic_get_output_bus_fmts, atomic_get_input_bus_fmts to negociate -the possible output and input formats for the current mode and monitor, -and use the negotiated formats in a basic atomic_check callback. - -Signed-off-by: Neil Armstrong ---- - drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 272 +++++++++++++++++++++- - 1 file changed, 268 insertions(+), 4 deletions(-) - -diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c -index 8da173798ed4..88da301dc086 100644 ---- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c -+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c -@@ -2101,11 +2101,10 @@ static int dw_hdmi_setup(struct dw_hdmi *hdmi, struct drm_display_mode *mode) - hdmi->hdmi_data.video_mode.mpixelrepetitionoutput = 0; - hdmi->hdmi_data.video_mode.mpixelrepetitioninput = 0; - -- /* TOFIX: Get input format from plat data or fallback to RGB888 */ - if (hdmi->plat_data->input_bus_format) - hdmi->hdmi_data.enc_in_bus_format = - hdmi->plat_data->input_bus_format; -- else -+ else if (hdmi->hdmi_data.enc_in_bus_format == MEDIA_BUS_FMT_FIXED) - hdmi->hdmi_data.enc_in_bus_format = MEDIA_BUS_FMT_RGB888_1X24; - - /* TOFIX: Get input encoding from plat data or fallback to none */ -@@ -2115,8 +2114,8 @@ static int dw_hdmi_setup(struct dw_hdmi *hdmi, struct drm_display_mode *mode) - else - hdmi->hdmi_data.enc_in_encoding = V4L2_YCBCR_ENC_DEFAULT; - -- /* TOFIX: Default to RGB888 output format */ -- hdmi->hdmi_data.enc_out_bus_format = MEDIA_BUS_FMT_RGB888_1X24; -+ if (hdmi->hdmi_data.enc_out_bus_format == MEDIA_BUS_FMT_FIXED) -+ hdmi->hdmi_data.enc_out_bus_format = MEDIA_BUS_FMT_RGB888_1X24; - - hdmi->hdmi_data.pix_repet_factor = 0; - hdmi->hdmi_data.hdcp_enable = 0; -@@ -2394,6 +2393,267 @@ static const struct drm_connector_helper_funcs dw_hdmi_connector_helper_funcs = - .atomic_check = dw_hdmi_connector_atomic_check, - }; - -+/* -+ * Possible output formats : -+ * - MEDIA_BUS_FMT_UYYVYY16_0_5X48, -+ * - MEDIA_BUS_FMT_UYYVYY12_0_5X36, -+ * - MEDIA_BUS_FMT_UYYVYY10_0_5X30, -+ * - MEDIA_BUS_FMT_UYYVYY8_0_5X24, -+ * - MEDIA_BUS_FMT_YUV16_1X48, -+ * - MEDIA_BUS_FMT_RGB161616_1X48, -+ * - MEDIA_BUS_FMT_UYVY12_1X24, -+ * - MEDIA_BUS_FMT_YUV12_1X36, -+ * - MEDIA_BUS_FMT_RGB121212_1X36, -+ * - MEDIA_BUS_FMT_UYVY10_1X20, -+ * - MEDIA_BUS_FMT_YUV10_1X30, -+ * - MEDIA_BUS_FMT_RGB101010_1X30, -+ * - MEDIA_BUS_FMT_UYVY8_1X16, -+ * - MEDIA_BUS_FMT_YUV8_1X24, -+ * - MEDIA_BUS_FMT_RGB888_1X24, -+ */ -+ -+/* Can return a maximum of 12 possible output formats for a mode/connector */ -+#define MAX_OUTPUT_SEL_FORMATS 12 -+ -+static u32 *dw_hdmi_bridge_atomic_get_output_bus_fmts(struct drm_bridge *bridge, -+ struct drm_bridge_state *bridge_state, -+ struct drm_crtc_state *crtc_state, -+ struct drm_connector_state *conn_state, -+ unsigned int *num_output_fmts) -+{ -+ struct drm_connector *conn = conn_state->connector; -+ struct drm_display_info *info = &conn->display_info; -+ struct drm_display_mode *mode = &crtc_state->mode; -+ u8 max_bpc = conn_state->max_requested_bpc; -+ bool is_hdmi2_sink = info->hdmi.scdc.supported || -+ (info->color_formats & DRM_COLOR_FORMAT_YCRCB420); -+ u32 *output_fmts; -+ int i = 0; -+ -+ *num_output_fmts = 0; -+ -+ output_fmts = kcalloc(MAX_OUTPUT_SEL_FORMATS, sizeof(*output_fmts), -+ GFP_KERNEL); -+ if (!output_fmts) -+ return NULL; -+ -+ /* -+ * If the current mode enforces 4:2:0, force the output but format -+ * to 4:2:0 and do not add the YUV422/444/RGB formats -+ */ -+ if (conn->ycbcr_420_allowed && -+ (drm_mode_is_420_only(info, mode) || -+ (is_hdmi2_sink && drm_mode_is_420_also(info, mode)))) { -+ -+ /* Order bus formats from 16bit to 8bit if supported */ -+ if (max_bpc >= 16 && info->bpc == 16 && -+ (info->hdmi.y420_dc_modes & DRM_EDID_YCBCR420_DC_48)) -+ output_fmts[i++] = MEDIA_BUS_FMT_UYYVYY16_0_5X48; -+ -+ if (max_bpc >= 12 && info->bpc >= 12 && -+ (info->hdmi.y420_dc_modes & DRM_EDID_YCBCR420_DC_36)) -+ output_fmts[i++] = MEDIA_BUS_FMT_UYYVYY12_0_5X36; -+ -+ if (max_bpc >= 10 && info->bpc >= 10 && -+ (info->hdmi.y420_dc_modes & DRM_EDID_YCBCR420_DC_30)) -+ output_fmts[i++] = MEDIA_BUS_FMT_UYYVYY10_0_5X30; -+ -+ /* Default 8bit fallback */ -+ output_fmts[i++] = MEDIA_BUS_FMT_UYYVYY8_0_5X24; -+ -+ *num_output_fmts = i; -+ -+ return output_fmts; -+ } -+ -+ /* -+ * Order bus formats from 16bit to 8bit and from YUV422 to RGB -+ * if supported. In any case the default RGB888 format is added -+ */ -+ -+ if (max_bpc >= 16 && info->bpc == 16) { -+ if (info->color_formats & DRM_COLOR_FORMAT_YCRCB444) -+ output_fmts[i++] = MEDIA_BUS_FMT_YUV16_1X48; -+ -+ output_fmts[i++] = MEDIA_BUS_FMT_RGB161616_1X48; -+ } -+ -+ if (max_bpc >= 12 && info->bpc >= 12) { -+ if (info->color_formats & DRM_COLOR_FORMAT_YCRCB422) -+ output_fmts[i++] = MEDIA_BUS_FMT_UYVY12_1X24; -+ -+ if (info->color_formats & DRM_COLOR_FORMAT_YCRCB444) -+ output_fmts[i++] = MEDIA_BUS_FMT_YUV12_1X36; -+ -+ output_fmts[i++] = MEDIA_BUS_FMT_RGB121212_1X36; -+ } -+ -+ if (max_bpc >= 10 && info->bpc >= 10) { -+ if (info->color_formats & DRM_COLOR_FORMAT_YCRCB422) -+ output_fmts[i++] = MEDIA_BUS_FMT_UYVY10_1X20; -+ -+ if (info->color_formats & DRM_COLOR_FORMAT_YCRCB444) -+ output_fmts[i++] = MEDIA_BUS_FMT_YUV10_1X30; -+ -+ output_fmts[i++] = MEDIA_BUS_FMT_RGB101010_1X30; -+ } -+ -+ if (info->color_formats & DRM_COLOR_FORMAT_YCRCB422) -+ output_fmts[i++] = MEDIA_BUS_FMT_UYVY8_1X16; -+ -+ if (info->color_formats & DRM_COLOR_FORMAT_YCRCB444) -+ output_fmts[i++] = MEDIA_BUS_FMT_YUV8_1X24; -+ -+ /* Default 8bit RGB fallback */ -+ output_fmts[i++] = MEDIA_BUS_FMT_RGB888_1X24; -+ -+ *num_output_fmts = i; -+ -+ return output_fmts; -+} -+ -+/* -+ * Possible input formats : -+ * - MEDIA_BUS_FMT_RGB888_1X24 -+ * - MEDIA_BUS_FMT_YUV8_1X24 -+ * - MEDIA_BUS_FMT_UYVY8_1X16 -+ * - MEDIA_BUS_FMT_UYYVYY8_0_5X24 -+ * - MEDIA_BUS_FMT_RGB101010_1X30 -+ * - MEDIA_BUS_FMT_YUV10_1X30 -+ * - MEDIA_BUS_FMT_UYVY10_1X20 -+ * - MEDIA_BUS_FMT_UYYVYY10_0_5X30 -+ * - MEDIA_BUS_FMT_RGB121212_1X36 -+ * - MEDIA_BUS_FMT_YUV12_1X36 -+ * - MEDIA_BUS_FMT_UYVY12_1X24 -+ * - MEDIA_BUS_FMT_UYYVYY12_0_5X36 -+ * - MEDIA_BUS_FMT_RGB161616_1X48 -+ * - MEDIA_BUS_FMT_YUV16_1X48 -+ * - MEDIA_BUS_FMT_UYYVYY16_0_5X48 -+ */ -+ -+/* Can return a maximum of 4 possible input formats for an output format */ -+#define MAX_INPUT_SEL_FORMATS 4 -+ -+static u32 *dw_hdmi_bridge_atomic_get_input_bus_fmts(struct drm_bridge *bridge, -+ struct drm_bridge_state *bridge_state, -+ struct drm_crtc_state *crtc_state, -+ struct drm_connector_state *conn_state, -+ u32 output_fmt, -+ unsigned int *num_input_fmts) -+{ -+ u32 *input_fmts; -+ int i = 0; -+ -+ *num_input_fmts = 0; -+ -+ input_fmts = kcalloc(MAX_INPUT_SEL_FORMATS, sizeof(*input_fmts), -+ GFP_KERNEL); -+ if (!input_fmts) -+ return NULL; -+ -+ switch (output_fmt) { -+ /* 8bit */ -+ case MEDIA_BUS_FMT_RGB888_1X24: -+ input_fmts[i++] = MEDIA_BUS_FMT_RGB888_1X24; -+ input_fmts[i++] = MEDIA_BUS_FMT_YUV8_1X24; -+ input_fmts[i++] = MEDIA_BUS_FMT_UYVY8_1X16; -+ break; -+ case MEDIA_BUS_FMT_YUV8_1X24: -+ input_fmts[i++] = MEDIA_BUS_FMT_YUV8_1X24; -+ input_fmts[i++] = MEDIA_BUS_FMT_UYVY8_1X16; -+ input_fmts[i++] = MEDIA_BUS_FMT_RGB888_1X24; -+ break; -+ case MEDIA_BUS_FMT_UYVY8_1X16: -+ input_fmts[i++] = MEDIA_BUS_FMT_UYVY8_1X16; -+ input_fmts[i++] = MEDIA_BUS_FMT_YUV8_1X24; -+ input_fmts[i++] = MEDIA_BUS_FMT_RGB888_1X24; -+ break; -+ -+ /* 10bit */ -+ case MEDIA_BUS_FMT_RGB101010_1X30: -+ input_fmts[i++] = MEDIA_BUS_FMT_RGB101010_1X30; -+ input_fmts[i++] = MEDIA_BUS_FMT_YUV10_1X30; -+ input_fmts[i++] = MEDIA_BUS_FMT_UYVY10_1X20; -+ break; -+ case MEDIA_BUS_FMT_YUV10_1X30: -+ input_fmts[i++] = MEDIA_BUS_FMT_YUV10_1X30; -+ input_fmts[i++] = MEDIA_BUS_FMT_UYVY10_1X20; -+ input_fmts[i++] = MEDIA_BUS_FMT_RGB101010_1X30; -+ break; -+ case MEDIA_BUS_FMT_UYVY10_1X20: -+ input_fmts[i++] = MEDIA_BUS_FMT_UYVY10_1X20; -+ input_fmts[i++] = MEDIA_BUS_FMT_YUV10_1X30; -+ input_fmts[i++] = MEDIA_BUS_FMT_RGB101010_1X30; -+ break; -+ -+ /* 12bit */ -+ case MEDIA_BUS_FMT_RGB121212_1X36: -+ input_fmts[i++] = MEDIA_BUS_FMT_RGB121212_1X36; -+ input_fmts[i++] = MEDIA_BUS_FMT_YUV12_1X36; -+ input_fmts[i++] = MEDIA_BUS_FMT_UYVY12_1X24; -+ break; -+ case MEDIA_BUS_FMT_YUV12_1X36: -+ input_fmts[i++] = MEDIA_BUS_FMT_YUV12_1X36; -+ input_fmts[i++] = MEDIA_BUS_FMT_UYVY12_1X24; -+ input_fmts[i++] = MEDIA_BUS_FMT_RGB121212_1X36; -+ break; -+ case MEDIA_BUS_FMT_UYVY12_1X24: -+ input_fmts[i++] = MEDIA_BUS_FMT_UYVY12_1X24; -+ input_fmts[i++] = MEDIA_BUS_FMT_YUV12_1X36; -+ input_fmts[i++] = MEDIA_BUS_FMT_RGB121212_1X36; -+ break; -+ -+ /* 16bit */ -+ case MEDIA_BUS_FMT_RGB161616_1X48: -+ input_fmts[i++] = MEDIA_BUS_FMT_RGB161616_1X48; -+ input_fmts[i++] = MEDIA_BUS_FMT_YUV16_1X48; -+ break; -+ case MEDIA_BUS_FMT_YUV16_1X48: -+ input_fmts[i++] = MEDIA_BUS_FMT_YUV16_1X48; -+ input_fmts[i++] = MEDIA_BUS_FMT_RGB161616_1X48; -+ break; -+ -+ /* 420 */ -+ case MEDIA_BUS_FMT_UYYVYY8_0_5X24: -+ case MEDIA_BUS_FMT_UYYVYY10_0_5X30: -+ case MEDIA_BUS_FMT_UYYVYY12_0_5X36: -+ case MEDIA_BUS_FMT_UYYVYY16_0_5X48: -+ input_fmts[i++] = output_fmt; -+ break; -+ } -+ -+ *num_input_fmts = i; -+ -+ if (*num_input_fmts == 0) { -+ kfree(input_fmts); -+ input_fmts = NULL; -+ } -+ -+ return input_fmts; -+} -+ -+static int dw_hdmi_bridge_atomic_check(struct drm_bridge *bridge, -+ struct drm_bridge_state *bridge_state, -+ struct drm_crtc_state *crtc_state, -+ struct drm_connector_state *conn_state) -+{ -+ struct dw_hdmi *hdmi = bridge->driver_private; -+ -+ dev_dbg(hdmi->dev, "selected output format %x\n", -+ bridge_state->output_bus_cfg.format); -+ -+ hdmi->hdmi_data.enc_out_bus_format = -+ bridge_state->output_bus_cfg.format; -+ -+ dev_dbg(hdmi->dev, "selected input format %x\n", -+ bridge_state->input_bus_cfg.format); -+ -+ hdmi->hdmi_data.enc_in_bus_format = -+ bridge_state->input_bus_cfg.format; -+ -+ return 0; -+} -+ - static int dw_hdmi_bridge_attach(struct drm_bridge *bridge) - { - struct dw_hdmi *hdmi = bridge->driver_private; -@@ -2502,6 +2762,9 @@ static void dw_hdmi_bridge_enable(struct drm_bridge *bridge) - static const struct drm_bridge_funcs dw_hdmi_bridge_funcs = { - .attach = dw_hdmi_bridge_attach, - .detach = dw_hdmi_bridge_detach, -+ .atomic_check = dw_hdmi_bridge_atomic_check, -+ .atomic_get_output_bus_fmts = dw_hdmi_bridge_atomic_get_output_bus_fmts, -+ .atomic_get_input_bus_fmts = dw_hdmi_bridge_atomic_get_input_bus_fmts, - .enable = dw_hdmi_bridge_enable, - .disable = dw_hdmi_bridge_disable, - .mode_set = dw_hdmi_bridge_mode_set, -@@ -2966,6 +3229,7 @@ __dw_hdmi_probe(struct platform_device *pdev, - - hdmi->bridge.driver_private = hdmi; - hdmi->bridge.funcs = &dw_hdmi_bridge_funcs; -+ - #ifdef CONFIG_OF - hdmi->bridge.of_node = pdev->dev.of_node; - #endif --- -2.17.1 - - -From 9c8d9cb1a3fa8b7cfe1052c1e6e549c294f65f69 Mon Sep 17 00:00:00 2001 -From: Neil Armstrong -Date: Wed, 18 Dec 2019 16:46:31 +0100 -Subject: [PATCH] drm/bridge: synopsys: dw-hdmi: allow ycbcr420 modes for >= - 0x200a - -Now the DW-HDMI Controller supports the HDMI2.0 modes, enable support -for these modes in the connector if the platform supports them. -We limit these modes to DW-HDMI IP version >= 0x200a which -are designed to support HDMI2.0 display modes. - -Signed-off-by: Neil Armstrong ---- - drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 6 ++++++ - include/drm/bridge/dw_hdmi.h | 1 + - 2 files changed, 7 insertions(+) - -diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c -index 88da301dc086..5749bdaba95b 100644 ---- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c -+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c -@@ -3234,6 +3234,12 @@ __dw_hdmi_probe(struct platform_device *pdev, - hdmi->bridge.of_node = pdev->dev.of_node; - #endif - -+ if (hdmi->version >= 0x200a) -+ hdmi->connector.ycbcr_420_allowed = -+ hdmi->plat_data->ycbcr_420_allowed; -+ else -+ hdmi->connector.ycbcr_420_allowed = false; -+ - memset(&pdevinfo, 0, sizeof(pdevinfo)); - pdevinfo.parent = dev; - pdevinfo.id = PLATFORM_DEVID_AUTO; -diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h -index 9d4d5cc47969..0b34a12c4a1c 100644 ---- a/include/drm/bridge/dw_hdmi.h -+++ b/include/drm/bridge/dw_hdmi.h -@@ -129,6 +129,7 @@ struct dw_hdmi_plat_data { - unsigned long input_bus_format; - unsigned long input_bus_encoding; - bool use_drm_infoframe; -+ bool ycbcr_420_allowed; - - /* Vendor PHY support */ - const struct dw_hdmi_phy_ops *phy_ops; --- -2.17.1 - diff --git a/patch/kernel/rk322x-current/01-linux-0008-fromlist-add-rockchip-nfc-driver.patch.disabled b/patch/kernel/rk322x-current/01-linux-0003-rockchip-fromlist.patch similarity index 55% rename from patch/kernel/rk322x-current/01-linux-0008-fromlist-add-rockchip-nfc-driver.patch.disabled rename to patch/kernel/rk322x-current/01-linux-0003-rockchip-fromlist.patch index 0afa2f2d6..1495e0bfe 100644 --- a/patch/kernel/rk322x-current/01-linux-0008-fromlist-add-rockchip-nfc-driver.patch.disabled +++ b/patch/kernel/rk322x-current/01-linux-0003-rockchip-fromlist.patch @@ -1,44 +1,279 @@ +From 01b6923a7d4b84609809a0695e58aeb7bd1376f1 Mon Sep 17 00:00:00 2001 +From: Yifeng Zhao +Date: Fri, 17 Jul 2020 17:24:17 +0800 +Subject: [PATCH] dt-bindings: mtd: Describe Rockchip RK3xxx NAND flash + controller + +Documentation support for Rockchip RK3xxx NAND flash controllers + +Signed-off-by: Yifeng Zhao +Reviewed-by: Rob Herring +--- + .../mtd/rockchip,nand-controller.yaml | 162 ++++++++++++++++++ + 1 file changed, 162 insertions(+) + create mode 100644 Documentation/devicetree/bindings/mtd/rockchip,nand-controller.yaml + +diff --git a/Documentation/devicetree/bindings/mtd/rockchip,nand-controller.yaml b/Documentation/devicetree/bindings/mtd/rockchip,nand-controller.yaml +new file mode 100644 +index 000000000000..b9d7a8c79402 +--- /dev/null ++++ b/Documentation/devicetree/bindings/mtd/rockchip,nand-controller.yaml +@@ -0,0 +1,162 @@ ++# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/mtd/rockchip,nand-controller.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: Rockchip SoCs NAND FLASH Controller (NFC) ++ ++allOf: ++ - $ref: "nand-controller.yaml#" ++ ++maintainers: ++ - Heiko Stuebner ++ ++properties: ++ compatible: ++ oneOf: ++ - const: rockchip,px30-nfc ++ - const: rockchip,rk2928-nfc ++ - const: rockchip,rv1108-nfc ++ - items: ++ - const: rockchip,rk3036-nfc ++ - const: rockchip,rk2928-nfc ++ - items: ++ - const: rockchip,rk3308-nfc ++ - const: rockchip,rv1108-nfc ++ ++ reg: ++ maxItems: 1 ++ ++ interrupts: ++ maxItems: 1 ++ ++ clocks: ++ minItems: 1 ++ items: ++ - description: Bus Clock ++ - description: Module Clock ++ ++ clock-names: ++ minItems: 1 ++ items: ++ - const: ahb ++ - const: nfc ++ ++ assigned-clocks: ++ maxItems: 1 ++ ++ assigned-clock-rates: ++ maxItems: 1 ++ ++ power-domains: ++ maxItems: 1 ++ ++patternProperties: ++ "^nand@[0-7]$": ++ type: object ++ properties: ++ reg: ++ minimum: 0 ++ maximum: 7 ++ ++ nand-ecc-mode: ++ const: hw ++ ++ nand-ecc-step-size: ++ const: 1024 ++ ++ nand-ecc-strength: ++ enum: [16, 24, 40, 60, 70] ++ description: ++ The ECC configurations that can be supported are as follows. ++ NFC v600 ECC 16, 24, 40, 60 ++ RK2928, RK3066, RK3188 ++ ++ NFC v622 ECC 16, 24, 40, 60 ++ RK3036, RK3128 ++ ++ NFC v800 ECC 16 ++ RK3308, RV1108 ++ ++ NFC v900 ECC 16, 40, 60, 70 ++ RK3326, PX30 ++ ++ nand-bus-width: ++ const: 8 ++ ++ rockchip,boot-blks: ++ minimum: 2 ++ default: 16 ++ allOf: ++ - $ref: /schemas/types.yaml#/definitions/uint32 ++ description: ++ The NFC driver need this information to select ECC ++ algorithms supported by the boot ROM. ++ Only used in combination with 'nand-is-boot-medium'. ++ ++ rockchip,boot-ecc-strength: ++ enum: [16, 24, 40, 60, 70] ++ allOf: ++ - $ref: /schemas/types.yaml#/definitions/uint32 ++ description: ++ If specified it indicates that a different BCH/ECC setting is ++ supported by the boot ROM. ++ NFC v600 ECC 16, 24 ++ RK2928, RK3066, RK3188 ++ ++ NFC v622 ECC 16, 24, 40, 60 ++ RK3036, RK3128 ++ ++ NFC v800 ECC 16 ++ RK3308, RV1108 ++ ++ NFC v900 ECC 16, 70 ++ RK3326, PX30 ++ ++ Only used in combination with 'nand-is-boot-medium'. ++ ++required: ++ - compatible ++ - reg ++ - interrupts ++ - clocks ++ - clock-names ++ ++unevaluatedProperties: false ++ ++examples: ++ - | ++ #include ++ #include ++ nfc: nand-controller@ff4b0000 { ++ compatible = "rockchip,rk3308-nfc", ++ "rockchip,rv1108-nfc"; ++ reg = <0xff4b0000 0x4000>; ++ interrupts = ; ++ clocks = <&cru HCLK_NANDC>, <&cru SCLK_NANDC>; ++ clock-names = "ahb", "nfc"; ++ assigned-clocks = <&clks SCLK_NANDC>; ++ assigned-clock-rates = <150000000>; ++ ++ pinctrl-0 = <&flash_ale &flash_bus8 &flash_cle &flash_csn0 ++ &flash_rdn &flash_rdy &flash_wrn>; ++ pinctrl-names = "default"; ++ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ nand@0 { ++ reg = <0>; ++ label = "rk-nand"; ++ nand-bus-width = <8>; ++ nand-ecc-mode = "hw"; ++ nand-ecc-step-size = <1024>; ++ nand-ecc-strength = <16>; ++ nand-is-boot-medium; ++ rockchip,boot-blks = <8>; ++ rockchip,boot-ecc-strength = <16>; ++ }; ++ }; ++ ++... + +From 8d00c3eb36f8fbccc159d6456bfd418a2841acff Mon Sep 17 00:00:00 2001 +From: Yifeng Zhao +Date: Fri, 17 Jul 2020 17:24:18 +0800 +Subject: [PATCH] mtd: rawnand: rockchip: NFC drivers for RK3308, RK2928 and + others + +This driver supports Rockchip NFC (NAND Flash Controller) found on RK3308, +RK2928, RKPX30, RV1108 and other SOCs. The driver has been tested using +8-bit NAND interface on the ARM based RK3308 platform. + +Support Rockchip SoCs and NFC versions: +- PX30 and RK3326(NFCv900). + ECC: 16/40/60/70 bits/1KB. + CLOCK: ahb and nfc. +- RK3308 and RV1108(NFCv800). + ECC: 16 bits/1KB. + CLOCK: ahb and nfc. +- RK3036 and RK3128(NFCv622). + ECC: 16/24/40/60 bits/1KB. + CLOCK: ahb and nfc. +- RK3066, RK3188 and RK2928(NFCv600). + ECC: 16/24/40/60 bits/1KB. + CLOCK: ahb. + +Supported features: +- Read full page data by DMA. +- Support HW ECC(one step is 1KB). +- Support 2 - 32K page size. +- Support 8 CS(depend on SoCs) + +Limitations: +- No support for the ecc step size is 512. +- Untested on some SoCs. +- No support for subpages. +- No support for the builtin randomizer. +- The original bad block mask is not supported. It is recommended to use + the BBT(bad block table). + +Signed-off-by: Yifeng Zhao +--- + drivers/mtd/nand/raw/Kconfig | 12 + + drivers/mtd/nand/raw/Makefile | 1 + + .../mtd/nand/raw/rockchip-nand-controller.c | 1422 +++++++++++++++++ + 3 files changed, 1435 insertions(+) + create mode 100644 drivers/mtd/nand/raw/rockchip-nand-controller.c + diff --git a/drivers/mtd/nand/raw/Kconfig b/drivers/mtd/nand/raw/Kconfig -index a80a46bb5b8b..8313b12a9d85 100644 +index 113f61052269..6492855d4a55 100644 --- a/drivers/mtd/nand/raw/Kconfig +++ b/drivers/mtd/nand/raw/Kconfig -@@ -433,6 +433,13 @@ config MTD_NAND_MESON - Enables support for NAND controller on Amlogic's Meson SoCs. - This controller is found on Meson SoCs. +@@ -461,6 +461,18 @@ config MTD_NAND_ARASAN + Enables the driver for the Arasan NAND flash controller on + Zynq Ultrascale+ MPSoC. +config MTD_NAND_ROCKCHIP + tristate "Rockchip NAND controller" -+ depends on ARCH_ROCKCHIP || COMPILE_TEST -+ depends on HAS_IOMEM ++ depends on ARCH_ROCKCHIP && HAS_IOMEM + help + Enables support for NAND controller on Rockchip SoCs. ++ There are four different versions of NAND FLASH Controllers, ++ including: ++ NFC v600: RK2928, RK3066, RK3188 ++ NFC v622: RK3036, RK3128 ++ NFC v800: RK3308, RV1108 ++ NFC v900: PX30, RK3326 + - config MTD_NAND_GPIO - tristate "GPIO assisted NAND controller" - depends on GPIOLIB || COMPILE_TEST + comment "Misc" + + config MTD_SM_COMMON diff --git a/drivers/mtd/nand/raw/Makefile b/drivers/mtd/nand/raw/Makefile -index 2d136b158fb7..8bafa59b8940 100644 +index 2930f5b9015d..960c9be25204 100644 --- a/drivers/mtd/nand/raw/Makefile +++ b/drivers/mtd/nand/raw/Makefile -@@ -58,6 +58,7 @@ obj-$(CONFIG_MTD_NAND_TEGRA) += tegra_nand.o - obj-$(CONFIG_MTD_NAND_STM32_FMC2) += stm32_fmc2_nand.o +@@ -58,6 +58,7 @@ obj-$(CONFIG_MTD_NAND_STM32_FMC2) += stm32_fmc2_nand.o obj-$(CONFIG_MTD_NAND_MESON) += meson_nand.o obj-$(CONFIG_MTD_NAND_CADENCE) += cadence-nand-controller.o -+obj-$(CONFIG_MTD_NAND_ROCKCHIP) += rockchip_nand.o + obj-$(CONFIG_MTD_NAND_ARASAN) += arasan-nand-controller.o ++obj-$(CONFIG_MTD_NAND_ROCKCHIP) += rockchip-nand-controller.o nand-objs := nand_base.o nand_legacy.o nand_bbt.o nand_timings.o nand_ids.o nand-objs += nand_onfi.o -diff --git a/drivers/mtd/nand/raw/rockchip_nand.c b/drivers/mtd/nand/raw/rockchip_nand.c +diff --git a/drivers/mtd/nand/raw/rockchip-nand-controller.c b/drivers/mtd/nand/raw/rockchip-nand-controller.c new file mode 100644 -index 000000000000..1e37a1b6c702 +index 000000000000..fec1360603e0 --- /dev/null -+++ b/drivers/mtd/nand/raw/rockchip_nand.c -@@ -0,0 +1,1315 @@ ++++ b/drivers/mtd/nand/raw/rockchip-nand-controller.c +@@ -0,0 +1,1422 @@ +// SPDX-License-Identifier: GPL-2.0 OR MIT +/* + * Rockchip NAND Flash controller driver. + * Copyright (C) 2020 Rockchip Inc. -+ * Authors: Yifeng Zhao ++ * Author: Yifeng Zhao + */ + +#include @@ -47,9 +282,9 @@ index 000000000000..1e37a1b6c702 +#include +#include +#include -+#include -+#include +#include ++#include ++#include +#include +#include +#include @@ -62,9 +297,9 @@ index 000000000000..1e37a1b6c702 + * NAND Page Data Layout: + * 1024 * n Data + m Bytes oob + * Original Bad Block Mask Location: -+ * first byte of oob(spare) ++ * First byte of oob(spare). + * nand_chip->oob_poi data layout: -+ * 4Bytes sys data + .... + 4Bytes sys data + ecc data ++ * 4Bytes sys data + .... + 4Bytes sys data + ecc data. + */ + +/* NAND controller register definition */ @@ -80,7 +315,7 @@ index 000000000000..1e37a1b6c702 +#define FLCTL_WR (1) /* 0: read, 1: write */ +#define FLCTL_XFER_ST BIT(2) +#define FLCTL_XFER_EN BIT(3) -+#define FLCTL_ACORRECT BIT(10) /* auto correct error bits */ ++#define FLCTL_ACORRECT BIT(10) /* Auto correct error bits. */ +#define FLCTL_XFER_READY BIT(20) +#define FLCTL_XFER_SECTOR (22) +#define FLCTL_TOG_FIX BIT(29) @@ -103,16 +338,15 @@ index 000000000000..1e37a1b6c702 +#define NFC_SRAM0 (0x1000) +#define NFC_SRAM1 (0x1400) +#define NFC_SRAM_SIZE (0x400) -+#define THIS_NAME "rk-nand" +#define NFC_TIMEOUT (500000) +#define NFC_MAX_OOB_PER_STEP 128 +#define NFC_MIN_OOB_PER_STEP 64 +#define MAX_DATA_SIZE 0xFFFC +#define MAX_ADDRESS_CYC 6 +#define NFC_ECC_MAX_MODES 4 -+#define NFC_MAX_NSELS (4) /* Some Soc only has 1 or 2 CSs */ -+#define NFC_SYS_DATA_SIZE (4) /* 4 bytes sys data in oob pre 1024 data */ -+#define RK_DEFAULT_CLOCK_RATE (150 * 1000 * 1000) /* 150 Mhz*/ ++#define NFC_MAX_NSELS (8) /* Some Socs only have 1 or 2 CSs. */ ++#define NFC_SYS_DATA_SIZE (4) /* 4 bytes sys data in oob pre 1024 data.*/ ++#define RK_DEFAULT_CLOCK_RATE (150 * 1000 * 1000) /* 150 Mhz */ +#define ACCTIMING(csrw, rwpw, rwcs) ((csrw) << 12 | (rwpw) << 5 | (rwcs)) + +enum nfc_type { @@ -139,7 +373,7 @@ index 000000000000..1e37a1b6c702 + u8 high_mask; +}; + -+/** ++/* + * @type: nfc version + * @ecc_strengths: ecc strengths + * @ecc_cfgs: ecc config values @@ -182,14 +416,17 @@ index 000000000000..1e37a1b6c702 + +struct rk_nfc_nand_chip { + struct list_head node; -+ struct nand_chip nand; ++ struct nand_chip chip; + -+ u32 spare_per_sector; -+ u32 oob_buf_per_sector; ++ u16 spare_per_sector; ++ u16 oob_buf_per_sector; ++ u16 boot_blks; ++ u16 boot_ecc; ++ u16 metadata_size; + -+ int nsels; ++ u8 nsels; + u8 sels[0]; -+ /* nothing after this field */ ++ /* Nothing after this field. */ +}; + +struct rk_nfc_clk { @@ -219,9 +456,9 @@ index 000000000000..1e37a1b6c702 + unsigned long assigned_cs; +}; + -+static inline struct rk_nfc_nand_chip *to_rk_nand(struct nand_chip *nand) ++static inline struct rk_nfc_nand_chip *to_rknand(struct nand_chip *chip) +{ -+ return container_of(nand, struct rk_nfc_nand_chip, nand); ++ return container_of(chip, struct rk_nfc_nand_chip, chip); +} + +static inline u8 *data_ptr(struct nand_chip *chip, const u8 *p, int i) @@ -238,11 +475,22 @@ index 000000000000..1e37a1b6c702 + return poi; +} + ++static inline u8 *oob_ecc_ptr(struct nand_chip *chip, int i) ++{ ++ struct rk_nfc_nand_chip *rknand = to_rknand(chip); ++ u8 *poi; ++ ++ poi = chip->oob_poi + rknand->metadata_size + ++ chip->ecc.bytes * i; ++ ++ return poi; ++} ++ +static inline int rk_data_len(struct nand_chip *chip) +{ -+ struct rk_nfc_nand_chip *rk_nand = to_rk_nand(chip); ++ struct rk_nfc_nand_chip *rknand = to_rknand(chip); + -+ return chip->ecc.size + rk_nand->spare_per_sector; ++ return chip->ecc.size + rknand->spare_per_sector; +} + +static inline u8 *rk_data_ptr(struct nand_chip *chip, int i) @@ -259,22 +507,22 @@ index 000000000000..1e37a1b6c702 + return nfc->buffer + i * rk_data_len(chip) + chip->ecc.size; +} + -+static void rk_nfc_select_chip(struct nand_chip *nand, int chip) ++static void rk_nfc_select_chip(struct nand_chip *chip, int cs) +{ -+ struct rk_nfc *nfc = nand_get_controller_data(nand); -+ struct rk_nfc_nand_chip *rk_nand = to_rk_nand(nand); ++ struct rk_nfc *nfc = nand_get_controller_data(chip); ++ struct rk_nfc_nand_chip *rknand = to_rknand(chip); + u32 val; + -+ if (chip < 0) { ++ if (cs < 0) { + nfc->selected_bank = -1; -+ /* Deselect the currently selected target */ ++ /* Deselect the currently selected target. */ + val = readl_relaxed(nfc->regs + NFC_FMCTL); + val &= ~FMCTL_CE_SEL_M; + writel(val, nfc->regs + NFC_FMCTL); + return; + } + -+ nfc->selected_bank = rk_nand->sels[chip]; ++ nfc->selected_bank = rknand->sels[cs]; + nfc->band_offset = NFC_BANK + nfc->selected_bank * NFC_BANK_STEP; + + val = readl_relaxed(nfc->regs + NFC_FMCTL); @@ -284,15 +532,15 @@ index 000000000000..1e37a1b6c702 + writel(val, nfc->regs + NFC_FMCTL); +} + -+static inline void rk_nfc_wait_ioready(struct rk_nfc *nfc) ++static inline int rk_nfc_wait_ioready(struct rk_nfc *nfc) +{ + int rc; + u32 val; + + rc = readl_poll_timeout_atomic(nfc->regs + NFC_FMCTL, val, + val & FMCTL_RDY, 10, NFC_TIMEOUT); -+ if (rc < 0) -+ dev_err(nfc->dev, "data not ready\n"); ++ ++ return rc; +} + +static inline u8 rk_nfc_read_byte(struct nand_chip *chip) @@ -329,12 +577,13 @@ index 000000000000..1e37a1b6c702 + const struct nand_subop *subop) +{ + struct rk_nfc *nfc = nand_get_controller_data(chip); -+ u32 cnt = 0; + unsigned int i, j, remaining, start; + int reg_offset = nfc->band_offset; ++ void __iomem *data_reg; + u8 *inbuf = NULL; + const u8 *outbuf; -+ void __iomem *data_reg; ++ u32 cnt = 0; ++ int ret = 0; + + for (i = 0; i < subop->ninstrs; i++) { + const struct nand_op_instr *instr = &subop->instrs[i]; @@ -372,12 +621,15 @@ index 000000000000..1e37a1b6c702 + break; + + case NAND_OP_WAITRDY_INSTR: -+ rk_nfc_wait_ioready(nfc); ++ if (rk_nfc_wait_ioready(nfc) < 0) { ++ ret = -ETIMEDOUT; ++ dev_err(nfc->dev, "IO not ready\n"); ++ } + break; + } + } + -+ return 0; ++ return ret; +} + +static const struct nand_op_parser rk_nfc_op_parser = NAND_OP_PARSER( @@ -417,17 +669,19 @@ index 000000000000..1e37a1b6c702 + if (csline == NAND_DATA_IFACE_CHECK_ONLY) + return 0; + -+ /* not onfi nand flash */ + if (!chip->parameters.onfi) + return 0; + + timings = nand_get_sdr_timings(conf); + if (IS_ERR(timings)) -+ return -ENOTSUPP; ++ return -EOPNOTSUPP; + -+ rate = clk_get_rate(nfc->clk.nfc_clk); ++ if (IS_ERR(nfc->clk.nfc_clk)) ++ rate = clk_get_rate(nfc->clk.ahb_clk); ++ else ++ rate = clk_get_rate(nfc->clk.nfc_clk); + -+ /* turn clock rate into KHZ */ ++ /* Turn clock rate into kHz. */ + rate /= 1000; + + tc2rw = 1; @@ -459,12 +713,34 @@ index 000000000000..1e37a1b6c702 + return 0; +} + ++static int rk_nfc_hw_ecc_setup(struct nand_chip *chip, ++ struct nand_ecc_ctrl *ecc, ++ uint32_t strength) ++{ ++ struct rk_nfc *nfc = nand_get_controller_data(chip); ++ u32 reg, i; ++ ++ for (i = 0; i < NFC_ECC_MAX_MODES; i++) { ++ if (ecc->strength == nfc->cfg->ecc_strengths[i]) { ++ reg = nfc->cfg->ecc_cfgs[i]; ++ break; ++ } ++ } ++ ++ if (i >= NFC_ECC_MAX_MODES) ++ return -EINVAL; ++ ++ writel(reg, nfc->regs + nfc->cfg->bchctl_off); ++ ++ return 0; ++} ++ +static void rk_nfc_xfer_start(struct rk_nfc *nfc, u8 rw, u8 n_KB, + dma_addr_t dma_data, dma_addr_t dma_oob) +{ + u32 dma_reg, fl_reg, bch_reg; + -+ dma_reg = DMA_ST | ((!rw) << DMA_WR) | DMA_EN | (2 << DMA_AHB_SIZE) | ++ dma_reg = DMA_ST | ((!rw) << DMA_WR) | DMA_EN | (2 << DMA_AHB_SIZE) | + (7 << DMA_BURST_SIZE) | (16 << DMA_INC_NUM); + + fl_reg = (rw << FLCTL_WR) | FLCTL_XFER_EN | FLCTL_ACORRECT | @@ -487,17 +763,15 @@ index 000000000000..1e37a1b6c702 + +static int rk_nfc_wait_for_xfer_done(struct rk_nfc *nfc) +{ -+ u32 reg; -+ int ret = 0; + void __iomem *ptr; ++ int ret = 0; ++ u32 reg; + + ptr = nfc->regs + nfc->cfg->flctl_off; + + ret = readl_poll_timeout_atomic(ptr, reg, + reg & FLCTL_XFER_READY, + 10, NFC_TIMEOUT); -+ if (ret) -+ dev_err(nfc->dev, "timeout reg=%x\n", reg); + + return ret; +} @@ -506,41 +780,51 @@ index 000000000000..1e37a1b6c702 + const u8 *buf, int page, int raw) +{ + struct rk_nfc *nfc = nand_get_controller_data(chip); ++ struct rk_nfc_nand_chip *rknand = to_rknand(chip); + struct nand_ecc_ctrl *ecc = &chip->ecc; -+ u8 *oob; -+ dma_addr_t dma_data, dma_oob; + int oob_step = (ecc->bytes > 60) ? NFC_MAX_OOB_PER_STEP : + NFC_MIN_OOB_PER_STEP; + int pages_per_blk = mtd->erasesize / mtd->writesize; ++ int ret = 0, i, boot_rom_mode = 0; ++ dma_addr_t dma_data, dma_oob; + u32 reg; -+ int ret = 0, i; ++ u8 *oob; + + nand_prog_page_begin_op(chip, page, 0, NULL, 0); + + if (!raw) { + memcpy(nfc->page_buf, buf, mtd->writesize); + memset(nfc->oob_buf, 0xff, oob_step * ecc->steps); -+ /* -+ * The first 8 blocks is stored loader, the first -+ * 32 bits of oob need link to next page address -+ * in the same block for Bootrom. -+ * Swap the first oob with the seventh oob, -+ * and bad block mask save at seventh oob. -+ */ -+ swap(chip->oob_poi[0], chip->oob_poi[7]); -+ for (i = 0; i < ecc->steps; i++) { -+ oob = chip->oob_poi + i * NFC_SYS_DATA_SIZE; -+ reg = (oob[2] << 16) | (oob[3] << 24); -+ if (!i && page < pages_per_blk * 8) -+ reg |= (page & (pages_per_blk - 1)) * 4; -+ else -+ reg |= oob[0] | (oob[1] << 8); + -+ if (nfc->cfg->type == NFC_V6 || -+ nfc->cfg->type == NFC_V8) -+ nfc->oob_buf[i * oob_step / 4] = reg; -+ else ++ /* ++ * The first 8(some devices are 4 or 16) blocks are in use by ++ * the boot ROM and the first 32 bits of oob need to link ++ * to the next page address in the same block. ++ * Config the ECC algorithm supported by the boot ROM. ++ */ ++ if (page < pages_per_blk * rknand->boot_blks && ++ chip->options & NAND_IS_BOOT_MEDIUM) { ++ boot_rom_mode = 1; ++ if (rknand->boot_ecc != ecc->strength) ++ rk_nfc_hw_ecc_setup(chip, ecc, ++ rknand->boot_ecc); ++ } ++ ++ for (i = 0; i < ecc->steps; i++) { ++ if (!i) { ++ reg = 0xFFFFFFFF; ++ } else { ++ oob = chip->oob_poi + (i - 1) * NFC_SYS_DATA_SIZE; ++ reg = oob[0] | oob[1] << 8 | oob[2] << 16 | ++ oob[3] << 24; ++ } ++ if (!i && boot_rom_mode) ++ reg = (page & (pages_per_blk - 1)) * 4; ++ ++ if (nfc->cfg->type == NFC_V9) + nfc->oob_buf[i] = reg; ++ else ++ nfc->oob_buf[i * oob_step / 4] = reg; + } + + dma_data = dma_map_single(nfc->dev, (void *)nfc->page_buf, @@ -549,7 +833,7 @@ index 000000000000..1e37a1b6c702 + ecc->steps * oob_step, + DMA_TO_DEVICE); + -+ init_completion(&nfc->done); ++ reinit_completion(&nfc->done); + writel(INT_DMA, nfc->regs + nfc->cfg->int_en_off); + + rk_nfc_xfer_start(nfc, NFC_WRITE, ecc->steps, dma_data, @@ -557,15 +841,29 @@ index 000000000000..1e37a1b6c702 + ret = wait_for_completion_timeout(&nfc->done, + msecs_to_jiffies(100)); + if (!ret) -+ ret = -ETIMEDOUT; ++ dev_warn(nfc->dev, "write: wait dma done timeout.\n"); ++ /* ++ * Whether the DMA transfer is completed or not. The driver ++ * needs to check the NFC`s status register to see if the data ++ * transfer was completed. ++ */ + ret = rk_nfc_wait_for_xfer_done(nfc); + + dma_unmap_single(nfc->dev, dma_data, mtd->writesize, + DMA_TO_DEVICE); + dma_unmap_single(nfc->dev, dma_oob, ecc->steps * oob_step, + DMA_TO_DEVICE); ++ ++ if (boot_rom_mode && rknand->boot_ecc != ecc->strength) ++ rk_nfc_hw_ecc_setup(chip, ecc, ecc->strength); ++ ++ if (ret) { ++ ret = -EIO; ++ dev_err(nfc->dev, ++ "write: wait transfer done timeout.\n"); ++ } + } else { -+ rk_nfc_write_buf(chip, buf, mtd->writesize + + mtd->oobsize); ++ rk_nfc_write_buf(chip, buf, mtd->writesize + mtd->oobsize); + } + + if (ret) @@ -573,7 +871,7 @@ index 000000000000..1e37a1b6c702 + + ret = nand_prog_page_end_op(chip); + -+ /* Deselect the currently selected target */ ++ /* Deselect the currently selected target. */ + rk_nfc_select_chip(chip, -1); + + return ret; @@ -587,14 +885,23 @@ index 000000000000..1e37a1b6c702 + u32 i; + + memset(nfc->buffer, 0xff, mtd->writesize + mtd->oobsize); -+ swap(chip->oob_poi[0], chip->oob_poi[7]); ++ + for (i = 0; i < chip->ecc.steps; i++) { + if (buf) + memcpy(rk_data_ptr(chip, i), data_ptr(chip, buf, i), + chip->ecc.size); + -+ memcpy(rk_oob_ptr(chip, i), oob_ptr(chip, i), -+ NFC_SYS_DATA_SIZE); ++ if (!i) ++ memcpy(rk_oob_ptr(chip, i), ++ oob_ptr(chip, chip->ecc.steps - 1), ++ NFC_SYS_DATA_SIZE); ++ else ++ memcpy(rk_oob_ptr(chip, i), oob_ptr(chip, i - 1), ++ NFC_SYS_DATA_SIZE); ++ ++ memcpy(rk_oob_ptr(chip, i) + NFC_SYS_DATA_SIZE, ++ oob_ecc_ptr(chip, i), ++ chip->ecc.bytes); + } + + return rk_nfc_write_page(mtd, chip, nfc->buffer, page, 1); @@ -610,12 +917,14 @@ index 000000000000..1e37a1b6c702 + u8 *buf, int page, int raw) +{ + struct rk_nfc *nfc = nand_get_controller_data(chip); ++ struct rk_nfc_nand_chip *rknand = to_rknand(chip); + struct nand_ecc_ctrl *ecc = &chip->ecc; -+ dma_addr_t dma_data, dma_oob; + int oob_step = (ecc->bytes > 60) ? NFC_MAX_OOB_PER_STEP : + NFC_MIN_OOB_PER_STEP; -+ int bitflips = 0; -+ int ret, i, bch_st; ++ int pages_per_blk = mtd->erasesize / mtd->writesize; ++ dma_addr_t dma_data, dma_oob; ++ int ret = 0, i, boot_rom_mode = 0; ++ int bitflips = 0, bch_st; + u8 *oob; + u32 tmp; + @@ -627,33 +936,58 @@ index 000000000000..1e37a1b6c702 + dma_oob = dma_map_single(nfc->dev, nfc->oob_buf, + ecc->steps * oob_step, + DMA_FROM_DEVICE); -+ init_completion(&nfc->done); ++ ++ /* ++ * The first 8(some devices are 4 or 16) blocks are in use by ++ * the boot ROM. ++ * Config the ECC algorithm supported by the boot ROM. ++ */ ++ if (page < pages_per_blk * rknand->boot_blks && ++ chip->options & NAND_IS_BOOT_MEDIUM) { ++ boot_rom_mode = 1; ++ if (rknand->boot_ecc != ecc->strength) ++ rk_nfc_hw_ecc_setup(chip, ecc, ++ rknand->boot_ecc); ++ } ++ ++ reinit_completion(&nfc->done); + writel(INT_DMA, nfc->regs + nfc->cfg->int_en_off); + rk_nfc_xfer_start(nfc, NFC_READ, ecc->steps, dma_data, + dma_oob); + ret = wait_for_completion_timeout(&nfc->done, + msecs_to_jiffies(100)); + if (!ret) -+ dev_warn(nfc->dev, "read ahb/dma done timeout\n"); -+ rk_nfc_wait_for_xfer_done(nfc); ++ dev_warn(nfc->dev, "read: wait dma done timeout.\n"); ++ /* ++ * Whether the DMA transfer is completed or not. The driver ++ * needs to check the NFC`s status register to see if the data ++ * transfer was completed. ++ */ ++ ret = rk_nfc_wait_for_xfer_done(nfc); + dma_unmap_single(nfc->dev, dma_data, mtd->writesize, + DMA_FROM_DEVICE); + dma_unmap_single(nfc->dev, dma_oob, ecc->steps * oob_step, + DMA_FROM_DEVICE); + -+ for (i = 0; i < ecc->steps; i++) { -+ oob = chip->oob_poi + i * NFC_SYS_DATA_SIZE; -+ if (nfc->cfg->type == NFC_V6 || -+ nfc->cfg->type == NFC_V8) -+ tmp = nfc->oob_buf[i * oob_step / 4]; -+ else ++ if (ret) { ++ bitflips = -EIO; ++ dev_err(nfc->dev, ++ "read: wait transfer done timeout.\n"); ++ goto out; ++ } ++ ++ for (i = 1; i < ecc->steps; i++) { ++ oob = chip->oob_poi + (i - 1) * NFC_SYS_DATA_SIZE; ++ if (nfc->cfg->type == NFC_V9) + tmp = nfc->oob_buf[i]; ++ else ++ tmp = nfc->oob_buf[i * oob_step / 4]; + *oob++ = (u8)tmp; + *oob++ = (u8)(tmp >> 8); + *oob++ = (u8)(tmp >> 16); + *oob++ = (u8)(tmp >> 24); + } -+ swap(chip->oob_poi[0], chip->oob_poi[7]); ++ + for (i = 0; i < ecc->steps / 2; i++) { + bch_st = readl_relaxed(nfc->regs + + nfc->cfg->bch_st_off + i * 4); @@ -671,17 +1005,18 @@ index 000000000000..1e37a1b6c702 + bitflips = max_t(u32, bitflips, ret); + } + } ++out: + memcpy(buf, nfc->page_buf, mtd->writesize); + -+ if (bitflips == -1) -+ dev_err(nfc->dev, "read_page %x %x %x %x %x %x\n", -+ page, bitflips, bch_st, ((u32 *)buf)[0], -+ ((u32 *)buf)[1], (u32)dma_data); ++ if (boot_rom_mode && rknand->boot_ecc != ecc->strength) ++ rk_nfc_hw_ecc_setup(chip, ecc, ecc->strength); ++ ++ if (bitflips < 0) ++ dev_err(nfc->dev, "read page: %x ecc error!\n", page); + } else { + rk_nfc_read_buf(chip, buf, mtd->writesize + mtd->oobsize); + } -+ -+ /* Deselect the currently selected target */ ++ /* Deselect the currently selected target. */ + rk_nfc_select_chip(chip, -1); + + return bitflips; @@ -714,14 +1049,22 @@ index 000000000000..1e37a1b6c702 + return ret; + + for (i = 0; i < chip->ecc.steps; i++) { -+ memcpy(oob_ptr(chip, i), rk_oob_ptr(chip, i), -+ NFC_SYS_DATA_SIZE); ++ if (!i) ++ memcpy(oob_ptr(chip, chip->ecc.steps - 1), ++ rk_oob_ptr(chip, i), ++ NFC_SYS_DATA_SIZE); ++ else ++ memcpy(oob_ptr(chip, i - 1), rk_oob_ptr(chip, i), ++ NFC_SYS_DATA_SIZE); ++ ++ memcpy(oob_ecc_ptr(chip, i), ++ rk_oob_ptr(chip, i) + NFC_SYS_DATA_SIZE, ++ chip->ecc.bytes); + + if (buf) + memcpy(data_ptr(chip, buf, i), rk_data_ptr(chip, i), + chip->ecc.size); + } -+ swap(chip->oob_poi[0], chip->oob_poi[7]); + + return ret; +} @@ -733,11 +1076,11 @@ index 000000000000..1e37a1b6c702 + +static inline void rk_nfc_hw_init(struct rk_nfc *nfc) +{ -+ /* disable flash wp */ ++ /* Disable flash wp. */ + writel(FMCTL_WP, nfc->regs + NFC_FMCTL); -+ /* config default timing */ ++ /* Config default timing 40ns at 150 Mhz nfc clock. */ + writel(0x1081, nfc->regs + NFC_FMWAIT); -+ /* disable randomizer and dma */ ++ /* Disable randomizer and DMA. */ + writel(0, nfc->regs + nfc->cfg->randmz_off); + writel(0, nfc->regs + nfc->cfg->dma_cfg_off); + writel(FLCTL_RST, nfc->regs + nfc->cfg->flctl_off); @@ -766,16 +1109,19 @@ index 000000000000..1e37a1b6c702 +{ + int ret; + -+ ret = clk_prepare_enable(clk->nfc_clk); -+ if (ret) { -+ dev_err(dev, "failed to enable nfc clk\n"); -+ return ret; ++ if (!IS_ERR(clk->nfc_clk)) { ++ ret = clk_prepare_enable(clk->nfc_clk); ++ if (ret) { ++ dev_err(dev, "failed to enable nfc clk\n"); ++ return ret; ++ } + } + + ret = clk_prepare_enable(clk->ahb_clk); + if (ret) { + dev_err(dev, "failed to enable ahb clk\n"); -+ clk_disable_unprepare(clk->nfc_clk); ++ if (!IS_ERR(clk->nfc_clk)) ++ clk_disable_unprepare(clk->nfc_clk); + return ret; + } + @@ -784,7 +1130,8 @@ index 000000000000..1e37a1b6c702 + +static void rk_nfc_disable_clk(struct rk_nfc_clk *clk) +{ -+ clk_disable_unprepare(clk->nfc_clk); ++ if (!IS_ERR(clk->nfc_clk)) ++ clk_disable_unprepare(clk->nfc_clk); + clk_disable_unprepare(clk->ahb_clk); +} + @@ -792,18 +1139,17 @@ index 000000000000..1e37a1b6c702 + struct mtd_oob_region *oob_region) +{ + struct nand_chip *chip = mtd_to_nand(mtd); ++ struct rk_nfc_nand_chip *rknand = to_rknand(chip); + -+ if (section >= chip->ecc.steps) ++ if (section) + return -ERANGE; + -+ if (!section) { -+ /* The first byte is bad block mask flag */ -+ oob_region->length = NFC_SYS_DATA_SIZE - 1; -+ oob_region->offset = 1; -+ } else { -+ oob_region->length = NFC_SYS_DATA_SIZE; -+ oob_region->offset = section * NFC_SYS_DATA_SIZE; -+ } ++ /* ++ * The beginning of the oob area stores the reserved data for the NFC, ++ * the size of the reserved data is NFC_SYS_DATA_SIZE bytes. ++ */ ++ oob_region->length = rknand->metadata_size - NFC_SYS_DATA_SIZE - 2; ++ oob_region->offset = NFC_SYS_DATA_SIZE + 2; + + return 0; +} @@ -812,11 +1158,12 @@ index 000000000000..1e37a1b6c702 + struct mtd_oob_region *oob_region) +{ + struct nand_chip *chip = mtd_to_nand(mtd); ++ struct rk_nfc_nand_chip *rknand = to_rknand(chip); + + if (section) + return -ERANGE; + -+ oob_region->offset = NFC_SYS_DATA_SIZE * chip->ecc.steps; ++ oob_region->offset = rknand->metadata_size; + oob_region->length = mtd->oobsize - oob_region->offset; + + return 0; @@ -827,70 +1174,44 @@ index 000000000000..1e37a1b6c702 + .ecc = rk_nfc_ooblayout_ecc, +}; + -+static int rk_nfc_hw_ecc_setup(struct mtd_info *mtd, -+ struct nand_ecc_ctrl *ecc, -+ uint32_t strength) -+{ -+ struct nand_chip *nand = mtd_to_nand(mtd); -+ struct rk_nfc *nfc = nand_get_controller_data(nand); -+ u32 reg, i; -+ -+ ecc->strength = strength; -+ ecc->steps = mtd->writesize / ecc->size; -+ ecc->bytes = DIV_ROUND_UP(ecc->strength * 14, 8); -+ /* HW ECC always work with even numbers of ECC bytes */ -+ ecc->bytes = ALIGN(ecc->bytes, 2); -+ -+ for (i = 0; i < NFC_ECC_MAX_MODES; i++) { -+ if (ecc->strength == nfc->cfg->ecc_strengths[i]) { -+ reg = nfc->cfg->ecc_cfgs[i]; -+ break; -+ } -+ } -+ -+ if (i >= NFC_ECC_MAX_MODES) -+ return -EINVAL; -+ -+ writel(reg, nfc->regs + nfc->cfg->bchctl_off); -+ -+ return 0; -+} -+ +static int rk_nfc_ecc_init(struct device *dev, struct mtd_info *mtd) +{ -+ struct nand_chip *nand = mtd_to_nand(mtd); -+ struct rk_nfc *nfc = nand_get_controller_data(nand); -+ struct nand_ecc_ctrl *ecc = &nand->ecc; ++ struct nand_chip *chip = mtd_to_nand(mtd); ++ struct rk_nfc *nfc = nand_get_controller_data(chip); ++ struct nand_ecc_ctrl *ecc = &chip->ecc; + const u8 *strengths = nfc->cfg->ecc_strengths; + u8 max_strength, nfc_max_strength; + int i; + + nfc_max_strength = nfc->cfg->ecc_strengths[0]; -+ /* if optional dt settings not present */ ++ /* If optional dt settings not present. */ + if (!ecc->size || !ecc->strength || + ecc->strength > nfc_max_strength) { -+ /* use datasheet requirements */ -+ ecc->strength = nand->base.eccreq.strength; -+ ecc->size = nand->base.eccreq.step_size; ++ /* Use datasheet requirements. */ ++ ecc->strength = chip->base.eccreq.strength; ++ ecc->size = chip->base.eccreq.step_size; + -+ /* -+ * align eccstrength and eccsize -+ * this controller only supports 512 and 1024 sizes -+ */ -+ if (nand->ecc.size < 1024) { ++ /* Align ECC strength and ECC size. */ ++ if (chip->ecc.size < 1024) { + if (mtd->writesize > 512) { -+ nand->ecc.size = 1024; -+ nand->ecc.strength <<= 1; ++ chip->ecc.size = 1024; ++ chip->ecc.strength <<= 1; + } else { -+ dev_err(dev, "ecc.size not supported\n"); ++ dev_err(dev, "Unsupported ecc.size\n"); + return -EINVAL; + } + } else { -+ nand->ecc.size = 1024; ++ chip->ecc.size = 1024; + } + + ecc->steps = mtd->writesize / ecc->size; -+ max_strength = ((mtd->oobsize / ecc->steps) - 4) * 8 / 14; ++ ++ /* ++ * HW ECC always requests the number of ECC bytes per 1024 byte ++ * blocks. 4 Bytes is oob for sys data. ++ */ ++ max_strength = ((mtd->oobsize / ecc->steps) - 4) * 8 / ++ fls(8 * 1024); + if (max_strength > nfc_max_strength) + max_strength = nfc_max_strength; + @@ -900,15 +1221,18 @@ index 000000000000..1e37a1b6c702 + } + + if (i >= 4) { -+ dev_err(nfc->dev, "unsupported strength\n"); -+ return -ENOTSUPP; ++ dev_err(nfc->dev, "Unsupported ECC strength\n"); ++ return -EOPNOTSUPP; + } + + ecc->strength = strengths[i]; + } -+ rk_nfc_hw_ecc_setup(mtd, ecc, ecc->strength); -+ dev_info(dev, "eccsize %d eccstrength %d\n", -+ nand->ecc.size, nand->ecc.strength); ++ ecc->steps = mtd->writesize / ecc->size; ++ ecc->bytes = DIV_ROUND_UP(ecc->strength * fls(8 * 1024), 8); ++ /* HW ECC always work with even numbers of ECC bytes. */ ++ ecc->bytes = ALIGN(ecc->bytes, 2); ++ ++ rk_nfc_hw_ecc_setup(chip, ecc, ecc->strength); + + return 0; +} @@ -918,13 +1242,13 @@ index 000000000000..1e37a1b6c702 + struct mtd_info *mtd = nand_to_mtd(chip); + struct device *dev = mtd->dev.parent; + struct rk_nfc *nfc = nand_get_controller_data(chip); -+ struct rk_nfc_nand_chip *rk_nand = to_rk_nand(chip); ++ struct rk_nfc_nand_chip *rknand = to_rknand(chip); + struct nand_ecc_ctrl *ecc = &chip->ecc; + int len; + int ret; + + if (chip->options & NAND_BUSWIDTH_16) { -+ dev_err(dev, "16bits buswidth not supported"); ++ dev_err(dev, "16 bits bus width not supported"); + return -EINVAL; + } + @@ -934,9 +1258,16 @@ index 000000000000..1e37a1b6c702 + ret = rk_nfc_ecc_init(dev, mtd); + if (ret) + return ret; -+ rk_nand->spare_per_sector = ecc->bytes + NFC_SYS_DATA_SIZE; ++ rknand->spare_per_sector = ecc->bytes + NFC_SYS_DATA_SIZE; ++ rknand->metadata_size = NFC_SYS_DATA_SIZE * ecc->steps; + -+ /* Check buffer first, avoid duplicate alloc buffer */ ++ if (rknand->metadata_size < NFC_SYS_DATA_SIZE + 2) { ++ dev_err(dev, ++ "Driver needs at least %d bytes of meta data\n", ++ NFC_SYS_DATA_SIZE + 2); ++ return -EIO; ++ } ++ /* Check buffer first, avoid duplicate alloc buffer. */ + if (nfc->buffer) + return 0; + @@ -949,7 +1280,6 @@ index 000000000000..1e37a1b6c702 + len = ecc->steps * NFC_MAX_OOB_PER_STEP; + nfc->oob_buf = devm_kzalloc(dev, len, GFP_KERNEL | GFP_DMA); + if (!nfc->oob_buf) { -+ devm_kfree(dev, nfc->buffer); + nfc->buffer = NULL; + nfc->oob_buf = NULL; + return -ENOMEM; @@ -977,8 +1307,8 @@ index 000000000000..1e37a1b6c702 +static int rk_nfc_nand_chip_init(struct device *dev, struct rk_nfc *nfc, + struct device_node *np) +{ -+ struct rk_nfc_nand_chip *chip; -+ struct nand_chip *nand; ++ struct rk_nfc_nand_chip *rknand; ++ struct nand_chip *chip; + struct mtd_info *mtd; + int nsels; + u32 tmp; @@ -993,12 +1323,12 @@ index 000000000000..1e37a1b6c702 + return -EINVAL; + } + -+ chip = devm_kzalloc(dev, sizeof(*chip) + nsels * sizeof(u8), -+ GFP_KERNEL); -+ if (!chip) ++ rknand = devm_kzalloc(dev, sizeof(*rknand) + nsels * sizeof(u8), ++ GFP_KERNEL); ++ if (!rknand) + return -ENOMEM; + -+ chip->nsels = nsels; ++ rknand->nsels = nsels; + for (i = 0; i < nsels; i++) { + ret = of_property_read_u32_index(np, "reg", i, &tmp); + if (ret) { @@ -1016,60 +1346,95 @@ index 000000000000..1e37a1b6c702 + return -EINVAL; + } + -+ chip->sels[i] = tmp; ++ rknand->sels[i] = tmp; + } + -+ nand = &chip->nand; -+ nand->controller = &nfc->controller; ++ chip = &rknand->chip; ++ chip->controller = &nfc->controller; + -+ nand_set_flash_node(nand, np); -+ nand_set_controller_data(nand, nfc); ++ nand_set_flash_node(chip, np); + -+ nand->options |= NAND_USE_BOUNCE_BUFFER | NAND_NO_SUBPAGE_WRITE; -+ nand->bbt_options = NAND_BBT_USE_FLASH | NAND_BBT_NO_OOB; ++ nand_set_controller_data(chip, nfc); + -+ /* set default mode in case dt entry is missing */ -+ nand->ecc.mode = NAND_ECC_HW; ++ chip->options |= NAND_USES_DMA | NAND_NO_SUBPAGE_WRITE; ++ chip->bbt_options = NAND_BBT_USE_FLASH | NAND_BBT_NO_OOB; + -+ mtd = nand_to_mtd(nand); ++ /* Set default mode in case dt entry is missing. */ ++ chip->ecc.mode = NAND_ECC_HW; ++ ++ mtd = nand_to_mtd(chip); + mtd->owner = THIS_MODULE; + mtd->dev.parent = dev; -+ mtd->name = THIS_NAME; ++ ++ if (!mtd->name) { ++ dev_err(nfc->dev, "NAND label property is mandatory\n"); ++ return -EINVAL; ++ } ++ + mtd_set_ooblayout(mtd, &rk_nfc_ooblayout_ops); + rk_nfc_hw_init(nfc); -+ ret = nand_scan(nand, nsels); ++ ret = nand_scan(chip, nsels); + if (ret) + return ret; ++ ++ if (chip->options & NAND_IS_BOOT_MEDIUM) { ++ ret = of_property_read_u32(np, "rockchip,boot-blks", &tmp); ++ rknand->boot_blks = ret ? 0 : tmp; ++ ++ ret = of_property_read_u32(np, "rockchip,boot-ecc-strength", ++ &tmp); ++ rknand->boot_ecc = ret ? chip->ecc.strength : tmp; ++ } ++ + ret = mtd_device_register(mtd, NULL, 0); + if (ret) { + dev_err(dev, "mtd parse partition error\n"); -+ nand_release(nand); ++ nand_cleanup(chip); + return ret; + } + -+ list_add_tail(&chip->node, &nfc->chips); ++ list_add_tail(&rknand->node, &nfc->chips); + + return 0; +} + ++static void rk_nfc_chips_cleanup(struct rk_nfc *nfc) ++{ ++ struct rk_nfc_nand_chip *rknand, *tmp; ++ struct nand_chip *chip; ++ int ret; ++ ++ list_for_each_entry_safe(rknand, tmp, &nfc->chips, node) { ++ chip = &rknand->chip; ++ ret = mtd_device_unregister(nand_to_mtd(chip)); ++ WARN_ON(ret); ++ nand_cleanup(chip); ++ list_del(&rknand->node); ++ } ++} ++ +static int rk_nfc_nand_chips_init(struct device *dev, struct rk_nfc *nfc) +{ -+ struct device_node *np = dev->of_node; -+ struct device_node *nand_np; -+ int ret = -EINVAL; -+ int tmp; ++ struct device_node *np = dev->of_node, *nand_np; ++ int nchips = of_get_child_count(np); ++ int ret; + -+ for_each_child_of_node(np, nand_np) { -+ tmp = rk_nfc_nand_chip_init(dev, nfc, nand_np); -+ if (tmp) { -+ of_node_put(nand_np); -+ return ret; -+ } -+ /* At least one nand chip is initialized */ -+ ret = 0; ++ if (!nchips || nchips > NFC_MAX_NSELS) { ++ dev_err(nfc->dev, "Incorrect number of NAND chips (%d)\n", ++ nchips); ++ return -EINVAL; + } + -+ return ret; ++ for_each_child_of_node(np, nand_np) { ++ ret = rk_nfc_nand_chip_init(dev, nfc, nand_np); ++ if (ret) { ++ of_node_put(nand_np); ++ rk_nfc_chips_cleanup(nfc); ++ return ret; ++ } ++ } ++ ++ return 0; +} + +static struct nfc_cfg nfc_v6_cfg = { @@ -1122,7 +1487,6 @@ index 000000000000..1e37a1b6c702 + .dma_oob_buf_off = 0x18, + .dma_st_off = 0x1C, + .bch_st_off = 0x20, -+ .bch_st_off = 0x20, + .randmz_off = 0x150, + .int_en_off = 0x16C, + .int_clr_off = 0x170, @@ -1185,29 +1549,13 @@ index 000000000000..1e37a1b6c702 +}; + +static const struct of_device_id rk_nfc_id_table[] = { -+ {.compatible = "rockchip,px30_nfc", ++ {.compatible = "rockchip,px30-nfc", + .data = &nfc_v9_cfg }, -+ {.compatible = "rockchip,rk3308_nfc", ++ {.compatible = "rockchip,rk2928-nfc", ++ .data = &nfc_v6_cfg }, ++ {.compatible = "rockchip,rv1108-nfc", + .data = &nfc_v8_cfg }, -+ {.compatible = "rockchip,rv1108_nfc", -+ .data = &nfc_v8_cfg }, -+ {.compatible = "rockchip,rk3066_nfc", -+ .data = &nfc_v6_cfg }, -+ {.compatible = "rockchip,rk3188_nfc", -+ .data = &nfc_v6_cfg }, -+ {.compatible = "rockchip,rk3288_nfc", -+ .data = &nfc_v6_cfg }, -+ {.compatible = "rockchip,rk3368_nfc", -+ .data = &nfc_v6_cfg }, -+ {.compatible = "rockchip,rk2928_nfc", -+ .data = &nfc_v6_cfg }, -+ {.compatible = "rockchip,rk3036_nfc", -+ .data = &nfc_v6_cfg }, -+ {.compatible = "rockchip,rk3128_nfc", -+ .data = &nfc_v6_cfg }, -+ {.compatible = "rockchip,rk3228_nfc", -+ .data = &nfc_v6_cfg }, -+ {} ++ { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, rk_nfc_id_table); + @@ -1215,7 +1563,6 @@ index 000000000000..1e37a1b6c702 +{ + struct device *dev = &pdev->dev; + struct rk_nfc *nfc; -+ struct resource *res; + int ret, irq; + + nfc = devm_kzalloc(dev, sizeof(*nfc), GFP_KERNEL); @@ -1229,18 +1576,20 @@ index 000000000000..1e37a1b6c702 + nfc->cfg = of_device_get_match_data(dev); + nfc->dev = dev; + -+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ nfc->regs = devm_ioremap_resource(dev, res); ++ init_completion(&nfc->done); ++ ++ nfc->regs = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(nfc->regs)) { + ret = PTR_ERR(nfc->regs); + goto release_nfc; + } ++ + nfc->clk.nfc_clk = devm_clk_get(dev, "nfc"); + if (IS_ERR(nfc->clk.nfc_clk)) { -+ dev_err(dev, "no nfc clk\n"); -+ ret = PTR_ERR(nfc->clk.nfc_clk); -+ goto release_nfc; ++ dev_dbg(dev, "no nfc clk\n"); ++ /* Some earlier models, such as rk3066, have no nfc clk. */ + } ++ + nfc->clk.ahb_clk = devm_clk_get(dev, "ahb"); + if (IS_ERR(nfc->clk.ahb_clk)) { + dev_err(dev, "no ahb clk\n"); @@ -1270,7 +1619,7 @@ index 000000000000..1e37a1b6c702 + + ret = rk_nfc_nand_chips_init(dev, nfc); + if (ret) { -+ dev_err(dev, "failed to init nand chips\n"); ++ dev_err(dev, "failed to init NAND chips\n"); + goto clk_disable; + } + return 0; @@ -1284,15 +1633,8 @@ index 000000000000..1e37a1b6c702 +static int rk_nfc_remove(struct platform_device *pdev) +{ + struct rk_nfc *nfc = platform_get_drvdata(pdev); -+ struct rk_nfc_nand_chip *chip; -+ -+ while (!list_empty(&nfc->chips)) { -+ chip = list_first_entry(&nfc->chips, struct rk_nfc_nand_chip, -+ node); -+ nand_release(&chip->nand); -+ list_del(&chip->node); -+ } + ++ rk_nfc_chips_cleanup(nfc); + rk_nfc_disable_clk(&nfc->clk); + + return 0; @@ -1310,8 +1652,8 @@ index 000000000000..1e37a1b6c702 +static int __maybe_unused rk_nfc_resume(struct device *dev) +{ + struct rk_nfc *nfc = dev_get_drvdata(dev); -+ struct rk_nfc_nand_chip *chip; -+ struct nand_chip *nand; ++ struct rk_nfc_nand_chip *rknand; ++ struct nand_chip *chip; + int ret; + u32 i; + @@ -1319,11 +1661,11 @@ index 000000000000..1e37a1b6c702 + if (ret) + return ret; + -+ /* reset NAND chip if VCC was powered off */ -+ list_for_each_entry(chip, &nfc->chips, node) { -+ nand = &chip->nand; -+ for (i = 0; i < chip->nsels; i++) -+ nand_reset(nand, i); ++ /* Reset NAND chip if VCC was powered off. */ ++ list_for_each_entry(rknand, &nfc->chips, node) { ++ chip = &rknand->chip; ++ for (i = 0; i < rknand->nsels; i++) ++ nand_reset(chip, i); + } + + return 0; @@ -1334,10 +1676,10 @@ index 000000000000..1e37a1b6c702 +}; + +static struct platform_driver rk_nfc_driver = { -+ .probe = rk_nfc_probe, ++ .probe = rk_nfc_probe, + .remove = rk_nfc_remove, + .driver = { -+ .name = THIS_NAME, ++ .name = "rockchip-nfc", + .of_match_table = rk_nfc_id_table, + .pm = &rk_nfc_pm_ops, + }, @@ -1348,167 +1690,267 @@ index 000000000000..1e37a1b6c702 +MODULE_LICENSE("Dual MIT/GPL"); +MODULE_AUTHOR("Yifeng Zhao "); +MODULE_DESCRIPTION("Rockchip Nand Flash Controller Driver"); -+MODULE_ALIAS("platform:rockchip_nand"); --- -2.17.1 ++MODULE_ALIAS("platform:rockchip-nand-controller"); - -From d8b77253afb7292f637d62877f7c2e87f440a1ff Mon Sep 17 00:00:00 2001 +From 9f9bc458898c407f25a6d38551713317161b0092 Mon Sep 17 00:00:00 2001 From: Yifeng Zhao -Date: Fri, 20 Mar 2020 17:33:41 +0800 -Subject: [PATCH] dt-bindings: mtd: Describe Rockchip RK3xxx NAND flash - controller +Date: Fri, 17 Jul 2020 17:24:19 +0800 +Subject: [PATCH] MAINTAINERS: add maintainers to ROCKCHIP NFC -Documentation support for Rockchip RK3xxx NAND flash controllers - -Signed-off-by: Yifeng Zhao -Reviewed-by: Rob Herring ---- - .../bindings/mtd/rockchip,nand.yaml | 101 ++++++++++++++++++ - 1 file changed, 101 insertions(+) - create mode 100644 Documentation/devicetree/bindings/mtd/rockchip,nand.yaml - -diff --git a/Documentation/devicetree/bindings/mtd/rockchip,nand.yaml b/Documentation/devicetree/bindings/mtd/rockchip,nand.yaml -new file mode 100644 -index 000000000000..907af0d52b6b ---- /dev/null -+++ b/Documentation/devicetree/bindings/mtd/rockchip,nand.yaml -@@ -0,0 +1,101 @@ -+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) -+%YAML 1.2 -+--- -+$id: http://devicetree.org/schemas/mtd/rockchip,nand.yaml# -+$schema: http://devicetree.org/meta-schemas/core.yaml# -+ -+title: Rockchip SoCs NAND FLASH Controller (NFC) Device Tree Bindings -+ -+allOf: -+ - $ref: "nand-controller.yaml" -+ -+maintainers: -+ - Yifeng Zhao -+ -+properties: -+ "#address-cells": true -+ "#size-cells": true -+ -+ compatible: -+ enum: -+ - rockchip,px30_nfc -+ - rockchip,rk3308_nfc -+ - rockchip,rv1108_nfc -+ - rockchip,rk3066_nfc -+ - rockchip,rk3188_nfc -+ - rockchip,rk3288_nfc -+ - rockchip,rk3368_nfc -+ - rockchip,rk2928_nfc -+ - rockchip,rk3036_nfc -+ - rockchip,rk3128_nfc -+ - rockchip,rk3228_nfc -+ -+ reg: -+ maxItems: 1 -+ -+ interrupts: -+ maxItems: 1 -+ -+ clocks: -+ items: -+ - description: Module Clock -+ - description: Bus Clock -+ -+ clock-names: -+ items: -+ - const: nfc -+ - const: ahb -+ -+patternProperties: -+ "^nand@[0-3]$": -+ type: object -+ properties: -+ reg: -+ minimum: 0 -+ maximum: 3 -+ -+ nand-ecc-step-size: -+ const: 1024 -+ -+ nand-ecc-strength: -+ enum: [16, 24 , 40, 60, 70] -+ -+ nand-bus-width: -+ const: 8 -+ -+required: -+ - compatible -+ - reg -+ - interrupts -+ - clocks -+ - clock-names -+ -+examples: -+ - | -+ #include -+ #include -+ nfc: nand-controller@ff4b0000 { -+ compatible = "rockchip,nfc"; -+ reg = <0x0 0xff4b0000 0x0 0x4000>; -+ interrupts = ; -+ clocks = <&cru SCLK_NANDC>, <&cru HCLK_NANDC>; -+ clock-names = "nfc", "ahb"; -+ assigned-clocks = <&clks SCLK_NANDC>; -+ assigned-clock-rates = <150000000>; -+ -+ pinctrl-names = "default"; -+ pinctrl-0 = <&flash_csn0 &flash_rdy &flash_ale &flash_cle -+ &flash_wrn &flash_rdn &flash_bus8>; -+ -+ #address-cells = <1>; -+ #size-cells = <0>; -+ nand@0 { -+ reg = <0>; -+ nand-ecc-mode = "hw"; -+ nand-ecc-strength = <16>; -+ nand-ecc-step-size = <1024>; -+ nand-bus-width = <8>; -+ }; -+ }; -+ -+... --- -2.17.1 - - -From 7c0fa2538944c2b988b3575020e4e8b81e8f01ed Mon Sep 17 00:00:00 2001 -From: Yifeng Zhao -Date: Fri, 20 Mar 2020 17:33:42 +0800 -Subject: [PATCH] MAINTAINERS: add maintainers to rockchip nfc +Add maintainers to ROCKCHIP NFC. Signed-off-by: Yifeng Zhao --- - MAINTAINERS | 2 ++ - 1 file changed, 2 insertions(+) + MAINTAINERS | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS -index 5a5332b3591d..0bff05c4c96d 100644 +index 4e2698cc7e23..db98a799f409 100644 --- a/MAINTAINERS +++ b/MAINTAINERS -@@ -2276,6 +2276,7 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/mmind/linux-rockchip.git +@@ -2344,12 +2344,12 @@ L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) + L: linux-rockchip@lists.infradead.org S: Maintained - F: Documentation/devicetree/bindings/i2c/i2c-rk3x.txt - F: Documentation/devicetree/bindings/mmc/rockchip-dw-mshc.yaml + T: git git://git.kernel.org/pub/scm/linux/kernel/git/mmind/linux-rockchip.git +F: Documentation/devicetree/bindings/*/*rockchip*.yaml + F: Documentation/devicetree/bindings/i2c/i2c-rk3x.yaml +-F: Documentation/devicetree/bindings/mmc/rockchip-dw-mshc.yaml +-F: Documentation/devicetree/bindings/spi/spi-rockchip.yaml F: arch/arm/boot/dts/rk3* F: arch/arm/boot/dts/rv1108* F: arch/arm/mach-rockchip/ -@@ -2283,6 +2284,7 @@ F: drivers/clk/rockchip/ - F: drivers/i2c/busses/i2c-rk3x.c - F: drivers/*/*rockchip* - F: drivers/*/*/*rockchip* +F: drivers/*/*/*/*rockchip* - F: sound/soc/rockchip/ - N: rockchip - --- -2.17.1 + F: drivers/*/*/*rockchip* + F: drivers/*/*rockchip* + F: drivers/clk/rockchip/ +From 48604da8047dc2bb8009ee7af76655b41fb0c337 Mon Sep 17 00:00:00 2001 +From: Yifeng Zhao +Date: Fri, 17 Jul 2020 17:24:20 +0800 +Subject: [PATCH] arm64: dts: rockchip: Add NFC node for RK3308 SoC + +Add NAND FLASH Controller(NFC) node for RK3308 SoC. + +Signed-off-by: Yifeng Zhao +Signed-off-by: Yifeng Zhao +--- + arch/arm64/boot/dts/rockchip/rk3308.dtsi | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +diff --git a/arch/arm64/boot/dts/rockchip/rk3308.dtsi b/arch/arm64/boot/dts/rockchip/rk3308.dtsi +index e8b754d415d8..e9d8610fccf5 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3308.dtsi ++++ b/arch/arm64/boot/dts/rockchip/rk3308.dtsi +@@ -629,6 +629,21 @@ sdio: mmc@ff4a0000 { + status = "disabled"; + }; + ++ nfc: nand-controller@ff4b0000 { ++ compatible = "rockchip,rk3308-nfc", ++ "rockchip,rv1108-nfc"; ++ reg = <0x0 0xff4b0000 0x0 0x4000>; ++ interrupts = ; ++ clocks = <&cru HCLK_NANDC>, <&cru SCLK_NANDC>; ++ clock-names = "ahb", "nfc"; ++ assigned-clocks = <&cru SCLK_NANDC>; ++ assigned-clock-rates = <150000000>; ++ pinctrl-0 = <&flash_ale &flash_bus8 &flash_cle &flash_csn0 ++ &flash_rdn &flash_rdy &flash_wrn>; ++ pinctrl-names = "default"; ++ status = "disabled"; ++ }; ++ + cru: clock-controller@ff500000 { + compatible = "rockchip,rk3308-cru"; + reg = <0x0 0xff500000 0x0 0x1000>; + +From 046465fffd8f588097ed6f78bc3f193639bd5657 Mon Sep 17 00:00:00 2001 +From: Yifeng Zhao +Date: Fri, 17 Jul 2020 17:25:29 +0800 +Subject: [PATCH] arm64: dts: rockchip: Add NFC node for PX30 SoC + +Add NAND FLASH Controller(NFC) node for PX30 SoC. + +Signed-off-by: Yifeng Zhao +--- + arch/arm64/boot/dts/rockchip/px30.dtsi | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +diff --git a/arch/arm64/boot/dts/rockchip/px30.dtsi b/arch/arm64/boot/dts/rockchip/px30.dtsi +index 2695ea8cda14..6cd67e80d623 100644 +--- a/arch/arm64/boot/dts/rockchip/px30.dtsi ++++ b/arch/arm64/boot/dts/rockchip/px30.dtsi +@@ -973,6 +973,21 @@ emmc: mmc@ff390000 { + status = "disabled"; + }; + ++ nfc: nand-controller@ff3b0000 { ++ compatible = "rockchip,px30-nfc"; ++ reg = <0x0 0xff3b0000 0x0 0x4000>; ++ interrupts = ; ++ clocks = <&cru HCLK_NANDC>, <&cru SCLK_NANDC>; ++ clock-names = "ahb", "nfc"; ++ assigned-clocks = <&cru SCLK_NANDC>; ++ assigned-clock-rates = <150000000>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&flash_ale &flash_bus8 &flash_cle &flash_cs0 ++ &flash_rdn &flash_rdy &flash_wrn &flash_dqs>; ++ power-domains = <&power PX30_PD_MMC_NAND>; ++ status = "disabled"; ++ }; ++ + gpu: gpu@ff400000 { + compatible = "rockchip,px30-mali", "arm,mali-bifrost"; + reg = <0x0 0xff400000 0x0 0x4000>; + +From e67947a6ea98d31eda5e900909bc762714e97062 Mon Sep 17 00:00:00 2001 +From: Yifeng Zhao +Date: Fri, 17 Jul 2020 17:25:30 +0800 +Subject: [PATCH] arm: dts: rockchip: Add NFC node for RV1108 SoC + +Add NAND FLASH Controller(NFC) node for RV1108 SoC. + +Signed-off-by: Yifeng Zhao +--- + arch/arm/boot/dts/rv1108.dtsi | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/arch/arm/boot/dts/rv1108.dtsi b/arch/arm/boot/dts/rv1108.dtsi +index a1a08cb9364e..1696ea19488b 100644 +--- a/arch/arm/boot/dts/rv1108.dtsi ++++ b/arch/arm/boot/dts/rv1108.dtsi +@@ -452,6 +452,17 @@ cru: clock-controller@20200000 { + #reset-cells = <1>; + }; + ++ nfc: nand-controller@30100000 { ++ compatible = "rockchip,rv1108-nfc"; ++ reg = <0x30100000 0x1000>; ++ interrupts = ; ++ clocks = <&cru HCLK_NANDC>, <&cru SCLK_NANDC>; ++ clock-names = "ahb", "nfc"; ++ assigned-clocks = <&cru SCLK_NANDC>; ++ assigned-clock-rates = <150000000>; ++ status = "disabled"; ++ }; ++ + emmc: mmc@30110000 { + compatible = "rockchip,rv1108-dw-mshc", "rockchip,rk3288-dw-mshc"; + reg = <0x30110000 0x4000>; + +From 9f1eb721bf42f1470fe280b4f501526a8addd76e Mon Sep 17 00:00:00 2001 +From: Yifeng Zhao +Date: Fri, 17 Jul 2020 17:25:31 +0800 +Subject: [PATCH] arm: dts: rockchip: Add NFC node for RK2928 and other SoCs + +Add NAND FLASH Controller(NFC) node for RK2928, RK3066, RK3168 +and RK3188 SoCs. + +Signed-off-by: Yifeng Zhao +--- + arch/arm/boot/dts/rk3xxx.dtsi | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/arch/arm/boot/dts/rk3xxx.dtsi b/arch/arm/boot/dts/rk3xxx.dtsi +index 859a7477909f..97415180d5bb 100644 +--- a/arch/arm/boot/dts/rk3xxx.dtsi ++++ b/arch/arm/boot/dts/rk3xxx.dtsi +@@ -276,6 +276,15 @@ emmc: mmc@1021c000 { + status = "disabled"; + }; + ++ nfc: nand-controller@10500000 { ++ compatible = "rockchip,rk2928-nfc"; ++ reg = <0x10500000 0x4000>; ++ interrupts = ; ++ clocks = <&cru HCLK_NANDC0>; ++ clock-names = "ahb"; ++ status = "disabled"; ++ }; ++ + pmu: pmu@20004000 { + compatible = "rockchip,rk3066-pmu", "syscon", "simple-mfd"; + reg = <0x20004000 0x100>; + +From b299d8bd1f7b704e89fcb320b4d851cfc3a6f5e9 Mon Sep 17 00:00:00 2001 +From: Yifeng Zhao +Date: Fri, 17 Jul 2020 17:25:32 +0800 +Subject: [PATCH] arm: dts: rockchip: Add NFC node for RK3036 SoC + +Add NAND FLASH Controller(NFC) node for RK3036 SoC. + +Signed-off-by: Yifeng Zhao +--- + arch/arm/boot/dts/rk3036.dtsi | 52 +++++++++++++++++++++++++++++++++++ + 1 file changed, 52 insertions(+) + +diff --git a/arch/arm/boot/dts/rk3036.dtsi b/arch/arm/boot/dts/rk3036.dtsi +index 093567022386..dda5a1f79aca 100644 +--- a/arch/arm/boot/dts/rk3036.dtsi ++++ b/arch/arm/boot/dts/rk3036.dtsi +@@ -292,6 +292,21 @@ i2s: i2s@10220000 { + status = "disabled"; + }; + ++ nfc: nand-controller@10500000 { ++ compatible = "rockchip,rk3036-nfc", ++ "rockchip,rk2928-nfc"; ++ reg = <0x10500000 0x4000>; ++ interrupts = ; ++ clocks = <&cru HCLK_NANDC>, <&cru SCLK_NANDC>; ++ clock-names = "ahb", "nfc"; ++ assigned-clocks = <&cru SCLK_NANDC>; ++ assigned-clock-rates = <150000000>; ++ pinctrl-0 = <&flash_ale &flash_bus8 &flash_cle &flash_csn0 ++ &flash_rdn &flash_rdy &flash_wrn>; ++ pinctrl-names = "default"; ++ status = "disabled"; ++ }; ++ + cru: clock-controller@20000000 { + compatible = "rockchip,rk3036-cru"; + reg = <0x20000000 0x1000>; +@@ -643,6 +658,43 @@ emmc_bus8: emmc-bus8 { + }; + }; + ++ nfc { ++ flash_ale: flash-ale { ++ rockchip,pins = <2 RK_PA0 1 &pcfg_pull_default>; ++ }; ++ ++ flash_bus8: flash-bus8 { ++ rockchip,pins = <1 RK_PD0 1 &pcfg_pull_default>, ++ <1 RK_PD1 1 &pcfg_pull_default>, ++ <1 RK_PD2 1 &pcfg_pull_default>, ++ <1 RK_PD3 1 &pcfg_pull_default>, ++ <1 RK_PD4 1 &pcfg_pull_default>, ++ <1 RK_PD5 1 &pcfg_pull_default>, ++ <1 RK_PD6 1 &pcfg_pull_default>, ++ <1 RK_PD7 1 &pcfg_pull_default>; ++ }; ++ ++ flash_cle: flash-cle { ++ rockchip,pins = <2 RK_PA1 1 &pcfg_pull_default>; ++ }; ++ ++ flash_csn0: flash-csn0 { ++ rockchip,pins = <2 RK_PA6 1 &pcfg_pull_default>; ++ }; ++ ++ flash_rdn: flash-rdn { ++ rockchip,pins = <2 RK_PA3 1 &pcfg_pull_default>; ++ }; ++ ++ flash_rdy: flash-rdy { ++ rockchip,pins = <2 RK_PA4 1 &pcfg_pull_default>; ++ }; ++ ++ flash_wrn: flash-wrn { ++ rockchip,pins = <2 RK_PA2 1 &pcfg_pull_default>; ++ }; ++ }; ++ + emac { + emac_xfer: emac-xfer { + rockchip,pins = <2 RK_PB2 1 &pcfg_pull_default>, /* crs_dvalid */ diff --git a/patch/kernel/rk322x-current/01-linux-0004-work-in-progress.patch.disabled b/patch/kernel/rk322x-current/01-linux-0004-work-in-progress.patch.disabled deleted file mode 100644 index c09268ef6..000000000 --- a/patch/kernel/rk322x-current/01-linux-0004-work-in-progress.patch.disabled +++ /dev/null @@ -1,2864 +0,0 @@ -diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c -index 5749bdaba95b..3b383f73fcb0 100644 ---- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c -+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c -@@ -197,7 +197,7 @@ struct dw_hdmi { - - hdmi_codec_plugged_cb plugged_cb; - struct device *codec_dev; -- enum drm_connector_status last_connector_result; -+ enum drm_connector_status last_connector_status; - }; - - #define HDMI_IH_PHY_STAT0_RX_SENSE \ -@@ -236,7 +236,7 @@ int dw_hdmi_set_plugged_cb(struct dw_hdmi *hdmi, hdmi_codec_plugged_cb fn, - mutex_lock(&hdmi->mutex); - hdmi->plugged_cb = fn; - hdmi->codec_dev = codec_dev; -- plugged = hdmi->last_connector_result == connector_status_connected; -+ plugged = hdmi->last_connector_status == connector_status_connected; - handle_plugged_change(hdmi, plugged); - mutex_unlock(&hdmi->mutex); - -@@ -2277,7 +2277,7 @@ dw_hdmi_connector_detect(struct drm_connector *connector, bool force) - { - struct dw_hdmi *hdmi = container_of(connector, struct dw_hdmi, - connector); -- enum drm_connector_status result; -+ enum drm_connector_status status; - - mutex_lock(&hdmi->mutex); - hdmi->force = DRM_FORCE_UNSPECIFIED; -@@ -2285,18 +2285,18 @@ dw_hdmi_connector_detect(struct drm_connector *connector, bool force) - dw_hdmi_update_phy_mask(hdmi); - mutex_unlock(&hdmi->mutex); - -- result = hdmi->phy.ops->read_hpd(hdmi, hdmi->phy.data); -+ status = hdmi->phy.ops->read_hpd(hdmi, hdmi->phy.data); - - mutex_lock(&hdmi->mutex); -- if (result != hdmi->last_connector_result) { -- dev_dbg(hdmi->dev, "read_hpd result: %d", result); -+ if (status != hdmi->last_connector_status) { -+ dev_dbg(hdmi->dev, "connector status: %d", status); - handle_plugged_change(hdmi, -- result == connector_status_connected); -- hdmi->last_connector_result = result; -+ status == connector_status_connected); -+ hdmi->last_connector_status = status; - } - mutex_unlock(&hdmi->mutex); - -- return result; -+ return status; - } - - static int dw_hdmi_connector_get_modes(struct drm_connector *connector) -@@ -3059,7 +3059,7 @@ __dw_hdmi_probe(struct platform_device *pdev, - hdmi->rxsense = true; - hdmi->phy_mask = (u8)~(HDMI_PHY_HPD | HDMI_PHY_RX_SENSE); - hdmi->mc_clkdis = 0x7f; -- hdmi->last_connector_result = connector_status_disconnected; -+ hdmi->last_connector_status = connector_status_disconnected; - - mutex_init(&hdmi->mutex); - mutex_init(&hdmi->audio_mutex); --- -2.17.1 - - -From 2cdd6cd8eae12254226b6f3e30c5bcc52ac93ca7 Mon Sep 17 00:00:00 2001 -From: Jonas Karlman -Date: Sun, 1 Dec 2019 20:51:22 +0000 -Subject: [PATCH] drm: dw-hdmi: extract handle_plugged_change call - -Signed-off-by: Jonas Karlman ---- - drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 22 ++++++++++++++-------- - 1 file changed, 14 insertions(+), 8 deletions(-) - -diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c -index 3b383f73fcb0..bb430c48488f 100644 ---- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c -+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c -@@ -228,6 +228,19 @@ static void handle_plugged_change(struct dw_hdmi *hdmi, bool plugged) - hdmi->plugged_cb(hdmi->codec_dev, plugged); - } - -+static void dw_hdmi_update_connector_status(struct dw_hdmi *hdmi, -+ enum drm_connector_status status) -+{ -+ mutex_lock(&hdmi->mutex); -+ if (status != hdmi->last_connector_status) { -+ dev_dbg(hdmi->dev, "connector status: %d", status); -+ handle_plugged_change(hdmi, -+ status == connector_status_connected); -+ hdmi->last_connector_status = status; -+ } -+ mutex_unlock(&hdmi->mutex); -+} -+ - int dw_hdmi_set_plugged_cb(struct dw_hdmi *hdmi, hdmi_codec_plugged_cb fn, - struct device *codec_dev) - { -@@ -2287,14 +2300,7 @@ dw_hdmi_connector_detect(struct drm_connector *connector, bool force) - - status = hdmi->phy.ops->read_hpd(hdmi, hdmi->phy.data); - -- mutex_lock(&hdmi->mutex); -- if (status != hdmi->last_connector_status) { -- dev_dbg(hdmi->dev, "connector status: %d", status); -- handle_plugged_change(hdmi, -- status == connector_status_connected); -- hdmi->last_connector_status = status; -- } -- mutex_unlock(&hdmi->mutex); -+ dw_hdmi_update_connector_status(hdmi, status); - - return status; - } --- -2.17.1 - - -From 979981e11fa3ba5e94d25d22f7d0cdc55e8f9348 Mon Sep 17 00:00:00 2001 -From: Jonas Karlman -Date: Sat, 28 Sep 2019 13:34:46 +0000 -Subject: [PATCH] drm: dw-hdmi: remove unused struct member - -Signed-off-by: Jonas Karlman ---- - drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 4 ---- - 1 file changed, 4 deletions(-) - -diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c -index bb430c48488f..06620adfed95 100644 ---- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c -+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c -@@ -41,8 +41,6 @@ - #define DDC_CI_ADDR 0x37 - #define DDC_SEGMENT_ADDR 0x30 - --#define HDMI_EDID_LEN 512 -- - /* DW-HDMI Controller >= 0x200a are at least compliant with SCDC version 1 */ - #define SCDC_MIN_SOURCE_VERSION 0x1 - -@@ -152,8 +150,6 @@ struct dw_hdmi { - - int vic; - -- u8 edid[HDMI_EDID_LEN]; -- - struct { - const struct dw_hdmi_phy_ops *ops; - const char *name; --- -2.17.1 - - -From 74adf054fd1d83d31f03085ec4574318cb135c95 Mon Sep 17 00:00:00 2001 -From: Jonas Karlman -Date: Sat, 28 Sep 2019 13:34:46 +0000 -Subject: [PATCH] drm: dw-hdmi: read edid in detect callback - -Signed-off-by: Jonas Karlman ---- - drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 79 +++++++++++++++++------ - 1 file changed, 58 insertions(+), 21 deletions(-) - -diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c -index 06620adfed95..a304dff5f1be 100644 ---- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c -+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c -@@ -150,6 +150,8 @@ struct dw_hdmi { - - int vic; - -+ struct edid *cached_edid; -+ - struct { - const struct dw_hdmi_phy_ops *ops; - const char *name; -@@ -2223,9 +2225,55 @@ static void initialize_hdmi_ih_mutes(struct dw_hdmi *hdmi) - hdmi_writeb(hdmi, ih_mute, HDMI_IH_MUTE); - } - -+static void dw_hdmi_clear_edid(struct drm_connector *connector) -+{ -+ struct dw_hdmi *hdmi = container_of(connector, struct dw_hdmi, -+ connector); -+ -+ if (!hdmi->cached_edid) -+ return; -+ -+ hdmi->sink_is_hdmi = false; -+ hdmi->sink_has_audio = false; -+ -+ kfree(hdmi->cached_edid); -+ hdmi->cached_edid = NULL; -+} -+ -+static void dw_hdmi_get_edid(struct drm_connector *connector) -+{ -+ struct dw_hdmi *hdmi = container_of(connector, struct dw_hdmi, -+ connector); -+ struct edid *edid; -+ -+ if (!hdmi->ddc || hdmi->cached_edid) -+ return; -+ -+ edid = drm_get_edid(connector, hdmi->ddc); -+ -+ if (edid && edid->input & DRM_EDID_INPUT_DIGITAL) { -+ dev_dbg(hdmi->dev, "got edid: width[%d] x height[%d]\n", -+ edid->width_cm, edid->height_cm); -+ -+ hdmi->sink_is_hdmi = drm_detect_hdmi_monitor(edid); -+ hdmi->sink_has_audio = drm_detect_monitor_audio(edid); -+ -+ hdmi->cached_edid = edid; -+ } else { -+ dev_dbg(hdmi->dev, "failed to get edid\n"); -+ -+ kfree(edid); -+ edid = NULL; -+ } -+ -+ drm_connector_update_edid_property(connector, edid); -+ cec_notifier_set_phys_addr_from_edid(hdmi->cec_notifier, edid); -+} -+ - static void dw_hdmi_poweron(struct dw_hdmi *hdmi) - { - hdmi->bridge_is_on = true; -+ dw_hdmi_get_edid(&hdmi->connector); - dw_hdmi_setup(hdmi, &hdmi->previous_mode); - } - -@@ -2296,6 +2344,11 @@ dw_hdmi_connector_detect(struct drm_connector *connector, bool force) - - status = hdmi->phy.ops->read_hpd(hdmi, hdmi->phy.data); - -+ if (status == connector_status_disconnected) -+ dw_hdmi_clear_edid(connector); -+ else -+ dw_hdmi_get_edid(connector); -+ - dw_hdmi_update_connector_status(hdmi, status); - - return status; -@@ -2305,28 +2358,8 @@ static int dw_hdmi_connector_get_modes(struct drm_connector *connector) - { - struct dw_hdmi *hdmi = container_of(connector, struct dw_hdmi, - connector); -- struct edid *edid; -- int ret = 0; -- -- if (!hdmi->ddc) -- return 0; - -- edid = drm_get_edid(connector, hdmi->ddc); -- if (edid) { -- dev_dbg(hdmi->dev, "got edid: width[%d] x height[%d]\n", -- edid->width_cm, edid->height_cm); -- -- hdmi->sink_is_hdmi = drm_detect_hdmi_monitor(edid); -- hdmi->sink_has_audio = drm_detect_monitor_audio(edid); -- drm_connector_update_edid_property(connector, edid); -- cec_notifier_set_phys_addr_from_edid(hdmi->cec_notifier, edid); -- ret = drm_add_edid_modes(connector, edid); -- kfree(edid); -- } else { -- dev_dbg(hdmi->dev, "failed to get edid\n"); -- } -- -- return ret; -+ return drm_add_edid_modes(connector, hdmi->cached_edid); - } - - static bool hdr_metadata_equal(const struct drm_connector_state *old_state, -@@ -2705,6 +2738,9 @@ static void dw_hdmi_bridge_detach(struct drm_bridge *bridge) - cec_notifier_conn_unregister(hdmi->cec_notifier); - hdmi->cec_notifier = NULL; - mutex_unlock(&hdmi->cec_notifier_mutex); -+ -+ kfree(hdmi->cached_edid); -+ hdmi->cached_edid = NULL; - } - - static enum drm_mode_status -@@ -3394,6 +3430,7 @@ EXPORT_SYMBOL_GPL(dw_hdmi_unbind); - - void dw_hdmi_resume(struct dw_hdmi *hdmi) - { -+ dw_hdmi_clear_edid(&hdmi->connector); - dw_hdmi_init_hw(hdmi); - } - EXPORT_SYMBOL_GPL(dw_hdmi_resume); --- -2.17.1 - - -From f44056d77b1e928d0eec26eef9d35ce3c7b04d30 Mon Sep 17 00:00:00 2001 -From: Jonas Karlman -Date: Sat, 28 Sep 2019 13:34:47 +0000 -Subject: [PATCH] drm: dw-hdmi: read edid in force callback - -Signed-off-by: Jonas Karlman ---- - drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 7 +++++++ - 1 file changed, 7 insertions(+) - -diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c -index a304dff5f1be..49a9611249d2 100644 ---- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c -+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c -@@ -2411,6 +2411,13 @@ static void dw_hdmi_connector_force(struct drm_connector *connector) - dw_hdmi_update_power(hdmi); - dw_hdmi_update_phy_mask(hdmi); - mutex_unlock(&hdmi->mutex); -+ -+ dw_hdmi_clear_edid(connector); -+ -+ if (connector->status != connector_status_connected) -+ return; -+ -+ dw_hdmi_get_edid(connector); - } - - static const struct drm_connector_funcs dw_hdmi_connector_funcs = { --- -2.17.1 - - -From 27119e85c5368957ac0182418a26d473dd94ab49 Mon Sep 17 00:00:00 2001 -From: Jonas Karlman -Date: Sat, 28 Sep 2019 13:34:47 +0000 -Subject: [PATCH] drm: dw-hdmi: invalidate cec phys addr in detect callback - -Signed-off-by: Jonas Karlman ---- - drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 17 +++-------------- - 1 file changed, 3 insertions(+), 14 deletions(-) - -diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c -index 49a9611249d2..b9fa6c3b07c0 100644 ---- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c -+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c -@@ -190,7 +190,6 @@ struct dw_hdmi { - void (*enable_audio)(struct dw_hdmi *hdmi); - void (*disable_audio)(struct dw_hdmi *hdmi); - -- struct mutex cec_notifier_mutex; - struct cec_notifier *cec_notifier; - - hdmi_codec_plugged_cb plugged_cb; -@@ -2238,6 +2237,8 @@ static void dw_hdmi_clear_edid(struct drm_connector *connector) - - kfree(hdmi->cached_edid); - hdmi->cached_edid = NULL; -+ -+ cec_notifier_phys_addr_invalidate(hdmi->cec_notifier); - } - - static void dw_hdmi_get_edid(struct drm_connector *connector) -@@ -2730,9 +2731,7 @@ static int dw_hdmi_bridge_attach(struct drm_bridge *bridge) - if (!notifier) - return -ENOMEM; - -- mutex_lock(&hdmi->cec_notifier_mutex); - hdmi->cec_notifier = notifier; -- mutex_unlock(&hdmi->cec_notifier_mutex); - - return 0; - } -@@ -2741,10 +2740,8 @@ static void dw_hdmi_bridge_detach(struct drm_bridge *bridge) - { - struct dw_hdmi *hdmi = bridge->driver_private; - -- mutex_lock(&hdmi->cec_notifier_mutex); - cec_notifier_conn_unregister(hdmi->cec_notifier); - hdmi->cec_notifier = NULL; -- mutex_unlock(&hdmi->cec_notifier_mutex); - - kfree(hdmi->cached_edid); - hdmi->cached_edid = NULL; -@@ -2912,18 +2909,11 @@ static irqreturn_t dw_hdmi_irq(int irq, void *dev_id) - * ask the source to re-read the EDID. - */ - if (intr_stat & -- (HDMI_IH_PHY_STAT0_RX_SENSE | HDMI_IH_PHY_STAT0_HPD)) { -+ (HDMI_IH_PHY_STAT0_RX_SENSE | HDMI_IH_PHY_STAT0_HPD)) - dw_hdmi_setup_rx_sense(hdmi, - phy_stat & HDMI_PHY_HPD, - phy_stat & HDMI_PHY_RX_SENSE); - -- if ((phy_stat & (HDMI_PHY_RX_SENSE | HDMI_PHY_HPD)) == 0) { -- mutex_lock(&hdmi->cec_notifier_mutex); -- cec_notifier_phys_addr_invalidate(hdmi->cec_notifier); -- mutex_unlock(&hdmi->cec_notifier_mutex); -- } -- } -- - if (intr_stat & HDMI_IH_PHY_STAT0_HPD) { - dev_dbg(hdmi->dev, "EVENT=%s\n", - phy_int_pol & HDMI_PHY_HPD ? "plugin" : "plugout"); -@@ -3108,7 +3098,6 @@ __dw_hdmi_probe(struct platform_device *pdev, - - mutex_init(&hdmi->mutex); - mutex_init(&hdmi->audio_mutex); -- mutex_init(&hdmi->cec_notifier_mutex); - spin_lock_init(&hdmi->audio_lock); - - ddc_node = of_parse_phandle(np, "ddc-i2c-bus", 0); --- -2.17.1 - - -From d6fca8d650a43ed3ef7d8efb3b51b2e7c3a0a8ba Mon Sep 17 00:00:00 2001 -From: Jonas Karlman -Date: Sun, 8 Dec 2019 23:41:44 +0000 -Subject: [PATCH] WIP: drm: dw-hdmi: do not force none scan mode - -Signed-off-by: Jonas Karlman ---- - drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 2 -- - 1 file changed, 2 deletions(-) - -diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c -index b9fa6c3b07c0..4d253e5a1c79 100644 ---- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c -+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c -@@ -1664,8 +1664,6 @@ static void hdmi_config_AVI(struct dw_hdmi *hdmi, struct drm_display_mode *mode) - HDMI_EXTENDED_COLORIMETRY_XV_YCC_601; - } - -- frame.scan_mode = HDMI_SCAN_MODE_NONE; -- - /* - * The Designware IP uses a different byte format from standard - * AVI info frames, though generally the bits are in the correct --- -2.17.1 - - -From b16f499ce83d7b9084073e813943ae98d4f5c716 Mon Sep 17 00:00:00 2001 -From: Jonas Karlman -Date: Sun, 8 Dec 2019 23:42:44 +0000 -Subject: [PATCH] WIP: drm: dw-hdmi: add content type connector property - -Signed-off-by: Jonas Karlman ---- - drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 8 +++++++- - 1 file changed, 7 insertions(+), 1 deletion(-) - -diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c -index 4d253e5a1c79..cd10554cde76 100644 ---- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c -+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c -@@ -1617,6 +1617,7 @@ static void hdmi_tx_hdcp_config(struct dw_hdmi *hdmi) - - static void hdmi_config_AVI(struct dw_hdmi *hdmi, struct drm_display_mode *mode) - { -+ const struct drm_connector_state *conn_state = hdmi->connector.state; - struct hdmi_avi_infoframe frame; - u8 val; - -@@ -1664,6 +1665,8 @@ static void hdmi_config_AVI(struct dw_hdmi *hdmi, struct drm_display_mode *mode) - HDMI_EXTENDED_COLORIMETRY_XV_YCC_601; - } - -+ drm_hdmi_avi_infoframe_content_type(&frame, conn_state); -+ - /* - * The Designware IP uses a different byte format from standard - * AVI info frames, though generally the bits are in the correct -@@ -2389,7 +2392,8 @@ static int dw_hdmi_connector_atomic_check(struct drm_connector *connector, - if (!crtc) - return 0; - -- if (!hdr_metadata_equal(old_state, new_state)) { -+ if (!hdr_metadata_equal(old_state, new_state) || -+ old_state->content_type != new_state->content_type) { - crtc_state = drm_atomic_get_crtc_state(state, crtc); - if (IS_ERR(crtc_state)) - return PTR_ERR(crtc_state); -@@ -2717,6 +2721,8 @@ static int dw_hdmi_bridge_attach(struct drm_bridge *bridge) - - drm_connector_attach_max_bpc_property(connector, 8, 16); - -+ drm_connector_attach_content_type_property(connector); -+ - if (hdmi->version >= 0x200a && hdmi->plat_data->use_drm_infoframe) - drm_object_attach_property(&connector->base, - connector->dev->mode_config.hdr_output_metadata_property, 0); --- -2.17.1 - - -From 2203d10f59f25af58fe1f5aaaceb3980ccea2f39 Mon Sep 17 00:00:00 2001 -From: Jonas Karlman -Date: Sun, 8 Dec 2019 23:43:55 +0000 -Subject: [PATCH] WIP: drm: dw-hdmi: add SPD infoframe - -Signed-off-by: Jonas Karlman ---- - drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 42 +++++++++++++++++++---- - drivers/gpu/drm/bridge/synopsys/dw-hdmi.h | 32 +++++++++-------- - 2 files changed, 53 insertions(+), 21 deletions(-) - -diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c -index cd10554cde76..5377c55e9927 100644 ---- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c -+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c -@@ -1733,6 +1733,35 @@ static void hdmi_config_AVI(struct dw_hdmi *hdmi, struct drm_display_mode *mode) - hdmi_writeb(hdmi, (frame.right_bar >> 8) & 0xff, HDMI_FC_AVISRB1); - } - -+static void hdmi_config_spd_infoframe(struct dw_hdmi *hdmi) -+{ -+ struct hdmi_spd_infoframe frame; -+ u8 buffer[29]; -+ ssize_t err; -+ int i; -+ -+ hdmi_mask_writeb(hdmi, 0, HDMI_FC_DATAUTO0, HDMI_FC_DATAUTO0_SPD_OFFSET, -+ HDMI_FC_DATAUTO0_SPD_MASK); -+ -+ err = hdmi_spd_infoframe_init(&frame, "DW", "HDMI"); -+ if (err < 0) -+ return; -+ -+ frame.sdi = HDMI_SPD_SDI_PC; -+ -+ err = hdmi_spd_infoframe_pack(&frame, buffer, sizeof(buffer)); -+ if (err < 0) { -+ dev_err(hdmi->dev, "Failed to pack spd infoframe: %zd\n", err); -+ return; -+ } -+ -+ for (i = 0; i < frame.length; i++) -+ hdmi_writeb(hdmi, buffer[4 + i], HDMI_FC_SPDVENDORNAME0 + i); -+ -+ hdmi_mask_writeb(hdmi, 1, HDMI_FC_DATAUTO0, HDMI_FC_DATAUTO0_SPD_OFFSET, -+ HDMI_FC_DATAUTO0_SPD_MASK); -+} -+ - static void hdmi_config_vendor_specific_infoframe(struct dw_hdmi *hdmi, - struct drm_display_mode *mode) - { -@@ -1776,12 +1805,6 @@ static void hdmi_config_vendor_specific_infoframe(struct dw_hdmi *hdmi, - if (frame.s3d_struct >= HDMI_3D_STRUCTURE_SIDE_BY_SIDE_HALF) - hdmi_writeb(hdmi, buffer[9], HDMI_FC_VSDPAYLOAD2); - -- /* Packet frame interpolation */ -- hdmi_writeb(hdmi, 1, HDMI_FC_DATAUTO1); -- -- /* Auto packets per frame and line spacing */ -- hdmi_writeb(hdmi, 0x11, HDMI_FC_DATAUTO2); -- - /* Configures the Frame Composer On RDRB mode */ - hdmi_mask_writeb(hdmi, 1, HDMI_FC_DATAUTO0, HDMI_FC_DATAUTO0_VSD_OFFSET, - HDMI_FC_DATAUTO0_VSD_MASK); -@@ -2158,8 +2181,15 @@ static int dw_hdmi_setup(struct dw_hdmi *hdmi, struct drm_display_mode *mode) - - /* HDMI Initialization Step F - Configure AVI InfoFrame */ - hdmi_config_AVI(hdmi, mode); -+ hdmi_config_spd_infoframe(hdmi); - hdmi_config_vendor_specific_infoframe(hdmi, mode); - hdmi_config_drm_infoframe(hdmi); -+ -+ /* Packet frame interpolation */ -+ hdmi_writeb(hdmi, 1, HDMI_FC_DATAUTO1); -+ -+ /* Auto packets per frame and line spacing */ -+ hdmi_writeb(hdmi, 0x11, HDMI_FC_DATAUTO2); - } else { - dev_dbg(hdmi->dev, "%s DVI mode\n", __func__); - } -diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h -index 1999db05bc3b..27a91128d0cc 100644 ---- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h -+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h -@@ -139,21 +139,21 @@ - #define HDMI_FC_SPDVENDORNAME5 0x104F - #define HDMI_FC_SPDVENDORNAME6 0x1050 - #define HDMI_FC_SPDVENDORNAME7 0x1051 --#define HDMI_FC_SDPPRODUCTNAME0 0x1052 --#define HDMI_FC_SDPPRODUCTNAME1 0x1053 --#define HDMI_FC_SDPPRODUCTNAME2 0x1054 --#define HDMI_FC_SDPPRODUCTNAME3 0x1055 --#define HDMI_FC_SDPPRODUCTNAME4 0x1056 --#define HDMI_FC_SDPPRODUCTNAME5 0x1057 --#define HDMI_FC_SDPPRODUCTNAME6 0x1058 --#define HDMI_FC_SDPPRODUCTNAME7 0x1059 --#define HDMI_FC_SDPPRODUCTNAME8 0x105A --#define HDMI_FC_SDPPRODUCTNAME9 0x105B --#define HDMI_FC_SDPPRODUCTNAME10 0x105C --#define HDMI_FC_SDPPRODUCTNAME11 0x105D --#define HDMI_FC_SDPPRODUCTNAME12 0x105E --#define HDMI_FC_SDPPRODUCTNAME13 0x105F --#define HDMI_FC_SDPPRODUCTNAME14 0x1060 -+#define HDMI_FC_SPDPRODUCTNAME0 0x1052 -+#define HDMI_FC_SPDPRODUCTNAME1 0x1053 -+#define HDMI_FC_SPDPRODUCTNAME2 0x1054 -+#define HDMI_FC_SPDPRODUCTNAME3 0x1055 -+#define HDMI_FC_SPDPRODUCTNAME4 0x1056 -+#define HDMI_FC_SPDPRODUCTNAME5 0x1057 -+#define HDMI_FC_SPDPRODUCTNAME6 0x1058 -+#define HDMI_FC_SPDPRODUCTNAME7 0x1059 -+#define HDMI_FC_SPDPRODUCTNAME8 0x105A -+#define HDMI_FC_SPDPRODUCTNAME9 0x105B -+#define HDMI_FC_SPDPRODUCTNAME10 0x105C -+#define HDMI_FC_SPDPRODUCTNAME11 0x105D -+#define HDMI_FC_SPDPRODUCTNAME12 0x105E -+#define HDMI_FC_SPDPRODUCTNAME13 0x105F -+#define HDMI_FC_SPDPRODUCTNAME14 0x1060 - #define HDMI_FC_SPDPRODUCTNAME15 0x1061 - #define HDMI_FC_SPDDEVICEINF 0x1062 - #define HDMI_FC_AUDSCONF 0x1063 -@@ -849,6 +849,8 @@ enum { - /* FC_DATAUTO0 field values */ - HDMI_FC_DATAUTO0_VSD_MASK = 0x08, - HDMI_FC_DATAUTO0_VSD_OFFSET = 3, -+ HDMI_FC_DATAUTO0_SPD_MASK = 0x10, -+ HDMI_FC_DATAUTO0_SPD_OFFSET = 4, - - /* PHY_CONF0 field values */ - HDMI_PHY_CONF0_PDZ_MASK = 0x80, --- -2.17.1 - - -From 02f9cee9acb20262ed704ac658c1f61fbcbb8294 Mon Sep 17 00:00:00 2001 -From: Jonas Karlman -Date: Sun, 29 Sep 2019 13:47:38 +0000 -Subject: [PATCH] WIP: drm: dw-hdmi: debugging logging - ---- - drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 28 +++++++++++++-- - drivers/video/hdmi.c | 44 +++++++++++++++++------ - 2 files changed, 59 insertions(+), 13 deletions(-) - -diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c -index 5377c55e9927..cc39b544ae6e 100644 ---- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c -+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c -@@ -1667,6 +1667,8 @@ static void hdmi_config_AVI(struct dw_hdmi *hdmi, struct drm_display_mode *mode) - - drm_hdmi_avi_infoframe_content_type(&frame, conn_state); - -+ hdmi_infoframe_log(KERN_INFO, hdmi->dev, (union hdmi_infoframe *)&frame); -+ - /* - * The Designware IP uses a different byte format from standard - * AVI info frames, though generally the bits are in the correct -@@ -1755,6 +1757,8 @@ static void hdmi_config_spd_infoframe(struct dw_hdmi *hdmi) - return; - } - -+ hdmi_infoframe_log(KERN_INFO, hdmi->dev, (union hdmi_infoframe *)&frame); -+ - for (i = 0; i < frame.length; i++) - hdmi_writeb(hdmi, buffer[4 + i], HDMI_FC_SPDVENDORNAME0 + i); - -@@ -1769,6 +1773,9 @@ static void hdmi_config_vendor_specific_infoframe(struct dw_hdmi *hdmi, - u8 buffer[10]; - ssize_t err; - -+ hdmi_mask_writeb(hdmi, 0, HDMI_FC_DATAUTO0, HDMI_FC_DATAUTO0_VSD_OFFSET, -+ HDMI_FC_DATAUTO0_VSD_MASK); -+ - err = drm_hdmi_vendor_infoframe_from_display_mode(&frame, - &hdmi->connector, - mode); -@@ -1787,8 +1794,8 @@ static void hdmi_config_vendor_specific_infoframe(struct dw_hdmi *hdmi, - err); - return; - } -- hdmi_mask_writeb(hdmi, 0, HDMI_FC_DATAUTO0, HDMI_FC_DATAUTO0_VSD_OFFSET, -- HDMI_FC_DATAUTO0_VSD_MASK); -+ -+ hdmi_infoframe_log(KERN_INFO, hdmi->dev, (union hdmi_infoframe *)&frame); - - /* Set the length of HDMI vendor specific InfoFrame payload */ - hdmi_writeb(hdmi, buffer[2], HDMI_FC_VSDSIZE); -@@ -1834,6 +1841,8 @@ static void hdmi_config_drm_infoframe(struct dw_hdmi *hdmi) - return; - } - -+ hdmi_infoframe_log(KERN_INFO, hdmi->dev, (union hdmi_infoframe *)&frame); -+ - hdmi_writeb(hdmi, frame.version, HDMI_FC_DRM_HB0); - hdmi_writeb(hdmi, frame.length, HDMI_FC_DRM_HB1); - -@@ -2368,6 +2377,9 @@ dw_hdmi_connector_detect(struct drm_connector *connector, bool force) - connector); - enum drm_connector_status status; - -+ DRM_DEBUG_KMS("[CONNECTOR:%d:%s] force=%d\n", -+ connector->base.id, connector->name, force); -+ - mutex_lock(&hdmi->mutex); - hdmi->force = DRM_FORCE_UNSPECIFIED; - dw_hdmi_update_power(hdmi); -@@ -2391,6 +2403,9 @@ static int dw_hdmi_connector_get_modes(struct drm_connector *connector) - struct dw_hdmi *hdmi = container_of(connector, struct dw_hdmi, - connector); - -+ DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", -+ connector->base.id, connector->name); -+ - return drm_add_edid_modes(connector, hdmi->cached_edid); - } - -@@ -2429,6 +2444,12 @@ static int dw_hdmi_connector_atomic_check(struct drm_connector *connector, - return PTR_ERR(crtc_state); - - crtc_state->mode_changed = true; -+ -+ DRM_DEBUG_KMS("[CONNECTOR:%d:%s] hdr_metadata_equal=false\n", -+ connector->base.id, connector->name); -+ } else { -+ DRM_DEBUG_KMS("[CONNECTOR:%d:%s] hdr_metadata_equal=true\n", -+ connector->base.id, connector->name); - } - - return 0; -@@ -2439,6 +2460,9 @@ static void dw_hdmi_connector_force(struct drm_connector *connector) - struct dw_hdmi *hdmi = container_of(connector, struct dw_hdmi, - connector); - -+ DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", -+ connector->base.id, connector->name); -+ - mutex_lock(&hdmi->mutex); - hdmi->force = connector->force; - dw_hdmi_update_power(hdmi); -diff --git a/drivers/video/hdmi.c b/drivers/video/hdmi.c -index 9c82e2a0a411..c3b96d3c59e1 100644 ---- a/drivers/video/hdmi.c -+++ b/drivers/video/hdmi.c -@@ -1419,6 +1419,27 @@ static void hdmi_audio_infoframe_log(const char *level, - frame->downmix_inhibit ? "Yes" : "No"); - } - -+static const char * -+hdmi_eotf_get_name(enum hdmi_eotf eotf) -+{ -+ if (eotf < 0 || eotf > 7) -+ return "Invalid"; -+ -+ switch (eotf) { -+ case HDMI_EOTF_TRADITIONAL_GAMMA_SDR: -+ return "Traditional Gamma - SDR"; -+ case HDMI_EOTF_TRADITIONAL_GAMMA_HDR: -+ return "Traditional Gamma - HDR"; -+ case HDMI_EOTF_SMPTE_ST2084: -+ return "SMPTE ST 2084"; -+ case HDMI_EOTF_BT_2100_HLG: -+ return "Hybrid Log-Gamma (HLG)"; -+ default: -+ break; -+ } -+ return "Reserved"; -+} -+ - static void hdmi_drm_infoframe_log(const char *level, - struct device *dev, - const struct hdmi_drm_infoframe *frame) -@@ -1427,24 +1448,25 @@ static void hdmi_drm_infoframe_log(const char *level, - - hdmi_infoframe_log_header(level, dev, - (struct hdmi_any_infoframe *)frame); -- hdmi_log("length: %d\n", frame->length); -- hdmi_log("metadata type: %d\n", frame->metadata_type); -- hdmi_log("eotf: %d\n", frame->eotf); -+ hdmi_log(" metadata type: %d\n", frame->metadata_type); -+ hdmi_log(" eotf: %s\n", hdmi_eotf_get_name(frame->eotf)); -+ -+ hdmi_log(" display primaries:\n"); - for (i = 0; i < 3; i++) { -- hdmi_log("x[%d]: %d\n", i, frame->display_primaries[i].x); -- hdmi_log("y[%d]: %d\n", i, frame->display_primaries[i].y); -+ hdmi_log(" x[%d]: %d\n", i, frame->display_primaries[i].x); -+ hdmi_log(" y[%d]: %d\n", i, frame->display_primaries[i].y); - } - -- hdmi_log("white point x: %d\n", frame->white_point.x); -- hdmi_log("white point y: %d\n", frame->white_point.y); -+ hdmi_log(" white point x: %d\n", frame->white_point.x); -+ hdmi_log(" white point y: %d\n", frame->white_point.y); - -- hdmi_log("max_display_mastering_luminance: %d\n", -+ hdmi_log(" max display mastering luminance: %d\n", - frame->max_display_mastering_luminance); -- hdmi_log("min_display_mastering_luminance: %d\n", -+ hdmi_log(" min display mastering luminance: %d\n", - frame->min_display_mastering_luminance); - -- hdmi_log("max_cll: %d\n", frame->max_cll); -- hdmi_log("max_fall: %d\n", frame->max_fall); -+ hdmi_log(" max cll: %d\n", frame->max_cll); -+ hdmi_log(" max fall: %d\n", frame->max_fall); - } - - static const char * --- -2.17.1 - - -From 3c3374a1fbf631037b9fa87a6ddbfdc921cdf16c Mon Sep 17 00:00:00 2001 -From: Jonas Karlman -Date: Tue, 26 Feb 2019 20:45:14 +0000 -Subject: [PATCH] WIP: dw-hdmi-cec: sleep 100ms on error - -Signed-off-by: Jonas Karlman ---- - drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c | 19 +++++++++++++++++-- - 1 file changed, 17 insertions(+), 2 deletions(-) - -diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c -index 70ab4fbdc23e..f6a85f73b90d 100644 ---- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c -+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c -@@ -4,6 +4,7 @@ - * - * Copyright (C) 2015-2017 Russell King. - */ -+#include - #include - #include - #include -@@ -129,8 +130,16 @@ static irqreturn_t dw_hdmi_cec_hardirq(int irq, void *data) - - dw_hdmi_write(cec, stat, HDMI_IH_CEC_STAT0); - -- if (stat & CEC_STAT_ERROR_INIT) { -- cec->tx_status = CEC_TX_STATUS_ERROR; -+ /* -+ * Status with both done and error_initiator bits have been seen -+ * on Rockchip RK3328 devices, transmit attempt seems to have failed -+ * when this happens, report as low drive and block cec-framework -+ * 100ms before core retransmits the failed message, this seems to -+ * mitigate the issue with failed transmit attempts. -+ */ -+ if ((stat & (CEC_STAT_DONE|CEC_STAT_ERROR_INIT)) == (CEC_STAT_DONE|CEC_STAT_ERROR_INIT)) { -+ pr_info("dw_hdmi_cec_hardirq: stat=%02x LOW_DRIVE\n", stat); -+ cec->tx_status = CEC_TX_STATUS_LOW_DRIVE; - cec->tx_done = true; - ret = IRQ_WAKE_THREAD; - } else if (stat & CEC_STAT_DONE) { -@@ -141,6 +150,10 @@ static irqreturn_t dw_hdmi_cec_hardirq(int irq, void *data) - cec->tx_status = CEC_TX_STATUS_NACK; - cec->tx_done = true; - ret = IRQ_WAKE_THREAD; -+ } else if (stat & CEC_STAT_ERROR_INIT) { -+ cec->tx_status = CEC_TX_STATUS_ERROR; -+ cec->tx_done = true; -+ ret = IRQ_WAKE_THREAD; - } - - if (stat & CEC_STAT_EOM) { -@@ -173,6 +186,8 @@ static irqreturn_t dw_hdmi_cec_thread(int irq, void *data) - - if (cec->tx_done) { - cec->tx_done = false; -+ if (cec->tx_status == CEC_TX_STATUS_LOW_DRIVE) -+ msleep(100); - cec_transmit_attempt_done(adap, cec->tx_status); - } - if (cec->rx_done) { --- -2.17.1 - - -From 8a6b932299c4cf68942cbe1809c4f6a846ef54a1 Mon Sep 17 00:00:00 2001 -From: Jonas Karlman -Date: Fri, 11 Oct 2019 08:01:37 +0000 -Subject: [PATCH] mmc: dw_mmc: add power_off callback - -Signed-off-by: Jonas Karlman ---- - drivers/mmc/host/dw_mmc.c | 3 +++ - drivers/mmc/host/dw_mmc.h | 1 + - 2 files changed, 4 insertions(+) - -diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c -index bc5278ab5707..f192963c2c68 100644 ---- a/drivers/mmc/host/dw_mmc.c -+++ b/drivers/mmc/host/dw_mmc.c -@@ -1495,6 +1495,9 @@ static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) - regulator_disable(mmc->supply.vqmmc); - slot->host->vqmmc_enabled = false; - -+ if (drv_data && drv_data->power_off) -+ drv_data->power_off(slot->host); -+ - regs = mci_readl(slot->host, PWREN); - regs &= ~(1 << slot->id); - mci_writel(slot->host, PWREN, regs); -diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h -index da5923a92e60..0b5c880364c5 100644 ---- a/drivers/mmc/host/dw_mmc.h -+++ b/drivers/mmc/host/dw_mmc.h -@@ -563,5 +563,6 @@ struct dw_mci_drv_data { - struct mmc_ios *ios); - int (*switch_voltage)(struct mmc_host *mmc, - struct mmc_ios *ios); -+ void (*power_off)(struct dw_mci *host); - }; - #endif /* _DW_MMC_H_ */ --- -2.17.1 - - -From bcde49e61ee5dc752e4af4b0195a1c91c550e299 Mon Sep 17 00:00:00 2001 -From: Jonas Karlman -Date: Fri, 11 Oct 2019 08:01:37 +0000 -Subject: [PATCH] mmc: dw_mmc-rockchip: try set vqmmc regulator to 3.3V on - power_off - -Signed-off-by: Jonas Karlman ---- - drivers/mmc/host/dw_mmc-rockchip.c | 27 +++++++++++++++++++++++++++ - 1 file changed, 27 insertions(+) - -diff --git a/drivers/mmc/host/dw_mmc-rockchip.c b/drivers/mmc/host/dw_mmc-rockchip.c -index d4d02134848c..05410f90ddd3 100644 ---- a/drivers/mmc/host/dw_mmc-rockchip.c -+++ b/drivers/mmc/host/dw_mmc-rockchip.c -@@ -24,6 +24,32 @@ struct dw_mci_rockchip_priv_data { - int num_phases; - }; - -+static void dw_mci_rk3288_power_off(struct dw_mci *host) -+{ -+ struct mmc_host *mmc = host->slot->mmc; -+ struct mmc_ios *ios = &mmc->ios; -+ int old_signal_voltage; -+ -+ if (IS_ERR(mmc->supply.vqmmc)) -+ return; -+ -+ if (mmc_host_is_spi(mmc)) -+ return; -+ -+ if (ios->vdd != 0 || ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330) -+ return; -+ -+ old_signal_voltage = ios->signal_voltage; -+ -+ ios->signal_voltage = MMC_SIGNAL_VOLTAGE_330; -+ ios->vdd = fls(mmc->ocr_avail) - 1; -+ -+ if (mmc_regulator_set_vqmmc(mmc, ios)) -+ ios->signal_voltage = old_signal_voltage; -+ -+ ios->vdd = 0; -+} -+ - static void dw_mci_rk3288_set_ios(struct dw_mci *host, struct mmc_ios *ios) - { - struct dw_mci_rockchip_priv_data *priv = host->priv; -@@ -319,6 +345,7 @@ static const struct dw_mci_drv_data rk3288_drv_data = { - .execute_tuning = dw_mci_rk3288_execute_tuning, - .parse_dt = dw_mci_rk3288_parse_dt, - .init = dw_mci_rockchip_init, -+ .power_off = dw_mci_rk3288_power_off, - }; - - static const struct of_device_id dw_mci_rockchip_match[] = { --- -2.17.1 - - -From 0cf5aae67b723a0e2e0d1d7041214920b5bf1e59 Mon Sep 17 00:00:00 2001 -From: Jonas Karlman -Date: Fri, 11 Oct 2019 08:01:37 +0000 -Subject: [PATCH] ARM: dts: rockchip: enable sd ultra-high speeds on - rk3288-tinker - -Signed-off-by: Jonas Karlman ---- - arch/arm/boot/dts/rk3288-tinker.dtsi | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/arch/arm/boot/dts/rk3288-tinker.dtsi b/arch/arm/boot/dts/rk3288-tinker.dtsi -index 312582c1bd37..67b32dc42220 100644 ---- a/arch/arm/boot/dts/rk3288-tinker.dtsi -+++ b/arch/arm/boot/dts/rk3288-tinker.dtsi -@@ -461,6 +461,7 @@ - disable-wp; /* wp not hooked up */ - pinctrl-names = "default"; - pinctrl-0 = <&sdmmc_clk &sdmmc_cmd &sdmmc_cd &sdmmc_bus4>; -+ sd-uhs-sdr104; - status = "okay"; - vmmc-supply = <&vcc33_sd>; - vqmmc-supply = <&vccio_sd>; --- -2.17.1 - - -From f74e8d61abd366cee71da7779109e5589b4c6c6e Mon Sep 17 00:00:00 2001 -From: Jonas Karlman -Date: Sun, 8 Dec 2019 13:49:45 +0000 -Subject: [PATCH] ARM: dts: rockchip: enable sd ultra-high speeds on - rk3288-miqi - -Signed-off-by: Jonas Karlman ---- - arch/arm/boot/dts/rk3288-miqi.dts | 5 +++-- - 1 file changed, 3 insertions(+), 2 deletions(-) - -diff --git a/arch/arm/boot/dts/rk3288-miqi.dts b/arch/arm/boot/dts/rk3288-miqi.dts -index c41d012c8850..820926e2feb1 100644 ---- a/arch/arm/boot/dts/rk3288-miqi.dts -+++ b/arch/arm/boot/dts/rk3288-miqi.dts -@@ -60,7 +60,7 @@ - - vcc_sd: sdmmc-regulator { - compatible = "regulator-fixed"; -- gpio = <&gpio7 RK_PB3 GPIO_ACTIVE_LOW>; -+ gpio = <&gpio7 RK_PB3 GPIO_ACTIVE_HIGH>; - pinctrl-names = "default"; - pinctrl-0 = <&sdmmc_pwr>; - regulator-name = "vcc_sd"; -@@ -197,7 +197,7 @@ - - vccio_sd: REG5 { - regulator-name = "vccio_sd"; -- regulator-min-microvolt = <3300000>; -+ regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <3300000>; - regulator-always-on; - }; -@@ -367,6 +367,7 @@ - disable-wp; - pinctrl-names = "default"; - pinctrl-0 = <&sdmmc_clk>, <&sdmmc_cmd>, <&sdmmc_cd>, <&sdmmc_bus4>; -+ sd-uhs-sdr104; - vmmc-supply = <&vcc_sd>; - vqmmc-supply = <&vccio_sd>; - status = "okay"; --- -2.17.1 - - -From f9ec6529193530bff8905ca5ffe36b884c93b12b Mon Sep 17 00:00:00 2001 -From: Jonas Karlman -Date: Fri, 11 Oct 2019 08:01:37 +0000 -Subject: [PATCH] arm64: dts: rockchip: enable sd ultra-high speeds on - rk3399-sapphire - -Signed-off-by: Jonas Karlman ---- - arch/arm64/boot/dts/rockchip/rk3399-sapphire.dtsi | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/arch/arm64/boot/dts/rockchip/rk3399-sapphire.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-sapphire.dtsi -index 1bc1579674e5..0885d48011ab 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3399-sapphire.dtsi -+++ b/arch/arm64/boot/dts/rockchip/rk3399-sapphire.dtsi -@@ -77,7 +77,7 @@ - gpio = <&gpio0 RK_PA1 GPIO_ACTIVE_HIGH>; - pinctrl-names = "default"; - pinctrl-0 = <&sdmmc0_pwr_h>; -- regulator-always-on; -+ regulator-boot-on; - regulator-max-microvolt = <3000000>; - regulator-min-microvolt = <3000000>; - regulator-name = "vcc3v0_sd"; -@@ -540,6 +540,7 @@ - max-frequency = <150000000>; - pinctrl-names = "default"; - pinctrl-0 = <&sdmmc_clk &sdmmc_cmd &sdmmc_cd &sdmmc_bus4>; -+ sd-uhs-sdr104; - vmmc-supply = <&vcc3v0_sd>; - vqmmc-supply = <&vcc_sdio>; - status = "okay"; --- -2.17.1 - - -From c73762d9ab7c852d7dc691b4d83a42b32ad09771 Mon Sep 17 00:00:00 2001 -From: Jonas Karlman -Date: Fri, 11 Oct 2019 08:01:37 +0000 -Subject: [PATCH] arm64: dts: rockchip: enable sd ultra-high speeds on - rk3399-rock-pi-4 - -Signed-off-by: Jonas Karlman ---- - arch/arm64/boot/dts/rockchip/rk3399-rock-pi-4.dts | 5 ++++- - 1 file changed, 4 insertions(+), 1 deletion(-) - -diff --git a/arch/arm64/boot/dts/rockchip/rk3399-rock-pi-4.dts b/arch/arm64/boot/dts/rockchip/rk3399-rock-pi-4.dts -index 3923ec01ef66..e4c71c77c3ef 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3399-rock-pi-4.dts -+++ b/arch/arm64/boot/dts/rockchip/rk3399-rock-pi-4.dts -@@ -307,7 +307,7 @@ - regulator-name = "vcc_sdio"; - regulator-always-on; - regulator-boot-on; -- regulator-min-microvolt = <3000000>; -+ regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <3000000>; - regulator-state-mem { - regulator-on-in-suspend; -@@ -609,6 +609,9 @@ - max-frequency = <150000000>; - pinctrl-names = "default"; - pinctrl-0 = <&sdmmc_clk &sdmmc_cd &sdmmc_cmd &sdmmc_bus4>; -+ sd-uhs-sdr104; -+ vmmc-supply = <&vcc3v3_sys>; -+ vqmmc-supply = <&vcc_sdio>; - status = "okay"; - }; - --- -2.17.1 - - -From c52ee775bd43bcecb26f464c28cdc9eb5bcc08b2 Mon Sep 17 00:00:00 2001 -From: Jonas Karlman -Date: Fri, 11 Oct 2019 08:01:38 +0000 -Subject: [PATCH] arm64: dts: rockchip: enable sd ultra-high speeds on - rk3399-rockpro64 - -Signed-off-by: Jonas Karlman ---- - .../boot/dts/rockchip/rk3399-rockpro64.dtsi | 22 +++++++++++++++++++ - 1 file changed, 22 insertions(+) - -diff --git a/arch/arm64/boot/dts/rockchip/rk3399-rockpro64.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-rockpro64.dtsi -index 9bca25801260..72c9bb2cfceb 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3399-rockpro64.dtsi -+++ b/arch/arm64/boot/dts/rockchip/rk3399-rockpro64.dtsi -@@ -108,6 +108,19 @@ - vin-supply = <&vcc12v_dcin>; - }; - -+ vcc3v0_sd: vcc3v0-sd { -+ compatible = "regulator-fixed"; -+ enable-active-high; -+ gpio = <&gpio0 RK_PA1 GPIO_ACTIVE_HIGH>; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&sdmmc0_pwr_h>; -+ regulator-boot-on; -+ regulator-max-microvolt = <3000000>; -+ regulator-min-microvolt = <3000000>; -+ regulator-name = "vcc3v0_sd"; -+ vin-supply = <&vcc3v3_sys>; -+ }; -+ - vcc3v3_sys: vcc3v3-sys { - compatible = "regulator-fixed"; - regulator-name = "vcc3v3_sys"; -@@ -603,6 +616,12 @@ - }; - }; - -+ sd { -+ sdmmc0_pwr_h: sdmmc0-pwr-h { -+ rockchip,pins = <0 RK_PA1 RK_FUNC_GPIO &pcfg_pull_none>; -+ }; -+ }; -+ - sdio-pwrseq { - wifi_enable_h: wifi-enable-h { - rockchip,pins = <0 RK_PB2 RK_FUNC_GPIO &pcfg_pull_none>; -@@ -661,6 +680,9 @@ - max-frequency = <150000000>; - pinctrl-names = "default"; - pinctrl-0 = <&sdmmc_clk &sdmmc_cmd &sdmmc_bus4>; -+ sd-uhs-sdr104; -+ vmmc-supply = <&vcc3v0_sd>; -+ vqmmc-supply = <&vcc_sdio>; - status = "okay"; - }; - --- -2.17.1 - - -From 5d729739be59fe9a3435f80f6b13945b0a50e3a1 Mon Sep 17 00:00:00 2001 -From: Jonas Karlman -Date: Sun, 8 Dec 2019 13:27:12 +0000 -Subject: [PATCH] ARM: dts: rockchip: fix sdmmc-regulator gpio warning on - rk3288-tinker - -Fixes sdmmc-regulator GPIO handle specifies active low - ignored - -Signed-off-by: Jonas Karlman ---- - arch/arm/boot/dts/rk3288-tinker.dtsi | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/arch/arm/boot/dts/rk3288-tinker.dtsi b/arch/arm/boot/dts/rk3288-tinker.dtsi -index 67b32dc42220..dc5b4d81a46c 100644 ---- a/arch/arm/boot/dts/rk3288-tinker.dtsi -+++ b/arch/arm/boot/dts/rk3288-tinker.dtsi -@@ -98,7 +98,7 @@ - - vcc_sd: sdmmc-regulator { - compatible = "regulator-fixed"; -- gpio = <&gpio7 11 GPIO_ACTIVE_LOW>; -+ gpio = <&gpio7 RK_PB3 GPIO_ACTIVE_HIGH>; - pinctrl-names = "default"; - pinctrl-0 = <&sdmmc_pwr>; - regulator-name = "vcc_sd"; --- -2.17.1 - - -From 896ce763b751403f9dcae8732335d53e5a6dcce9 Mon Sep 17 00:00:00 2001 -From: Jonas Karlman -Date: Thu, 7 Feb 2019 22:03:38 +0000 -Subject: [PATCH] ARM: dts: rockchip: rename hdmi sound card on rk3288-tinker - ---- - arch/arm/boot/dts/rk3288-tinker.dtsi | 3 +-- - 1 file changed, 1 insertion(+), 2 deletions(-) - -diff --git a/arch/arm/boot/dts/rk3288-tinker.dtsi b/arch/arm/boot/dts/rk3288-tinker.dtsi -index dc5b4d81a46c..49b64f4908cd 100644 ---- a/arch/arm/boot/dts/rk3288-tinker.dtsi -+++ b/arch/arm/boot/dts/rk3288-tinker.dtsi -@@ -75,7 +75,7 @@ - sound { - compatible = "simple-audio-card"; - simple-audio-card,format = "i2s"; -- simple-audio-card,name = "rockchip,tinker-codec"; -+ simple-audio-card,name = "HDMI"; - simple-audio-card,mclk-fs = <512>; - - simple-audio-card,codec { -@@ -352,7 +352,6 @@ - }; - - &i2s { -- #sound-dai-cells = <0>; - status = "okay"; - }; - --- -2.17.1 - - -From de9b4be54fd5ad12a33aa35aa46421b74411ee75 Mon Sep 17 00:00:00 2001 -From: Jonas Karlman -Date: Sun, 8 Dec 2019 13:49:19 +0000 -Subject: [PATCH] ARM: dts: rockchip: add hdmi sound node on rk3288-miqi - -Signed-off-by: Jonas Karlman ---- - arch/arm/boot/dts/rk3288-miqi.dts | 19 +++++++++++++++++++ - 1 file changed, 19 insertions(+) - -diff --git a/arch/arm/boot/dts/rk3288-miqi.dts b/arch/arm/boot/dts/rk3288-miqi.dts -index 820926e2feb1..0e17f66f142f 100644 ---- a/arch/arm/boot/dts/rk3288-miqi.dts -+++ b/arch/arm/boot/dts/rk3288-miqi.dts -@@ -37,6 +37,21 @@ - }; - }; - -+ sound { -+ compatible = "simple-audio-card"; -+ simple-audio-card,format = "i2s"; -+ simple-audio-card,name = "HDMI"; -+ simple-audio-card,mclk-fs = <512>; -+ -+ simple-audio-card,codec { -+ sound-dai = <&hdmi>; -+ }; -+ -+ simple-audio-card,cpu { -+ sound-dai = <&i2s>; -+ }; -+ }; -+ - vcc_flash: flash-regulator { - compatible = "regulator-fixed"; - regulator-name = "vcc_flash"; -@@ -267,6 +282,10 @@ - status = "okay"; - }; - -+&i2s { -+ status = "okay"; -+}; -+ - &io_domains { - status = "okay"; - --- -2.17.1 - - -From 882e6f0dcf1af01c4bfcf18b07c54894cc6b441e Mon Sep 17 00:00:00 2001 -From: Jonas Karlman -Date: Mon, 2 Dec 2019 22:35:51 +0000 -Subject: [PATCH] ARM: dts: rockchip: enable ARM Mali GPU on rk3288-miqi - -Signed-off-by: Jonas Karlman ---- - arch/arm/boot/dts/rk3288-miqi.dts | 5 +++++ - 1 file changed, 5 insertions(+) - -diff --git a/arch/arm/boot/dts/rk3288-miqi.dts b/arch/arm/boot/dts/rk3288-miqi.dts -index 0e17f66f142f..2bee891466f5 100644 ---- a/arch/arm/boot/dts/rk3288-miqi.dts -+++ b/arch/arm/boot/dts/rk3288-miqi.dts -@@ -126,6 +126,11 @@ - status = "ok"; - }; - -+&gpu { -+ mali-supply = <&vdd_gpu>; -+ status = "okay"; -+}; -+ - &hdmi { - ddc-i2c-bus = <&i2c5>; - status = "okay"; --- -2.17.1 - - -From 72c61d5558abf21a5bb3e9ac4603a99a2594a647 Mon Sep 17 00:00:00 2001 -From: Jonas Karlman -Date: Sat, 14 Dec 2019 01:43:17 +0000 -Subject: [PATCH] ARM: dts: rockchip: enable cec on rk3288-miqi - -Signed-off-by: Jonas Karlman ---- - arch/arm/boot/dts/rk3288-miqi.dts | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/arch/arm/boot/dts/rk3288-miqi.dts b/arch/arm/boot/dts/rk3288-miqi.dts -index 2bee891466f5..8428095934f5 100644 ---- a/arch/arm/boot/dts/rk3288-miqi.dts -+++ b/arch/arm/boot/dts/rk3288-miqi.dts -@@ -133,6 +133,8 @@ - - &hdmi { - ddc-i2c-bus = <&i2c5>; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&hdmi_cec_c0>; - status = "okay"; - }; - --- -2.17.1 - - -From d189fcfc6950f6a2f67662e3b024eff83b929322 Mon Sep 17 00:00:00 2001 -From: Jonas Karlman -Date: Sun, 10 Mar 2019 19:18:36 +0000 -Subject: [PATCH] arm64: dts: rockchip: remove dc_12v regulator on - rk3328-roc-cc - -Remove unnecessary dc_12v regulator node on ROC-RK3328-CC, -the device uses 5v micro-usb as power input. - -Signed-off-by: Jonas Karlman ---- - arch/arm64/boot/dts/rockchip/rk3328-roc-cc.dts | 10 ---------- - 1 file changed, 10 deletions(-) - -diff --git a/arch/arm64/boot/dts/rockchip/rk3328-roc-cc.dts b/arch/arm64/boot/dts/rockchip/rk3328-roc-cc.dts -index 8d553c92182a..c4d908bcc82c 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3328-roc-cc.dts -+++ b/arch/arm64/boot/dts/rockchip/rk3328-roc-cc.dts -@@ -21,15 +21,6 @@ - #clock-cells = <0>; - }; - -- dc_12v: dc-12v { -- compatible = "regulator-fixed"; -- regulator-name = "dc_12v"; -- regulator-always-on; -- regulator-boot-on; -- regulator-min-microvolt = <12000000>; -- regulator-max-microvolt = <12000000>; -- }; -- - vcc_sd: sdmmc-regulator { - compatible = "regulator-fixed"; - gpio = <&gpio0 RK_PD6 GPIO_ACTIVE_LOW>; -@@ -73,7 +64,6 @@ - regulator-boot-on; - regulator-min-microvolt = <5000000>; - regulator-max-microvolt = <5000000>; -- vin-supply = <&dc_12v>; - }; - - vcc_phy: vcc-phy-regulator { --- -2.17.1 - - -From f6da47eada3ffa241c3c37917827ffa278391991 Mon Sep 17 00:00:00 2001 -From: Jonas Karlman -Date: Sun, 10 Mar 2019 19:23:58 +0000 -Subject: [PATCH] arm64: dts: rockchip: add ir-receiver node on rk3328-roc-cc - -Add ir-receiver node to enable on-board IR on ROC-RK3328-CC. - -Signed-off-by: Jonas Karlman ---- - arch/arm64/boot/dts/rockchip/rk3328-roc-cc.dts | 13 +++++++++++++ - 1 file changed, 13 insertions(+) - -diff --git a/arch/arm64/boot/dts/rockchip/rk3328-roc-cc.dts b/arch/arm64/boot/dts/rockchip/rk3328-roc-cc.dts -index c4d908bcc82c..5a4aadffe9de 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3328-roc-cc.dts -+++ b/arch/arm64/boot/dts/rockchip/rk3328-roc-cc.dts -@@ -73,6 +73,13 @@ - regulator-boot-on; - }; - -+ ir-receiver { -+ compatible = "gpio-ir-receiver"; -+ gpios = <&gpio2 RK_PA2 GPIO_ACTIVE_LOW>; -+ pinctrl-0 = <&ir_int>; -+ pinctrl-names = "default"; -+ }; -+ - leds { - compatible = "gpio-leds"; - -@@ -273,6 +280,12 @@ - }; - - &pinctrl { -+ ir { -+ ir_int: ir-int { -+ rockchip,pins = <2 RK_PA2 RK_FUNC_GPIO &pcfg_pull_none>; -+ }; -+ }; -+ - pmic { - pmic_int_l: pmic-int-l { - rockchip,pins = <1 RK_PD0 RK_FUNC_GPIO &pcfg_pull_up>; --- -2.17.1 - - -From 5b7cc260ec063a6cd695ab0119d355b5a72c1a19 Mon Sep 17 00:00:00 2001 -From: Jonas Karlman -Date: Sun, 24 Mar 2019 11:20:51 +0000 -Subject: [PATCH] arm64: dts: rockchip: set tshut mode and priority on - rk3328-roc-cc - -Signed-off-by: Jonas Karlman ---- - arch/arm64/boot/dts/rockchip/rk3328-roc-cc.dts | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/arch/arm64/boot/dts/rockchip/rk3328-roc-cc.dts b/arch/arm64/boot/dts/rockchip/rk3328-roc-cc.dts -index 5a4aadffe9de..71f3cd206e13 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3328-roc-cc.dts -+++ b/arch/arm64/boot/dts/rockchip/rk3328-roc-cc.dts -@@ -317,6 +317,8 @@ - }; - - &tsadc { -+ rockchip,hw-tshut-mode = <0>; -+ rockchip,hw-tshut-polarity = <0>; - status = "okay"; - }; - --- -2.17.1 - - -From 456c5f7d3accc12acfc84cf6baddb5dcf05836aa Mon Sep 17 00:00:00 2001 -From: Jonas Karlman -Date: Sun, 24 Mar 2019 11:22:06 +0000 -Subject: [PATCH] arm64: dts: rockchip: rename vcc_sdio regulator on - rk3328-roc-cc - -Signed-off-by: Jonas Karlman ---- - arch/arm64/boot/dts/rockchip/rk3328-roc-cc.dts | 8 ++++---- - 1 file changed, 4 insertions(+), 4 deletions(-) - -diff --git a/arch/arm64/boot/dts/rockchip/rk3328-roc-cc.dts b/arch/arm64/boot/dts/rockchip/rk3328-roc-cc.dts -index 71f3cd206e13..95ff8f60e21f 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3328-roc-cc.dts -+++ b/arch/arm64/boot/dts/rockchip/rk3328-roc-cc.dts -@@ -33,12 +33,12 @@ - vin-supply = <&vcc_io>; - }; - -- vcc_sdio: sdmmcio-regulator { -+ vccio_sd: sdmmcio-regulator { - compatible = "regulator-gpio"; - gpios = <&grf_gpio 0 GPIO_ACTIVE_HIGH>; - states = <1800000 0x1 - 3300000 0x0>; -- regulator-name = "vcc_sdio"; -+ regulator-name = "vccio_sd"; - regulator-type = "voltage"; - regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <3300000>; -@@ -272,7 +272,7 @@ - - vccio1-supply = <&vcc_io>; - vccio2-supply = <&vcc18_emmc>; -- vccio3-supply = <&vcc_sdio>; -+ vccio3-supply = <&vccio_sd>; - vccio4-supply = <&vcc_18>; - vccio5-supply = <&vcc_io>; - vccio6-supply = <&vcc_io>; -@@ -312,7 +312,7 @@ - sd-uhs-sdr50; - sd-uhs-sdr104; - vmmc-supply = <&vcc_sd>; -- vqmmc-supply = <&vcc_sdio>; -+ vqmmc-supply = <&vccio_sd>; - status = "okay"; - }; - --- -2.17.1 - - -From e077bfec3ae60d827dd8c4a6c1f777e88f2c2a53 Mon Sep 17 00:00:00 2001 -From: Jonas Karlman -Date: Sun, 24 Mar 2019 17:18:39 +0000 -Subject: [PATCH] arm64: dts: rockchip: use recommended regulator limits on - rk3328-roc-cc - -Signed-off-by: Jonas Karlman ---- - arch/arm64/boot/dts/rockchip/rk3328-roc-cc.dts | 10 ++++++---- - 1 file changed, 6 insertions(+), 4 deletions(-) - -diff --git a/arch/arm64/boot/dts/rockchip/rk3328-roc-cc.dts b/arch/arm64/boot/dts/rockchip/rk3328-roc-cc.dts -index 95ff8f60e21f..35d1f89f844c 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3328-roc-cc.dts -+++ b/arch/arm64/boot/dts/rockchip/rk3328-roc-cc.dts -@@ -185,8 +185,9 @@ - regulators { - vdd_logic: DCDC_REG1 { - regulator-name = "vdd_logic"; -- regulator-min-microvolt = <712500>; -- regulator-max-microvolt = <1450000>; -+ regulator-min-microvolt = <900000>; -+ regulator-max-microvolt = <1150000>; -+ regulator-ramp-delay = <12500>; - regulator-always-on; - regulator-boot-on; - regulator-state-mem { -@@ -197,8 +198,9 @@ - - vdd_arm: DCDC_REG2 { - regulator-name = "vdd_arm"; -- regulator-min-microvolt = <712500>; -- regulator-max-microvolt = <1450000>; -+ regulator-min-microvolt = <950000>; -+ regulator-max-microvolt = <1350000>; -+ regulator-ramp-delay = <12500>; - regulator-always-on; - regulator-boot-on; - regulator-state-mem { --- -2.17.1 - - -From b66dcf8f337f9308ba232880f48a93d6594bbf5b Mon Sep 17 00:00:00 2001 -From: Jonas Karlman -Date: Sun, 21 Apr 2019 10:28:27 +0000 -Subject: [PATCH] arm64: dts: rockchip: use recommended regulator limits on - rk3328-rock64 - -Signed-off-by: Jonas Karlman ---- - arch/arm64/boot/dts/rockchip/rk3328-rock64.dts | 8 ++++---- - 1 file changed, 4 insertions(+), 4 deletions(-) - -diff --git a/arch/arm64/boot/dts/rockchip/rk3328-rock64.dts b/arch/arm64/boot/dts/rockchip/rk3328-rock64.dts -index 62936b432f9a..3725fcc7bb38 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3328-rock64.dts -+++ b/arch/arm64/boot/dts/rockchip/rk3328-rock64.dts -@@ -193,8 +193,8 @@ - regulators { - vdd_logic: DCDC_REG1 { - regulator-name = "vdd_logic"; -- regulator-min-microvolt = <712500>; -- regulator-max-microvolt = <1450000>; -+ regulator-min-microvolt = <900000>; -+ regulator-max-microvolt = <1150000>; - regulator-ramp-delay = <12500>; - regulator-always-on; - regulator-boot-on; -@@ -206,8 +206,8 @@ - - vdd_arm: DCDC_REG2 { - regulator-name = "vdd_arm"; -- regulator-min-microvolt = <712500>; -- regulator-max-microvolt = <1450000>; -+ regulator-min-microvolt = <950000>; -+ regulator-max-microvolt = <1350000>; - regulator-ramp-delay = <12500>; - regulator-always-on; - regulator-boot-on; --- -2.17.1 - - -From 52aeabe772f86828a7fd7b2d5f5ca4706214d09f Mon Sep 17 00:00:00 2001 -From: Jonas Karlman -Date: Sun, 24 Mar 2019 11:23:55 +0000 -Subject: [PATCH] arm64: dts: rockchip: fix vccio4-supply on rk3328-roc-cc - -Signed-off-by: Jonas Karlman ---- - arch/arm64/boot/dts/rockchip/rk3328-roc-cc.dts | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/arch/arm64/boot/dts/rockchip/rk3328-roc-cc.dts b/arch/arm64/boot/dts/rockchip/rk3328-roc-cc.dts -index 35d1f89f844c..dd18510fa473 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3328-roc-cc.dts -+++ b/arch/arm64/boot/dts/rockchip/rk3328-roc-cc.dts -@@ -275,7 +275,7 @@ - vccio1-supply = <&vcc_io>; - vccio2-supply = <&vcc18_emmc>; - vccio3-supply = <&vccio_sd>; -- vccio4-supply = <&vcc_18>; -+ vccio4-supply = <&vcc_io>; - vccio5-supply = <&vcc_io>; - vccio6-supply = <&vcc_io>; - pmuio-supply = <&vcc_io>; --- -2.17.1 - - -From 589b2803582c476ae058e4fe2157eaa332c15bbf Mon Sep 17 00:00:00 2001 -From: Jonas Karlman -Date: Sun, 21 Apr 2019 18:13:30 +0000 -Subject: [PATCH] arm64: dts: rockchip: fix vccio4-supply on rk3328-rock64 - ---- - arch/arm64/boot/dts/rockchip/rk3328-rock64.dts | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/arch/arm64/boot/dts/rockchip/rk3328-rock64.dts b/arch/arm64/boot/dts/rockchip/rk3328-rock64.dts -index 3725fcc7bb38..1af6c56a4451 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3328-rock64.dts -+++ b/arch/arm64/boot/dts/rockchip/rk3328-rock64.dts -@@ -295,7 +295,7 @@ - vccio1-supply = <&vcc_io>; - vccio2-supply = <&vcc18_emmc>; - vccio3-supply = <&vcc_io>; -- vccio4-supply = <&vcc_18>; -+ vccio4-supply = <&vcc_io>; - vccio5-supply = <&vcc_io>; - vccio6-supply = <&vcc_io>; - pmuio-supply = <&vcc_io>; --- -2.17.1 - - -From 23aa1a305bffe72c7fb26afac16c475569bef79a Mon Sep 17 00:00:00 2001 -From: Jonas Karlman -Date: Sun, 21 Apr 2019 18:07:33 +0000 -Subject: [PATCH] arm64: dts: rockchip: fix fixed-regulator gpio warning on - rk3328 - ---- - arch/arm64/boot/dts/rockchip/rk3328-roc-cc.dts | 2 +- - arch/arm64/boot/dts/rockchip/rk3328-rock64.dts | 6 +++--- - 2 files changed, 4 insertions(+), 4 deletions(-) - -diff --git a/arch/arm64/boot/dts/rockchip/rk3328-roc-cc.dts b/arch/arm64/boot/dts/rockchip/rk3328-roc-cc.dts -index dd18510fa473..48695a2dce7d 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3328-roc-cc.dts -+++ b/arch/arm64/boot/dts/rockchip/rk3328-roc-cc.dts -@@ -23,7 +23,7 @@ - - vcc_sd: sdmmc-regulator { - compatible = "regulator-fixed"; -- gpio = <&gpio0 RK_PD6 GPIO_ACTIVE_LOW>; -+ gpio = <&gpio0 RK_PD6 GPIO_ACTIVE_HIGH>; - pinctrl-names = "default"; - pinctrl-0 = <&sdmmc0m1_gpio>; - regulator-boot-on; -diff --git a/arch/arm64/boot/dts/rockchip/rk3328-rock64.dts b/arch/arm64/boot/dts/rockchip/rk3328-rock64.dts -index 1af6c56a4451..7cca8808257e 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3328-rock64.dts -+++ b/arch/arm64/boot/dts/rockchip/rk3328-rock64.dts -@@ -23,7 +23,7 @@ - - vcc_sd: sdmmc-regulator { - compatible = "regulator-fixed"; -- gpio = <&gpio0 RK_PD6 GPIO_ACTIVE_LOW>; -+ gpio = <&gpio0 RK_PD6 GPIO_ACTIVE_HIGH>; - pinctrl-names = "default"; - pinctrl-0 = <&sdmmc0m1_gpio>; - regulator-name = "vcc_sd"; -@@ -34,7 +34,7 @@ - - vcc_host_5v: vcc-host-5v-regulator { - compatible = "regulator-fixed"; -- gpio = <&gpio0 RK_PA2 GPIO_ACTIVE_LOW>; -+ gpio = <&gpio0 RK_PA2 GPIO_ACTIVE_HIGH>; - pinctrl-names = "default"; - pinctrl-0 = <&usb20_host_drv>; - regulator-name = "vcc_host_5v"; -@@ -45,7 +45,7 @@ - - vcc_host1_5v: vcc_otg_5v: vcc-host1-5v-regulator { - compatible = "regulator-fixed"; -- gpio = <&gpio0 RK_PA2 GPIO_ACTIVE_LOW>; -+ gpio = <&gpio0 RK_PA2 GPIO_ACTIVE_HIGH>; - pinctrl-names = "default"; - pinctrl-0 = <&usb20_host_drv>; - regulator-name = "vcc_host1_5v"; --- -2.17.1 - - -From b05c9d16191a716ba106abf6226410270ffa89a0 Mon Sep 17 00:00:00 2001 -From: Jonas Karlman -Date: Sun, 17 Mar 2019 22:38:09 +0000 -Subject: [PATCH] arm64: dts: rockchip: update gpu node on rk3328 - ---- - arch/arm64/boot/dts/rockchip/rk3328.dtsi | 7 +++++++ - 1 file changed, 7 insertions(+) - -diff --git a/arch/arm64/boot/dts/rockchip/rk3328.dtsi b/arch/arm64/boot/dts/rockchip/rk3328.dtsi -index 1f53ead52c7f..1b45131e8e48 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3328.dtsi -+++ b/arch/arm64/boot/dts/rockchip/rk3328.dtsi -@@ -319,6 +319,10 @@ - #address-cells = <1>; - #size-cells = <0>; - -+ pd_gpu@RK3328_PD_GPU { -+ reg = ; -+ clocks = <&cru ACLK_GPU>; -+ }; - pd_hevc@RK3328_PD_HEVC { - reg = ; - }; -@@ -621,6 +625,7 @@ - "ppmmu1"; - clocks = <&cru ACLK_GPU>, <&cru ACLK_GPU>; - clock-names = "bus", "core"; -+ power-domains = <&power RK3328_PD_GPU>; - resets = <&cru SRST_GPU_A>; - }; - -@@ -793,6 +798,7 @@ - <&cru ACLK_BUS_PRE>, <&cru HCLK_BUS_PRE>, - <&cru PCLK_BUS_PRE>, <&cru ACLK_PERI_PRE>, - <&cru HCLK_PERI>, <&cru PCLK_PERI>, -+ <&cru ACLK_GPU>, - <&cru SCLK_RTC32K>; - assigned-clock-parents = - <&cru HDMIPHY>, <&cru PLL_APLL>, -@@ -814,6 +820,7 @@ - <150000000>, <75000000>, - <75000000>, <150000000>, - <75000000>, <75000000>, -+ <500000000>, - <32768>; - }; - --- -2.17.1 - - -From c047d9759f3b5376259657dc0608a51252371219 Mon Sep 17 00:00:00 2001 -From: Jonas Karlman -Date: Sun, 8 Dec 2019 23:12:19 +0000 -Subject: [PATCH] arm64: dts: rockchip: add spdif audio pipeline on rk3328 - -Signed-off-by: Jonas Karlman ---- - arch/arm64/boot/dts/rockchip/rk3328.dtsi | 20 ++++++++++++++++++++ - 1 file changed, 20 insertions(+) - -diff --git a/arch/arm64/boot/dts/rockchip/rk3328.dtsi b/arch/arm64/boot/dts/rockchip/rk3328.dtsi -index 1b45131e8e48..c6f7cec13d15 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3328.dtsi -+++ b/arch/arm64/boot/dts/rockchip/rk3328.dtsi -@@ -210,6 +210,26 @@ - method = "smc"; - }; - -+ spdif_out: spdif-out { -+ compatible = "linux,spdif-dit"; -+ #sound-dai-cells = <0>; -+ status = "disabled"; -+ }; -+ -+ spdif_sound: spdif-sound { -+ compatible = "simple-audio-card"; -+ simple-audio-card,name = "SPDIF"; -+ status = "disabled"; -+ -+ simple-audio-card,cpu { -+ sound-dai = <&spdif>; -+ }; -+ -+ simple-audio-card,codec { -+ sound-dai = <&spdif_out>; -+ }; -+ }; -+ - timer { - compatible = "arm,armv8-timer"; - interrupts = , --- -2.17.1 - - -From 8d8e7349b476ae980239abfdb8c460ccd5e3df0a Mon Sep 17 00:00:00 2001 -From: Jonas Karlman -Date: Tue, 19 Mar 2019 22:18:47 +0000 -Subject: [PATCH] arm64: dts: rockchip: enable sound nodes on rk3328-roc-cc - ---- - .../arm64/boot/dts/rockchip/rk3328-roc-cc.dts | 33 +++++++++++++++++++ - 1 file changed, 33 insertions(+) - -diff --git a/arch/arm64/boot/dts/rockchip/rk3328-roc-cc.dts b/arch/arm64/boot/dts/rockchip/rk3328-roc-cc.dts -index 48695a2dce7d..a340a23cf073 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3328-roc-cc.dts -+++ b/arch/arm64/boot/dts/rockchip/rk3328-roc-cc.dts -@@ -101,6 +101,14 @@ - }; - }; - -+&analog_sound { -+ status = "okay"; -+}; -+ -+&codec { -+ status = "okay"; -+}; -+ - &cpu0 { - cpu-supply = <&vdd_arm>; - }; -@@ -158,6 +166,10 @@ - status = "okay"; - }; - -+&hdmi_sound { -+ status = "okay"; -+}; -+ - &i2c1 { - status = "okay"; - -@@ -269,6 +281,14 @@ - }; - }; - -+&i2s0 { -+ status = "okay"; -+}; -+ -+&i2s1 { -+ status = "okay"; -+}; -+ - &io_domains { - status = "okay"; - -@@ -318,6 +338,19 @@ - status = "okay"; - }; - -+&spdif { -+ pinctrl-0 = <&spdifm0_tx>; -+ status = "okay"; -+}; -+ -+&spdif_out { -+ status = "okay"; -+}; -+ -+&spdif_sound { -+ status = "okay"; -+}; -+ - &tsadc { - rockchip,hw-tshut-mode = <0>; - rockchip,hw-tshut-polarity = <0>; --- -2.17.1 - - -From b906dcd1489dd042dc67d9328952e18011fd6960 Mon Sep 17 00:00:00 2001 -From: Jonas Karlman -Date: Sun, 29 Dec 2019 22:13:22 +0000 -Subject: [PATCH] arm64: dts: rockchip: add mmc reset on rk3328 - ---- - arch/arm64/boot/dts/rockchip/rk3328.dtsi | 6 ++++++ - 1 file changed, 6 insertions(+) - -diff --git a/arch/arm64/boot/dts/rockchip/rk3328.dtsi b/arch/arm64/boot/dts/rockchip/rk3328.dtsi -index c6f7cec13d15..b92645187b19 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3328.dtsi -+++ b/arch/arm64/boot/dts/rockchip/rk3328.dtsi -@@ -890,6 +890,8 @@ - clock-names = "biu", "ciu", "ciu-drive", "ciu-sample"; - fifo-depth = <0x100>; - max-frequency = <150000000>; -+ resets = <&cru SRST_MMC0>; -+ reset-names = "reset"; - status = "disabled"; - }; - -@@ -902,6 +904,8 @@ - clock-names = "biu", "ciu", "ciu-drive", "ciu-sample"; - fifo-depth = <0x100>; - max-frequency = <150000000>; -+ resets = <&cru SRST_SDIO>; -+ reset-names = "reset"; - status = "disabled"; - }; - -@@ -914,6 +918,8 @@ - clock-names = "biu", "ciu", "ciu-drive", "ciu-sample"; - fifo-depth = <0x100>; - max-frequency = <150000000>; -+ resets = <&cru SRST_EMMC>; -+ reset-names = "reset"; - status = "disabled"; - }; - --- -2.17.1 - - -From 584300ab010fa3ab29f5f402d94274740d231e1c Mon Sep 17 00:00:00 2001 -From: Jonas Karlman -Date: Sun, 29 Dec 2019 22:14:02 +0000 -Subject: [PATCH] arm64: dts: rockchip: add sdmmc_ext node on rk3328 - ---- - arch/arm64/boot/dts/rockchip/rk3328.dtsi | 14 ++++++++++++++ - 1 file changed, 14 insertions(+) - -diff --git a/arch/arm64/boot/dts/rockchip/rk3328.dtsi b/arch/arm64/boot/dts/rockchip/rk3328.dtsi -index b92645187b19..cc44e17c8c43 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3328.dtsi -+++ b/arch/arm64/boot/dts/rockchip/rk3328.dtsi -@@ -1018,6 +1018,20 @@ - status = "disabled"; - }; - -+ sdmmc_ext: dwmmc@ff5f0000 { -+ compatible = "rockchip,rk3328-dw-mshc", "rockchip,rk3288-dw-mshc"; -+ reg = <0x0 0xff5f0000 0x0 0x4000>; -+ interrupts = ; -+ clocks = <&cru HCLK_SDMMC_EXT>, <&cru SCLK_SDMMC_EXT>, -+ <&cru SCLK_SDMMC_EXT_DRV>, <&cru SCLK_SDMMC_EXT_SAMPLE>; -+ clock-names = "biu", "ciu", "ciu-drive", "ciu-sample"; -+ fifo-depth = <0x100>; -+ max-frequency = <150000000>; -+ resets = <&cru SRST_SDMMCEXT>; -+ reset-names = "reset"; -+ status = "disabled"; -+ }; -+ - gic: interrupt-controller@ff811000 { - compatible = "arm,gic-400"; - #interrupt-cells = <3>; --- -2.17.1 - - -From af46e567772628417233844bb0994437f842d2a3 Mon Sep 17 00:00:00 2001 -From: Jonas Karlman -Date: Sun, 29 Dec 2019 22:14:36 +0000 -Subject: [PATCH] WIP: arm64: dts: rockchip: add rkvdec power domain on rk3328 - ---- - arch/arm64/boot/dts/rockchip/rk3328.dtsi | 5 +++++ - 1 file changed, 5 insertions(+) - -diff --git a/arch/arm64/boot/dts/rockchip/rk3328.dtsi b/arch/arm64/boot/dts/rockchip/rk3328.dtsi -index cc44e17c8c43..a4b0947f82a7 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3328.dtsi -+++ b/arch/arm64/boot/dts/rockchip/rk3328.dtsi -@@ -348,6 +348,10 @@ - }; - pd_video@RK3328_PD_VIDEO { - reg = ; -+ clocks = <&cru ACLK_RKVDEC>, -+ <&cru HCLK_RKVDEC>, -+ <&cru SCLK_VDEC_CABAC>, -+ <&cru SCLK_VDEC_CORE>; - }; - pd_vpu@RK3328_PD_VPU { - reg = ; -@@ -701,6 +705,7 @@ - clocks = <&cru ACLK_RKVDEC>, <&cru HCLK_RKVDEC>; - clock-names = "aclk", "iface"; - #iommu-cells = <0>; -+ power-domains = <&power RK3328_PD_VIDEO>; - status = "disabled"; - }; - --- -2.17.1 - - -From fe5ff9c9fcb07b629f57282a25eba796616fbb50 Mon Sep 17 00:00:00 2001 -From: Jonas Karlman -Date: Sun, 8 Dec 2019 23:23:41 +0000 -Subject: [PATCH] WIP: arm64: dts: rockchip: split sound cards on rk3328-rock64 - -Signed-off-by: Jonas Karlman ---- - .../arm64/boot/dts/rockchip/rk3328-rock64.dts | 54 +++++++------------ - 1 file changed, 18 insertions(+), 36 deletions(-) - -diff --git a/arch/arm64/boot/dts/rockchip/rk3328-rock64.dts b/arch/arm64/boot/dts/rockchip/rk3328-rock64.dts -index 7cca8808257e..e926616b4a0c 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3328-rock64.dts -+++ b/arch/arm64/boot/dts/rockchip/rk3328-rock64.dts -@@ -83,34 +83,14 @@ - linux,default-trigger = "heartbeat"; - }; - }; -+}; - -- sound { -- compatible = "audio-graph-card"; -- label = "rockchip,rk3328"; -- dais = <&i2s1_p0 -- &spdif_p0>; -- }; -- -- spdif-dit { -- compatible = "linux,spdif-dit"; -- #sound-dai-cells = <0>; -- -- port { -- dit_p0_0: endpoint { -- remote-endpoint = <&spdif_p0_0>; -- }; -- }; -- }; -+&analog_sound { -+ status = "okay"; - }; - - &codec { - status = "okay"; -- -- port@0 { -- codec_p0_0: endpoint { -- remote-endpoint = <&i2s1_p0_0>; -- }; -- }; - }; - - &cpu0 { -@@ -166,6 +146,10 @@ - status = "okay"; - }; - -+&hdmi_sound { -+ status = "okay"; -+}; -+ - &i2c1 { - status = "okay"; - -@@ -277,16 +261,12 @@ - }; - }; - --&i2s1 { -+&i2s0 { - status = "okay"; -+}; - -- i2s1_p0: port { -- i2s1_p0_0: endpoint { -- dai-format = "i2s"; -- mclk-fs = <256>; -- remote-endpoint = <&codec_p0_0>; -- }; -- }; -+&i2s1 { -+ status = "okay"; - }; - - &io_domains { -@@ -336,12 +316,14 @@ - &spdif { - pinctrl-0 = <&spdifm0_tx>; - status = "okay"; -+}; - -- spdif_p0: port { -- spdif_p0_0: endpoint { -- remote-endpoint = <&dit_p0_0>; -- }; -- }; -+&spdif_out { -+ status = "okay"; -+}; -+ -+&spdif_sound { -+ status = "okay"; - }; - - &spi0 { --- -2.17.1 - - -From 1c472df59bdd77b5f9dc651e4c25959cd53a2778 Mon Sep 17 00:00:00 2001 -From: Jonas Karlman -Date: Sun, 8 Dec 2019 23:26:37 +0000 -Subject: [PATCH] WIP: arm64: dts: rockchip: add mali-supply on rk3328-rock64 - and rk3328-roc-cc - -Signed-off-by: Jonas Karlman ---- - arch/arm64/boot/dts/rockchip/rk3328-roc-cc.dts | 4 ++++ - arch/arm64/boot/dts/rockchip/rk3328-rock64.dts | 4 ++++ - 2 files changed, 8 insertions(+) - -diff --git a/arch/arm64/boot/dts/rockchip/rk3328-roc-cc.dts b/arch/arm64/boot/dts/rockchip/rk3328-roc-cc.dts -index a340a23cf073..3e564ba682b6 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3328-roc-cc.dts -+++ b/arch/arm64/boot/dts/rockchip/rk3328-roc-cc.dts -@@ -158,6 +158,10 @@ - status = "okay"; - }; - -+&gpu { -+ mali-supply = <&vdd_logic>; -+}; -+ - &hdmi { - status = "okay"; - }; -diff --git a/arch/arm64/boot/dts/rockchip/rk3328-rock64.dts b/arch/arm64/boot/dts/rockchip/rk3328-rock64.dts -index e926616b4a0c..9023f311f89b 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3328-rock64.dts -+++ b/arch/arm64/boot/dts/rockchip/rk3328-rock64.dts -@@ -138,6 +138,10 @@ - status = "okay"; - }; - -+&gpu { -+ mali-supply = <&vdd_logic>; -+}; -+ - &hdmi { - status = "okay"; - }; --- -2.17.1 - - -From 2fae05a90a56a71c1ad749a96fac8eeb8beefaf0 Mon Sep 17 00:00:00 2001 -From: Jonas Karlman -Date: Mon, 30 Dec 2019 00:30:38 +0000 -Subject: [PATCH] WIP: arm64: dts: rockchip: misc updates on rk3328-rock64 and - rk3328-roc-cc - ---- - .../arm64/boot/dts/rockchip/rk3328-roc-cc.dts | 34 +++++----------- - .../arm64/boot/dts/rockchip/rk3328-rock64.dts | 39 +++++++------------ - 2 files changed, 22 insertions(+), 51 deletions(-) - -diff --git a/arch/arm64/boot/dts/rockchip/rk3328-roc-cc.dts b/arch/arm64/boot/dts/rockchip/rk3328-roc-cc.dts -index 3e564ba682b6..b58948f478a1 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3328-roc-cc.dts -+++ b/arch/arm64/boot/dts/rockchip/rk3328-roc-cc.dts -@@ -26,7 +26,6 @@ - gpio = <&gpio0 RK_PD6 GPIO_ACTIVE_HIGH>; - pinctrl-names = "default"; - pinctrl-0 = <&sdmmc0m1_gpio>; -- regulator-boot-on; - regulator-name = "vcc_sd"; - regulator-min-microvolt = <3300000>; - regulator-max-microvolt = <3300000>; -@@ -54,25 +53,17 @@ - pinctrl-0 = <&usb20_host_drv>; - regulator-name = "vcc_host1_5v"; - regulator-always-on; -+ regulator-boot-on; - vin-supply = <&vcc_sys>; - }; - - vcc_sys: vcc-sys { - compatible = "regulator-fixed"; - regulator-name = "vcc_sys"; -- regulator-always-on; -- regulator-boot-on; - regulator-min-microvolt = <5000000>; - regulator-max-microvolt = <5000000>; - }; - -- vcc_phy: vcc-phy-regulator { -- compatible = "regulator-fixed"; -- regulator-name = "vcc_phy"; -- regulator-always-on; -- regulator-boot-on; -- }; -- - ir-receiver { - compatible = "gpio-ir-receiver"; - gpios = <&gpio2 RK_PA2 GPIO_ACTIVE_LOW>; -@@ -128,7 +119,6 @@ - &emmc { - bus-width = <8>; - cap-mmc-highspeed; -- max-frequency = <150000000>; - mmc-ddr-1_8v; - mmc-hs200-1_8v; - non-removable; -@@ -143,16 +133,15 @@ - assigned-clocks = <&cru SCLK_MAC2IO>, <&cru SCLK_MAC2IO_EXT>; - assigned-clock-parents = <&gmac_clkin>, <&gmac_clkin>; - clock_in_out = "input"; -- phy-supply = <&vcc_phy>; - phy-mode = "rgmii"; -+ phy-supply = <&vcc_io>; - pinctrl-names = "default"; - pinctrl-0 = <&rgmiim1_pins>; - snps,aal; -+ snps,pbl = <0x4>; - snps,reset-gpio = <&gpio1 RK_PC2 GPIO_ACTIVE_LOW>; - snps,reset-active-low; - snps,reset-delays-us = <0 10000 50000>; -- snps,rxpbl = <0x4>; -- snps,txpbl = <0x4>; - tx_delay = <0x24>; - rx_delay = <0x18>; - status = "okay"; -@@ -294,8 +283,6 @@ - }; - - &io_domains { -- status = "okay"; -- - vccio1-supply = <&vcc_io>; - vccio2-supply = <&vcc18_emmc>; - vccio3-supply = <&vccio_sd>; -@@ -303,6 +290,7 @@ - vccio5-supply = <&vcc_io>; - vccio6-supply = <&vcc_io>; - pmuio-supply = <&vcc_io>; -+ status = "okay"; - }; - - &pinctrl { -@@ -330,13 +318,8 @@ - cap-mmc-highspeed; - cap-sd-highspeed; - disable-wp; -- max-frequency = <150000000>; - pinctrl-names = "default"; - pinctrl-0 = <&sdmmc0_clk &sdmmc0_cmd &sdmmc0_dectn &sdmmc0_bus4>; -- sd-uhs-sdr12; -- sd-uhs-sdr25; -- sd-uhs-sdr50; -- sd-uhs-sdr104; - vmmc-supply = <&vcc_sd>; - vqmmc-supply = <&vccio_sd>; - status = "okay"; -@@ -361,23 +344,24 @@ - status = "okay"; - }; - --&u2phy { -+&uart2 { - status = "okay"; - }; - --&u2phy_host { -+&u2phy { - status = "okay"; - }; - --&u2phy_otg { -+&u2phy_host { - status = "okay"; - }; - --&uart2 { -+&u2phy_otg { - status = "okay"; - }; - - &usb20_otg { -+ dr_mode = "host"; - status = "okay"; - }; - -diff --git a/arch/arm64/boot/dts/rockchip/rk3328-rock64.dts b/arch/arm64/boot/dts/rockchip/rk3328-rock64.dts -index 9023f311f89b..345c045c58e6 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3328-rock64.dts -+++ b/arch/arm64/boot/dts/rockchip/rk3328-rock64.dts -@@ -32,7 +32,7 @@ - vin-supply = <&vcc_io>; - }; - -- vcc_host_5v: vcc-host-5v-regulator { -+ vcc_host_5v: vcc_host1_5v: vcc_otg_5v: vcc-host-5v-regulator { - compatible = "regulator-fixed"; - gpio = <&gpio0 RK_PA2 GPIO_ACTIVE_HIGH>; - pinctrl-names = "default"; -@@ -43,22 +43,9 @@ - vin-supply = <&vcc_sys>; - }; - -- vcc_host1_5v: vcc_otg_5v: vcc-host1-5v-regulator { -- compatible = "regulator-fixed"; -- gpio = <&gpio0 RK_PA2 GPIO_ACTIVE_HIGH>; -- pinctrl-names = "default"; -- pinctrl-0 = <&usb20_host_drv>; -- regulator-name = "vcc_host1_5v"; -- regulator-always-on; -- regulator-boot-on; -- vin-supply = <&vcc_sys>; -- }; -- - vcc_sys: vcc-sys { - compatible = "regulator-fixed"; - regulator-name = "vcc_sys"; -- regulator-always-on; -- regulator-boot-on; - regulator-min-microvolt = <5000000>; - regulator-max-microvolt = <5000000>; - }; -@@ -112,6 +99,7 @@ - &emmc { - bus-width = <8>; - cap-mmc-highspeed; -+ mmc-ddr-1_8v; - mmc-hs200-1_8v; - non-removable; - pinctrl-names = "default"; -@@ -125,11 +113,12 @@ - assigned-clocks = <&cru SCLK_MAC2IO>, <&cru SCLK_MAC2IO_EXT>; - assigned-clock-parents = <&gmac_clkin>, <&gmac_clkin>; - clock_in_out = "input"; -- phy-supply = <&vcc_io>; - phy-mode = "rgmii"; -+ phy-supply = <&vcc_io>; - pinctrl-names = "default"; - pinctrl-0 = <&rgmiim1_pins>; -- snps,force_thresh_dma_mode; -+ snps,aal; -+ snps,pbl = <0x4>; - snps,reset-gpio = <&gpio1 RK_PC2 GPIO_ACTIVE_LOW>; - snps,reset-active-low; - snps,reset-delays-us = <0 10000 50000>; -@@ -176,7 +165,7 @@ - vcc3-supply = <&vcc_sys>; - vcc4-supply = <&vcc_sys>; - vcc5-supply = <&vcc_io>; -- vcc6-supply = <&vcc_sys>; -+ vcc6-supply = <&vcc_io>; - - regulators { - vdd_logic: DCDC_REG1 { -@@ -274,8 +263,6 @@ - }; - - &io_domains { -- status = "okay"; -- - vccio1-supply = <&vcc_io>; - vccio2-supply = <&vcc18_emmc>; - vccio3-supply = <&vcc_io>; -@@ -283,6 +270,7 @@ - vccio5-supply = <&vcc_io>; - vccio6-supply = <&vcc_io>; - pmuio-supply = <&vcc_io>; -+ status = "okay"; - }; - - &pinctrl { -@@ -310,7 +298,6 @@ - cap-mmc-highspeed; - cap-sd-highspeed; - disable-wp; -- max-frequency = <150000000>; - pinctrl-names = "default"; - pinctrl-0 = <&sdmmc0_clk &sdmmc0_cmd &sdmmc0_dectn &sdmmc0_bus4>; - vmmc-supply = <&vcc_sd>; -@@ -354,14 +341,14 @@ - - &u2phy { - status = "okay"; -+}; - -- u2phy_host: host-port { -- status = "okay"; -- }; -+&u2phy_host { -+ status = "okay"; -+}; - -- u2phy_otg: otg-port { -- status = "okay"; -- }; -+&u2phy_otg { -+ status = "okay"; - }; - - &usb20_otg { --- -2.17.1 - - -From 902ee56bf269bf4337eec25f0dc7d343bb9172b9 Mon Sep 17 00:00:00 2001 -From: Jonas Karlman -Date: Sun, 12 May 2019 12:40:00 +0000 -Subject: [PATCH] arm64: dts: rockchip: add rk3328-rockbox - ---- - arch/arm64/boot/dts/rockchip/Makefile | 1 + - .../boot/dts/rockchip/rk3328-rockbox.dts | 349 ++++++++++++++++++ - 2 files changed, 350 insertions(+) - create mode 100644 arch/arm64/boot/dts/rockchip/rk3328-rockbox.dts - -diff --git a/arch/arm64/boot/dts/rockchip/Makefile b/arch/arm64/boot/dts/rockchip/Makefile -index 60d9437096c7..1df8933cb084 100644 ---- a/arch/arm64/boot/dts/rockchip/Makefile -+++ b/arch/arm64/boot/dts/rockchip/Makefile -@@ -5,6 +5,7 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3308-roc-cc.dtb - dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3328-a1.dtb - dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3328-evb.dtb - dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3328-rock64.dtb -+dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3328-rockbox.dtb - dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3328-roc-cc.dtb - dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3368-evb-act8846.dtb - dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3368-geekbox.dtb -diff --git a/arch/arm64/boot/dts/rockchip/rk3328-rockbox.dts b/arch/arm64/boot/dts/rockchip/rk3328-rockbox.dts -new file mode 100644 -index 000000000000..b82708cfe742 ---- /dev/null -+++ b/arch/arm64/boot/dts/rockchip/rk3328-rockbox.dts -@@ -0,0 +1,349 @@ -+// SPDX-License-Identifier: (GPL-2.0+ OR MIT) -+/* -+ * Copyright (c) 2017 PINE64 -+ */ -+ -+/dts-v1/; -+#include "rk3328.dtsi" -+ -+/ { -+ model = "Popcorn Hour RockBox Basic"; -+ compatible = "popcornhour,rockbox", "rockchip,rk3328"; -+ -+ chosen { -+ stdout-path = "serial2:1500000n8"; -+ }; -+ -+ vcc_sd: sdmmc-regulator { -+ compatible = "regulator-fixed"; -+ gpio = <&gpio0 RK_PD6 GPIO_ACTIVE_HIGH>; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&sdmmc0m1_gpio>; -+ regulator-name = "vcc_sd"; -+ regulator-min-microvolt = <3300000>; -+ regulator-max-microvolt = <3300000>; -+ vin-supply = <&vcc_io>; -+ }; -+ -+ vcc_host_5v: vcc_host1_5v: vcc_otg_5v: vcc-host-5v-regulator { -+ compatible = "regulator-fixed"; -+ regulator-name = "vcc_host_5v"; -+ regulator-always-on; -+ regulator-boot-on; -+ vin-supply = <&vcc_sys>; -+ }; -+ -+ vcc_sys: vcc-sys { -+ compatible = "regulator-fixed"; -+ regulator-name = "vcc_sys"; -+ regulator-min-microvolt = <5000000>; -+ regulator-max-microvolt = <5000000>; -+ }; -+ -+ ir-receiver { -+ compatible = "gpio-ir-receiver"; -+ gpios = <&gpio2 RK_PA2 GPIO_ACTIVE_LOW>; -+ linux,rc-map-name = "rc-pine64"; -+ pinctrl-0 = <&ir_int>; -+ pinctrl-names = "default"; -+ }; -+ -+ leds { -+ compatible = "gpio-leds"; -+ -+ power { -+ gpios = <&rk805 0 GPIO_ACTIVE_HIGH>; -+ linux,default-trigger = "default-on"; -+ default-state = "on"; -+ }; -+ }; -+ -+ sdio_pwrseq: sdio-pwrseq { -+ compatible = "mmc-pwrseq-simple"; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&wifi_enable_h>; -+ reset-gpios = <&gpio1 RK_PC2 GPIO_ACTIVE_LOW>; -+ }; -+}; -+ -+&cpu0 { -+ cpu-supply = <&vdd_arm>; -+}; -+ -+&cpu1 { -+ cpu-supply = <&vdd_arm>; -+}; -+ -+&cpu2 { -+ cpu-supply = <&vdd_arm>; -+}; -+ -+&cpu3 { -+ cpu-supply = <&vdd_arm>; -+}; -+ -+&emmc { -+ bus-width = <8>; -+ cap-mmc-highspeed; -+ mmc-ddr-1_8v; -+ mmc-hs200-1_8v; -+ non-removable; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&emmc_clk &emmc_cmd &emmc_bus8>; -+ vmmc-supply = <&vcc_io>; -+ vqmmc-supply = <&vcc18_emmc>; -+ status = "okay"; -+}; -+ -+&gmac2phy { -+ assigned-clocks = <&cru SCLK_MAC2PHY_SRC>; -+ assigned-clock-rate = <50000000>; -+ assigned-clocks = <&cru SCLK_MAC2PHY>; -+ assigned-clock-parents = <&cru SCLK_MAC2PHY_SRC>; -+ clock_in_out = "output"; -+ phy-supply = <&vcc_io>; -+ status = "okay"; -+}; -+ -+&gpu { -+ mali-supply = <&vdd_logic>; -+}; -+ -+&hdmi { -+ status = "okay"; -+}; -+ -+&hdmiphy { -+ status = "okay"; -+}; -+ -+&hdmi_sound { -+ status = "okay"; -+}; -+ -+&i2c1 { -+ status = "okay"; -+ -+ rk805: rk805@18 { -+ compatible = "rockchip,rk805"; -+ reg = <0x18>; -+ interrupt-parent = <&gpio2>; -+ interrupts = <6 IRQ_TYPE_LEVEL_LOW>; -+ #clock-cells = <1>; -+ clock-output-names = "xin32k", "rk805-clkout2"; -+ gpio-controller; -+ #gpio-cells = <2>; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&pmic_int_l>; -+ rockchip,system-power-controller; -+ wakeup-source; -+ -+ vcc1-supply = <&vcc_sys>; -+ vcc2-supply = <&vcc_sys>; -+ vcc3-supply = <&vcc_sys>; -+ vcc4-supply = <&vcc_sys>; -+ vcc5-supply = <&vcc_io>; -+ vcc6-supply = <&vcc_io>; -+ -+ regulators { -+ vdd_logic: DCDC_REG1 { -+ regulator-name = "vdd_logic"; -+ regulator-min-microvolt = <900000>; -+ regulator-max-microvolt = <1150000>; -+ regulator-ramp-delay = <12500>; -+ regulator-always-on; -+ regulator-boot-on; -+ regulator-state-mem { -+ regulator-on-in-suspend; -+ regulator-suspend-microvolt = <1000000>; -+ }; -+ }; -+ -+ vdd_arm: DCDC_REG2 { -+ regulator-name = "vdd_arm"; -+ regulator-min-microvolt = <950000>; -+ regulator-max-microvolt = <1350000>; -+ regulator-ramp-delay = <12500>; -+ regulator-always-on; -+ regulator-boot-on; -+ regulator-state-mem { -+ regulator-on-in-suspend; -+ regulator-suspend-microvolt = <950000>; -+ }; -+ }; -+ -+ vcc_ddr: DCDC_REG3 { -+ regulator-name = "vcc_ddr"; -+ regulator-always-on; -+ regulator-boot-on; -+ regulator-state-mem { -+ regulator-on-in-suspend; -+ }; -+ }; -+ -+ vcc_io: DCDC_REG4 { -+ regulator-name = "vcc_io"; -+ regulator-min-microvolt = <3300000>; -+ regulator-max-microvolt = <3300000>; -+ regulator-always-on; -+ regulator-boot-on; -+ regulator-state-mem { -+ regulator-on-in-suspend; -+ regulator-suspend-microvolt = <3300000>; -+ }; -+ }; -+ -+ vcc_18: LDO_REG1 { -+ regulator-name = "vcc_18"; -+ regulator-min-microvolt = <1800000>; -+ regulator-max-microvolt = <1800000>; -+ regulator-always-on; -+ regulator-boot-on; -+ regulator-state-mem { -+ regulator-on-in-suspend; -+ regulator-suspend-microvolt = <1800000>; -+ }; -+ }; -+ -+ vcc18_emmc: LDO_REG2 { -+ regulator-name = "vcc18_emmc"; -+ regulator-min-microvolt = <1800000>; -+ regulator-max-microvolt = <1800000>; -+ regulator-always-on; -+ regulator-boot-on; -+ regulator-state-mem { -+ regulator-on-in-suspend; -+ regulator-suspend-microvolt = <1800000>; -+ }; -+ }; -+ -+ vdd_10: LDO_REG3 { -+ regulator-name = "vdd_10"; -+ regulator-min-microvolt = <1000000>; -+ regulator-max-microvolt = <1000000>; -+ regulator-always-on; -+ regulator-boot-on; -+ regulator-state-mem { -+ regulator-on-in-suspend; -+ regulator-suspend-microvolt = <1000000>; -+ }; -+ }; -+ }; -+ }; -+}; -+ -+&i2s0 { -+ status = "okay"; -+}; -+ -+&io_domains { -+ vccio1-supply = <&vcc_io>; -+ vccio2-supply = <&vcc18_emmc>; -+ vccio3-supply = <&vcc_io>; -+ vccio4-supply = <&vcc_io>; -+ vccio5-supply = <&vcc_io>; -+ vccio6-supply = <&vcc_io>; -+ pmuio-supply = <&vcc_io>; -+ status = "okay"; -+}; -+ -+&pinctrl { -+ ir { -+ ir_int: ir-int { -+ rockchip,pins = <2 RK_PA2 RK_FUNC_GPIO &pcfg_pull_none>; -+ }; -+ }; -+ -+ pmic { -+ pmic_int_l: pmic-int-l { -+ rockchip,pins = <2 RK_PA6 RK_FUNC_GPIO &pcfg_pull_up>; -+ }; -+ }; -+ -+ sdio-pwrseq { -+ wifi_enable_h: wifi-enable-h { -+ rockchip,pins = <1 RK_PC2 RK_FUNC_GPIO &pcfg_pull_none_4ma>, -+ <1 RK_PC3 RK_FUNC_GPIO &pcfg_pull_none_4ma>; -+ }; -+ }; -+}; -+ -+&sdio { -+ bus-width = <4>; -+ cap-sd-highspeed; -+ cap-sdio-irq; -+ keep-power-in-suspend; -+ mmc-pwrseq = <&sdio_pwrseq>; -+ non-removable; -+ num-slots = <1>; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&sdmmc1_bus4 &sdmmc1_cmd &sdmmc1_clk>; -+ status = "disabled"; -+}; -+ -+&sdmmc { -+ bus-width = <4>; -+ cap-mmc-highspeed; -+ cap-sd-highspeed; -+ disable-wp; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&sdmmc0_clk &sdmmc0_cmd &sdmmc0_dectn &sdmmc0_bus4>; -+ vmmc-supply = <&vcc_sd>; -+ status = "okay"; -+}; -+ -+&spdif { -+ pinctrl-0 = <&spdifm0_tx>; -+ status = "okay"; -+}; -+ -+&spdif_out { -+ status = "okay"; -+}; -+ -+&spdif_sound { -+ status = "okay"; -+}; -+ -+&tsadc { -+ rockchip,hw-tshut-mode = <0>; -+ rockchip,hw-tshut-polarity = <0>; -+ status = "okay"; -+}; -+ -+&uart2 { -+ status = "okay"; -+}; -+ -+&u2phy { -+ status = "okay"; -+}; -+ -+&u2phy_host { -+ status = "okay"; -+}; -+ -+&u2phy_otg { -+ status = "okay"; -+}; -+ -+&usb20_otg { -+ dr_mode = "host"; -+ status = "okay"; -+}; -+ -+&usb_host0_ehci { -+ status = "okay"; -+}; -+ -+&usb_host0_ohci { -+ status = "okay"; -+}; -+ -+&vop { -+ status = "okay"; -+}; -+ -+&vop_mmu { -+ status = "okay"; -+}; --- -2.17.1 - - -From 175d289ac91694f01eaf5914a7e124ec1de1f9ac Mon Sep 17 00:00:00 2001 -From: Jonas Karlman -Date: Sun, 8 Dec 2019 21:29:55 +0000 -Subject: [PATCH] arm64: dts: rockchip: enable hdmi sound on rk3399-firefly - ---- - arch/arm64/boot/dts/rockchip/rk3399-firefly.dts | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/arch/arm64/boot/dts/rockchip/rk3399-firefly.dts b/arch/arm64/boot/dts/rockchip/rk3399-firefly.dts -index d63faf38cc81..e9e2a6fb623b 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3399-firefly.dts -+++ b/arch/arm64/boot/dts/rockchip/rk3399-firefly.dts -@@ -263,6 +263,10 @@ - status = "okay"; - }; - -+&hdmi_sound { -+ status = "okay"; -+}; -+ - &i2c0 { - clock-frequency = <400000>; - i2c-scl-rising-time-ns = <168>; --- -2.17.1 - - -From f8982a639da0310faf15639a8a068e7534b97b57 Mon Sep 17 00:00:00 2001 -From: Jonas Karlman -Date: Sun, 14 Apr 2019 21:25:34 +0000 -Subject: [PATCH] arm64: dts: rockchip: enable hdmi sound on rk3399-orangepi - ---- - arch/arm64/boot/dts/rockchip/rk3399-orangepi.dts | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/arch/arm64/boot/dts/rockchip/rk3399-orangepi.dts b/arch/arm64/boot/dts/rockchip/rk3399-orangepi.dts -index 9c659f3115c8..bfb9fa11adcc 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3399-orangepi.dts -+++ b/arch/arm64/boot/dts/rockchip/rk3399-orangepi.dts -@@ -517,6 +517,10 @@ - }; - }; - -+&i2s2 { -+ status = "okay"; -+}; -+ - &io_domains { - status = "okay"; - bt656-supply = <&vcc_3v0>; --- -2.17.1 - diff --git a/patch/kernel/rk322x-current/01-linux-0005-for-libreelec.patch.disabled b/patch/kernel/rk322x-current/01-linux-0005-for-libreelec.patch.disabled deleted file mode 100644 index 22589ab70..000000000 --- a/patch/kernel/rk322x-current/01-linux-0005-for-libreelec.patch.disabled +++ /dev/null @@ -1,1651 +0,0 @@ -diff --git a/Documentation/devicetree/bindings/usb/rockchip,dwc3.txt b/Documentation/devicetree/bindings/usb/rockchip,dwc3.txt -index c8c4b00ecb94..4ca357835a48 100644 ---- a/Documentation/devicetree/bindings/usb/rockchip,dwc3.txt -+++ b/Documentation/devicetree/bindings/usb/rockchip,dwc3.txt -@@ -1,7 +1,9 @@ - Rockchip SuperSpeed DWC3 USB SoC controller - - Required properties: --- compatible: should contain "rockchip,rk3399-dwc3" for rk3399 SoC -+- compatible: should be one of the following: -+ - "rockchip,rk3399-dwc3": for rk3399 SoC -+ - "rockchip,rk3328-dwc3", "rockchip,rk3399-dwc3": for rk3328 SoC - - clocks: A list of phandle + clock-specifier pairs for the - clocks listed in clock-names - - clock-names: Should contain the following: --- -2.17.1 - - -From 041ddb731b5e025e1bea4d3d68c30f09521ca8dd Mon Sep 17 00:00:00 2001 -From: William Wu -Date: Mon, 4 Dec 2017 10:40:39 +0100 -Subject: [PATCH] arm64: dts: rockchip: add usb3 controller node for RK3328 - SoCs - -RK3328 has one USB 3.0 OTG controller which uses DWC_USB3 -core's general architecture. It can act as static xHCI host -controller, static device controller, USB 3.0/2.0 OTG basing -on ID of USB3.0 PHY. - -Signed-off-by: William Wu -Signed-off-by: Heiko Stuebner ---- - arch/arm64/boot/dts/rockchip/rk3328.dtsi | 32 ++++++++++++++++++++++++ - 1 file changed, 32 insertions(+) - -diff --git a/arch/arm64/boot/dts/rockchip/rk3328.dtsi b/arch/arm64/boot/dts/rockchip/rk3328.dtsi -index a4b0947f82a7..bc9186f66d9c 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3328.dtsi -+++ b/arch/arm64/boot/dts/rockchip/rk3328.dtsi -@@ -1037,6 +1037,38 @@ - status = "disabled"; - }; - -+ usbdrd3: usb@ff600000 { -+ compatible = "rockchip,rk3328-dwc3", "rockchip,rk3399-dwc3"; -+ clocks = <&cru SCLK_USB3OTG_REF>, <&cru SCLK_USB3OTG_SUSPEND>, -+ <&cru ACLK_USB3OTG>; -+ clock-names = "ref_clk", "suspend_clk", -+ "bus_clk"; -+ resets = <&cru SRST_USB3OTG>; -+ reset-names = "usb3-otg"; -+ #address-cells = <2>; -+ #size-cells = <2>; -+ ranges; -+ status = "disabled"; -+ -+ usbdrd_dwc3: dwc3@ff600000 { -+ compatible = "snps,dwc3"; -+ reg = <0x0 0xff600000 0x0 0x100000>; -+ interrupts = ; -+ clocks = <&cru SCLK_USB3OTG_REF>, <&cru ACLK_USB3OTG>, -+ <&cru SCLK_USB3OTG_SUSPEND>; -+ clock-names = "ref", "bus_early", "suspend"; -+ dr_mode = "otg"; -+ phy_type = "utmi_wide"; -+ snps,dis_enblslpm_quirk; -+ snps,dis-u2-freeclk-exists-quirk; -+ snps,dis_u2_susphy_quirk; -+ snps,dis_u3_susphy_quirk; -+ snps,dis-del-phy-power-chg-quirk; -+ snps,dis-tx-ipgap-linecheck-quirk; -+ status = "disabled"; -+ }; -+ }; -+ - gic: interrupt-controller@ff811000 { - compatible = "arm,gic-400"; - #interrupt-cells = <3>; --- -2.17.1 - - -From 6b2ec0b7974089cd179241595d76f204151a0329 Mon Sep 17 00:00:00 2001 -From: Heiko Stuebner -Date: Mon, 4 Dec 2017 10:40:41 +0100 -Subject: [PATCH] arm64: dts: rockchip: enable usb3 nodes on rk3328-rock64 - -Enable the nodes to make the usb3 port usable on that board. - -Signed-off-by: Heiko Stuebner ---- - arch/arm64/boot/dts/rockchip/rk3328-rock64.dts | 9 +++++++++ - 1 file changed, 9 insertions(+) - -diff --git a/arch/arm64/boot/dts/rockchip/rk3328-rock64.dts b/arch/arm64/boot/dts/rockchip/rk3328-rock64.dts -index 345c045c58e6..1cc3a8f5c3d7 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3328-rock64.dts -+++ b/arch/arm64/boot/dts/rockchip/rk3328-rock64.dts -@@ -364,6 +364,15 @@ - status = "okay"; - }; - -+&usbdrd3 { -+ status = "okay"; -+}; -+ -+&usbdrd_dwc3 { -+ dr_mode = "host"; -+ status = "okay"; -+}; -+ - &vop { - status = "okay"; - }; --- -2.17.1 - - -From 39e4f61930b2b6108ae6423698f233d6d2b57958 Mon Sep 17 00:00:00 2001 -From: Jonas Karlman -Date: Tue, 12 Mar 2019 19:42:03 +0000 -Subject: [PATCH] arm64: dts: rockchip: enable usb3 nodes on rk3328-roc-cc - -Enable the nodes to make the usb3 port usable on that board. - -Signed-off-by: Jonas Karlman ---- - arch/arm64/boot/dts/rockchip/rk3328-roc-cc.dts | 9 +++++++++ - 1 file changed, 9 insertions(+) - -diff --git a/arch/arm64/boot/dts/rockchip/rk3328-roc-cc.dts b/arch/arm64/boot/dts/rockchip/rk3328-roc-cc.dts -index b58948f478a1..78e0e23d1efb 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3328-roc-cc.dts -+++ b/arch/arm64/boot/dts/rockchip/rk3328-roc-cc.dts -@@ -373,6 +373,15 @@ - status = "okay"; - }; - -+&usbdrd3 { -+ status = "okay"; -+}; -+ -+&usbdrd_dwc3 { -+ dr_mode = "host"; -+ status = "okay"; -+}; -+ - &vop { - status = "okay"; - }; --- -2.17.1 - - -From aec6055775b63eaeb6b4a509b37aa6718fa2f84f Mon Sep 17 00:00:00 2001 -From: Jonas Karlman -Date: Sun, 12 May 2019 12:40:00 +0000 -Subject: [PATCH] arm64: dts: rockchip: enable usb3 nodes on rk3328-rockbox - ---- - arch/arm64/boot/dts/rockchip/rk3328-rockbox.dts | 9 +++++++++ - 1 file changed, 9 insertions(+) - -diff --git a/arch/arm64/boot/dts/rockchip/rk3328-rockbox.dts b/arch/arm64/boot/dts/rockchip/rk3328-rockbox.dts -index b82708cfe742..6f5eab7c0050 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3328-rockbox.dts -+++ b/arch/arm64/boot/dts/rockchip/rk3328-rockbox.dts -@@ -340,6 +340,15 @@ - status = "okay"; - }; - -+&usbdrd3 { -+ status = "okay"; -+}; -+ -+&usbdrd_dwc3 { -+ dr_mode = "host"; -+ status = "okay"; -+}; -+ - &vop { - status = "okay"; - }; --- -2.17.1 - - -From b1c19ab3e134c7ba1c0352b484fa5b3591f5af4d Mon Sep 17 00:00:00 2001 -From: Jonas Karlman -Date: Thu, 7 Feb 2019 22:03:15 +0000 -Subject: [PATCH] HACK: ARM: dts: rockchip: disable vopl node on rk3288 - ---- - arch/arm/boot/dts/rk3288-miqi.dts | 8 -------- - arch/arm/boot/dts/rk3288-tinker.dtsi | 8 -------- - 2 files changed, 16 deletions(-) - -diff --git a/arch/arm/boot/dts/rk3288-miqi.dts b/arch/arm/boot/dts/rk3288-miqi.dts -index 8428095934f5..8d8a4f49e4af 100644 ---- a/arch/arm/boot/dts/rk3288-miqi.dts -+++ b/arch/arm/boot/dts/rk3288-miqi.dts -@@ -438,14 +438,6 @@ - status = "okay"; - }; - --&vopl { -- status = "okay"; --}; -- --&vopl_mmu { -- status = "okay"; --}; -- - &wdt { - status = "okay"; - }; -diff --git a/arch/arm/boot/dts/rk3288-tinker.dtsi b/arch/arm/boot/dts/rk3288-tinker.dtsi -index 49b64f4908cd..5976c9a8eb0c 100644 ---- a/arch/arm/boot/dts/rk3288-tinker.dtsi -+++ b/arch/arm/boot/dts/rk3288-tinker.dtsi -@@ -534,14 +534,6 @@ - status = "okay"; - }; - --&vopl { -- status = "okay"; --}; -- --&vopl_mmu { -- status = "okay"; --}; -- - &wdt { - status = "okay"; - }; --- -2.17.1 - - -From b255ef1b90ebee3cfb44b545f75aa00e653411e8 Mon Sep 17 00:00:00 2001 -From: Jonas Karlman -Date: Mon, 15 Apr 2019 05:06:50 +0000 -Subject: [PATCH] HACK: arm64: dts: rockchip: disable vopl node on rk3399 - ---- - arch/arm64/boot/dts/rockchip/rk3399-firefly.dts | 8 -------- - arch/arm64/boot/dts/rockchip/rk3399-khadas-edge.dtsi | 8 -------- - arch/arm64/boot/dts/rockchip/rk3399-nanopi4.dtsi | 8 -------- - arch/arm64/boot/dts/rockchip/rk3399-orangepi.dts | 8 -------- - arch/arm64/boot/dts/rockchip/rk3399-roc-pc.dtsi | 8 -------- - arch/arm64/boot/dts/rockchip/rk3399-rock-pi-4.dts | 8 -------- - arch/arm64/boot/dts/rockchip/rk3399-rock960.dtsi | 8 -------- - arch/arm64/boot/dts/rockchip/rk3399-sapphire.dtsi | 8 -------- - 8 files changed, 64 deletions(-) - -diff --git a/arch/arm64/boot/dts/rockchip/rk3399-firefly.dts b/arch/arm64/boot/dts/rockchip/rk3399-firefly.dts -index e9e2a6fb623b..ee38f6da9368 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3399-firefly.dts -+++ b/arch/arm64/boot/dts/rockchip/rk3399-firefly.dts -@@ -801,11 +801,3 @@ - &vopb_mmu { - status = "okay"; - }; -- --&vopl { -- status = "okay"; --}; -- --&vopl_mmu { -- status = "okay"; --}; -diff --git a/arch/arm64/boot/dts/rockchip/rk3399-khadas-edge.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-khadas-edge.dtsi -index e87a04477440..f22f54dd0b73 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3399-khadas-edge.dtsi -+++ b/arch/arm64/boot/dts/rockchip/rk3399-khadas-edge.dtsi -@@ -797,11 +797,3 @@ - &vopb_mmu { - status = "okay"; - }; -- --&vopl { -- status = "okay"; --}; -- --&vopl_mmu { -- status = "okay"; --}; -diff --git a/arch/arm64/boot/dts/rockchip/rk3399-nanopi4.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-nanopi4.dtsi -index c88018a0ef35..002ed18477e6 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3399-nanopi4.dtsi -+++ b/arch/arm64/boot/dts/rockchip/rk3399-nanopi4.dtsi -@@ -747,11 +747,3 @@ - &vopb_mmu { - status = "okay"; - }; -- --&vopl { -- status = "okay"; --}; -- --&vopl_mmu { -- status = "okay"; --}; -diff --git a/arch/arm64/boot/dts/rockchip/rk3399-orangepi.dts b/arch/arm64/boot/dts/rockchip/rk3399-orangepi.dts -index bfb9fa11adcc..aa7f5e89ad72 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3399-orangepi.dts -+++ b/arch/arm64/boot/dts/rockchip/rk3399-orangepi.dts -@@ -787,11 +787,3 @@ - &vopb_mmu { - status = "okay"; - }; -- --&vopl { -- status = "okay"; --}; -- --&vopl_mmu { -- status = "okay"; --}; -diff --git a/arch/arm64/boot/dts/rockchip/rk3399-roc-pc.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-roc-pc.dtsi -index 9f225e9c3d54..e917060f34c7 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3399-roc-pc.dtsi -+++ b/arch/arm64/boot/dts/rockchip/rk3399-roc-pc.dtsi -@@ -804,11 +804,3 @@ - &vopb_mmu { - status = "okay"; - }; -- --&vopl { -- status = "okay"; --}; -- --&vopl_mmu { -- status = "okay"; --}; -diff --git a/arch/arm64/boot/dts/rockchip/rk3399-rock-pi-4.dts b/arch/arm64/boot/dts/rockchip/rk3399-rock-pi-4.dts -index e4c71c77c3ef..4fdbc692b138 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3399-rock-pi-4.dts -+++ b/arch/arm64/boot/dts/rockchip/rk3399-rock-pi-4.dts -@@ -728,11 +728,3 @@ - &vopb_mmu { - status = "okay"; - }; -- --&vopl { -- status = "okay"; --}; -- --&vopl_mmu { -- status = "okay"; --}; -diff --git a/arch/arm64/boot/dts/rockchip/rk3399-rock960.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-rock960.dtsi -index b69f0f2cbd67..aab612855670 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3399-rock960.dtsi -+++ b/arch/arm64/boot/dts/rockchip/rk3399-rock960.dtsi -@@ -654,11 +654,3 @@ - &vopb_mmu { - status = "okay"; - }; -- --&vopl { -- status = "okay"; --}; -- --&vopl_mmu { -- status = "okay"; --}; -diff --git a/arch/arm64/boot/dts/rockchip/rk3399-sapphire.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-sapphire.dtsi -index 0885d48011ab..471161b1accf 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3399-sapphire.dtsi -+++ b/arch/arm64/boot/dts/rockchip/rk3399-sapphire.dtsi -@@ -639,11 +639,3 @@ - &vopb_mmu { - status = "okay"; - }; -- --&vopl { -- status = "okay"; --}; -- --&vopl_mmu { -- status = "okay"; --}; --- -2.17.1 - - -From 915a6f4cd5cb34c183e26f1c0889f93e55fa9de9 Mon Sep 17 00:00:00 2001 -From: Jonas Karlman -Date: Sun, 14 Apr 2019 21:16:31 +0000 -Subject: [PATCH] HACK: arm64: dts: rockchip: rename hdmi sound card on rk3399 - ---- - arch/arm64/boot/dts/rockchip/rk3399.dtsi | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/arch/arm64/boot/dts/rockchip/rk3399.dtsi b/arch/arm64/boot/dts/rockchip/rk3399.dtsi -index 33cc21fcf4c1..adc8c1058196 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3399.dtsi -+++ b/arch/arm64/boot/dts/rockchip/rk3399.dtsi -@@ -1735,7 +1735,7 @@ - compatible = "simple-audio-card"; - simple-audio-card,format = "i2s"; - simple-audio-card,mclk-fs = <256>; -- simple-audio-card,name = "hdmi-sound"; -+ simple-audio-card,name = "HDMI"; - status = "disabled"; - - simple-audio-card,cpu { --- -2.17.1 - - -From 259475f3ec472d65fe037e5c6c4d217062e4a55c Mon Sep 17 00:00:00 2001 -From: Jonas Karlman -Date: Sun, 12 May 2019 12:40:00 +0000 -Subject: [PATCH] WIP: arm64: dts: rockchip: add rk3328-box devices - ---- - arch/arm64/boot/dts/rockchip/Makefile | 3 + - .../boot/dts/rockchip/rk3328-box-trn9.dts | 420 ++++++++++++++++++ - .../boot/dts/rockchip/rk3328-box-z28.dts | 367 +++++++++++++++ - arch/arm64/boot/dts/rockchip/rk3328-box.dts | 400 +++++++++++++++++ - 4 files changed, 1190 insertions(+) - create mode 100644 arch/arm64/boot/dts/rockchip/rk3328-box-trn9.dts - create mode 100644 arch/arm64/boot/dts/rockchip/rk3328-box-z28.dts - create mode 100644 arch/arm64/boot/dts/rockchip/rk3328-box.dts - -diff --git a/arch/arm64/boot/dts/rockchip/Makefile b/arch/arm64/boot/dts/rockchip/Makefile -index 1df8933cb084..9ff568832af7 100644 ---- a/arch/arm64/boot/dts/rockchip/Makefile -+++ b/arch/arm64/boot/dts/rockchip/Makefile -@@ -3,6 +3,9 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += px30-evb.dtb - dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3308-evb.dtb - dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3308-roc-cc.dtb - dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3328-a1.dtb -+dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3328-box.dtb -+dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3328-box-trn9.dtb -+dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3328-box-z28.dtb - dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3328-evb.dtb - dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3328-rock64.dtb - dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3328-rockbox.dtb -diff --git a/arch/arm64/boot/dts/rockchip/rk3328-box-trn9.dts b/arch/arm64/boot/dts/rockchip/rk3328-box-trn9.dts -new file mode 100644 -index 000000000000..e611d12ea375 ---- /dev/null -+++ b/arch/arm64/boot/dts/rockchip/rk3328-box-trn9.dts -@@ -0,0 +1,420 @@ -+// SPDX-License-Identifier: (GPL-2.0+ OR MIT) -+/* -+ * Copyright (c) 2017 PINE64 -+ */ -+ -+/dts-v1/; -+#include "rk3328.dtsi" -+ -+/ { -+ model = "Rockchip RK3328 TRN9"; -+ compatible = "rockchip,rk3328-box-trn9", "rockchip,rk3328"; -+ -+ gmac_clkin: external-gmac-clock { -+ compatible = "fixed-clock"; -+ clock-frequency = <125000000>; -+ clock-output-names = "gmac_clkin"; -+ #clock-cells = <0>; -+ }; -+ -+ vcc_sd: sdmmc-regulator { -+ compatible = "regulator-fixed"; -+ gpio = <&gpio0 RK_PD6 GPIO_ACTIVE_HIGH>; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&sdmmc0m1_gpio>; -+ regulator-name = "vcc_sd"; -+ regulator-min-microvolt = <3300000>; -+ regulator-max-microvolt = <3300000>; -+ vin-supply = <&vcc_io>; -+ }; -+ -+ vcc_host_5v: vcc-host-5v-regulator { -+ compatible = "regulator-fixed"; -+ enable-active-high; -+ gpio = <&gpio0 RK_PA0 GPIO_ACTIVE_HIGH>; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&usb30_host_drv>; -+ regulator-name = "vcc_host_5v"; -+ regulator-always-on; -+ regulator-boot-on; -+ vin-supply = <&vcc_sys>; -+ }; -+ -+ vcc_host1_5v: vcc_otg_5v: vcc-host1-5v-regulator { -+ compatible = "regulator-fixed"; -+ enable-active-high; -+ gpio = <&gpio0 RK_PA2 GPIO_ACTIVE_HIGH>; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&usb20_host_drv>; -+ regulator-name = "vcc_host1_5v"; -+ regulator-always-on; -+ regulator-boot-on; -+ vin-supply = <&vcc_sys>; -+ }; -+ -+ vcc_sys: vcc-sys { -+ compatible = "regulator-fixed"; -+ regulator-name = "vcc_sys"; -+ regulator-min-microvolt = <5000000>; -+ regulator-max-microvolt = <5000000>; -+ }; -+ -+ ir-receiver { -+ compatible = "gpio-ir-receiver"; -+ gpios = <&gpio2 RK_PA2 GPIO_ACTIVE_LOW>; -+ pinctrl-0 = <&ir_int>; -+ pinctrl-names = "default"; -+ }; -+ -+ leds { -+ compatible = "gpio-leds"; -+ -+ power { -+ gpios = <&rk805 0 GPIO_ACTIVE_LOW>; -+ linux,default-trigger = "default-on"; -+ default-state = "on"; -+ }; -+ }; -+ -+ sdio_pwrseq: sdio-pwrseq { -+ compatible = "mmc-pwrseq-simple"; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&wifi_enable_h>; -+ reset-gpios = <&gpio3 RK_PB0 GPIO_ACTIVE_LOW>; -+ }; -+}; -+ -+&analog_sound { -+ status = "okay"; -+}; -+ -+&codec { -+ status = "okay"; -+}; -+ -+&cpu0 { -+ cpu-supply = <&vdd_arm>; -+}; -+ -+&cpu1 { -+ cpu-supply = <&vdd_arm>; -+}; -+ -+&cpu2 { -+ cpu-supply = <&vdd_arm>; -+}; -+ -+&cpu3 { -+ cpu-supply = <&vdd_arm>; -+}; -+ -+&emmc { -+ bus-width = <8>; -+ cap-mmc-highspeed; -+ mmc-ddr-1_8v; -+ mmc-hs200-1_8v; -+ non-removable; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&emmc_clk &emmc_cmd &emmc_bus8>; -+ vmmc-supply = <&vcc_io>; -+ vqmmc-supply = <&vcc18_emmc>; -+ status = "okay"; -+}; -+ -+&gmac2io { -+ assigned-clocks = <&cru SCLK_MAC2IO>, <&cru SCLK_MAC2IO_EXT>; -+ assigned-clock-parents = <&gmac_clkin>, <&gmac_clkin>; -+ clock_in_out = "input"; -+ phy-mode = "rgmii"; -+ phy-supply = <&vcc_io>; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&rgmiim1_pins>; -+ snps,aal; -+ snps,pbl = <0x4>; -+ snps,reset-gpio = <&gpio2 RK_PC1 GPIO_ACTIVE_LOW>; -+ snps,reset-active-low; -+ snps,reset-delays-us = <0 10000 50000>; -+ tx_delay = <0x26>; -+ rx_delay = <0x11>; -+ status = "okay"; -+}; -+ -+&gpu { -+ mali-supply = <&vdd_logic>; -+}; -+ -+&hdmi { -+ status = "okay"; -+}; -+ -+&hdmiphy { -+ status = "okay"; -+}; -+ -+&hdmi_sound { -+ status = "okay"; -+}; -+ -+&i2c1 { -+ status = "okay"; -+ -+ rk805: rk805@18 { -+ compatible = "rockchip,rk805"; -+ reg = <0x18>; -+ interrupt-parent = <&gpio2>; -+ interrupts = <6 IRQ_TYPE_LEVEL_LOW>; -+ #clock-cells = <1>; -+ clock-output-names = "xin32k", "rk805-clkout2"; -+ gpio-controller; -+ #gpio-cells = <2>; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&pmic_int_l>; -+ rockchip,system-power-controller; -+ wakeup-source; -+ -+ vcc1-supply = <&vcc_sys>; -+ vcc2-supply = <&vcc_sys>; -+ vcc3-supply = <&vcc_sys>; -+ vcc4-supply = <&vcc_sys>; -+ vcc5-supply = <&vcc_io>; -+ vcc6-supply = <&vcc_io>; -+ -+ regulators { -+ vdd_logic: DCDC_REG1 { -+ regulator-name = "vdd_logic"; -+ regulator-min-microvolt = <900000>; -+ regulator-max-microvolt = <1150000>; -+ regulator-ramp-delay = <12500>; -+ regulator-always-on; -+ regulator-boot-on; -+ regulator-state-mem { -+ regulator-on-in-suspend; -+ regulator-suspend-microvolt = <1000000>; -+ }; -+ }; -+ -+ vdd_arm: DCDC_REG2 { -+ regulator-name = "vdd_arm"; -+ regulator-min-microvolt = <950000>; -+ regulator-max-microvolt = <1350000>; -+ regulator-ramp-delay = <12500>; -+ regulator-always-on; -+ regulator-boot-on; -+ regulator-state-mem { -+ regulator-on-in-suspend; -+ regulator-suspend-microvolt = <950000>; -+ }; -+ }; -+ -+ vcc_ddr: DCDC_REG3 { -+ regulator-name = "vcc_ddr"; -+ regulator-always-on; -+ regulator-boot-on; -+ regulator-state-mem { -+ regulator-on-in-suspend; -+ }; -+ }; -+ -+ vcc_io: DCDC_REG4 { -+ regulator-name = "vcc_io"; -+ regulator-min-microvolt = <3300000>; -+ regulator-max-microvolt = <3300000>; -+ regulator-always-on; -+ regulator-boot-on; -+ regulator-state-mem { -+ regulator-on-in-suspend; -+ regulator-suspend-microvolt = <3300000>; -+ }; -+ }; -+ -+ vcc_18: LDO_REG1 { -+ regulator-name = "vcc_18"; -+ regulator-min-microvolt = <1800000>; -+ regulator-max-microvolt = <1800000>; -+ regulator-always-on; -+ regulator-boot-on; -+ regulator-state-mem { -+ regulator-on-in-suspend; -+ regulator-suspend-microvolt = <1800000>; -+ }; -+ }; -+ -+ vcc18_emmc: LDO_REG2 { -+ regulator-name = "vcc18_emmc"; -+ regulator-min-microvolt = <1800000>; -+ regulator-max-microvolt = <1800000>; -+ regulator-always-on; -+ regulator-boot-on; -+ regulator-state-mem { -+ regulator-on-in-suspend; -+ regulator-suspend-microvolt = <1800000>; -+ }; -+ }; -+ -+ vdd_10: LDO_REG3 { -+ regulator-name = "vdd_10"; -+ regulator-min-microvolt = <1000000>; -+ regulator-max-microvolt = <1000000>; -+ regulator-always-on; -+ regulator-boot-on; -+ regulator-state-mem { -+ regulator-on-in-suspend; -+ regulator-suspend-microvolt = <1000000>; -+ }; -+ }; -+ }; -+ }; -+}; -+ -+&i2s0 { -+ status = "okay"; -+}; -+ -+&i2s1 { -+ status = "okay"; -+}; -+ -+&io_domains { -+ vccio1-supply = <&vcc_io>; -+ vccio2-supply = <&vcc18_emmc>; -+ vccio3-supply = <&vcc_io>; -+ vccio4-supply = <&vcc_18>; -+ vccio5-supply = <&vcc_io>; -+ vccio6-supply = <&vcc_18>; -+ pmuio-supply = <&vcc_io>; -+ status = "okay"; -+}; -+ -+&pinctrl { -+ pinctrl-names = "default"; -+ pinctrl-0 = <&clk_32k_out>; -+ -+ clk_32k { -+ clk_32k_out: clk-32k-out { -+ rockchip,pins = <1 RK_PD4 RK_FUNC_1 &pcfg_pull_none>; -+ }; -+ }; -+ -+ ir { -+ ir_int: ir-int { -+ rockchip,pins = <2 RK_PA2 RK_FUNC_GPIO &pcfg_pull_none>; -+ }; -+ }; -+ -+ pmic { -+ pmic_int_l: pmic-int-l { -+ rockchip,pins = <2 RK_PA6 RK_FUNC_GPIO &pcfg_pull_up>; -+ }; -+ }; -+ -+ sdio-pwrseq { -+ wifi_enable_h: wifi-enable-h { -+ rockchip,pins = <3 RK_PB0 RK_FUNC_GPIO &pcfg_pull_none>, -+ <3 RK_PA1 RK_FUNC_GPIO &pcfg_pull_none_4ma>, -+ <1 RK_PD0 RK_FUNC_GPIO &pcfg_pull_none>, -+ <1 RK_PD2 RK_FUNC_GPIO &pcfg_pull_none>; -+ }; -+ }; -+ -+ usb2 { -+ usb20_host_drv: usb20-host-drv { -+ rockchip,pins = <0 RK_PA2 RK_FUNC_GPIO &pcfg_pull_none>; -+ }; -+ }; -+ -+ usb3 { -+ usb30_host_drv: usb30-host-drv { -+ rockchip,pins = <0 RK_PA0 RK_FUNC_GPIO &pcfg_pull_none>; -+ }; -+ }; -+}; -+ -+&sdmmc_ext { -+ bus-width = <4>; -+ cap-sd-highspeed; -+ cap-sdio-irq; -+ keep-power-in-suspend; -+ mmc-pwrseq = <&sdio_pwrseq>; -+ non-removable; -+ num-slots = <1>; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&sdmmc0ext_bus4 &sdmmc0ext_cmd &sdmmc0ext_clk>; -+ sd-uhs-sdr104; -+ status = "okay"; -+}; -+ -+&sdmmc { -+ bus-width = <4>; -+ cap-mmc-highspeed; -+ cap-sd-highspeed; -+ disable-wp; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&sdmmc0_clk &sdmmc0_cmd &sdmmc0_dectn &sdmmc0_bus4>; -+ vmmc-supply = <&vcc_sd>; -+ status = "okay"; -+}; -+ -+&spdif { -+ pinctrl-0 = <&spdifm0_tx>; -+ status = "okay"; -+}; -+ -+&spdif_out { -+ status = "okay"; -+}; -+ -+&spdif_sound { -+ status = "okay"; -+}; -+ -+&tsadc { -+ rockchip,hw-tshut-mode = <0>; -+ rockchip,hw-tshut-polarity = <0>; -+ status = "okay"; -+}; -+ -+&uart2 { -+ status = "okay"; -+}; -+ -+&u2phy { -+ status = "okay"; -+}; -+ -+&u2phy_host { -+ status = "okay"; -+}; -+ -+&u2phy_otg { -+ status = "okay"; -+}; -+ -+&usb20_otg { -+ dr_mode = "host"; -+ status = "okay"; -+}; -+ -+&usb_host0_ehci { -+ status = "okay"; -+}; -+ -+&usb_host0_ohci { -+ status = "okay"; -+}; -+ -+&usbdrd3 { -+ status = "okay"; -+}; -+ -+&usbdrd_dwc3 { -+ dr_mode = "host"; -+ status = "okay"; -+}; -+ -+&vop { -+ status = "okay"; -+}; -+ -+&vop_mmu { -+ status = "okay"; -+}; -diff --git a/arch/arm64/boot/dts/rockchip/rk3328-box-z28.dts b/arch/arm64/boot/dts/rockchip/rk3328-box-z28.dts -new file mode 100644 -index 000000000000..797b92924f21 ---- /dev/null -+++ b/arch/arm64/boot/dts/rockchip/rk3328-box-z28.dts -@@ -0,0 +1,367 @@ -+// SPDX-License-Identifier: (GPL-2.0+ OR MIT) -+/* -+ * Copyright (c) 2017 PINE64 -+ */ -+ -+/dts-v1/; -+#include "rk3328.dtsi" -+ -+/ { -+ model = "Rockchip RK3328 Z28"; -+ compatible = "rockchip,rk3328-box-z28", "rockchip,rk3328"; -+ -+ chosen { -+ stdout-path = "serial2:1500000n8"; -+ }; -+ -+ vcc_sd: sdmmc-regulator { -+ compatible = "regulator-fixed"; -+ gpio = <&gpio0 RK_PD6 GPIO_ACTIVE_HIGH>; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&sdmmc0m1_gpio>; -+ regulator-name = "vcc_sd"; -+ regulator-min-microvolt = <3300000>; -+ regulator-max-microvolt = <3300000>; -+ vin-supply = <&vcc_io>; -+ }; -+ -+ vcc_host_5v: vcc-host-5v-regulator { -+ compatible = "regulator-fixed"; -+ enable-active-high; -+ gpio = <&gpio0 RK_PA0 GPIO_ACTIVE_HIGH>; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&usb30_host_drv>; -+ regulator-name = "vcc_host_5v"; -+ regulator-always-on; -+ regulator-boot-on; -+ vin-supply = <&vcc_sys>; -+ }; -+ -+ vcc_host1_5v: vcc_otg_5v: vcc-host1-5v-regulator { -+ compatible = "regulator-fixed"; -+ enable-active-high; -+ gpio = <&gpio0 RK_PA2 GPIO_ACTIVE_HIGH>; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&usb20_host_drv>; -+ regulator-name = "vcc_host1_5v"; -+ regulator-always-on; -+ regulator-boot-on; -+ vin-supply = <&vcc_sys>; -+ }; -+ -+ vcc_sys: vcc-sys { -+ compatible = "regulator-fixed"; -+ regulator-name = "vcc_sys"; -+ regulator-min-microvolt = <5000000>; -+ regulator-max-microvolt = <5000000>; -+ }; -+ -+ ir-receiver { -+ compatible = "gpio-ir-receiver"; -+ gpios = <&gpio2 RK_PA2 GPIO_ACTIVE_LOW>; -+ pinctrl-0 = <&ir_int>; -+ pinctrl-names = "default"; -+ }; -+ -+ leds { -+ compatible = "gpio-leds"; -+ -+ power { -+ gpios = <&rk805 0 GPIO_ACTIVE_HIGH>; -+ linux,default-trigger = "default-on"; -+ default-state = "on"; -+ }; -+ }; -+}; -+ -+&cpu0 { -+ cpu-supply = <&vdd_arm>; -+}; -+ -+&cpu1 { -+ cpu-supply = <&vdd_arm>; -+}; -+ -+&cpu2 { -+ cpu-supply = <&vdd_arm>; -+}; -+ -+&cpu3 { -+ cpu-supply = <&vdd_arm>; -+}; -+ -+&emmc { -+ bus-width = <8>; -+ cap-mmc-highspeed; -+ mmc-ddr-1_8v; -+ mmc-hs200-1_8v; -+ non-removable; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&emmc_clk &emmc_cmd &emmc_bus8>; -+ vmmc-supply = <&vcc_io>; -+ vqmmc-supply = <&vcc18_emmc>; -+ status = "okay"; -+}; -+ -+&gmac2phy { -+ assigned-clocks = <&cru SCLK_MAC2PHY_SRC>; -+ assigned-clock-rate = <50000000>; -+ assigned-clocks = <&cru SCLK_MAC2PHY>; -+ assigned-clock-parents = <&cru SCLK_MAC2PHY_SRC>; -+ clock_in_out = "output"; -+ phy-supply = <&vcc_io>; -+ status = "okay"; -+}; -+ -+&gpu { -+ mali-supply = <&vdd_logic>; -+}; -+ -+&hdmi { -+ status = "okay"; -+}; -+ -+&hdmiphy { -+ status = "okay"; -+}; -+ -+&hdmi_sound { -+ status = "okay"; -+}; -+ -+&i2c1 { -+ status = "okay"; -+ -+ rk805: rk805@18 { -+ compatible = "rockchip,rk805"; -+ reg = <0x18>; -+ interrupt-parent = <&gpio2>; -+ interrupts = <6 IRQ_TYPE_LEVEL_LOW>; -+ #clock-cells = <1>; -+ clock-output-names = "xin32k", "rk805-clkout2"; -+ gpio-controller; -+ #gpio-cells = <2>; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&pmic_int_l>; -+ rockchip,system-power-controller; -+ wakeup-source; -+ -+ vcc1-supply = <&vcc_sys>; -+ vcc2-supply = <&vcc_sys>; -+ vcc3-supply = <&vcc_sys>; -+ vcc4-supply = <&vcc_sys>; -+ vcc5-supply = <&vcc_io>; -+ vcc6-supply = <&vcc_io>; -+ -+ regulators { -+ vdd_logic: DCDC_REG1 { -+ regulator-name = "vdd_logic"; -+ regulator-min-microvolt = <900000>; -+ regulator-max-microvolt = <1150000>; -+ regulator-ramp-delay = <12500>; -+ regulator-always-on; -+ regulator-boot-on; -+ regulator-state-mem { -+ regulator-on-in-suspend; -+ regulator-suspend-microvolt = <1000000>; -+ }; -+ }; -+ -+ vdd_arm: DCDC_REG2 { -+ regulator-name = "vdd_arm"; -+ regulator-min-microvolt = <950000>; -+ regulator-max-microvolt = <1350000>; -+ regulator-ramp-delay = <12500>; -+ regulator-always-on; -+ regulator-boot-on; -+ regulator-state-mem { -+ regulator-on-in-suspend; -+ regulator-suspend-microvolt = <950000>; -+ }; -+ }; -+ -+ vcc_ddr: DCDC_REG3 { -+ regulator-name = "vcc_ddr"; -+ regulator-always-on; -+ regulator-boot-on; -+ regulator-state-mem { -+ regulator-on-in-suspend; -+ }; -+ }; -+ -+ vcc_io: DCDC_REG4 { -+ regulator-name = "vcc_io"; -+ regulator-min-microvolt = <3300000>; -+ regulator-max-microvolt = <3300000>; -+ regulator-always-on; -+ regulator-boot-on; -+ regulator-state-mem { -+ regulator-on-in-suspend; -+ regulator-suspend-microvolt = <3300000>; -+ }; -+ }; -+ -+ vcc_18: LDO_REG1 { -+ regulator-name = "vcc_18"; -+ regulator-min-microvolt = <1800000>; -+ regulator-max-microvolt = <1800000>; -+ regulator-always-on; -+ regulator-boot-on; -+ regulator-state-mem { -+ regulator-on-in-suspend; -+ regulator-suspend-microvolt = <1800000>; -+ }; -+ }; -+ -+ vcc18_emmc: LDO_REG2 { -+ regulator-name = "vcc18_emmc"; -+ regulator-min-microvolt = <1800000>; -+ regulator-max-microvolt = <1800000>; -+ regulator-always-on; -+ regulator-boot-on; -+ regulator-state-mem { -+ regulator-on-in-suspend; -+ regulator-suspend-microvolt = <1800000>; -+ }; -+ }; -+ -+ vdd_10: LDO_REG3 { -+ regulator-name = "vdd_10"; -+ regulator-min-microvolt = <1000000>; -+ regulator-max-microvolt = <1000000>; -+ regulator-always-on; -+ regulator-boot-on; -+ regulator-state-mem { -+ regulator-on-in-suspend; -+ regulator-suspend-microvolt = <1000000>; -+ }; -+ }; -+ }; -+ }; -+}; -+ -+&i2s0 { -+ status = "okay"; -+}; -+ -+&io_domains { -+ vccio1-supply = <&vcc_io>; -+ vccio2-supply = <&vcc18_emmc>; -+ vccio3-supply = <&vcc_io>; -+ vccio4-supply = <&vcc_18>; -+ vccio5-supply = <&vcc_io>; -+ vccio6-supply = <&vcc_io>; -+ pmuio-supply = <&vcc_io>; -+ status = "okay"; -+}; -+ -+&pinctrl { -+ pinctrl-names = "default"; -+ pinctrl-0 = <&clk_32k_out>; -+ -+ clk_32k { -+ clk_32k_out: clk-32k-out { -+ rockchip,pins = <1 RK_PD4 RK_FUNC_1 &pcfg_pull_none>; -+ }; -+ }; -+ -+ ir { -+ ir_int: ir-int { -+ rockchip,pins = <2 RK_PA2 RK_FUNC_GPIO &pcfg_pull_none>; -+ }; -+ }; -+ -+ pmic { -+ pmic_int_l: pmic-int-l { -+ rockchip,pins = <2 RK_PA6 RK_FUNC_GPIO &pcfg_pull_up>; -+ }; -+ }; -+ -+ usb2 { -+ usb20_host_drv: usb20-host-drv { -+ rockchip,pins = <0 RK_PA2 RK_FUNC_GPIO &pcfg_pull_none>; -+ }; -+ }; -+ -+ usb3 { -+ usb30_host_drv: usb30-host-drv { -+ rockchip,pins = <0 RK_PA0 RK_FUNC_GPIO &pcfg_pull_none>; -+ }; -+ }; -+}; -+ -+&sdmmc { -+ bus-width = <4>; -+ cap-mmc-highspeed; -+ cap-sd-highspeed; -+ disable-wp; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&sdmmc0_clk &sdmmc0_cmd &sdmmc0_dectn &sdmmc0_bus4>; -+ vmmc-supply = <&vcc_sd>; -+ status = "okay"; -+}; -+ -+&spdif { -+ pinctrl-0 = <&spdifm0_tx>; -+ status = "okay"; -+}; -+ -+&spdif_out { -+ status = "okay"; -+}; -+ -+&spdif_sound { -+ status = "okay"; -+}; -+ -+&tsadc { -+ rockchip,hw-tshut-mode = <0>; -+ rockchip,hw-tshut-polarity = <0>; -+ status = "okay"; -+}; -+ -+&uart2 { -+ status = "okay"; -+}; -+ -+&u2phy { -+ status = "okay"; -+}; -+ -+&u2phy_host { -+ status = "okay"; -+}; -+ -+&u2phy_otg { -+ status = "okay"; -+}; -+ -+&usb20_otg { -+ dr_mode = "host"; -+ status = "okay"; -+}; -+ -+&usb_host0_ehci { -+ status = "okay"; -+}; -+ -+&usb_host0_ohci { -+ status = "okay"; -+}; -+ -+&usbdrd3 { -+ status = "okay"; -+}; -+ -+&usbdrd_dwc3 { -+ dr_mode = "host"; -+ status = "okay"; -+}; -+ -+&vop { -+ status = "okay"; -+}; -+ -+&vop_mmu { -+ status = "okay"; -+}; -diff --git a/arch/arm64/boot/dts/rockchip/rk3328-box.dts b/arch/arm64/boot/dts/rockchip/rk3328-box.dts -new file mode 100644 -index 000000000000..2526147fd48b ---- /dev/null -+++ b/arch/arm64/boot/dts/rockchip/rk3328-box.dts -@@ -0,0 +1,400 @@ -+// SPDX-License-Identifier: (GPL-2.0+ OR MIT) -+/* -+ * Copyright (c) 2017 PINE64 -+ */ -+ -+/dts-v1/; -+#include "rk3328.dtsi" -+ -+/ { -+ model = "Rockchip RK3328 BOX"; -+ compatible = "rockchip,rk3328-box", "rockchip,rk3328"; -+ -+ chosen { -+ stdout-path = "serial2:1500000n8"; -+ }; -+ -+ vcc_sd: sdmmc-regulator { -+ compatible = "regulator-fixed"; -+ gpio = <&gpio0 RK_PD6 GPIO_ACTIVE_HIGH>; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&sdmmc0m1_gpio>; -+ regulator-name = "vcc_sd"; -+ regulator-min-microvolt = <3300000>; -+ regulator-max-microvolt = <3300000>; -+ vin-supply = <&vcc_io>; -+ }; -+ -+ vcc_host_5v: vcc-host-5v-regulator { -+ compatible = "regulator-fixed"; -+ enable-active-high; -+ gpio = <&gpio0 RK_PA0 GPIO_ACTIVE_HIGH>; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&usb30_host_drv>; -+ regulator-name = "vcc_host_5v"; -+ regulator-always-on; -+ regulator-boot-on; -+ vin-supply = <&vcc_sys>; -+ }; -+ -+ vcc_host1_5v: vcc_otg_5v: vcc-host1-5v-regulator { -+ compatible = "regulator-fixed"; -+ enable-active-high; -+ gpio = <&gpio0 RK_PA2 GPIO_ACTIVE_HIGH>; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&usb20_host_drv>; -+ regulator-name = "vcc_host1_5v"; -+ regulator-always-on; -+ regulator-boot-on; -+ vin-supply = <&vcc_sys>; -+ }; -+ -+ vcc_sys: vcc-sys { -+ compatible = "regulator-fixed"; -+ regulator-name = "vcc_sys"; -+ regulator-min-microvolt = <5000000>; -+ regulator-max-microvolt = <5000000>; -+ }; -+ -+ ir-receiver { -+ compatible = "gpio-ir-receiver"; -+ gpios = <&gpio2 RK_PA2 GPIO_ACTIVE_LOW>; -+ pinctrl-0 = <&ir_int>; -+ pinctrl-names = "default"; -+ }; -+ -+ leds { -+ compatible = "gpio-leds"; -+ -+ led1 { -+ gpios = <&rk805 0 GPIO_ACTIVE_LOW>; -+ linux,default-trigger = "default-on"; -+ default-state = "on"; -+ }; -+ -+ led2 { -+ gpios = <&rk805 1 GPIO_ACTIVE_LOW>; -+ linux,default-trigger = "mmc0"; -+ }; -+ }; -+ -+ sdio_pwrseq: sdio-pwrseq { -+ compatible = "mmc-pwrseq-simple"; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&wifi_enable_h>; -+ reset-gpios = <&gpio1 RK_PC2 GPIO_ACTIVE_LOW>; -+ }; -+}; -+ -+&cpu0 { -+ cpu-supply = <&vdd_arm>; -+}; -+ -+&cpu1 { -+ cpu-supply = <&vdd_arm>; -+}; -+ -+&cpu2 { -+ cpu-supply = <&vdd_arm>; -+}; -+ -+&cpu3 { -+ cpu-supply = <&vdd_arm>; -+}; -+ -+&emmc { -+ bus-width = <8>; -+ cap-mmc-highspeed; -+ mmc-ddr-1_8v; -+ mmc-hs200-1_8v; -+ non-removable; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&emmc_clk &emmc_cmd &emmc_bus8>; -+ vmmc-supply = <&vcc_io>; -+ vqmmc-supply = <&vcc18_emmc>; -+ status = "okay"; -+}; -+ -+&gmac2phy { -+ assigned-clocks = <&cru SCLK_MAC2PHY_SRC>; -+ assigned-clock-rate = <50000000>; -+ assigned-clocks = <&cru SCLK_MAC2PHY>; -+ assigned-clock-parents = <&cru SCLK_MAC2PHY_SRC>; -+ clock_in_out = "output"; -+ phy-supply = <&vcc_io>; -+ status = "okay"; -+}; -+ -+&gpu { -+ mali-supply = <&vdd_logic>; -+}; -+ -+&hdmi { -+ status = "okay"; -+}; -+ -+&hdmiphy { -+ status = "okay"; -+}; -+ -+&hdmi_sound { -+ status = "okay"; -+}; -+ -+&i2c1 { -+ status = "okay"; -+ -+ rk805: rk805@18 { -+ compatible = "rockchip,rk805"; -+ reg = <0x18>; -+ interrupt-parent = <&gpio2>; -+ interrupts = <6 IRQ_TYPE_LEVEL_LOW>; -+ #clock-cells = <1>; -+ clock-output-names = "xin32k", "rk805-clkout2"; -+ gpio-controller; -+ #gpio-cells = <2>; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&pmic_int_l>; -+ rockchip,system-power-controller; -+ wakeup-source; -+ -+ vcc1-supply = <&vcc_sys>; -+ vcc2-supply = <&vcc_sys>; -+ vcc3-supply = <&vcc_sys>; -+ vcc4-supply = <&vcc_sys>; -+ vcc5-supply = <&vcc_io>; -+ vcc6-supply = <&vcc_io>; -+ -+ regulators { -+ vdd_logic: DCDC_REG1 { -+ regulator-name = "vdd_logic"; -+ regulator-min-microvolt = <900000>; -+ regulator-max-microvolt = <1150000>; -+ regulator-ramp-delay = <12500>; -+ regulator-always-on; -+ regulator-boot-on; -+ regulator-state-mem { -+ regulator-on-in-suspend; -+ regulator-suspend-microvolt = <1000000>; -+ }; -+ }; -+ -+ vdd_arm: DCDC_REG2 { -+ regulator-name = "vdd_arm"; -+ regulator-min-microvolt = <950000>; -+ regulator-max-microvolt = <1350000>; -+ regulator-ramp-delay = <12500>; -+ regulator-always-on; -+ regulator-boot-on; -+ regulator-state-mem { -+ regulator-on-in-suspend; -+ regulator-suspend-microvolt = <950000>; -+ }; -+ }; -+ -+ vcc_ddr: DCDC_REG3 { -+ regulator-name = "vcc_ddr"; -+ regulator-always-on; -+ regulator-boot-on; -+ regulator-state-mem { -+ regulator-on-in-suspend; -+ }; -+ }; -+ -+ vcc_io: DCDC_REG4 { -+ regulator-name = "vcc_io"; -+ regulator-min-microvolt = <3300000>; -+ regulator-max-microvolt = <3300000>; -+ regulator-always-on; -+ regulator-boot-on; -+ regulator-state-mem { -+ regulator-on-in-suspend; -+ regulator-suspend-microvolt = <3300000>; -+ }; -+ }; -+ -+ vcc_18: LDO_REG1 { -+ regulator-name = "vcc_18"; -+ regulator-min-microvolt = <1800000>; -+ regulator-max-microvolt = <1800000>; -+ regulator-always-on; -+ regulator-boot-on; -+ regulator-state-mem { -+ regulator-on-in-suspend; -+ regulator-suspend-microvolt = <1800000>; -+ }; -+ }; -+ -+ vcc18_emmc: LDO_REG2 { -+ regulator-name = "vcc18_emmc"; -+ regulator-min-microvolt = <1800000>; -+ regulator-max-microvolt = <1800000>; -+ regulator-always-on; -+ regulator-boot-on; -+ regulator-state-mem { -+ regulator-on-in-suspend; -+ regulator-suspend-microvolt = <1800000>; -+ }; -+ }; -+ -+ vdd_10: LDO_REG3 { -+ regulator-name = "vdd_10"; -+ regulator-min-microvolt = <1000000>; -+ regulator-max-microvolt = <1000000>; -+ regulator-always-on; -+ regulator-boot-on; -+ regulator-state-mem { -+ regulator-on-in-suspend; -+ regulator-suspend-microvolt = <1000000>; -+ }; -+ }; -+ }; -+ }; -+}; -+ -+&i2s0 { -+ status = "okay"; -+}; -+ -+&io_domains { -+ vccio1-supply = <&vcc_io>; -+ vccio2-supply = <&vcc18_emmc>; -+ vccio3-supply = <&vcc_io>; -+ vccio4-supply = <&vcc_18>; -+ vccio5-supply = <&vcc_io>; -+ vccio6-supply = <&vcc_io>; -+ pmuio-supply = <&vcc_io>; -+ status = "okay"; -+}; -+ -+&pinctrl { -+ pinctrl-names = "default"; -+ pinctrl-0 = <&clk_32k_out>; -+ -+ clk_32k { -+ clk_32k_out: clk-32k-out { -+ rockchip,pins = <1 RK_PD4 RK_FUNC_1 &pcfg_pull_none>; -+ }; -+ }; -+ -+ ir { -+ ir_int: ir-int { -+ rockchip,pins = <2 RK_PA2 RK_FUNC_GPIO &pcfg_pull_none>; -+ }; -+ }; -+ -+ pmic { -+ pmic_int_l: pmic-int-l { -+ rockchip,pins = <2 RK_PA6 RK_FUNC_GPIO &pcfg_pull_up>; -+ }; -+ }; -+ -+ sdio-pwrseq { -+ wifi_enable_h: wifi-enable-h { -+ rockchip,pins = <1 RK_PC2 RK_FUNC_GPIO &pcfg_pull_none_4ma>, -+ <1 RK_PC3 RK_FUNC_GPIO &pcfg_pull_none_4ma>; -+ }; -+ }; -+ -+ usb2 { -+ usb20_host_drv: usb20-host-drv { -+ rockchip,pins = <0 RK_PA2 RK_FUNC_GPIO &pcfg_pull_none>; -+ }; -+ }; -+ -+ usb3 { -+ usb30_host_drv: usb30-host-drv { -+ rockchip,pins = <0 RK_PA0 RK_FUNC_GPIO &pcfg_pull_none>; -+ }; -+ }; -+}; -+ -+&sdio { -+ bus-width = <4>; -+ cap-sd-highspeed; -+ cap-sdio-irq; -+ keep-power-in-suspend; -+ mmc-pwrseq = <&sdio_pwrseq>; -+ non-removable; -+ num-slots = <1>; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&sdmmc1_bus4 &sdmmc1_cmd &sdmmc1_clk>; -+ sd-uhs-sdr104; -+ status = "disabled"; -+}; -+ -+&sdmmc { -+ bus-width = <4>; -+ cap-mmc-highspeed; -+ cap-sd-highspeed; -+ disable-wp; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&sdmmc0_clk &sdmmc0_cmd &sdmmc0_dectn &sdmmc0_bus4>; -+ vmmc-supply = <&vcc_sd>; -+ status = "okay"; -+}; -+ -+&spdif { -+ pinctrl-0 = <&spdifm0_tx>; -+ status = "okay"; -+}; -+ -+&spdif_out { -+ status = "okay"; -+}; -+ -+&spdif_sound { -+ status = "okay"; -+}; -+ -+&tsadc { -+ rockchip,hw-tshut-mode = <0>; -+ rockchip,hw-tshut-polarity = <0>; -+ status = "okay"; -+}; -+ -+&uart2 { -+ status = "okay"; -+}; -+ -+&u2phy { -+ status = "okay"; -+}; -+ -+&u2phy_host { -+ status = "okay"; -+}; -+ -+&u2phy_otg { -+ status = "okay"; -+}; -+ -+&usb20_otg { -+ dr_mode = "host"; -+ status = "okay"; -+}; -+ -+&usb_host0_ehci { -+ status = "okay"; -+}; -+ -+&usb_host0_ohci { -+ status = "okay"; -+}; -+ -+&usbdrd3 { -+ status = "okay"; -+}; -+ -+&usbdrd_dwc3 { -+ dr_mode = "host"; -+ status = "okay"; -+}; -+ -+&vop { -+ status = "okay"; -+}; -+ -+&vop_mmu { -+ status = "okay"; -+}; --- -2.17.1 - diff --git a/patch/kernel/rk322x-current/01-linux-0006-experimental.patch.disabled b/patch/kernel/rk322x-current/01-linux-0006-experimental.patch.disabled deleted file mode 100644 index 892c5b859..000000000 --- a/patch/kernel/rk322x-current/01-linux-0006-experimental.patch.disabled +++ /dev/null @@ -1,1825 +0,0 @@ -diff --git a/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c b/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c -index 9ca20c947283..b0ac1d3ee390 100644 ---- a/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c -+++ b/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c -@@ -790,8 +790,8 @@ static int inno_hdmi_phy_rk3328_clk_set_rate(struct clk_hw *hw, - RK3328_PRE_PLL_POWER_DOWN); - - /* Configure pre-pll */ -- inno_update_bits(inno, 0xa0, RK3228_PCLK_VCO_DIV_5_MASK, -- RK3228_PCLK_VCO_DIV_5(cfg->vco_div_5_en)); -+ inno_update_bits(inno, 0xa0, RK3328_PCLK_VCO_DIV_5_MASK, -+ RK3328_PCLK_VCO_DIV_5(cfg->vco_div_5_en)); - inno_write(inno, 0xa1, RK3328_PRE_PLL_PRE_DIV(cfg->prediv)); - - val = RK3328_SPREAD_SPECTRUM_MOD_DISABLE; --- -2.17.1 - - -From 0ae81f8167f59ad2c781dc51f2b2fa3e0c9f976b Mon Sep 17 00:00:00 2001 -From: Jonas Karlman -Date: Fri, 20 Dec 2019 08:12:42 +0000 -Subject: [PATCH] phy/rockchip: inno-hdmi: round fractal pixclock in rk3328 - recalc_rate - -inno_hdmi_phy_rk3328_clk_recalc_rate() is returning a rate not found -in the pre pll config table when the fractal divider is used. -This can prevent proper power_on because a tmdsclock for the new rate -is not found in the pre pll config table. - -Fix this by saving and returning a rounded pixel rate that exist -in the pre pll config table. - -Fixes: 53706a116863 ("phy: add Rockchip Innosilicon hdmi phy") -Signed-off-by: Zheng Yang -Signed-off-by: Jonas Karlman ---- - drivers/phy/rockchip/phy-rockchip-inno-hdmi.c | 8 +++++--- - 1 file changed, 5 insertions(+), 3 deletions(-) - -diff --git a/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c b/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c -index b0ac1d3ee390..093d2334e8cd 100644 ---- a/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c -+++ b/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c -@@ -745,10 +745,12 @@ unsigned long inno_hdmi_phy_rk3328_clk_recalc_rate(struct clk_hw *hw, - do_div(vco, (nd * (no_a == 1 ? no_b : no_a) * no_d * 2)); - } - -- inno->pixclock = vco; -- dev_dbg(inno->dev, "%s rate %lu\n", __func__, inno->pixclock); -+ inno->pixclock = DIV_ROUND_CLOSEST((unsigned long)vco, 1000) * 1000; - -- return vco; -+ dev_dbg(inno->dev, "%s rate %lu vco %llu\n", -+ __func__, inno->pixclock, vco); -+ -+ return inno->pixclock; - } - - static long inno_hdmi_phy_rk3328_clk_round_rate(struct clk_hw *hw, --- -2.17.1 - - -From fcb6a75bac484bec5443241965757b2d7cf99182 Mon Sep 17 00:00:00 2001 -From: Jonas Karlman -Date: Fri, 20 Dec 2019 08:12:42 +0000 -Subject: [PATCH] phy/rockchip: inno-hdmi: remove unused no_c from rk3328 - recalc_rate - -no_c is not used in any calculation, lets remove it. - -Signed-off-by: Jonas Karlman ---- - drivers/phy/rockchip/phy-rockchip-inno-hdmi.c | 5 +---- - 1 file changed, 1 insertion(+), 4 deletions(-) - -diff --git a/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c b/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c -index 093d2334e8cd..06db69c8373e 100644 ---- a/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c -+++ b/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c -@@ -714,7 +714,7 @@ unsigned long inno_hdmi_phy_rk3328_clk_recalc_rate(struct clk_hw *hw, - { - struct inno_hdmi_phy *inno = to_inno_hdmi_phy(hw); - unsigned long frac; -- u8 nd, no_a, no_b, no_c, no_d; -+ u8 nd, no_a, no_b, no_d; - u64 vco; - u16 nf; - -@@ -737,9 +737,6 @@ unsigned long inno_hdmi_phy_rk3328_clk_recalc_rate(struct clk_hw *hw, - no_b = inno_read(inno, 0xa5) & RK3328_PRE_PLL_PCLK_DIV_B_MASK; - no_b >>= RK3328_PRE_PLL_PCLK_DIV_B_SHIFT; - no_b += 2; -- no_c = inno_read(inno, 0xa6) & RK3328_PRE_PLL_PCLK_DIV_C_MASK; -- no_c >>= RK3328_PRE_PLL_PCLK_DIV_C_SHIFT; -- no_c = 1 << no_c; - no_d = inno_read(inno, 0xa6) & RK3328_PRE_PLL_PCLK_DIV_D_MASK; - - do_div(vco, (nd * (no_a == 1 ? no_b : no_a) * no_d * 2)); --- -2.17.1 - - -From 8da78b0cf0c522be59656ed24a0018bd2fbea5a8 Mon Sep 17 00:00:00 2001 -From: Jonas Karlman -Date: Fri, 20 Dec 2019 08:12:42 +0000 -Subject: [PATCH] phy/rockchip: inno-hdmi: do not power on rk3328 post pll on - reg write - -inno_write is used to configure 0xaa reg, that also hold the -POST_PLL_POWER_DOWN bit. -When POST_PLL_REFCLK_SEL_TMDS is configured the power down bit is not -taken into consideration. - -Fix this by keeping the power down bit until configuration is complete. -Also reorder the reg write order for consistency. - -Fixes: 53706a116863 ("phy: add Rockchip Innosilicon hdmi phy") -Signed-off-by: Jonas Karlman ---- - drivers/phy/rockchip/phy-rockchip-inno-hdmi.c | 6 ++++-- - 1 file changed, 4 insertions(+), 2 deletions(-) - -diff --git a/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c b/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c -index 06db69c8373e..3a59a6da0440 100644 ---- a/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c -+++ b/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c -@@ -1020,9 +1020,10 @@ inno_hdmi_phy_rk3328_power_on(struct inno_hdmi_phy *inno, - - inno_write(inno, 0xac, RK3328_POST_PLL_FB_DIV_7_0(cfg->fbdiv)); - if (cfg->postdiv == 1) { -- inno_write(inno, 0xaa, RK3328_POST_PLL_REFCLK_SEL_TMDS); - inno_write(inno, 0xab, RK3328_POST_PLL_FB_DIV_8(cfg->fbdiv) | - RK3328_POST_PLL_PRE_DIV(cfg->prediv)); -+ inno_write(inno, 0xaa, RK3328_POST_PLL_REFCLK_SEL_TMDS | -+ RK3328_POST_PLL_POWER_DOWN); - } else { - v = (cfg->postdiv / 2) - 1; - v &= RK3328_POST_PLL_POST_DIV_MASK; -@@ -1030,7 +1031,8 @@ inno_hdmi_phy_rk3328_power_on(struct inno_hdmi_phy *inno, - inno_write(inno, 0xab, RK3328_POST_PLL_FB_DIV_8(cfg->fbdiv) | - RK3328_POST_PLL_PRE_DIV(cfg->prediv)); - inno_write(inno, 0xaa, RK3328_POST_PLL_POST_DIV_ENABLE | -- RK3328_POST_PLL_REFCLK_SEL_TMDS); -+ RK3328_POST_PLL_REFCLK_SEL_TMDS | -+ RK3328_POST_PLL_POWER_DOWN); - } - - for (v = 0; v < 14; v++) --- -2.17.1 - - -From 790af1279068ad1cc4ef471d90050570a850f426 Mon Sep 17 00:00:00 2001 -From: Jonas Karlman -Date: Fri, 20 Dec 2019 08:12:42 +0000 -Subject: [PATCH] phy/rockchip: inno-hdmi: force set_rate on power_on - -Regular 8-bit and Deep Color video formats mainly differ in TMDS rate and -not in pixel clock rate. -When the hdmiphy clock is configured with the same pixel clock rate using -clk_set_rate() the clock framework do not signal the hdmi phy driver -to set_rate when switching between 8-bit and Deep Color. -This result in pre/post pll not being re-configured when switching between -regular 8-bit and Deep Color video formats. - -Fix this by calling set_rate in power_on to force pre pll re-configuration. - -Signed-off-by: Jonas Karlman ---- - drivers/phy/rockchip/phy-rockchip-inno-hdmi.c | 13 +++++++++++++ - 1 file changed, 13 insertions(+) - -diff --git a/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c b/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c -index 3a59a6da0440..3719309ad0d0 100644 ---- a/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c -+++ b/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c -@@ -245,6 +245,7 @@ struct inno_hdmi_phy { - struct clk_hw hw; - struct clk *phyclk; - unsigned long pixclock; -+ unsigned long tmdsclock; - }; - - struct pre_pll_config { -@@ -485,6 +486,8 @@ static int inno_hdmi_phy_power_on(struct phy *phy) - - dev_dbg(inno->dev, "Inno HDMI PHY Power On\n"); - -+ inno->plat_data->clk_ops->set_rate(&inno->hw, inno->pixclock, 24000000); -+ - ret = clk_prepare_enable(inno->phyclk); - if (ret) - return ret; -@@ -509,6 +512,8 @@ static int inno_hdmi_phy_power_off(struct phy *phy) - - clk_disable_unprepare(inno->phyclk); - -+ inno->tmdsclock = 0; -+ - dev_dbg(inno->dev, "Inno HDMI PHY Power Off\n"); - - return 0; -@@ -628,6 +633,9 @@ static int inno_hdmi_phy_rk3228_clk_set_rate(struct clk_hw *hw, - dev_dbg(inno->dev, "%s rate %lu tmdsclk %lu\n", - __func__, rate, tmdsclock); - -+ if (inno->pixclock == rate && inno->tmdsclock == tmdsclock) -+ return 0; -+ - cfg = inno_hdmi_phy_get_pre_pll_cfg(inno, rate); - if (IS_ERR(cfg)) - return PTR_ERR(cfg); -@@ -670,6 +678,7 @@ static int inno_hdmi_phy_rk3228_clk_set_rate(struct clk_hw *hw, - } - - inno->pixclock = rate; -+ inno->tmdsclock = tmdsclock; - - return 0; - } -@@ -781,6 +790,9 @@ static int inno_hdmi_phy_rk3328_clk_set_rate(struct clk_hw *hw, - dev_dbg(inno->dev, "%s rate %lu tmdsclk %lu\n", - __func__, rate, tmdsclock); - -+ if (inno->pixclock == rate && inno->tmdsclock == tmdsclock) -+ return 0; -+ - cfg = inno_hdmi_phy_get_pre_pll_cfg(inno, rate); - if (IS_ERR(cfg)) - return PTR_ERR(cfg); -@@ -820,6 +832,7 @@ static int inno_hdmi_phy_rk3328_clk_set_rate(struct clk_hw *hw, - } - - inno->pixclock = rate; -+ inno->tmdsclock = tmdsclock; - - return 0; - } --- -2.17.1 - - -From 852eb17bca3ae36762eb2975bb9a5642cf0865d8 Mon Sep 17 00:00:00 2001 -From: Jonas Karlman -Date: Sat, 21 Dec 2019 23:52:16 +0000 -Subject: [PATCH] drm/rockchip: vop: limit resolution width to 3840 - -Using a destination width that is more then 3840 pixels -is not supported in scl_vop_cal_scl_fac(). - -Work around this limitation by filtering all modes with -a width above 3840. - -Signed-off-by: Jonas Karlman ---- - drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 10 ++++++++++ - 1 file changed, 10 insertions(+) - -diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c -index d04b3492bdac..f181897cbfad 100644 ---- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c -+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c -@@ -1036,6 +1036,15 @@ static void vop_crtc_disable_vblank(struct drm_crtc *crtc) - spin_unlock_irqrestore(&vop->irq_lock, flags); - } - -+enum drm_mode_status vop_crtc_mode_valid(struct drm_crtc *crtc, -+ const struct drm_display_mode *mode) -+{ -+ if (mode->hdisplay > 3840) -+ return MODE_BAD_HVALUE; -+ -+ return MODE_OK; -+} -+ - static bool vop_crtc_mode_fixup(struct drm_crtc *crtc, - const struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) -@@ -1377,6 +1386,7 @@ static void vop_crtc_atomic_flush(struct drm_crtc *crtc, - } - - static const struct drm_crtc_helper_funcs vop_crtc_helper_funcs = { -+ .mode_valid = vop_crtc_mode_valid, - .mode_fixup = vop_crtc_mode_fixup, - .atomic_check = vop_crtc_atomic_check, - .atomic_begin = vop_crtc_atomic_begin, --- -2.17.1 - - -From 1f18ed83f51df960be0688db39b086b9a58ef7d1 Mon Sep 17 00:00:00 2001 -From: Jonas Karlman -Date: Sun, 22 Dec 2019 12:43:36 +0000 -Subject: [PATCH] drm/rockchip: dw-hdmi: allow high tmds bit rates - -Prepare support for High TMDS Bit Rates used by HDMI2.0 display modes. - -Signed-off-by: Jonas Karlman ---- - drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c -index 7f56d8c3491d..fae38b323a0c 100644 ---- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c -+++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c -@@ -318,6 +318,8 @@ static int dw_hdmi_rockchip_genphy_init(struct dw_hdmi *dw_hdmi, void *data, - { - struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data; - -+ dw_hdmi_set_high_tmds_clock_ratio(dw_hdmi); -+ - return phy_power_on(hdmi->phy); - } - --- -2.17.1 - - -From d8ee714e54380f7b09dd088944f5c030aa1ee320 Mon Sep 17 00:00:00 2001 -From: Jonas Karlman -Date: Sun, 22 Dec 2019 12:35:16 +0000 -Subject: [PATCH] drm/rockchip: dw-hdmi: require valid vpll clock rate on - rk3228/rk3328 - -RK3228/RK3328 can only support clock rates defined in the pre pll table. -Lets validate the mode clock rate against the pre pll config and filter -out any mode with a clock rate returning error from clk_round_rate(). - -Signed-off-by: Jonas Karlman ---- - drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 17 +++++++++++++++++ - 1 file changed, 17 insertions(+) - -diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c -index fae38b323a0c..45fcdce3f27f 100644 ---- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c -+++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c -@@ -245,6 +245,22 @@ static void dw_hdmi_rockchip_encoder_disable(struct drm_encoder *encoder) - { - } - -+static enum drm_mode_status -+dw_hdmi_rockchip_encoder_mode_valid(struct drm_encoder *encoder, -+ const struct drm_display_mode *mode) -+{ -+ struct rockchip_hdmi *hdmi = to_rockchip_hdmi(encoder); -+ long rate; -+ -+ if (hdmi->vpll_clk) { -+ rate = clk_round_rate(hdmi->vpll_clk, mode->clock * 1000); -+ if (rate < 0) -+ return MODE_CLOCK_RANGE; -+ } -+ -+ return MODE_OK; -+} -+ - static bool - dw_hdmi_rockchip_encoder_mode_fixup(struct drm_encoder *encoder, - const struct drm_display_mode *mode, -@@ -306,6 +322,7 @@ dw_hdmi_rockchip_encoder_atomic_check(struct drm_encoder *encoder, - } - - static const struct drm_encoder_helper_funcs dw_hdmi_rockchip_encoder_helper_funcs = { -+ .mode_valid = dw_hdmi_rockchip_encoder_mode_valid, - .mode_fixup = dw_hdmi_rockchip_encoder_mode_fixup, - .mode_set = dw_hdmi_rockchip_encoder_mode_set, - .enable = dw_hdmi_rockchip_encoder_enable, --- -2.17.1 - - -From f305ae2094370127c797a4af3772bd9ff4e8dfc2 Mon Sep 17 00:00:00 2001 -From: Jonas Karlman -Date: Sun, 22 Dec 2019 23:42:45 +0000 -Subject: [PATCH] clk: rockchip: set parent rate for DCLK_VOP clock on rk3228 - -Signed-off-by: Jonas Karlman ---- - drivers/clk/rockchip/clk-rk3228.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/drivers/clk/rockchip/clk-rk3228.c b/drivers/clk/rockchip/clk-rk3228.c -index d17cfb7a3ff4..25f79af22cb8 100644 ---- a/drivers/clk/rockchip/clk-rk3228.c -+++ b/drivers/clk/rockchip/clk-rk3228.c -@@ -410,7 +410,7 @@ static struct rockchip_clk_branch rk3228_clk_branches[] __initdata = { - RK2928_CLKSEL_CON(29), 0, 3, DFLAGS), - DIV(0, "sclk_vop_pre", "sclk_vop_src", 0, - RK2928_CLKSEL_CON(27), 8, 8, DFLAGS), -- MUX(DCLK_VOP, "dclk_vop", mux_dclk_vop_p, 0, -+ MUX(DCLK_VOP, "dclk_vop", mux_dclk_vop_p, CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT, - RK2928_CLKSEL_CON(27), 1, 1, MFLAGS), - - FACTOR(0, "xin12m", "xin24m", 0, 1, 2), --- -2.17.1 - - -From 69f1bbcbc9c02c34f4fda49191ccae1f9dac410e Mon Sep 17 00:00:00 2001 -From: Jonas Karlman -Date: Sun, 15 Dec 2019 10:05:46 +0000 -Subject: [PATCH] arm64: dts: rockchip: increase vop clock rate on rk3328 - -The VOP on RK3328 needs to run faster in order to procude a proper -3840x2160 signal. - -Signed-off-by: Jonas Karlman ---- - arch/arm64/boot/dts/rockchip/rk3328.dtsi | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/arch/arm64/boot/dts/rockchip/rk3328.dtsi b/arch/arm64/boot/dts/rockchip/rk3328.dtsi -index bc9186f66d9c..d4cfb1066c5a 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3328.dtsi -+++ b/arch/arm64/boot/dts/rockchip/rk3328.dtsi -@@ -834,8 +834,8 @@ - <0>, <24000000>, - <24000000>, <24000000>, - <15000000>, <15000000>, -- <100000000>, <100000000>, -- <100000000>, <100000000>, -+ <300000000>, <100000000>, -+ <400000000>, <100000000>, - <50000000>, <100000000>, - <100000000>, <100000000>, - <50000000>, <50000000>, --- -2.17.1 - - -From 2aeb955b7a259182df7c2244531abd4bf233f60b Mon Sep 17 00:00:00 2001 -From: Jonas Karlman -Date: Sun, 22 Dec 2019 23:43:40 +0000 -Subject: [PATCH] arm64: dts: rockchip: add vpll clock to hdmi node on rk3328 - -Add the hdmiphy clock as the vpll in hdmi node. - -Signed-off-by: Jonas Karlman ---- - arch/arm64/boot/dts/rockchip/rk3328.dtsi | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/arch/arm64/boot/dts/rockchip/rk3328.dtsi b/arch/arm64/boot/dts/rockchip/rk3328.dtsi -index d4cfb1066c5a..991d2a830887 100644 ---- a/arch/arm64/boot/dts/rockchip/rk3328.dtsi -+++ b/arch/arm64/boot/dts/rockchip/rk3328.dtsi -@@ -750,9 +750,11 @@ - ; - clocks = <&cru PCLK_HDMI>, - <&cru SCLK_HDMI_SFC>, -+ <&hdmiphy>, - <&cru SCLK_RTC32K>; - clock-names = "iahb", - "isfr", -+ "vpll", - "cec"; - phys = <&hdmiphy>; - phy-names = "hdmi"; --- -2.17.1 - - -From a972a8f4fbc0db4c71fcf2d7eb1c1dcc31a8d089 Mon Sep 17 00:00:00 2001 -From: Jonas Karlman -Date: Sun, 22 Dec 2019 23:43:58 +0000 -Subject: [PATCH] ARM: dts: rockchip: add vpll clock to hdmi node on rk3228 - -Add the hdmiphy clock as the vpll in hdmi node. - -Signed-off-by: Jonas Karlman ---- - arch/arm/boot/dts/rk322x.dtsi | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/arch/arm/boot/dts/rk322x.dtsi b/arch/arm/boot/dts/rk322x.dtsi -index 4e90efdc9630..1e31f6898797 100644 ---- a/arch/arm/boot/dts/rk322x.dtsi -+++ b/arch/arm/boot/dts/rk322x.dtsi -@@ -639,8 +639,8 @@ - interrupts = ; - assigned-clocks = <&cru SCLK_HDMI_PHY>; - assigned-clock-parents = <&hdmi_phy>; -- clocks = <&cru SCLK_HDMI_HDCP>, <&cru PCLK_HDMI_CTRL>, <&cru SCLK_HDMI_CEC>; -- clock-names = "isfr", "iahb", "cec"; -+ clocks = <&cru SCLK_HDMI_HDCP>, <&cru PCLK_HDMI_CTRL>, <&hdmi_phy>, <&cru SCLK_HDMI_CEC>; -+ clock-names = "isfr", "iahb", "vpll", "cec"; - pinctrl-names = "default"; - pinctrl-0 = <&hdmii2c_xfer &hdmi_hpd &hdmi_cec>; - resets = <&cru SRST_HDMI_P>; --- -2.17.1 - - -From ad13781b15e2a4657e52147461565b99e16dca65 Mon Sep 17 00:00:00 2001 -From: Jonas Karlman -Date: Sun, 22 Dec 2019 10:42:02 +0000 -Subject: [PATCH] drm/rockchip: dw-hdmi: limit tmds to 340mhz on rk3228/rk3328 - -RK3228/RK3328 does not provide a stable hdmi signal at TMDS rates -above 371.25MHz (340MHz pixel clock). - -Limit the pixel clock rate to 340MHz to provide a stable signal. -Also limit the pixel clock to the display reported max tmds clock. - -Signed-off-by: Jonas Karlman ---- - drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 22 +++++++++++++++++++-- - 1 file changed, 20 insertions(+), 2 deletions(-) - -diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c -index 45fcdce3f27f..66c14df4a680 100644 ---- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c -+++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c -@@ -237,6 +237,24 @@ dw_hdmi_rockchip_mode_valid(struct drm_connector *connector, - return (valid) ? MODE_OK : MODE_BAD; - } - -+static enum drm_mode_status -+dw_hdmi_rk3228_mode_valid(struct drm_connector *connector, -+ const struct drm_display_mode *mode) -+{ -+ struct drm_display_info *info = &connector->display_info; -+ int max_tmds_clock = max(info->max_tmds_clock, 165000); -+ int clock = mode->clock; -+ -+ if (connector->ycbcr_420_allowed && drm_mode_is_420(info, mode) && -+ (info->color_formats & DRM_COLOR_FORMAT_YCRCB420)) -+ clock /= 2; -+ -+ if (clock > max_tmds_clock || clock > 340000) -+ return MODE_CLOCK_HIGH; -+ -+ return MODE_OK; -+} -+ - static const struct drm_encoder_funcs dw_hdmi_rockchip_encoder_funcs = { - .destroy = drm_encoder_cleanup, - }; -@@ -424,7 +442,7 @@ static struct rockchip_hdmi_chip_data rk3228_chip_data = { - }; - - static const struct dw_hdmi_plat_data rk3228_hdmi_drv_data = { -- .mode_valid = dw_hdmi_rockchip_mode_valid, -+ .mode_valid = dw_hdmi_rk3228_mode_valid, - .mpll_cfg = rockchip_mpll_cfg, - .cur_ctr = rockchip_cur_ctr, - .phy_config = rockchip_phy_config, -@@ -461,7 +479,7 @@ static struct rockchip_hdmi_chip_data rk3328_chip_data = { - }; - - static const struct dw_hdmi_plat_data rk3328_hdmi_drv_data = { -- .mode_valid = dw_hdmi_rockchip_mode_valid, -+ .mode_valid = dw_hdmi_rk3228_mode_valid, - .mpll_cfg = rockchip_mpll_cfg, - .cur_ctr = rockchip_cur_ctr, - .phy_config = rockchip_phy_config, --- -2.17.1 - - -From 8e950f0d07a1cea3ad58bd654c91a747d2902c6c Mon Sep 17 00:00:00 2001 -From: Jonas Karlman -Date: Sun, 22 Dec 2019 10:42:27 +0000 -Subject: [PATCH] drm/rockchip: dw-hdmi: remove unused plat_data on - rk3228/rk3328 - -mpll_cfg/cur_ctr/phy_config is not used when phy_force_vendor is true, -lets remove them. - -Signed-off-by: Jonas Karlman ---- - drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 6 ------ - 1 file changed, 6 deletions(-) - -diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c -index 66c14df4a680..a813299e97a2 100644 ---- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c -+++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c -@@ -443,9 +443,6 @@ static struct rockchip_hdmi_chip_data rk3228_chip_data = { - - static const struct dw_hdmi_plat_data rk3228_hdmi_drv_data = { - .mode_valid = dw_hdmi_rk3228_mode_valid, -- .mpll_cfg = rockchip_mpll_cfg, -- .cur_ctr = rockchip_cur_ctr, -- .phy_config = rockchip_phy_config, - .phy_data = &rk3228_chip_data, - .phy_ops = &rk3228_hdmi_phy_ops, - .phy_name = "inno_dw_hdmi_phy2", -@@ -480,9 +477,6 @@ static struct rockchip_hdmi_chip_data rk3328_chip_data = { - - static const struct dw_hdmi_plat_data rk3328_hdmi_drv_data = { - .mode_valid = dw_hdmi_rk3228_mode_valid, -- .mpll_cfg = rockchip_mpll_cfg, -- .cur_ctr = rockchip_cur_ctr, -- .phy_config = rockchip_phy_config, - .phy_data = &rk3328_chip_data, - .phy_ops = &rk3328_hdmi_phy_ops, - .phy_name = "inno_dw_hdmi_phy2", --- -2.17.1 - - -From 34326d29065869cc262b2f1644310ec9417dac29 Mon Sep 17 00:00:00 2001 -From: Algea Cao -Date: Fri, 18 May 2018 14:32:08 +0800 -Subject: [PATCH] phy/rockchip: inno-hdmi: Support more pre-pll configuration - -Adding the following freq cfg in 8-bit and 10-bit color depth: - -{ - 40000000, 65000000, 71000000, 83500000, 85750000, - 88750000, 108000000, 119000000, 162000000 -} - -New freq has been validated by quantumdata 980. - -For some freq which can't be got by only using integer freq div, -frac freq div is needed, Such as 88.75Mhz 10-bit. But The actual -freq is different from the target freq, We must try to narrow -the gap between them. RK322X only support integer freq div. - -The VCO of pre-PLL must be more than 2Ghz, otherwise PLL may be -unlocked. - -Signed-off-by: Algea Cao -Signed-off-by: Jonas Karlman ---- - drivers/phy/rockchip/phy-rockchip-inno-hdmi.c | 74 ++++++++++++------- - 1 file changed, 49 insertions(+), 25 deletions(-) - -diff --git a/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c b/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c -index 3719309ad0d0..bb8bdf5e3301 100644 ---- a/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c -+++ b/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c -@@ -291,32 +291,56 @@ struct inno_hdmi_phy_drv_data { - const struct phy_config *phy_cfg_table; - }; - -+/* -+ * If only using integer freq div can't get frequency we want, frac -+ * freq div is needed. For example, pclk 88.75 Mhz and tmdsclk -+ * 110.9375 Mhz must use frac div 0xF00000. The actual frequency is different -+ * from the target frequency. Such as the tmds clock 110.9375 Mhz, -+ * the actual tmds clock we get is 110.93719 Mhz. It is important -+ * to note that RK322X platforms do not support frac div. -+ */ - static const struct pre_pll_config pre_pll_cfg_table[] = { -- { 27000000, 27000000, 1, 90, 3, 2, 2, 10, 3, 3, 4, 0, 0}, -- { 27000000, 33750000, 1, 90, 1, 3, 3, 10, 3, 3, 4, 0, 0}, -- { 40000000, 40000000, 1, 80, 2, 2, 2, 12, 2, 2, 2, 0, 0}, -- { 59341000, 59341000, 1, 98, 3, 1, 2, 1, 3, 3, 4, 0, 0xE6AE6B}, -- { 59400000, 59400000, 1, 99, 3, 1, 1, 1, 3, 3, 4, 0, 0}, -- { 59341000, 74176250, 1, 98, 0, 3, 3, 1, 3, 3, 4, 0, 0xE6AE6B}, -- { 59400000, 74250000, 1, 99, 1, 2, 2, 1, 3, 3, 4, 0, 0}, -- { 74176000, 74176000, 1, 98, 1, 2, 2, 1, 2, 3, 4, 0, 0xE6AE6B}, -- { 74250000, 74250000, 1, 99, 1, 2, 2, 1, 2, 3, 4, 0, 0}, -- { 74176000, 92720000, 4, 494, 1, 2, 2, 1, 3, 3, 4, 0, 0x816817}, -- { 74250000, 92812500, 4, 495, 1, 2, 2, 1, 3, 3, 4, 0, 0}, -- {148352000, 148352000, 1, 98, 1, 1, 1, 1, 2, 2, 2, 0, 0xE6AE6B}, -- {148500000, 148500000, 1, 99, 1, 1, 1, 1, 2, 2, 2, 0, 0}, -- {148352000, 185440000, 4, 494, 0, 2, 2, 1, 3, 2, 2, 0, 0x816817}, -- {148500000, 185625000, 4, 495, 0, 2, 2, 1, 3, 2, 2, 0, 0}, -- {296703000, 296703000, 1, 98, 0, 1, 1, 1, 0, 2, 2, 0, 0xE6AE6B}, -- {297000000, 297000000, 1, 99, 0, 1, 1, 1, 0, 2, 2, 0, 0}, -- {296703000, 370878750, 4, 494, 1, 2, 0, 1, 3, 1, 1, 0, 0x816817}, -- {297000000, 371250000, 4, 495, 1, 2, 0, 1, 3, 1, 1, 0, 0}, -- {593407000, 296703500, 1, 98, 0, 1, 1, 1, 0, 2, 1, 0, 0xE6AE6B}, -- {594000000, 297000000, 1, 99, 0, 1, 1, 1, 0, 2, 1, 0, 0}, -- {593407000, 370879375, 4, 494, 1, 2, 0, 1, 3, 1, 1, 1, 0x816817}, -- {594000000, 371250000, 4, 495, 1, 2, 0, 1, 3, 1, 1, 1, 0}, -- {593407000, 593407000, 1, 98, 0, 2, 0, 1, 0, 1, 1, 0, 0xE6AE6B}, -- {594000000, 594000000, 1, 99, 0, 2, 0, 1, 0, 1, 1, 0, 0}, -+ { 27000000, 27000000, 1, 90, 3, 2, 2, 10, 3, 3, 4, 0, 0}, -+ { 27000000, 33750000, 1, 90, 1, 3, 3, 10, 3, 3, 4, 0, 0}, -+ { 40000000, 40000000, 1, 80, 2, 2, 2, 12, 2, 2, 2, 0, 0}, -+ { 40000000, 50000000, 1, 100, 2, 2, 2, 1, 0, 0, 15, 0, 0}, -+ { 59341000, 59341000, 1, 98, 3, 1, 2, 1, 3, 3, 4, 0, 0xE6AE6B}, -+ { 59400000, 59400000, 1, 99, 3, 1, 1, 1, 3, 3, 4, 0, 0}, -+ { 59341000, 74176250, 1, 98, 0, 3, 3, 1, 3, 3, 4, 0, 0xE6AE6B}, -+ { 59400000, 74250000, 1, 99, 1, 2, 2, 1, 3, 3, 4, 0, 0}, -+ { 65000000, 65000000, 1, 130, 2, 2, 2, 1, 0, 0, 12, 0, 0}, -+ { 65000000, 81250000, 3, 325, 0, 3, 3, 1, 0, 0, 10, 0, 0}, -+ { 71000000, 71000000, 3, 284, 0, 3, 3, 1, 0, 0, 8, 0, 0}, -+ { 71000000, 88750000, 3, 355, 0, 3, 3, 1, 0, 0, 10, 0, 0}, -+ { 74176000, 74176000, 1, 98, 1, 2, 2, 1, 2, 3, 4, 0, 0xE6AE6B}, -+ { 74250000, 74250000, 1, 99, 1, 2, 2, 1, 2, 3, 4, 0, 0}, -+ { 74176000, 92720000, 4, 494, 1, 2, 2, 1, 3, 3, 4, 0, 0x816817}, -+ { 74250000, 92812500, 4, 495, 1, 2, 2, 1, 3, 3, 4, 0, 0}, -+ { 83500000, 83500000, 2, 167, 2, 1, 1, 1, 0, 0, 6, 0, 0}, -+ { 83500000, 104375000, 1, 104, 2, 1, 1, 1, 1, 0, 5, 0, 0x600000}, -+ { 85750000, 85750000, 3, 343, 0, 3, 3, 1, 0, 0, 8, 0, 0}, -+ { 88750000, 88750000, 3, 355, 0, 3, 3, 1, 0, 0, 8, 0, 0}, -+ { 88750000, 110937500, 1, 110, 2, 1, 1, 1, 1, 0, 5, 0, 0xF00000}, -+ {108000000, 108000000, 1, 90, 3, 0, 0, 1, 0, 0, 5, 0, 0}, -+ {108000000, 135000000, 1, 90, 0, 2, 2, 1, 0, 0, 5, 0, 0}, -+ {119000000, 119000000, 1, 119, 2, 1, 1, 1, 0, 0, 6, 0, 0}, -+ {119000000, 148750000, 1, 99, 0, 2, 2, 1, 0, 0, 5, 0, 0x2AAAAA}, -+ {148352000, 148352000, 1, 98, 1, 1, 1, 1, 2, 2, 2, 0, 0xE6AE6B}, -+ {148500000, 148500000, 1, 99, 1, 1, 1, 1, 2, 2, 2, 0, 0}, -+ {148352000, 185440000, 4, 494, 0, 2, 2, 1, 3, 2, 2, 0, 0x816817}, -+ {148500000, 185625000, 4, 495, 0, 2, 2, 1, 3, 2, 2, 0, 0}, -+ {162000000, 162000000, 1, 108, 0, 2, 2, 1, 0, 0, 4, 0, 0}, -+ {162000000, 202500000, 1, 135, 0, 2, 2, 1, 0, 0, 5, 0, 0}, -+ {296703000, 296703000, 1, 98, 0, 1, 1, 1, 0, 2, 2, 0, 0xE6AE6B}, -+ {297000000, 297000000, 1, 99, 0, 1, 1, 1, 0, 2, 2, 0, 0}, -+ {296703000, 370878750, 4, 494, 1, 2, 0, 1, 3, 1, 1, 0, 0x816817}, -+ {297000000, 371250000, 4, 495, 1, 2, 0, 1, 3, 1, 1, 0, 0}, -+ {593407000, 296703500, 1, 98, 0, 1, 1, 1, 0, 2, 1, 0, 0xE6AE6B}, -+ {594000000, 297000000, 1, 99, 0, 1, 1, 1, 0, 2, 1, 0, 0}, -+ {593407000, 370879375, 4, 494, 1, 2, 0, 1, 3, 1, 1, 1, 0x816817}, -+ {594000000, 371250000, 4, 495, 1, 2, 0, 1, 3, 1, 1, 1, 0}, -+ {593407000, 593407000, 1, 98, 0, 2, 0, 1, 0, 1, 1, 0, 0xE6AE6B}, -+ {594000000, 594000000, 1, 99, 0, 2, 0, 1, 0, 1, 1, 0, 0}, - { /* sentinel */ } - }; - --- -2.17.1 - - -From e63e0475c82b77a9e255b1dd354df20e02a73390 Mon Sep 17 00:00:00 2001 -From: Jonas Karlman -Date: Fri, 20 Dec 2019 08:12:43 +0000 -Subject: [PATCH] WIP: drm/bridge: dw-hdmi: limit mode and bus format to - max_tmds_clock - ---- - drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 121 ++++++++++++++-------- - 1 file changed, 78 insertions(+), 43 deletions(-) - -diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c -index cc39b544ae6e..66e3fed23f4b 100644 ---- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c -+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c -@@ -1854,6 +1854,21 @@ static void hdmi_config_drm_infoframe(struct dw_hdmi *hdmi) - HDMI_FC_PACKET_TX_EN_DRM_MASK, HDMI_FC_PACKET_TX_EN); - } - -+static unsigned int -+hdmi_get_tmdsclock(unsigned int bus_format, unsigned int pixelclock) -+{ -+ int color_depth = hdmi_bus_fmt_color_depth(bus_format); -+ unsigned int tmdsclock = pixelclock; -+ -+ if (!hdmi_bus_fmt_is_yuv422(bus_format) && color_depth > 8) -+ tmdsclock = (u64)pixelclock * color_depth / 8; -+ -+ if (hdmi_bus_fmt_is_yuv420(bus_format)) -+ tmdsclock /= 2; -+ -+ return tmdsclock; -+} -+ - static void hdmi_av_composer(struct dw_hdmi *hdmi, - const struct drm_display_mode *mode) - { -@@ -1863,28 +1878,12 @@ static void hdmi_av_composer(struct dw_hdmi *hdmi, - int hblank, vblank, h_de_hs, v_de_vs, hsync_len, vsync_len; - unsigned int vdisplay, hdisplay; - -- vmode->mtmdsclock = vmode->mpixelclock = mode->clock * 1000; -+ vmode->mpixelclock = mode->clock * 1000; -+ vmode->mtmdsclock = -+ hdmi_get_tmdsclock(hdmi->hdmi_data.enc_out_bus_format, -+ vmode->mpixelclock); - - dev_dbg(hdmi->dev, "final pixclk = %d\n", vmode->mpixelclock); -- -- if (!hdmi_bus_fmt_is_yuv422(hdmi->hdmi_data.enc_out_bus_format)) { -- switch (hdmi_bus_fmt_color_depth( -- hdmi->hdmi_data.enc_out_bus_format)) { -- case 16: -- vmode->mtmdsclock = (u64)vmode->mpixelclock * 2; -- break; -- case 12: -- vmode->mtmdsclock = (u64)vmode->mpixelclock * 3 / 2; -- break; -- case 10: -- vmode->mtmdsclock = (u64)vmode->mpixelclock * 5 / 4; -- break; -- } -- } -- -- if (hdmi_bus_fmt_is_yuv420(hdmi->hdmi_data.enc_out_bus_format)) -- vmode->mtmdsclock /= 2; -- - dev_dbg(hdmi->dev, "final tmdsclk = %d\n", vmode->mtmdsclock); - - /* Set up HDMI_FC_INVIDCONF */ -@@ -2511,8 +2510,21 @@ static const struct drm_connector_helper_funcs dw_hdmi_connector_helper_funcs = - * - MEDIA_BUS_FMT_RGB888_1X24, - */ - --/* Can return a maximum of 12 possible output formats for a mode/connector */ --#define MAX_OUTPUT_SEL_FORMATS 12 -+static bool is_tmds_allowed(struct drm_display_info *info, -+ struct drm_display_mode *mode, -+ u32 bus_format) -+{ -+ unsigned long tmdsclock = hdmi_get_tmdsclock(bus_format, mode->clock); -+ int max_tmds_clock = max(info->max_tmds_clock, 165000); -+ -+ if (max_tmds_clock >= tmdsclock) -+ return true; -+ -+ return false; -+} -+ -+/* Can return a maximum of 16 possible output formats for a mode/connector */ -+#define MAX_OUTPUT_SEL_FORMATS 16 - - static u32 *dw_hdmi_bridge_atomic_get_output_bus_fmts(struct drm_bridge *bridge, - struct drm_bridge_state *bridge_state, -@@ -2524,8 +2536,6 @@ static u32 *dw_hdmi_bridge_atomic_get_output_bus_fmts(struct drm_bridge *bridge, - struct drm_display_info *info = &conn->display_info; - struct drm_display_mode *mode = &crtc_state->mode; - u8 max_bpc = conn_state->max_requested_bpc; -- bool is_hdmi2_sink = info->hdmi.scdc.supported || -- (info->color_formats & DRM_COLOR_FORMAT_YCRCB420); - u32 *output_fmts; - int i = 0; - -@@ -2540,29 +2550,33 @@ static u32 *dw_hdmi_bridge_atomic_get_output_bus_fmts(struct drm_bridge *bridge, - * If the current mode enforces 4:2:0, force the output but format - * to 4:2:0 and do not add the YUV422/444/RGB formats - */ -- if (conn->ycbcr_420_allowed && -- (drm_mode_is_420_only(info, mode) || -- (is_hdmi2_sink && drm_mode_is_420_also(info, mode)))) { -+ if (conn->ycbcr_420_allowed && drm_mode_is_420(info, mode) && -+ (info->color_formats & DRM_COLOR_FORMAT_YCRCB420)) { - - /* Order bus formats from 16bit to 8bit if supported */ - if (max_bpc >= 16 && info->bpc == 16 && -- (info->hdmi.y420_dc_modes & DRM_EDID_YCBCR420_DC_48)) -+ (info->hdmi.y420_dc_modes & DRM_EDID_YCBCR420_DC_48) && -+ is_tmds_allowed(info, mode, MEDIA_BUS_FMT_UYYVYY16_0_5X48)) - output_fmts[i++] = MEDIA_BUS_FMT_UYYVYY16_0_5X48; - - if (max_bpc >= 12 && info->bpc >= 12 && -- (info->hdmi.y420_dc_modes & DRM_EDID_YCBCR420_DC_36)) -+ (info->hdmi.y420_dc_modes & DRM_EDID_YCBCR420_DC_36) && -+ is_tmds_allowed(info, mode, MEDIA_BUS_FMT_UYYVYY12_0_5X36)) - output_fmts[i++] = MEDIA_BUS_FMT_UYYVYY12_0_5X36; - - if (max_bpc >= 10 && info->bpc >= 10 && -- (info->hdmi.y420_dc_modes & DRM_EDID_YCBCR420_DC_30)) -+ (info->hdmi.y420_dc_modes & DRM_EDID_YCBCR420_DC_30) && -+ is_tmds_allowed(info, mode, MEDIA_BUS_FMT_UYYVYY10_0_5X30)) - output_fmts[i++] = MEDIA_BUS_FMT_UYYVYY10_0_5X30; - - /* Default 8bit fallback */ -- output_fmts[i++] = MEDIA_BUS_FMT_UYYVYY8_0_5X24; -+ if (is_tmds_allowed(info, mode, MEDIA_BUS_FMT_UYYVYY8_0_5X24)) -+ output_fmts[i++] = MEDIA_BUS_FMT_UYYVYY8_0_5X24; - - *num_output_fmts = i; - -- return output_fmts; -+ if (drm_mode_is_420_only(info, mode)) -+ return output_fmts; - } - - /* -@@ -2571,40 +2585,51 @@ static u32 *dw_hdmi_bridge_atomic_get_output_bus_fmts(struct drm_bridge *bridge, - */ - - if (max_bpc >= 16 && info->bpc == 16) { -- if (info->color_formats & DRM_COLOR_FORMAT_YCRCB444) -+ if ((info->color_formats & DRM_COLOR_FORMAT_YCRCB444) && -+ is_tmds_allowed(info, mode, MEDIA_BUS_FMT_YUV16_1X48)) - output_fmts[i++] = MEDIA_BUS_FMT_YUV16_1X48; - -- output_fmts[i++] = MEDIA_BUS_FMT_RGB161616_1X48; -+ if (is_tmds_allowed(info, mode, MEDIA_BUS_FMT_RGB161616_1X48)) -+ output_fmts[i++] = MEDIA_BUS_FMT_RGB161616_1X48; - } - - if (max_bpc >= 12 && info->bpc >= 12) { -- if (info->color_formats & DRM_COLOR_FORMAT_YCRCB422) -+ if ((info->color_formats & DRM_COLOR_FORMAT_YCRCB422) && -+ is_tmds_allowed(info, mode, MEDIA_BUS_FMT_UYVY12_1X24)) - output_fmts[i++] = MEDIA_BUS_FMT_UYVY12_1X24; - -- if (info->color_formats & DRM_COLOR_FORMAT_YCRCB444) -+ if ((info->color_formats & DRM_COLOR_FORMAT_YCRCB444) && -+ is_tmds_allowed(info, mode, MEDIA_BUS_FMT_YUV12_1X36)) - output_fmts[i++] = MEDIA_BUS_FMT_YUV12_1X36; - -- output_fmts[i++] = MEDIA_BUS_FMT_RGB121212_1X36; -+ if (is_tmds_allowed(info, mode, MEDIA_BUS_FMT_RGB121212_1X36)) -+ output_fmts[i++] = MEDIA_BUS_FMT_RGB121212_1X36; - } - - if (max_bpc >= 10 && info->bpc >= 10) { -- if (info->color_formats & DRM_COLOR_FORMAT_YCRCB422) -+ if ((info->color_formats & DRM_COLOR_FORMAT_YCRCB422) && -+ is_tmds_allowed(info, mode, MEDIA_BUS_FMT_UYVY10_1X20)) - output_fmts[i++] = MEDIA_BUS_FMT_UYVY10_1X20; - -- if (info->color_formats & DRM_COLOR_FORMAT_YCRCB444) -+ if ((info->color_formats & DRM_COLOR_FORMAT_YCRCB444) && -+ is_tmds_allowed(info, mode, MEDIA_BUS_FMT_YUV10_1X30)) - output_fmts[i++] = MEDIA_BUS_FMT_YUV10_1X30; - -- output_fmts[i++] = MEDIA_BUS_FMT_RGB101010_1X30; -+ if (is_tmds_allowed(info, mode, MEDIA_BUS_FMT_RGB101010_1X30)) -+ output_fmts[i++] = MEDIA_BUS_FMT_RGB101010_1X30; - } - -- if (info->color_formats & DRM_COLOR_FORMAT_YCRCB422) -+ if ((info->color_formats & DRM_COLOR_FORMAT_YCRCB422) && -+ is_tmds_allowed(info, mode, MEDIA_BUS_FMT_UYVY8_1X16)) - output_fmts[i++] = MEDIA_BUS_FMT_UYVY8_1X16; - -- if (info->color_formats & DRM_COLOR_FORMAT_YCRCB444) -+ if ((info->color_formats & DRM_COLOR_FORMAT_YCRCB444) && -+ is_tmds_allowed(info, mode, MEDIA_BUS_FMT_YUV8_1X24)) - output_fmts[i++] = MEDIA_BUS_FMT_YUV8_1X24; - - /* Default 8bit RGB fallback */ -- output_fmts[i++] = MEDIA_BUS_FMT_RGB888_1X24; -+ if (is_tmds_allowed(info, mode, MEDIA_BUS_FMT_RGB888_1X24)) -+ output_fmts[i++] = MEDIA_BUS_FMT_RGB888_1X24; - - *num_output_fmts = i; - -@@ -2811,12 +2836,22 @@ dw_hdmi_bridge_mode_valid(struct drm_bridge *bridge, - { - struct dw_hdmi *hdmi = bridge->driver_private; - struct drm_connector *connector = &hdmi->connector; -+ struct drm_display_info *info = &connector->display_info; - enum drm_mode_status mode_status = MODE_OK; -+ int max_tmds_clock = max(info->max_tmds_clock, 165000); -+ int clock = mode->clock; - - /* We don't support double-clocked modes */ - if (mode->flags & DRM_MODE_FLAG_DBLCLK) - return MODE_BAD; - -+ if (connector->ycbcr_420_allowed && drm_mode_is_420(info, mode) && -+ (info->color_formats & DRM_COLOR_FORMAT_YCRCB420)) -+ clock /= 2; -+ -+ if (clock > max_tmds_clock) -+ return MODE_CLOCK_HIGH; -+ - if (hdmi->plat_data->mode_valid) - mode_status = hdmi->plat_data->mode_valid(connector, mode); - --- -2.17.1 - - -From 5c3bbae0afe43b4856b9c9e344bb7eea3702e4f0 Mon Sep 17 00:00:00 2001 -From: Jonas Karlman -Date: Sat, 21 Dec 2019 06:23:52 +0000 -Subject: [PATCH] WIP: drm/bridge: dw-hdmi: do not enable csc for yuv2yuv - ---- - drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 12 +++++++++++- - 1 file changed, 11 insertions(+), 1 deletion(-) - -diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c -index 66e3fed23f4b..df1789cd8712 100644 ---- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c -+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c -@@ -966,6 +966,14 @@ static void hdmi_video_sample(struct dw_hdmi *hdmi) - - static int is_color_space_conversion(struct dw_hdmi *hdmi) - { -+ if (hdmi_bus_fmt_is_yuv444(hdmi->hdmi_data.enc_in_bus_format) && -+ hdmi_bus_fmt_is_yuv422(hdmi->hdmi_data.enc_out_bus_format)) -+ return 0; -+ -+ if (hdmi_bus_fmt_is_yuv422(hdmi->hdmi_data.enc_in_bus_format) && -+ hdmi_bus_fmt_is_yuv444(hdmi->hdmi_data.enc_out_bus_format)) -+ return 0; -+ - return hdmi->hdmi_data.enc_in_bus_format != hdmi->hdmi_data.enc_out_bus_format; - } - -@@ -2050,7 +2058,9 @@ static void dw_hdmi_enable_video_path(struct dw_hdmi *hdmi) - hdmi_writeb(hdmi, hdmi->mc_clkdis, HDMI_MC_CLKDIS); - - /* Enable csc path */ -- if (is_color_space_conversion(hdmi)) { -+ if (is_color_space_conversion(hdmi) || -+ is_color_space_decimation(hdmi) || -+ is_color_space_interpolation(hdmi)) { - hdmi->mc_clkdis &= ~HDMI_MC_CLKDIS_CSCCLK_DISABLE; - hdmi_writeb(hdmi, hdmi->mc_clkdis, HDMI_MC_CLKDIS); - } --- -2.17.1 - - -From fd86f78d28a4b6c5fc7440e42916f3f86a7797a4 Mon Sep 17 00:00:00 2001 -From: Jonas Karlman -Date: Fri, 20 Dec 2019 08:12:42 +0000 -Subject: [PATCH] drm/rockchip: dw-hdmi: add bridge and switch to - drm_bridge_funcs - -Switch the dw-hdmi driver to drm_bridge_funcs by implementing -a new local bridge, connecting it to the dw-hdmi bridge. - -Signed-off-by: Jonas Karlman ---- - drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 65 ++++++++++----------- - 1 file changed, 31 insertions(+), 34 deletions(-) - -diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c -index a813299e97a2..8bc42090d0a3 100644 ---- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c -+++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c -@@ -67,6 +67,7 @@ struct rockchip_hdmi { - struct device *dev; - struct regmap *regmap; - struct drm_encoder encoder; -+ struct drm_bridge bridge; - const struct rockchip_hdmi_chip_data *chip_data; - struct clk *vpll_clk; - struct clk *grf_clk; -@@ -259,15 +260,11 @@ static const struct drm_encoder_funcs dw_hdmi_rockchip_encoder_funcs = { - .destroy = drm_encoder_cleanup, - }; - --static void dw_hdmi_rockchip_encoder_disable(struct drm_encoder *encoder) --{ --} -- - static enum drm_mode_status --dw_hdmi_rockchip_encoder_mode_valid(struct drm_encoder *encoder, -- const struct drm_display_mode *mode) -+dw_hdmi_rockchip_bridge_mode_valid(struct drm_bridge *bridge, -+ const struct drm_display_mode *mode) - { -- struct rockchip_hdmi *hdmi = to_rockchip_hdmi(encoder); -+ struct rockchip_hdmi *hdmi = to_rockchip_hdmi(bridge); - long rate; - - if (hdmi->vpll_clk) { -@@ -279,26 +276,20 @@ dw_hdmi_rockchip_encoder_mode_valid(struct drm_encoder *encoder, - return MODE_OK; - } - --static bool --dw_hdmi_rockchip_encoder_mode_fixup(struct drm_encoder *encoder, -- const struct drm_display_mode *mode, -- struct drm_display_mode *adj_mode) --{ -- return true; --} -- --static void dw_hdmi_rockchip_encoder_mode_set(struct drm_encoder *encoder, -- struct drm_display_mode *mode, -- struct drm_display_mode *adj_mode) -+static void -+dw_hdmi_rockchip_bridge_mode_set(struct drm_bridge *bridge, -+ const struct drm_display_mode *mode, -+ const struct drm_display_mode *adjusted_mode) - { -- struct rockchip_hdmi *hdmi = to_rockchip_hdmi(encoder); -+ struct rockchip_hdmi *hdmi = to_rockchip_hdmi(bridge); - -- clk_set_rate(hdmi->vpll_clk, adj_mode->clock * 1000); -+ clk_set_rate(hdmi->vpll_clk, adjusted_mode->clock * 1000); - } - --static void dw_hdmi_rockchip_encoder_enable(struct drm_encoder *encoder) -+static void dw_hdmi_rockchip_bridge_enable(struct drm_bridge *bridge) - { -- struct rockchip_hdmi *hdmi = to_rockchip_hdmi(encoder); -+ struct rockchip_hdmi *hdmi = to_rockchip_hdmi(bridge); -+ struct drm_encoder *encoder = bridge->encoder; - u32 val; - int ret; - -@@ -327,9 +318,10 @@ static void dw_hdmi_rockchip_encoder_enable(struct drm_encoder *encoder) - } - - static int --dw_hdmi_rockchip_encoder_atomic_check(struct drm_encoder *encoder, -- struct drm_crtc_state *crtc_state, -- struct drm_connector_state *conn_state) -+dw_hdmi_rockchip_bridge_atomic_check(struct drm_bridge *bridge, -+ struct drm_bridge_state *bridge_state, -+ struct drm_crtc_state *crtc_state, -+ struct drm_connector_state *conn_state) - { - struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc_state); - -@@ -339,13 +331,11 @@ dw_hdmi_rockchip_encoder_atomic_check(struct drm_encoder *encoder, - return 0; - } - --static const struct drm_encoder_helper_funcs dw_hdmi_rockchip_encoder_helper_funcs = { -- .mode_valid = dw_hdmi_rockchip_encoder_mode_valid, -- .mode_fixup = dw_hdmi_rockchip_encoder_mode_fixup, -- .mode_set = dw_hdmi_rockchip_encoder_mode_set, -- .enable = dw_hdmi_rockchip_encoder_enable, -- .disable = dw_hdmi_rockchip_encoder_disable, -- .atomic_check = dw_hdmi_rockchip_encoder_atomic_check, -+static const struct drm_bridge_funcs dw_hdmi_rockchip_bridge_funcs = { -+ .mode_valid = dw_hdmi_rockchip_bridge_mode_valid, -+ .mode_set = dw_hdmi_rockchip_bridge_mode_set, -+ .enable = dw_hdmi_rockchip_bridge_enable, -+ .atomic_check = dw_hdmi_rockchip_bridge_atomic_check, - }; - - static int dw_hdmi_rockchip_genphy_init(struct dw_hdmi *dw_hdmi, void *data, -@@ -523,6 +513,7 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master, - struct dw_hdmi_plat_data *plat_data; - const struct of_device_id *match; - struct drm_device *drm = data; -+ struct drm_bridge *next_bridge; - struct drm_encoder *encoder; - struct rockchip_hdmi *hdmi; - int ret; -@@ -576,13 +567,15 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master, - return ret; - } - -- drm_encoder_helper_add(encoder, &dw_hdmi_rockchip_encoder_helper_funcs); - drm_encoder_init(drm, encoder, &dw_hdmi_rockchip_encoder_funcs, - DRM_MODE_ENCODER_TMDS, NULL); - -+ hdmi->bridge.funcs = &dw_hdmi_rockchip_bridge_funcs; -+ drm_bridge_attach(encoder, &hdmi->bridge, NULL); -+ - platform_set_drvdata(pdev, hdmi); - -- hdmi->hdmi = dw_hdmi_bind(pdev, encoder, plat_data); -+ hdmi->hdmi = dw_hdmi_probe(pdev, plat_data); - - /* - * If dw_hdmi_bind() fails we'll never call dw_hdmi_unbind(), -@@ -594,6 +587,10 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master, - clk_disable_unprepare(hdmi->vpll_clk); - } - -+ next_bridge = of_drm_find_bridge(pdev->dev.of_node); -+ if (next_bridge) -+ drm_bridge_attach(encoder, next_bridge, &hdmi->bridge); -+ - return ret; - } - --- -2.17.1 - - -From 1e915225fe362b6ab98bec9bc71c62315347eccb Mon Sep 17 00:00:00 2001 -From: Jonas Karlman -Date: Fri, 20 Dec 2019 08:12:42 +0000 -Subject: [PATCH] drm/rockchip: dw-hdmi: enable bridge bus format negotiation - -Enable bridge format negotiation by implementing -atomic_get_input_bus_fmts and support for 8-bit RGB 4:4:4. - -Signed-off-by: Jonas Karlman ---- - drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 35 +++++++++++++++++++++ - 1 file changed, 35 insertions(+) - -diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c -index 8bc42090d0a3..83a22a061e52 100644 ---- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c -+++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c -@@ -317,6 +317,16 @@ static void dw_hdmi_rockchip_bridge_enable(struct drm_bridge *bridge) - ret ? "LIT" : "BIG"); - } - -+static bool is_rgb(u32 format) -+{ -+ switch (format) { -+ case MEDIA_BUS_FMT_RGB888_1X24: -+ return true; -+ default: -+ return false; -+ } -+} -+ - static int - dw_hdmi_rockchip_bridge_atomic_check(struct drm_bridge *bridge, - struct drm_bridge_state *bridge_state, -@@ -331,11 +341,36 @@ dw_hdmi_rockchip_bridge_atomic_check(struct drm_bridge *bridge, - return 0; - } - -+static u32 *dw_hdmi_rockchip_get_input_bus_fmts(struct drm_bridge *bridge, -+ struct drm_bridge_state *bridge_state, -+ struct drm_crtc_state *crtc_state, -+ struct drm_connector_state *conn_state, -+ u32 output_fmt, -+ unsigned int *num_input_fmts) -+{ -+ u32 *input_fmt; -+ -+ *num_input_fmts = 0; -+ -+ if (!is_rgb(output_fmt)) -+ return NULL; -+ -+ input_fmt = kzalloc(sizeof(*input_fmt), GFP_KERNEL); -+ if (!input_fmt) -+ return NULL; -+ -+ *num_input_fmts = 1; -+ *input_fmt = output_fmt; -+ -+ return input_fmt; -+} -+ - static const struct drm_bridge_funcs dw_hdmi_rockchip_bridge_funcs = { - .mode_valid = dw_hdmi_rockchip_bridge_mode_valid, - .mode_set = dw_hdmi_rockchip_bridge_mode_set, - .enable = dw_hdmi_rockchip_bridge_enable, - .atomic_check = dw_hdmi_rockchip_bridge_atomic_check, -+ .atomic_get_input_bus_fmts = dw_hdmi_rockchip_get_input_bus_fmts, - }; - - static int dw_hdmi_rockchip_genphy_init(struct dw_hdmi *dw_hdmi, void *data, --- -2.17.1 - - -From b4cbb8eae8f3a5dbdbb844d59dfd7c979a88f66a Mon Sep 17 00:00:00 2001 -From: Jonas Karlman -Date: Fri, 20 Dec 2019 08:12:42 +0000 -Subject: [PATCH] WIP: drm/rockchip: dw_hdmi: add 10-bit rgb bus format - ---- - drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 41 +++++++++++++++++++++ - drivers/gpu/drm/rockchip/rockchip_drm_drv.h | 2 + - drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 10 ++++- - 3 files changed, 52 insertions(+), 1 deletion(-) - -diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c -index 83a22a061e52..3c8a95cd38dc 100644 ---- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c -+++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c -@@ -76,6 +76,7 @@ struct rockchip_hdmi { - }; - - #define to_rockchip_hdmi(x) container_of(x, struct rockchip_hdmi, x) -+#define to_crtc_state(x) container_of(x, struct drm_crtc_state, x) - - static const struct dw_hdmi_mpll_config rockchip_mpll_cfg[] = { - { -@@ -282,6 +283,11 @@ dw_hdmi_rockchip_bridge_mode_set(struct drm_bridge *bridge, - const struct drm_display_mode *adjusted_mode) - { - struct rockchip_hdmi *hdmi = to_rockchip_hdmi(bridge); -+ struct drm_crtc_state *crtc_state = to_crtc_state(adjusted_mode); -+ struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc_state); -+ -+ if (hdmi->phy) -+ phy_set_bus_width(hdmi->phy, s->bus_width); - - clk_set_rate(hdmi->vpll_clk, adjusted_mode->clock * 1000); - } -@@ -320,6 +326,7 @@ static void dw_hdmi_rockchip_bridge_enable(struct drm_bridge *bridge) - static bool is_rgb(u32 format) - { - switch (format) { -+ case MEDIA_BUS_FMT_RGB101010_1X30: - case MEDIA_BUS_FMT_RGB888_1X24: - return true; - default: -@@ -327,6 +334,16 @@ static bool is_rgb(u32 format) - } - } - -+static bool is_10bit(u32 format) -+{ -+ switch (format) { -+ case MEDIA_BUS_FMT_RGB101010_1X30: -+ return true; -+ default: -+ return false; -+ } -+} -+ - static int - dw_hdmi_rockchip_bridge_atomic_check(struct drm_bridge *bridge, - struct drm_bridge_state *bridge_state, -@@ -334,9 +351,24 @@ dw_hdmi_rockchip_bridge_atomic_check(struct drm_bridge *bridge, - struct drm_connector_state *conn_state) - { - struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc_state); -+ struct drm_atomic_state *state = bridge_state->base.state; -+ struct drm_crtc_state *old_crtc_state; -+ struct rockchip_crtc_state *old_state; -+ u32 format = bridge_state->output_bus_cfg.format; - - s->output_mode = ROCKCHIP_OUT_MODE_AAAA; - s->output_type = DRM_MODE_CONNECTOR_HDMIA; -+ s->output_bpc = 10; -+ s->bus_format = format; -+ s->bus_width = is_10bit(format) ? 10 : 8; -+ -+ old_crtc_state = drm_atomic_get_old_crtc_state(state, conn_state->crtc); -+ if (old_crtc_state && !crtc_state->mode_changed) { -+ old_state = to_rockchip_crtc_state(old_crtc_state); -+ if (s->bus_format != old_state->bus_format || -+ s->bus_width != old_state->bus_width) -+ crtc_state->mode_changed = true; -+ } - - return 0; - } -@@ -348,10 +380,19 @@ static u32 *dw_hdmi_rockchip_get_input_bus_fmts(struct drm_bridge *bridge, - u32 output_fmt, - unsigned int *num_input_fmts) - { -+ struct rockchip_hdmi *hdmi = to_rockchip_hdmi(bridge); -+ struct drm_encoder *encoder = bridge->encoder; - u32 *input_fmt; -+ bool has_10bit = true; - - *num_input_fmts = 0; - -+ if (drm_of_encoder_active_endpoint_id(hdmi->dev->of_node, encoder)) -+ has_10bit = false; -+ -+ if (!has_10bit && is_10bit(output_fmt)) -+ return NULL; -+ - if (!is_rgb(output_fmt)) - return NULL; - -diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h -index c5b06048124e..af1b85d8f7ee 100644 ---- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h -+++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h -@@ -30,6 +30,8 @@ struct rockchip_crtc_state { - int output_mode; - int output_bpc; - int output_flags; -+ u32 bus_format; -+ int bus_width; - }; - #define to_rockchip_crtc_state(s) \ - container_of(s, struct rockchip_crtc_state, base) -diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c -index f181897cbfad..e59213d3ea62 100644 ---- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c -+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c -@@ -1402,13 +1402,21 @@ static void vop_crtc_destroy(struct drm_crtc *crtc) - - static struct drm_crtc_state *vop_crtc_duplicate_state(struct drm_crtc *crtc) - { -- struct rockchip_crtc_state *rockchip_state; -+ struct rockchip_crtc_state *rockchip_state, *s; -+ -+ if (WARN_ON(!crtc->state)) -+ return NULL; - - rockchip_state = kzalloc(sizeof(*rockchip_state), GFP_KERNEL); - if (!rockchip_state) - return NULL; - - __drm_atomic_helper_crtc_duplicate_state(crtc, &rockchip_state->base); -+ -+ s = to_rockchip_crtc_state(crtc->state); -+ rockchip_state->bus_format = s->bus_format; -+ rockchip_state->bus_width = s->bus_width; -+ - return &rockchip_state->base; - } - --- -2.17.1 - - -From 9fedc6efc787bddfad71c6145cf3cbee49ea257d Mon Sep 17 00:00:00 2001 -From: Jonas Karlman -Date: Fri, 20 Dec 2019 08:12:43 +0000 -Subject: [PATCH] WIP: drm/rockchip: add yuv444 support - ---- - drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 29 ++++++++++++++++++++- - drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 29 +++++++++++++++++++++ - drivers/gpu/drm/rockchip/rockchip_drm_vop.h | 5 ++++ - drivers/gpu/drm/rockchip/rockchip_vop_reg.c | 10 +++++++ - 4 files changed, 72 insertions(+), 1 deletion(-) - -diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c -index 3c8a95cd38dc..9b3c2318ce0e 100644 ---- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c -+++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c -@@ -61,6 +61,7 @@ struct rockchip_hdmi_chip_data { - int lcdsel_grf_reg; - u32 lcdsel_big; - u32 lcdsel_lit; -+ bool ycbcr_444_allowed; - }; - - struct rockchip_hdmi { -@@ -334,10 +335,22 @@ static bool is_rgb(u32 format) - } - } - -+static bool is_yuv444(u32 format) -+{ -+ switch (format) { -+ case MEDIA_BUS_FMT_YUV10_1X30: -+ case MEDIA_BUS_FMT_YUV8_1X24: -+ return true; -+ default: -+ return false; -+ } -+} -+ - static bool is_10bit(u32 format) - { - switch (format) { - case MEDIA_BUS_FMT_RGB101010_1X30: -+ case MEDIA_BUS_FMT_YUV10_1X30: - return true; - default: - return false; -@@ -354,12 +367,22 @@ dw_hdmi_rockchip_bridge_atomic_check(struct drm_bridge *bridge, - struct drm_atomic_state *state = bridge_state->base.state; - struct drm_crtc_state *old_crtc_state; - struct rockchip_crtc_state *old_state; -+ struct drm_bridge *next_bridge; -+ struct drm_bridge_state *next_bridge_state; - u32 format = bridge_state->output_bus_cfg.format; - - s->output_mode = ROCKCHIP_OUT_MODE_AAAA; - s->output_type = DRM_MODE_CONNECTOR_HDMIA; - s->output_bpc = 10; - s->bus_format = format; -+ -+ next_bridge = drm_bridge_get_next_bridge(bridge); -+ if (next_bridge) { -+ next_bridge_state = drm_atomic_get_new_bridge_state(state, -+ next_bridge); -+ format = next_bridge_state->output_bus_cfg.format; -+ } -+ - s->bus_width = is_10bit(format) ? 10 : 8; - - old_crtc_state = drm_atomic_get_old_crtc_state(state, conn_state->crtc); -@@ -393,7 +416,10 @@ static u32 *dw_hdmi_rockchip_get_input_bus_fmts(struct drm_bridge *bridge, - if (!has_10bit && is_10bit(output_fmt)) - return NULL; - -- if (!is_rgb(output_fmt)) -+ if (is_yuv444(output_fmt)) { -+ if (!hdmi->chip_data->ycbcr_444_allowed) -+ return NULL; -+ } else if (!is_rgb(output_fmt)) - return NULL; - - input_fmt = kzalloc(sizeof(*input_fmt), GFP_KERNEL); -@@ -539,6 +565,7 @@ static const struct dw_hdmi_phy_ops rk3328_hdmi_phy_ops = { - - static struct rockchip_hdmi_chip_data rk3328_chip_data = { - .lcdsel_grf_reg = -1, -+ .ycbcr_444_allowed = true, - }; - - static const struct dw_hdmi_plat_data rk3328_hdmi_drv_data = { -diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c -index e59213d3ea62..5bf833ea8ce2 100644 ---- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c -+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c -@@ -274,6 +274,17 @@ static enum vop_data_format vop_convert_format(uint32_t format) - } - } - -+static bool is_yuv_output(uint32_t bus_format) -+{ -+ switch (bus_format) { -+ case MEDIA_BUS_FMT_YUV8_1X24: -+ case MEDIA_BUS_FMT_YUV10_1X30: -+ return true; -+ default: -+ return false; -+ } -+} -+ - static uint16_t scl_vop_cal_scale(enum scale_mode mode, uint32_t src, - uint32_t dst, bool is_horizontal, - int vsu_mode, int *vskiplines) -@@ -1181,6 +1192,7 @@ static void vop_crtc_atomic_enable(struct drm_crtc *crtc, - u16 vact_end = vact_st + vdisplay; - uint32_t pin_pol, val; - int dither_bpc = s->output_bpc ? s->output_bpc : 10; -+ bool yuv_output = is_yuv_output(s->bus_format); - int ret; - - if (old_state && old_state->self_refresh_active) { -@@ -1254,6 +1266,8 @@ static void vop_crtc_atomic_enable(struct drm_crtc *crtc, - !(vop_data->feature & VOP_FEATURE_OUTPUT_RGB10)) - s->output_mode = ROCKCHIP_OUT_MODE_P888; - -+ VOP_REG_SET(vop, common, dsp_data_swap, yuv_output ? 2 : 0); -+ - if (s->output_mode == ROCKCHIP_OUT_MODE_AAAA && dither_bpc <= 8) - VOP_REG_SET(vop, common, pre_dither_down, 1); - else -@@ -1269,6 +1283,21 @@ static void vop_crtc_atomic_enable(struct drm_crtc *crtc, - - VOP_REG_SET(vop, common, out_mode, s->output_mode); - -+ VOP_REG_SET(vop, common, overlay_mode, yuv_output); -+ VOP_REG_SET(vop, common, dsp_out_yuv, yuv_output); -+ -+ /* -+ * Background color is 10bit depth if vop version >= 3.5 -+ */ -+ if (!yuv_output) -+ val = 0; -+ else if (VOP_MAJOR(vop_data->version) == 3 && -+ VOP_MINOR(vop_data->version) >= 5) -+ val = 0x20010200; -+ else -+ val = 0x801080; -+ VOP_REG_SET(vop, common, dsp_background, val); -+ - VOP_REG_SET(vop, modeset, htotal_pw, (htotal << 16) | hsync_len); - val = hact_st << 16; - val |= hact_end; -diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h -index 0b3d18c457b2..9393cf12b1db 100644 ---- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h -+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h -@@ -77,6 +77,11 @@ struct vop_common { - struct vop_reg mmu_en; - struct vop_reg out_mode; - struct vop_reg standby; -+ -+ struct vop_reg overlay_mode; -+ struct vop_reg dsp_data_swap; -+ struct vop_reg dsp_out_yuv; -+ struct vop_reg dsp_background; - }; - - struct vop_misc { -diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c -index 7a9d979c8d5d..b99e902d949e 100644 ---- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c -+++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c -@@ -606,6 +606,11 @@ static const struct vop_common rk3288_common = { - .dsp_blank = VOP_REG(RK3288_DSP_CTRL0, 0x3, 18), - .out_mode = VOP_REG(RK3288_DSP_CTRL0, 0xf, 0), - .cfg_done = VOP_REG_SYNC(RK3288_REG_CFG_DONE, 0x1, 0), -+ -+ .overlay_mode = VOP_REG(RK3288_SYS_CTRL, 0x1, 16), -+ .dsp_data_swap = VOP_REG(RK3288_DSP_CTRL0, 0x1f, 12), -+ .dsp_out_yuv = VOP_REG(RK3288_POST_SCL_CTRL, 0x1, 2), -+ .dsp_background = VOP_REG(RK3288_DSP_BG, 0xffffffff, 0), - }; - - /* -@@ -914,6 +919,11 @@ static const struct vop_common rk3328_common = { - .dsp_blank = VOP_REG(RK3328_DSP_CTRL0, 0x3, 18), - .out_mode = VOP_REG(RK3328_DSP_CTRL0, 0xf, 0), - .cfg_done = VOP_REG_SYNC(RK3328_REG_CFG_DONE, 0x1, 0), -+ -+ .overlay_mode = VOP_REG(RK3328_SYS_CTRL, 0x1, 16), -+ .dsp_data_swap = VOP_REG(RK3328_DSP_CTRL0, 0x1f, 12), -+ .dsp_out_yuv = VOP_REG(RK3328_POST_SCL_CTRL, 0x1, 2), -+ .dsp_background = VOP_REG(RK3328_DSP_BG, 0xffffffff, 0), - }; - - static const struct vop_intr rk3328_vop_intr = { --- -2.17.1 - - -From 111c35c19a742d7b76b6f548103f8b561c45a186 Mon Sep 17 00:00:00 2001 -From: Jonas Karlman -Date: Fri, 20 Dec 2019 08:12:43 +0000 -Subject: [PATCH] WIP: drm/rockchip: add yuv420 support - ---- - drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 22 +++++++++++++++++++++ - drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 18 ++++++++++++++++- - drivers/gpu/drm/rockchip/rockchip_drm_vop.h | 10 ++++++---- - drivers/gpu/drm/rockchip/rockchip_vop_reg.c | 2 ++ - 4 files changed, 47 insertions(+), 5 deletions(-) - -diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c -index 9b3c2318ce0e..eb405cb3d1f6 100644 ---- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c -+++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c -@@ -346,9 +346,21 @@ static bool is_yuv444(u32 format) - } - } - -+static bool is_yuv420(u32 format) -+{ -+ switch (format) { -+ case MEDIA_BUS_FMT_UYYVYY10_0_5X30: -+ case MEDIA_BUS_FMT_UYYVYY8_0_5X24: -+ return true; -+ default: -+ return false; -+ } -+} -+ - static bool is_10bit(u32 format) - { - switch (format) { -+ case MEDIA_BUS_FMT_UYYVYY10_0_5X30: - case MEDIA_BUS_FMT_RGB101010_1X30: - case MEDIA_BUS_FMT_YUV10_1X30: - return true; -@@ -385,6 +397,11 @@ dw_hdmi_rockchip_bridge_atomic_check(struct drm_bridge *bridge, - - s->bus_width = is_10bit(format) ? 10 : 8; - -+ if (is_yuv420(format)) { -+ s->output_mode = ROCKCHIP_OUT_MODE_YUV420; -+ s->bus_width /= 2; -+ } -+ - old_crtc_state = drm_atomic_get_old_crtc_state(state, conn_state->crtc); - if (old_crtc_state && !crtc_state->mode_changed) { - old_state = to_rockchip_crtc_state(old_crtc_state); -@@ -405,6 +422,7 @@ static u32 *dw_hdmi_rockchip_get_input_bus_fmts(struct drm_bridge *bridge, - { - struct rockchip_hdmi *hdmi = to_rockchip_hdmi(bridge); - struct drm_encoder *encoder = bridge->encoder; -+ struct drm_connector *connector = conn_state->connector; - u32 *input_fmt; - bool has_10bit = true; - -@@ -419,6 +437,9 @@ static u32 *dw_hdmi_rockchip_get_input_bus_fmts(struct drm_bridge *bridge, - if (is_yuv444(output_fmt)) { - if (!hdmi->chip_data->ycbcr_444_allowed) - return NULL; -+ } else if (is_yuv420(output_fmt)) { -+ if (!connector->ycbcr_420_allowed) -+ return NULL; - } else if (!is_rgb(output_fmt)) - return NULL; - -@@ -575,6 +596,7 @@ static const struct dw_hdmi_plat_data rk3328_hdmi_drv_data = { - .phy_name = "inno_dw_hdmi_phy2", - .phy_force_vendor = true, - .use_drm_infoframe = true, -+ .ycbcr_420_allowed = true, - }; - - static struct rockchip_hdmi_chip_data rk3399_chip_data = { -diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c -index 5bf833ea8ce2..b8c0d2fcc52a 100644 ---- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c -+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c -@@ -275,6 +275,19 @@ static enum vop_data_format vop_convert_format(uint32_t format) - } - - static bool is_yuv_output(uint32_t bus_format) -+{ -+ switch (bus_format) { -+ case MEDIA_BUS_FMT_YUV8_1X24: -+ case MEDIA_BUS_FMT_YUV10_1X30: -+ case MEDIA_BUS_FMT_UYYVYY8_0_5X24: -+ case MEDIA_BUS_FMT_UYYVYY10_0_5X30: -+ return true; -+ default: -+ return false; -+ } -+} -+ -+static bool has_uv_swapped(uint32_t bus_format) - { - switch (bus_format) { - case MEDIA_BUS_FMT_YUV8_1X24: -@@ -1266,7 +1279,7 @@ static void vop_crtc_atomic_enable(struct drm_crtc *crtc, - !(vop_data->feature & VOP_FEATURE_OUTPUT_RGB10)) - s->output_mode = ROCKCHIP_OUT_MODE_P888; - -- VOP_REG_SET(vop, common, dsp_data_swap, yuv_output ? 2 : 0); -+ VOP_REG_SET(vop, common, dsp_data_swap, has_uv_swapped(s->bus_format) ? 2 : 0); - - if (s->output_mode == ROCKCHIP_OUT_MODE_AAAA && dither_bpc <= 8) - VOP_REG_SET(vop, common, pre_dither_down, 1); -@@ -1283,6 +1296,9 @@ static void vop_crtc_atomic_enable(struct drm_crtc *crtc, - - VOP_REG_SET(vop, common, out_mode, s->output_mode); - -+ VOP_REG_SET(vop, common, dclk_ddr, -+ s->output_mode == ROCKCHIP_OUT_MODE_YUV420 ? 1 : 0); -+ - VOP_REG_SET(vop, common, overlay_mode, yuv_output); - VOP_REG_SET(vop, common, dsp_out_yuv, yuv_output); - -diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h -index 9393cf12b1db..89fe8d5c7721 100644 ---- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h -+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h -@@ -79,6 +79,7 @@ struct vop_common { - struct vop_reg standby; - - struct vop_reg overlay_mode; -+ struct vop_reg dclk_ddr; - struct vop_reg dsp_data_swap; - struct vop_reg dsp_out_yuv; - struct vop_reg dsp_background; -@@ -230,11 +231,12 @@ struct vop_data { - /* - * display output interface supported by rockchip lcdc - */ --#define ROCKCHIP_OUT_MODE_P888 0 --#define ROCKCHIP_OUT_MODE_P666 1 --#define ROCKCHIP_OUT_MODE_P565 2 -+#define ROCKCHIP_OUT_MODE_P888 0 -+#define ROCKCHIP_OUT_MODE_P666 1 -+#define ROCKCHIP_OUT_MODE_P565 2 -+#define ROCKCHIP_OUT_MODE_YUV420 14 - /* for use special outface */ --#define ROCKCHIP_OUT_MODE_AAAA 15 -+#define ROCKCHIP_OUT_MODE_AAAA 15 - - /* output flags */ - #define ROCKCHIP_OUTPUT_DSI_DUAL BIT(0) -diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c -index b99e902d949e..73d24c6bbf05 100644 ---- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c -+++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c -@@ -608,6 +608,7 @@ static const struct vop_common rk3288_common = { - .cfg_done = VOP_REG_SYNC(RK3288_REG_CFG_DONE, 0x1, 0), - - .overlay_mode = VOP_REG(RK3288_SYS_CTRL, 0x1, 16), -+ .dclk_ddr = VOP_REG(RK3288_DSP_CTRL0, 0x1, 8), - .dsp_data_swap = VOP_REG(RK3288_DSP_CTRL0, 0x1f, 12), - .dsp_out_yuv = VOP_REG(RK3288_POST_SCL_CTRL, 0x1, 2), - .dsp_background = VOP_REG(RK3288_DSP_BG, 0xffffffff, 0), -@@ -921,6 +922,7 @@ static const struct vop_common rk3328_common = { - .cfg_done = VOP_REG_SYNC(RK3328_REG_CFG_DONE, 0x1, 0), - - .overlay_mode = VOP_REG(RK3328_SYS_CTRL, 0x1, 16), -+ .dclk_ddr = VOP_REG(RK3328_DSP_CTRL0, 0x1, 8), - .dsp_data_swap = VOP_REG(RK3328_DSP_CTRL0, 0x1f, 12), - .dsp_out_yuv = VOP_REG(RK3328_POST_SCL_CTRL, 0x1, 2), - .dsp_background = VOP_REG(RK3328_DSP_BG, 0xffffffff, 0), --- -2.17.1 - - -From a8f40af332f87e74015d578a14e4491d1e0c9291 Mon Sep 17 00:00:00 2001 -From: Jonas Karlman -Date: Sun, 8 Dec 2019 23:49:00 +0000 -Subject: [PATCH] WIP: drm/bridge: dw-hdmi: signal default quant range - ---- - drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c -index df1789cd8712..14a1131cfc21 100644 ---- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c -+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c -@@ -1673,6 +1673,9 @@ static void hdmi_config_AVI(struct dw_hdmi *hdmi, struct drm_display_mode *mode) - HDMI_EXTENDED_COLORIMETRY_XV_YCC_601; - } - -+ drm_hdmi_avi_infoframe_quant_range(&frame, &hdmi->connector, mode, -+ drm_default_rgb_quant_range(mode)); -+ - drm_hdmi_avi_infoframe_content_type(&frame, conn_state); - - hdmi_infoframe_log(KERN_INFO, hdmi->dev, (union hdmi_infoframe *)&frame); --- -2.17.1 - - -From aa34fb23453ea76f533d0af601ec0ce5ee9d8312 Mon Sep 17 00:00:00 2001 -From: Jonas Karlman -Date: Fri, 20 Dec 2019 08:12:43 +0000 -Subject: [PATCH] WIP: drm/bridge: dw-hdmi: use avmute during modeset - ---- - drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 4 ++++ - drivers/gpu/drm/bridge/synopsys/dw-hdmi.h | 4 ++++ - 2 files changed, 8 insertions(+) - -diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c -index 14a1131cfc21..6344c8aac13e 100644 ---- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c -+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c -@@ -2328,10 +2328,14 @@ static void dw_hdmi_poweron(struct dw_hdmi *hdmi) - hdmi->bridge_is_on = true; - dw_hdmi_get_edid(&hdmi->connector); - dw_hdmi_setup(hdmi, &hdmi->previous_mode); -+ -+ hdmi_writeb(hdmi, HDMI_FC_GCP_CLEAR_AVMUTE, HDMI_FC_GCP); - } - - static void dw_hdmi_poweroff(struct dw_hdmi *hdmi) - { -+ hdmi_writeb(hdmi, HDMI_FC_GCP_SET_AVMUTE, HDMI_FC_GCP); -+ - if (hdmi->phy.enabled) { - hdmi->phy.ops->disable(hdmi, hdmi->phy.data); - hdmi->phy.enabled = false; -diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h -index 27a91128d0cc..3810326794cc 100644 ---- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h -+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h -@@ -842,6 +842,10 @@ enum { - HDMI_FC_AVICONF3_QUANT_RANGE_LIMITED = 0x00, - HDMI_FC_AVICONF3_QUANT_RANGE_FULL = 0x04, - -+/* HDMI_FC_GCP */ -+ HDMI_FC_GCP_SET_AVMUTE = 0x2, -+ HDMI_FC_GCP_CLEAR_AVMUTE = 0x1, -+ - /* FC_DBGFORCE field values */ - HDMI_FC_DBGFORCE_FORCEAUDIO = 0x10, - HDMI_FC_DBGFORCE_FORCEVIDEO = 0x1, --- -2.17.1 - diff --git a/patch/kernel/rk322x-current/01-linux-0007-fromlist-drm-lima-and-panfrost-for-5.8-plus.patch.disabled b/patch/kernel/rk322x-current/01-linux-0007-fromlist-drm-lima-and-panfrost-for-5.8-plus.patch.disabled deleted file mode 100644 index 9d3dbcbe0..000000000 --- a/patch/kernel/rk322x-current/01-linux-0007-fromlist-drm-lima-and-panfrost-for-5.8-plus.patch.disabled +++ /dev/null @@ -1,4172 +0,0 @@ -diff --git a/drivers/gpu/drm/panfrost/panfrost_gpu.c b/drivers/gpu/drm/panfrost/panfrost_gpu.c -index 8822ec13a0d6..cdebe9a9ade7 100644 ---- a/drivers/gpu/drm/panfrost/panfrost_gpu.c -+++ b/drivers/gpu/drm/panfrost/panfrost_gpu.c -@@ -351,7 +351,7 @@ int panfrost_gpu_init(struct panfrost_device *pfdev) - return -ENODEV; - - err = devm_request_irq(pfdev->dev, irq, panfrost_gpu_irq_handler, -- IRQF_SHARED, "gpu", pfdev); -+ IRQF_SHARED, KBUILD_MODNAME "-gpu", pfdev); - if (err) { - dev_err(pfdev->dev, "failed to request gpu irq"); - return err; -diff --git a/drivers/gpu/drm/panfrost/panfrost_job.c b/drivers/gpu/drm/panfrost/panfrost_job.c -index 9a1a72a748e7..7914b1570841 100644 ---- a/drivers/gpu/drm/panfrost/panfrost_job.c -+++ b/drivers/gpu/drm/panfrost/panfrost_job.c -@@ -508,7 +508,7 @@ int panfrost_job_init(struct panfrost_device *pfdev) - return -ENODEV; - - ret = devm_request_irq(pfdev->dev, irq, panfrost_job_irq_handler, -- IRQF_SHARED, "job", pfdev); -+ IRQF_SHARED, KBUILD_MODNAME "-job", pfdev); - if (ret) { - dev_err(pfdev->dev, "failed to request job irq"); - return ret; -diff --git a/drivers/gpu/drm/panfrost/panfrost_mmu.c b/drivers/gpu/drm/panfrost/panfrost_mmu.c -index 5d75f8cf6477..ed28aeba6d59 100644 ---- a/drivers/gpu/drm/panfrost/panfrost_mmu.c -+++ b/drivers/gpu/drm/panfrost/panfrost_mmu.c -@@ -640,9 +640,11 @@ int panfrost_mmu_init(struct panfrost_device *pfdev) - if (irq <= 0) - return -ENODEV; - -- err = devm_request_threaded_irq(pfdev->dev, irq, panfrost_mmu_irq_handler, -+ err = devm_request_threaded_irq(pfdev->dev, irq, -+ panfrost_mmu_irq_handler, - panfrost_mmu_irq_handler_thread, -- IRQF_SHARED, "mmu", pfdev); -+ IRQF_SHARED, KBUILD_MODNAME "-mmu", -+ pfdev); - - if (err) { - dev_err(pfdev->dev, "failed to request mmu irq"); --- -2.17.1 - - -From feabec154cc4e8e3e9f1005fc0fc2ad2d0d828ed Mon Sep 17 00:00:00 2001 -From: Qiang Yu -Date: Thu, 16 Jan 2020 21:11:53 +0800 -Subject: [PATCH] drm/lima: update register info - -From Mali r10p0 kernel driver source code. - -Reviewed-by: Vasily Khoruzhick -Tested-by: Andreas Baierl -Signed-off-by: Qiang Yu ---- - drivers/gpu/drm/lima/lima_regs.h | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/drivers/gpu/drm/lima/lima_regs.h b/drivers/gpu/drm/lima/lima_regs.h -index ace8ecefbe90..0124c90e0153 100644 ---- a/drivers/gpu/drm/lima/lima_regs.h -+++ b/drivers/gpu/drm/lima/lima_regs.h -@@ -239,6 +239,7 @@ - #define LIMA_MMU_STATUS_REPLAY_BUFFER_EMPTY BIT(4) - #define LIMA_MMU_STATUS_PAGE_FAULT_IS_WRITE BIT(5) - #define LIMA_MMU_STATUS_BUS_ID(x) ((x >> 6) & 0x1F) -+#define LIMA_MMU_STATUS_STALL_NOT_ACTIVE BIT(31) - #define LIMA_MMU_COMMAND 0x0008 - #define LIMA_MMU_COMMAND_ENABLE_PAGING 0x00 - #define LIMA_MMU_COMMAND_DISABLE_PAGING 0x01 --- -2.17.1 - - -From a39f09230ca6ddf9e147e86c1bad9850913f6d52 Mon Sep 17 00:00:00 2001 -From: Qiang Yu -Date: Thu, 16 Jan 2020 21:11:54 +0800 -Subject: [PATCH] drm/lima: add lima_vm_map_bo - -For dynamically mapping added backup memory of lima_bo to vm. -This is a preparation for adding heap buffer support. - -Reviewed-by: Vasily Khoruzhick -Tested-by: Andreas Baierl -Signed-off-by: Qiang Yu ---- - drivers/gpu/drm/lima/lima_vm.c | 42 ++++++++++++++++++++++++++++++++++ - drivers/gpu/drm/lima/lima_vm.h | 1 + - 2 files changed, 43 insertions(+) - -diff --git a/drivers/gpu/drm/lima/lima_vm.c b/drivers/gpu/drm/lima/lima_vm.c -index 840e2350d872..2e513841de6c 100644 ---- a/drivers/gpu/drm/lima/lima_vm.c -+++ b/drivers/gpu/drm/lima/lima_vm.c -@@ -277,3 +277,45 @@ void lima_vm_print(struct lima_vm *vm) - } - } - } -+ -+int lima_vm_map_bo(struct lima_vm *vm, struct lima_bo *bo, int pageoff) -+{ -+ struct lima_bo_va *bo_va; -+ struct sg_dma_page_iter sg_iter; -+ int offset = 0, err; -+ u32 base; -+ -+ mutex_lock(&bo->lock); -+ -+ bo_va = lima_vm_bo_find(vm, bo); -+ if (!bo_va) { -+ err = -ENOENT; -+ goto err_out0; -+ } -+ -+ mutex_lock(&vm->lock); -+ -+ base = bo_va->node.start + (pageoff << PAGE_SHIFT); -+ for_each_sg_dma_page(bo->base.sgt->sgl, &sg_iter, -+ bo->base.sgt->nents, pageoff) { -+ err = lima_vm_map_page(vm, sg_page_iter_dma_address(&sg_iter), -+ base + offset); -+ if (err) -+ goto err_out1; -+ -+ offset += PAGE_SIZE; -+ } -+ -+ mutex_unlock(&vm->lock); -+ -+ mutex_unlock(&bo->lock); -+ return 0; -+ -+err_out1: -+ if (offset) -+ lima_vm_unmap_range(vm, base, base + offset - 1); -+ mutex_unlock(&vm->lock); -+err_out0: -+ mutex_unlock(&bo->lock); -+ return err; -+} -diff --git a/drivers/gpu/drm/lima/lima_vm.h b/drivers/gpu/drm/lima/lima_vm.h -index e0bdedcf14dd..22aeec77d84d 100644 ---- a/drivers/gpu/drm/lima/lima_vm.h -+++ b/drivers/gpu/drm/lima/lima_vm.h -@@ -58,5 +58,6 @@ static inline void lima_vm_put(struct lima_vm *vm) - } - - void lima_vm_print(struct lima_vm *vm); -+int lima_vm_map_bo(struct lima_vm *vm, struct lima_bo *bo, int pageoff); - - #endif --- -2.17.1 - - -From 7855619e0208555bf2568e143747d86b882aa6f7 Mon Sep 17 00:00:00 2001 -From: Qiang Yu -Date: Thu, 16 Jan 2020 21:11:55 +0800 -Subject: [PATCH] drm/lima: support heap buffer creation - -heap buffer is used as output of GP and input of PP for -Mali Utgard GPU. Size of heap buffer depends on the task -so is a runtime variable. - -Previously we just create a large enough buffer as heap -buffer. Now we add a heap buffer type to be able to -increase the backup memory dynamically when GP fail due -to lack of heap memory. - -Reviewed-by: Vasily Khoruzhick -Tested-by: Andreas Baierl -Signed-off-by: Qiang Yu ---- - drivers/gpu/drm/lima/lima_drv.c | 6 +- - drivers/gpu/drm/lima/lima_drv.h | 1 + - drivers/gpu/drm/lima/lima_gem.c | 134 ++++++++++++++++++++++++++++++-- - drivers/gpu/drm/lima/lima_gem.h | 4 + - drivers/gpu/drm/lima/lima_vm.c | 4 +- - include/uapi/drm/lima_drm.h | 9 ++- - 6 files changed, 147 insertions(+), 11 deletions(-) - -diff --git a/drivers/gpu/drm/lima/lima_drv.c b/drivers/gpu/drm/lima/lima_drv.c -index 124efe4fa97b..18f88aaef1a2 100644 ---- a/drivers/gpu/drm/lima/lima_drv.c -+++ b/drivers/gpu/drm/lima/lima_drv.c -@@ -15,10 +15,14 @@ - #include "lima_vm.h" - - int lima_sched_timeout_ms; -+uint lima_heap_init_nr_pages = 8; - - MODULE_PARM_DESC(sched_timeout_ms, "task run timeout in ms"); - module_param_named(sched_timeout_ms, lima_sched_timeout_ms, int, 0444); - -+MODULE_PARM_DESC(heap_init_nr_pages, "heap buffer init number of pages"); -+module_param_named(heap_init_nr_pages, lima_heap_init_nr_pages, uint, 0444); -+ - static int lima_ioctl_get_param(struct drm_device *dev, void *data, struct drm_file *file) - { - struct drm_lima_get_param *args = data; -@@ -68,7 +72,7 @@ static int lima_ioctl_gem_create(struct drm_device *dev, void *data, struct drm_ - if (args->pad) - return -EINVAL; - -- if (args->flags) -+ if (args->flags & ~(LIMA_BO_FLAG_HEAP)) - return -EINVAL; - - if (args->size == 0) -diff --git a/drivers/gpu/drm/lima/lima_drv.h b/drivers/gpu/drm/lima/lima_drv.h -index 69c7344715c9..f492ecc6a5d9 100644 ---- a/drivers/gpu/drm/lima/lima_drv.h -+++ b/drivers/gpu/drm/lima/lima_drv.h -@@ -9,6 +9,7 @@ - #include "lima_ctx.h" - - extern int lima_sched_timeout_ms; -+extern uint lima_heap_init_nr_pages; - - struct lima_vm; - struct lima_bo; -diff --git a/drivers/gpu/drm/lima/lima_gem.c b/drivers/gpu/drm/lima/lima_gem.c -index d0059d8c97d8..5404e0d668db 100644 ---- a/drivers/gpu/drm/lima/lima_gem.c -+++ b/drivers/gpu/drm/lima/lima_gem.c -@@ -4,6 +4,8 @@ - #include - #include - #include -+#include -+#include - - #include - #include -@@ -15,6 +17,83 @@ - #include "lima_gem.h" - #include "lima_vm.h" - -+int lima_heap_alloc(struct lima_bo *bo, struct lima_vm *vm) -+{ -+ struct page **pages; -+ struct address_space *mapping = bo->base.base.filp->f_mapping; -+ struct device *dev = bo->base.base.dev->dev; -+ size_t old_size = bo->heap_size; -+ size_t new_size = bo->heap_size ? bo->heap_size * 2 : -+ (lima_heap_init_nr_pages << PAGE_SHIFT); -+ struct sg_table sgt; -+ int i, ret; -+ -+ if (bo->heap_size >= bo->base.base.size) -+ return -ENOSPC; -+ -+ new_size = min(new_size, bo->base.base.size); -+ -+ mutex_lock(&bo->base.pages_lock); -+ -+ if (bo->base.pages) { -+ pages = bo->base.pages; -+ } else { -+ pages = kvmalloc_array(bo->base.base.size >> PAGE_SHIFT, -+ sizeof(*pages), GFP_KERNEL | __GFP_ZERO); -+ if (!pages) { -+ mutex_unlock(&bo->base.pages_lock); -+ return -ENOMEM; -+ } -+ -+ bo->base.pages = pages; -+ bo->base.pages_use_count = 1; -+ -+ mapping_set_unevictable(mapping); -+ } -+ -+ for (i = old_size >> PAGE_SHIFT; i < new_size >> PAGE_SHIFT; i++) { -+ struct page *page = shmem_read_mapping_page(mapping, i); -+ -+ if (IS_ERR(page)) { -+ mutex_unlock(&bo->base.pages_lock); -+ return PTR_ERR(page); -+ } -+ pages[i] = page; -+ } -+ -+ mutex_unlock(&bo->base.pages_lock); -+ -+ ret = sg_alloc_table_from_pages(&sgt, pages, i, 0, -+ new_size, GFP_KERNEL); -+ if (ret) -+ return ret; -+ -+ if (bo->base.sgt) { -+ dma_unmap_sg(dev, bo->base.sgt->sgl, -+ bo->base.sgt->nents, DMA_BIDIRECTIONAL); -+ sg_free_table(bo->base.sgt); -+ } else { -+ bo->base.sgt = kmalloc(sizeof(*bo->base.sgt), GFP_KERNEL); -+ if (!bo->base.sgt) { -+ sg_free_table(&sgt); -+ return -ENOMEM; -+ } -+ } -+ -+ dma_map_sg(dev, sgt.sgl, sgt.nents, DMA_BIDIRECTIONAL); -+ -+ *bo->base.sgt = sgt; -+ -+ if (vm) { -+ ret = lima_vm_map_bo(vm, bo, old_size >> PAGE_SHIFT); -+ if (ret) -+ return ret; -+ } -+ -+ bo->heap_size = new_size; -+ return 0; -+} -+ - int lima_gem_create_handle(struct drm_device *dev, struct drm_file *file, - u32 size, u32 flags, u32 *handle) - { -@@ -22,7 +101,8 @@ int lima_gem_create_handle(struct drm_device *dev, struct drm_file *file, - gfp_t mask; - struct drm_gem_shmem_object *shmem; - struct drm_gem_object *obj; -- struct sg_table *sgt; -+ struct lima_bo *bo; -+ bool is_heap = flags & LIMA_BO_FLAG_HEAP; - - shmem = drm_gem_shmem_create(dev, size); - if (IS_ERR(shmem)) -@@ -36,10 +116,18 @@ int lima_gem_create_handle(struct drm_device *dev, struct drm_file *file, - mask |= __GFP_DMA32; - mapping_set_gfp_mask(obj->filp->f_mapping, mask); - -- sgt = drm_gem_shmem_get_pages_sgt(obj); -- if (IS_ERR(sgt)) { -- err = PTR_ERR(sgt); -- goto out; -+ if (is_heap) { -+ bo = to_lima_bo(obj); -+ err = lima_heap_alloc(bo, NULL); -+ if (err) -+ goto out; -+ } else { -+ struct sg_table *sgt = drm_gem_shmem_get_pages_sgt(obj); -+ -+ if (IS_ERR(sgt)) { -+ err = PTR_ERR(sgt); -+ goto out; -+ } - } - - err = drm_gem_handle_create(file, obj, handle); -@@ -79,17 +167,47 @@ static void lima_gem_object_close(struct drm_gem_object *obj, struct drm_file *f - lima_vm_bo_del(vm, bo); - } - -+static int lima_gem_pin(struct drm_gem_object *obj) -+{ -+ struct lima_bo *bo = to_lima_bo(obj); -+ -+ if (bo->heap_size) -+ return -EINVAL; -+ -+ return drm_gem_shmem_pin(obj); -+} -+ -+static void *lima_gem_vmap(struct drm_gem_object *obj) -+{ -+ struct lima_bo *bo = to_lima_bo(obj); -+ -+ if (bo->heap_size) -+ return ERR_PTR(-EINVAL); -+ -+ return drm_gem_shmem_vmap(obj); -+} -+ -+static int lima_gem_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma) -+{ -+ struct lima_bo *bo = to_lima_bo(obj); -+ -+ if (bo->heap_size) -+ return -EINVAL; -+ -+ return drm_gem_shmem_mmap(obj, vma); -+} -+ - static const struct drm_gem_object_funcs lima_gem_funcs = { - .free = lima_gem_free_object, - .open = lima_gem_object_open, - .close = lima_gem_object_close, - .print_info = drm_gem_shmem_print_info, -- .pin = drm_gem_shmem_pin, -+ .pin = lima_gem_pin, - .unpin = drm_gem_shmem_unpin, - .get_sg_table = drm_gem_shmem_get_sg_table, -- .vmap = drm_gem_shmem_vmap, -+ .vmap = lima_gem_vmap, - .vunmap = drm_gem_shmem_vunmap, -- .mmap = drm_gem_shmem_mmap, -+ .mmap = lima_gem_mmap, - }; - - struct drm_gem_object *lima_gem_create_object(struct drm_device *dev, size_t size) -diff --git a/drivers/gpu/drm/lima/lima_gem.h b/drivers/gpu/drm/lima/lima_gem.h -index 1800feb3e47f..ccea06142f4b 100644 ---- a/drivers/gpu/drm/lima/lima_gem.h -+++ b/drivers/gpu/drm/lima/lima_gem.h -@@ -7,12 +7,15 @@ - #include - - struct lima_submit; -+struct lima_vm; - - struct lima_bo { - struct drm_gem_shmem_object base; - - struct mutex lock; - struct list_head va; -+ -+ size_t heap_size; - }; - - static inline struct lima_bo * -@@ -31,6 +34,7 @@ static inline struct dma_resv *lima_bo_resv(struct lima_bo *bo) - return bo->base.base.resv; - } - -+int lima_heap_alloc(struct lima_bo *bo, struct lima_vm *vm); - struct drm_gem_object *lima_gem_create_object(struct drm_device *dev, size_t size); - int lima_gem_create_handle(struct drm_device *dev, struct drm_file *file, - u32 size, u32 flags, u32 *handle); -diff --git a/drivers/gpu/drm/lima/lima_vm.c b/drivers/gpu/drm/lima/lima_vm.c -index 2e513841de6c..5b92fb82674a 100644 ---- a/drivers/gpu/drm/lima/lima_vm.c -+++ b/drivers/gpu/drm/lima/lima_vm.c -@@ -155,6 +155,7 @@ int lima_vm_bo_add(struct lima_vm *vm, struct lima_bo *bo, bool create) - void lima_vm_bo_del(struct lima_vm *vm, struct lima_bo *bo) - { - struct lima_bo_va *bo_va; -+ u32 size; - - mutex_lock(&bo->lock); - -@@ -166,8 +167,9 @@ void lima_vm_bo_del(struct lima_vm *vm, struct lima_bo *bo) - - mutex_lock(&vm->lock); - -+ size = bo->heap_size ? bo->heap_size : bo_va->node.size; - lima_vm_unmap_range(vm, bo_va->node.start, -- bo_va->node.start + bo_va->node.size - 1); -+ bo_va->node.start + size - 1); - - drm_mm_remove_node(&bo_va->node); - -diff --git a/include/uapi/drm/lima_drm.h b/include/uapi/drm/lima_drm.h -index 95a00fb867e6..1ec58d652a5a 100644 ---- a/include/uapi/drm/lima_drm.h -+++ b/include/uapi/drm/lima_drm.h -@@ -32,12 +32,19 @@ struct drm_lima_get_param { - __u64 value; /* out, parameter value */ - }; - -+/* -+ * heap buffer dynamically increase backup memory size when GP task fail -+ * due to lack of heap memory. size field of heap buffer is an up bound of -+ * the backup memory which can be set to a fairly large value. -+ */ -+#define LIMA_BO_FLAG_HEAP (1 << 0) -+ - /** - * create a buffer for used by GPU - */ - struct drm_lima_gem_create { - __u32 size; /* in, buffer size */ -- __u32 flags; /* in, currently no flags, must be zero */ -+ __u32 flags; /* in, buffer flags */ - __u32 handle; /* out, GEM buffer handle */ - __u32 pad; /* pad, must be zero */ - }; --- -2.17.1 - - -From a9e57ad7709f2f0794da7ec3ef69fa0075c715d5 Mon Sep 17 00:00:00 2001 -From: Qiang Yu -Date: Thu, 16 Jan 2020 21:11:56 +0800 -Subject: [PATCH] drm/lima: recover task by enlarging heap buffer - -Increase heap buffer backup memory when GP receive PLBU -out of memory interrupt, then resume the task. - -Reviewed-by: Vasily Khoruzhick -Tested-by: Andreas Baierl -Signed-off-by: Qiang Yu ---- - drivers/gpu/drm/lima/lima_gp.c | 58 +++++++++++++++++++++++++++++-- - drivers/gpu/drm/lima/lima_mmu.c | 5 +++ - drivers/gpu/drm/lima/lima_mmu.h | 1 + - drivers/gpu/drm/lima/lima_sched.c | 35 ++++++++++++++++--- - drivers/gpu/drm/lima/lima_sched.h | 6 ++++ - 5 files changed, 98 insertions(+), 7 deletions(-) - -diff --git a/drivers/gpu/drm/lima/lima_gp.c b/drivers/gpu/drm/lima/lima_gp.c -index ccf49faedebf..52b210f9a605 100644 ---- a/drivers/gpu/drm/lima/lima_gp.c -+++ b/drivers/gpu/drm/lima/lima_gp.c -@@ -11,6 +11,8 @@ - #include "lima_device.h" - #include "lima_gp.h" - #include "lima_regs.h" -+#include "lima_gem.h" -+#include "lima_vm.h" - - #define gp_write(reg, data) writel(data, ip->iomem + reg) - #define gp_read(reg) readl(ip->iomem + reg) -@@ -20,6 +22,7 @@ static irqreturn_t lima_gp_irq_handler(int irq, void *data) - struct lima_ip *ip = data; - struct lima_device *dev = ip->dev; - struct lima_sched_pipe *pipe = dev->pipe + lima_pipe_gp; -+ struct lima_sched_task *task = pipe->current_task; - u32 state = gp_read(LIMA_GP_INT_STAT); - u32 status = gp_read(LIMA_GP_STATUS); - bool done = false; -@@ -29,8 +32,16 @@ static irqreturn_t lima_gp_irq_handler(int irq, void *data) - return IRQ_NONE; - - if (state & LIMA_GP_IRQ_MASK_ERROR) { -- dev_err(dev->dev, "gp error irq state=%x status=%x\n", -- state, status); -+ if ((state & LIMA_GP_IRQ_MASK_ERROR) == -+ LIMA_GP_IRQ_PLBU_OUT_OF_MEM) { -+ dev_dbg(dev->dev, "gp out of heap irq status=%x\n", -+ status); -+ } else { -+ dev_err(dev->dev, "gp error irq state=%x status=%x\n", -+ state, status); -+ if (task) -+ task->recoverable = false; -+ } - - /* mask all interrupts before hard reset */ - gp_write(LIMA_GP_INT_MASK, 0); -@@ -43,6 +54,7 @@ static irqreturn_t lima_gp_irq_handler(int irq, void *data) - bool active = status & (LIMA_GP_STATUS_VS_ACTIVE | - LIMA_GP_STATUS_PLBU_ACTIVE); - done = valid && !active; -+ pipe->error = false; - } - - gp_write(LIMA_GP_INT_CLEAR, state); -@@ -121,6 +133,22 @@ static void lima_gp_task_run(struct lima_sched_pipe *pipe, - u32 cmd = 0; - int i; - -+ /* update real heap buffer size for GP */ -+ for (i = 0; i < task->num_bos; i++) { -+ struct lima_bo *bo = task->bos[i]; -+ -+ if (bo->heap_size && -+ lima_vm_get_va(task->vm, bo) == -+ f[LIMA_GP_PLBU_ALLOC_START_ADDR >> 2]) { -+ f[LIMA_GP_PLBU_ALLOC_END_ADDR >> 2] = -+ f[LIMA_GP_PLBU_ALLOC_START_ADDR >> 2] + -+ bo->heap_size; -+ task->recoverable = true; -+ task->heap = bo; -+ break; -+ } -+ } -+ - if (f[LIMA_GP_VSCL_START_ADDR >> 2] != - f[LIMA_GP_VSCL_END_ADDR >> 2]) - cmd |= LIMA_GP_CMD_START_VS; -@@ -184,6 +212,31 @@ static void lima_gp_task_mmu_error(struct lima_sched_pipe *pipe) - lima_sched_pipe_task_done(pipe); - } - -+static int lima_gp_task_recover(struct lima_sched_pipe *pipe) -+{ -+ struct lima_ip *ip = pipe->processor[0]; -+ struct lima_sched_task *task = pipe->current_task; -+ struct drm_lima_gp_frame *frame = task->frame; -+ u32 *f = frame->frame; -+ size_t fail_size = -+ f[LIMA_GP_PLBU_ALLOC_END_ADDR >> 2] - -+ f[LIMA_GP_PLBU_ALLOC_START_ADDR >> 2]; -+ -+ if (fail_size == task->heap->heap_size) { -+ int ret; -+ -+ ret = lima_heap_alloc(task->heap, task->vm); -+ if (ret < 0) -+ return ret; -+ } -+ -+ gp_write(LIMA_GP_INT_MASK, LIMA_GP_IRQ_MASK_USED); -+ gp_write(LIMA_GP_PLBU_ALLOC_END_ADDR, -+ f[LIMA_GP_PLBU_ALLOC_START_ADDR >> 2] + task->heap->heap_size); -+ gp_write(LIMA_GP_CMD, LIMA_GP_CMD_UPDATE_PLBU_ALLOC); -+ return 0; -+} -+ - static void lima_gp_print_version(struct lima_ip *ip) - { - u32 version, major, minor; -@@ -270,6 +323,7 @@ int lima_gp_pipe_init(struct lima_device *dev) - pipe->task_fini = lima_gp_task_fini; - pipe->task_error = lima_gp_task_error; - pipe->task_mmu_error = lima_gp_task_mmu_error; -+ pipe->task_recover = lima_gp_task_recover; - - return 0; - } -diff --git a/drivers/gpu/drm/lima/lima_mmu.c b/drivers/gpu/drm/lima/lima_mmu.c -index 97ec09dee572..f79d2af427e7 100644 ---- a/drivers/gpu/drm/lima/lima_mmu.c -+++ b/drivers/gpu/drm/lima/lima_mmu.c -@@ -99,6 +99,11 @@ void lima_mmu_fini(struct lima_ip *ip) - - } - -+void lima_mmu_flush_tlb(struct lima_ip *ip) -+{ -+ mmu_write(LIMA_MMU_COMMAND, LIMA_MMU_COMMAND_ZAP_CACHE); -+} -+ - void lima_mmu_switch_vm(struct lima_ip *ip, struct lima_vm *vm) - { - struct lima_device *dev = ip->dev; -diff --git a/drivers/gpu/drm/lima/lima_mmu.h b/drivers/gpu/drm/lima/lima_mmu.h -index 8c78319bcc8e..4f8ccbebcba1 100644 ---- a/drivers/gpu/drm/lima/lima_mmu.h -+++ b/drivers/gpu/drm/lima/lima_mmu.h -@@ -10,6 +10,7 @@ struct lima_vm; - int lima_mmu_init(struct lima_ip *ip); - void lima_mmu_fini(struct lima_ip *ip); - -+void lima_mmu_flush_tlb(struct lima_ip *ip); - void lima_mmu_switch_vm(struct lima_ip *ip, struct lima_vm *vm); - void lima_mmu_page_fault_resume(struct lima_ip *ip); - -diff --git a/drivers/gpu/drm/lima/lima_sched.c b/drivers/gpu/drm/lima/lima_sched.c -index b561dd05bd62..3886999b4533 100644 ---- a/drivers/gpu/drm/lima/lima_sched.c -+++ b/drivers/gpu/drm/lima/lima_sched.c -@@ -313,6 +313,26 @@ static const struct drm_sched_backend_ops lima_sched_ops = { - .free_job = lima_sched_free_job, - }; - -+static void lima_sched_recover_work(struct work_struct *work) -+{ -+ struct lima_sched_pipe *pipe = -+ container_of(work, struct lima_sched_pipe, recover_work); -+ int i; -+ -+ for (i = 0; i < pipe->num_l2_cache; i++) -+ lima_l2_cache_flush(pipe->l2_cache[i]); -+ -+ if (pipe->bcast_mmu) { -+ lima_mmu_flush_tlb(pipe->bcast_mmu); -+ } else { -+ for (i = 0; i < pipe->num_mmu; i++) -+ lima_mmu_flush_tlb(pipe->mmu[i]); -+ } -+ -+ if (pipe->task_recover(pipe)) -+ drm_sched_fault(&pipe->base); -+} -+ - int lima_sched_pipe_init(struct lima_sched_pipe *pipe, const char *name) - { - unsigned int timeout = lima_sched_timeout_ms > 0 ? -@@ -321,6 +341,8 @@ int lima_sched_pipe_init(struct lima_sched_pipe *pipe, const char *name) - pipe->fence_context = dma_fence_context_alloc(1); - spin_lock_init(&pipe->fence_lock); - -+ INIT_WORK(&pipe->recover_work, lima_sched_recover_work); -+ - return drm_sched_init(&pipe->base, &lima_sched_ops, 1, 0, - msecs_to_jiffies(timeout), name); - } -@@ -332,11 +354,14 @@ void lima_sched_pipe_fini(struct lima_sched_pipe *pipe) - - void lima_sched_pipe_task_done(struct lima_sched_pipe *pipe) - { -- if (pipe->error) -- drm_sched_fault(&pipe->base); -- else { -- struct lima_sched_task *task = pipe->current_task; -- -+ struct lima_sched_task *task = pipe->current_task; -+ -+ if (pipe->error) { -+ if (task && task->recoverable) -+ schedule_work(&pipe->recover_work); -+ else -+ drm_sched_fault(&pipe->base); -+ } else { - pipe->task_fini(pipe); - dma_fence_signal(task->fence); - } -diff --git a/drivers/gpu/drm/lima/lima_sched.h b/drivers/gpu/drm/lima/lima_sched.h -index 1d814fecbcc0..d64393fb50a9 100644 ---- a/drivers/gpu/drm/lima/lima_sched.h -+++ b/drivers/gpu/drm/lima/lima_sched.h -@@ -20,6 +20,9 @@ struct lima_sched_task { - struct lima_bo **bos; - int num_bos; - -+ bool recoverable; -+ struct lima_bo *heap; -+ - /* pipe fence */ - struct dma_fence *fence; - }; -@@ -68,6 +71,9 @@ struct lima_sched_pipe { - void (*task_fini)(struct lima_sched_pipe *pipe); - void (*task_error)(struct lima_sched_pipe *pipe); - void (*task_mmu_error)(struct lima_sched_pipe *pipe); -+ int (*task_recover)(struct lima_sched_pipe *pipe); -+ -+ struct work_struct recover_work; - }; - - int lima_sched_task_init(struct lima_sched_task *task, --- -2.17.1 - - -From 6e3dc43aea43e83182588b79dd85e9c5f4d1d033 Mon Sep 17 00:00:00 2001 -From: Qiang Yu -Date: Thu, 16 Jan 2020 21:11:57 +0800 -Subject: [PATCH] drm/lima: increase driver version to 1.1 - -Increase driver version for mesa driver to identify -the support of new heap buffer interface. - -Reviewed-by: Vasily Khoruzhick -Tested-by: Andreas Baierl -Signed-off-by: Qiang Yu ---- - drivers/gpu/drm/lima/lima_drv.c | 10 ++++++++-- - 1 file changed, 8 insertions(+), 2 deletions(-) - -diff --git a/drivers/gpu/drm/lima/lima_drv.c b/drivers/gpu/drm/lima/lima_drv.c -index 18f88aaef1a2..2daac64d8955 100644 ---- a/drivers/gpu/drm/lima/lima_drv.c -+++ b/drivers/gpu/drm/lima/lima_drv.c -@@ -245,6 +245,12 @@ static const struct drm_ioctl_desc lima_drm_driver_ioctls[] = { - - DEFINE_DRM_GEM_FOPS(lima_drm_driver_fops); - -+/** -+ * Changelog: -+ * -+ * - 1.1.0 - add heap buffer support -+ */ -+ - static struct drm_driver lima_drm_driver = { - .driver_features = DRIVER_RENDER | DRIVER_GEM | DRIVER_SYNCOBJ, - .open = lima_drm_driver_open, -@@ -254,9 +260,9 @@ static struct drm_driver lima_drm_driver = { - .fops = &lima_drm_driver_fops, - .name = "lima", - .desc = "lima DRM", -- .date = "20190217", -+ .date = "20191231", - .major = 1, -- .minor = 0, -+ .minor = 1, - .patchlevel = 0, - - .gem_create_object = lima_gem_create_object, --- -2.17.1 - - -From 1a3901778598bc71d64bdbb71ea2278113aeb611 Mon Sep 17 00:00:00 2001 -From: Vasily Khoruzhick -Date: Fri, 14 Feb 2020 19:50:26 -0800 -Subject: [PATCH] drm/lima: fix recovering from PLBU out of memory - -It looks like on PLBU_OUT_OF_MEM interrupt we need to resume from where we -stopped, i.e. new PLBU heap start is old end. Also update end address -in GP frame to grow heap on 2nd and subsequent out of memory interrupts. - -Fixes: 2081e8dcf1ee ("drm/lima: recover task by enlarging heap buffer") -Signed-off-by: Vasily Khoruzhick -Signed-off-by: Qiang Yu ---- - drivers/gpu/drm/lima/lima_gp.c | 7 ++++++- - 1 file changed, 6 insertions(+), 1 deletion(-) - -diff --git a/drivers/gpu/drm/lima/lima_gp.c b/drivers/gpu/drm/lima/lima_gp.c -index 52b210f9a605..d8841c870d90 100644 ---- a/drivers/gpu/drm/lima/lima_gp.c -+++ b/drivers/gpu/drm/lima/lima_gp.c -@@ -231,8 +231,13 @@ static int lima_gp_task_recover(struct lima_sched_pipe *pipe) - } - - gp_write(LIMA_GP_INT_MASK, LIMA_GP_IRQ_MASK_USED); -+ /* Resume from where we stopped, i.e. new start is old end */ -+ gp_write(LIMA_GP_PLBU_ALLOC_START_ADDR, -+ f[LIMA_GP_PLBU_ALLOC_END_ADDR >> 2]); -+ f[LIMA_GP_PLBU_ALLOC_END_ADDR >> 2] = -+ f[LIMA_GP_PLBU_ALLOC_START_ADDR >> 2] + task->heap->heap_size; - gp_write(LIMA_GP_PLBU_ALLOC_END_ADDR, -- f[LIMA_GP_PLBU_ALLOC_START_ADDR >> 2] + task->heap->heap_size); -+ f[LIMA_GP_PLBU_ALLOC_END_ADDR >> 2]); - gp_write(LIMA_GP_CMD, LIMA_GP_CMD_UPDATE_PLBU_ALLOC); - return 0; - } --- -2.17.1 - - -From 619bbf1237ff25c39fbef0809bdfb28aa691e925 Mon Sep 17 00:00:00 2001 -From: Nicolas Boichat -Date: Fri, 7 Feb 2020 13:26:23 +0800 -Subject: [PATCH] drm/panfrost: Improve error reporting in - panfrost_gpu_power_on - -It is useful to know which component cannot be powered on. - -Signed-off-by: Nicolas Boichat -Reviewed-by: Alyssa Rosenzweig -Reviewed-by: Steven Price -Signed-off-by: Rob Herring ---- - drivers/gpu/drm/panfrost/panfrost_gpu.c | 14 ++++++++++---- - 1 file changed, 10 insertions(+), 4 deletions(-) - -diff --git a/drivers/gpu/drm/panfrost/panfrost_gpu.c b/drivers/gpu/drm/panfrost/panfrost_gpu.c -index cdebe9a9ade7..2881f439ff85 100644 ---- a/drivers/gpu/drm/panfrost/panfrost_gpu.c -+++ b/drivers/gpu/drm/panfrost/panfrost_gpu.c -@@ -308,21 +308,27 @@ void panfrost_gpu_power_on(struct panfrost_device *pfdev) - gpu_write(pfdev, L2_PWRON_LO, pfdev->features.l2_present); - ret = readl_relaxed_poll_timeout(pfdev->iomem + L2_READY_LO, - val, val == pfdev->features.l2_present, 100, 1000); -+ if (ret) -+ dev_err(pfdev->dev, "error powering up gpu L2"); - - gpu_write(pfdev, STACK_PWRON_LO, pfdev->features.stack_present); -- ret |= readl_relaxed_poll_timeout(pfdev->iomem + STACK_READY_LO, -+ ret = readl_relaxed_poll_timeout(pfdev->iomem + STACK_READY_LO, - val, val == pfdev->features.stack_present, 100, 1000); -+ if (ret) -+ dev_err(pfdev->dev, "error powering up gpu stack"); - - gpu_write(pfdev, SHADER_PWRON_LO, pfdev->features.shader_present); -- ret |= readl_relaxed_poll_timeout(pfdev->iomem + SHADER_READY_LO, -+ ret = readl_relaxed_poll_timeout(pfdev->iomem + SHADER_READY_LO, - val, val == pfdev->features.shader_present, 100, 1000); -+ if (ret) -+ dev_err(pfdev->dev, "error powering up gpu shader"); - - gpu_write(pfdev, TILER_PWRON_LO, pfdev->features.tiler_present); -- ret |= readl_relaxed_poll_timeout(pfdev->iomem + TILER_READY_LO, -+ ret = readl_relaxed_poll_timeout(pfdev->iomem + TILER_READY_LO, - val, val == pfdev->features.tiler_present, 100, 1000); - - if (ret) -- dev_err(pfdev->dev, "error powering up gpu"); -+ dev_err(pfdev->dev, "error powering up gpu tiler"); - } - - void panfrost_gpu_power_off(struct panfrost_device *pfdev) --- -2.17.1 - - -From 96780fcbe44b27fda4c273d5b9b726dc4ba1ab5b Mon Sep 17 00:00:00 2001 -From: Nicolas Boichat -Date: Fri, 7 Feb 2020 13:26:24 +0800 -Subject: [PATCH] drm/panfrost: Add support for multiple regulators - -Some GPUs, namely, the bifrost/g72 part on MT8183, have a second -regulator for their SRAM, let's add support for that. - -We extend the framework in a generic manner so that we could -support more than 2 regulators, if required. - -Signed-off-by: Nicolas Boichat -Reviewed-by: Steven Price -Reviwed-by: Mark Brown -Signed-off-by: Rob Herring ---- - drivers/gpu/drm/panfrost/panfrost_device.c | 26 +++++++++++++------- - drivers/gpu/drm/panfrost/panfrost_device.h | 15 +++++++++++- - drivers/gpu/drm/panfrost/panfrost_drv.c | 28 +++++++++++++++------- - 3 files changed, 51 insertions(+), 18 deletions(-) - -diff --git a/drivers/gpu/drm/panfrost/panfrost_device.c b/drivers/gpu/drm/panfrost/panfrost_device.c -index 238fb6d54df4..3720d50f6d9f 100644 ---- a/drivers/gpu/drm/panfrost/panfrost_device.c -+++ b/drivers/gpu/drm/panfrost/panfrost_device.c -@@ -87,18 +87,27 @@ static void panfrost_clk_fini(struct panfrost_device *pfdev) - - static int panfrost_regulator_init(struct panfrost_device *pfdev) - { -- int ret; -+ int ret, i; - -- pfdev->regulator = devm_regulator_get(pfdev->dev, "mali"); -- if (IS_ERR(pfdev->regulator)) { -- ret = PTR_ERR(pfdev->regulator); -- dev_err(pfdev->dev, "failed to get regulator: %d\n", ret); -+ if (WARN(pfdev->comp->num_supplies > ARRAY_SIZE(pfdev->regulators), -+ "Too many supplies in compatible structure.\n")) -+ return -EINVAL; -+ -+ for (i = 0; i < pfdev->comp->num_supplies; i++) -+ pfdev->regulators[i].supply = pfdev->comp->supply_names[i]; -+ -+ ret = devm_regulator_bulk_get(pfdev->dev, -+ pfdev->comp->num_supplies, -+ pfdev->regulators); -+ if (ret < 0) { -+ dev_err(pfdev->dev, "failed to get regulators: %d\n", ret); - return ret; - } - -- ret = regulator_enable(pfdev->regulator); -+ ret = regulator_bulk_enable(pfdev->comp->num_supplies, -+ pfdev->regulators); - if (ret < 0) { -- dev_err(pfdev->dev, "failed to enable regulator: %d\n", ret); -+ dev_err(pfdev->dev, "failed to enable regulators: %d\n", ret); - return ret; - } - -@@ -107,7 +116,8 @@ static int panfrost_regulator_init(struct panfrost_device *pfdev) - - static void panfrost_regulator_fini(struct panfrost_device *pfdev) - { -- regulator_disable(pfdev->regulator); -+ regulator_bulk_disable(pfdev->comp->num_supplies, -+ pfdev->regulators); - } - - int panfrost_device_init(struct panfrost_device *pfdev) -diff --git a/drivers/gpu/drm/panfrost/panfrost_device.h b/drivers/gpu/drm/panfrost/panfrost_device.h -index 06713811b92c..c9468bc5573a 100644 ---- a/drivers/gpu/drm/panfrost/panfrost_device.h -+++ b/drivers/gpu/drm/panfrost/panfrost_device.h -@@ -7,6 +7,7 @@ - - #include - #include -+#include - #include - #include - #include -@@ -19,6 +20,7 @@ struct panfrost_job; - struct panfrost_perfcnt; - - #define NUM_JOB_SLOTS 3 -+#define MAX_REGULATORS 2 - - struct panfrost_features { - u16 id; -@@ -51,6 +53,16 @@ struct panfrost_features { - unsigned long hw_issues[64 / BITS_PER_LONG]; - }; - -+/* -+ * Features that cannot be automatically detected and need matching using the -+ * compatible string, typically SoC-specific. -+ */ -+struct panfrost_compatible { -+ /* Supplies count and names. */ -+ int num_supplies; -+ const char * const *supply_names; -+}; -+ - struct panfrost_device { - struct device *dev; - struct drm_device *ddev; -@@ -59,10 +71,11 @@ struct panfrost_device { - void __iomem *iomem; - struct clk *clock; - struct clk *bus_clock; -- struct regulator *regulator; -+ struct regulator_bulk_data regulators[MAX_REGULATORS]; - struct reset_control *rstc; - - struct panfrost_features features; -+ const struct panfrost_compatible *comp; - - spinlock_t as_lock; - unsigned long as_in_use_mask; -diff --git a/drivers/gpu/drm/panfrost/panfrost_drv.c b/drivers/gpu/drm/panfrost/panfrost_drv.c -index b7a618db3ee2..4d0850752623 100644 ---- a/drivers/gpu/drm/panfrost/panfrost_drv.c -+++ b/drivers/gpu/drm/panfrost/panfrost_drv.c -@@ -584,6 +584,10 @@ static int panfrost_probe(struct platform_device *pdev) - - platform_set_drvdata(pdev, pfdev); - -+ pfdev->comp = of_device_get_match_data(&pdev->dev); -+ if (!pfdev->comp) -+ return -ENODEV; -+ - /* Allocate and initialze the DRM device. */ - ddev = drm_dev_alloc(&panfrost_drm_driver, &pdev->dev); - if (IS_ERR(ddev)) -@@ -655,16 +659,22 @@ static int panfrost_remove(struct platform_device *pdev) - return 0; - } - -+const char * const default_supplies[] = { "mali" }; -+static const struct panfrost_compatible default_data = { -+ .num_supplies = ARRAY_SIZE(default_supplies), -+ .supply_names = default_supplies, -+}; -+ - static const struct of_device_id dt_match[] = { -- { .compatible = "arm,mali-t604" }, -- { .compatible = "arm,mali-t624" }, -- { .compatible = "arm,mali-t628" }, -- { .compatible = "arm,mali-t720" }, -- { .compatible = "arm,mali-t760" }, -- { .compatible = "arm,mali-t820" }, -- { .compatible = "arm,mali-t830" }, -- { .compatible = "arm,mali-t860" }, -- { .compatible = "arm,mali-t880" }, -+ { .compatible = "arm,mali-t604", .data = &default_data, }, -+ { .compatible = "arm,mali-t624", .data = &default_data, }, -+ { .compatible = "arm,mali-t628", .data = &default_data, }, -+ { .compatible = "arm,mali-t720", .data = &default_data, }, -+ { .compatible = "arm,mali-t760", .data = &default_data, }, -+ { .compatible = "arm,mali-t820", .data = &default_data, }, -+ { .compatible = "arm,mali-t830", .data = &default_data, }, -+ { .compatible = "arm,mali-t860", .data = &default_data, }, -+ { .compatible = "arm,mali-t880", .data = &default_data, }, - {} - }; - MODULE_DEVICE_TABLE(of, dt_match); --- -2.17.1 - - -From 7de0cdd88c14fec1927a563e843fae6e6c79f6be Mon Sep 17 00:00:00 2001 -From: Nicolas Boichat -Date: Fri, 7 Feb 2020 13:26:25 +0800 -Subject: [PATCH] drm/panfrost: Add support for multiple power domains - -When there is a single power domain per device, the core will -ensure the power domain is switched on (so it is technically -equivalent to having not power domain specified at all). - -However, when there are multiple domains, as in MT8183 Bifrost -GPU, we need to handle them in driver code. - -Signed-off-by: Nicolas Boichat -Reviewed-by: Ulf Hansson -Reviewed-by: Steven Price -Signed-off-by: Rob Herring ---- - drivers/gpu/drm/panfrost/panfrost_device.c | 97 ++++++++++++++++++++-- - drivers/gpu/drm/panfrost/panfrost_device.h | 11 +++ - drivers/gpu/drm/panfrost/panfrost_drv.c | 2 + - 3 files changed, 102 insertions(+), 8 deletions(-) - -diff --git a/drivers/gpu/drm/panfrost/panfrost_device.c b/drivers/gpu/drm/panfrost/panfrost_device.c -index 3720d50f6d9f..8136babd3ba9 100644 ---- a/drivers/gpu/drm/panfrost/panfrost_device.c -+++ b/drivers/gpu/drm/panfrost/panfrost_device.c -@@ -5,6 +5,7 @@ - #include - #include - #include -+#include - #include - - #include "panfrost_device.h" -@@ -120,6 +121,79 @@ static void panfrost_regulator_fini(struct panfrost_device *pfdev) - pfdev->regulators); - } - -+static void panfrost_pm_domain_fini(struct panfrost_device *pfdev) -+{ -+ int i; -+ -+ for (i = 0; i < ARRAY_SIZE(pfdev->pm_domain_devs); i++) { -+ if (!pfdev->pm_domain_devs[i]) -+ break; -+ -+ if (pfdev->pm_domain_links[i]) -+ device_link_del(pfdev->pm_domain_links[i]); -+ -+ dev_pm_domain_detach(pfdev->pm_domain_devs[i], true); -+ } -+} -+ -+static int panfrost_pm_domain_init(struct panfrost_device *pfdev) -+{ -+ int err; -+ int i, num_domains; -+ -+ num_domains = of_count_phandle_with_args(pfdev->dev->of_node, -+ "power-domains", -+ "#power-domain-cells"); -+ -+ /* -+ * Single domain is handled by the core, and, if only a single power -+ * the power domain is requested, the property is optional. -+ */ -+ if (num_domains < 2 && pfdev->comp->num_pm_domains < 2) -+ return 0; -+ -+ if (num_domains != pfdev->comp->num_pm_domains) { -+ dev_err(pfdev->dev, -+ "Incorrect number of power domains: %d provided, %d needed\n", -+ num_domains, pfdev->comp->num_pm_domains); -+ return -EINVAL; -+ } -+ -+ if (WARN(num_domains > ARRAY_SIZE(pfdev->pm_domain_devs), -+ "Too many supplies in compatible structure.\n")) -+ return -EINVAL; -+ -+ for (i = 0; i < num_domains; i++) { -+ pfdev->pm_domain_devs[i] = -+ dev_pm_domain_attach_by_name(pfdev->dev, -+ pfdev->comp->pm_domain_names[i]); -+ if (IS_ERR_OR_NULL(pfdev->pm_domain_devs[i])) { -+ err = PTR_ERR(pfdev->pm_domain_devs[i]) ? : -ENODATA; -+ pfdev->pm_domain_devs[i] = NULL; -+ dev_err(pfdev->dev, -+ "failed to get pm-domain %s(%d): %d\n", -+ pfdev->comp->pm_domain_names[i], i, err); -+ goto err; -+ } -+ -+ pfdev->pm_domain_links[i] = device_link_add(pfdev->dev, -+ pfdev->pm_domain_devs[i], DL_FLAG_PM_RUNTIME | -+ DL_FLAG_STATELESS | DL_FLAG_RPM_ACTIVE); -+ if (!pfdev->pm_domain_links[i]) { -+ dev_err(pfdev->pm_domain_devs[i], -+ "adding device link failed!\n"); -+ err = -ENODEV; -+ goto err; -+ } -+ } -+ -+ return 0; -+ -+err: -+ panfrost_pm_domain_fini(pfdev); -+ return err; -+} -+ - int panfrost_device_init(struct panfrost_device *pfdev) - { - int err; -@@ -150,37 +224,43 @@ int panfrost_device_init(struct panfrost_device *pfdev) - goto err_out1; - } - -+ err = panfrost_pm_domain_init(pfdev); -+ if (err) -+ goto err_out2; -+ - res = platform_get_resource(pfdev->pdev, IORESOURCE_MEM, 0); - pfdev->iomem = devm_ioremap_resource(pfdev->dev, res); - if (IS_ERR(pfdev->iomem)) { - dev_err(pfdev->dev, "failed to ioremap iomem\n"); - err = PTR_ERR(pfdev->iomem); -- goto err_out2; -+ goto err_out3; - } - - err = panfrost_gpu_init(pfdev); - if (err) -- goto err_out2; -+ goto err_out3; - - err = panfrost_mmu_init(pfdev); - if (err) -- goto err_out3; -+ goto err_out4; - - err = panfrost_job_init(pfdev); - if (err) -- goto err_out4; -+ goto err_out5; - - err = panfrost_perfcnt_init(pfdev); - if (err) -- goto err_out5; -+ goto err_out6; - - return 0; --err_out5: -+err_out6: - panfrost_job_fini(pfdev); --err_out4: -+err_out5: - panfrost_mmu_fini(pfdev); --err_out3: -+err_out4: - panfrost_gpu_fini(pfdev); -+err_out3: -+ panfrost_pm_domain_fini(pfdev); - err_out2: - panfrost_reset_fini(pfdev); - err_out1: -@@ -196,6 +276,7 @@ void panfrost_device_fini(struct panfrost_device *pfdev) - panfrost_job_fini(pfdev); - panfrost_mmu_fini(pfdev); - panfrost_gpu_fini(pfdev); -+ panfrost_pm_domain_fini(pfdev); - panfrost_reset_fini(pfdev); - panfrost_regulator_fini(pfdev); - panfrost_clk_fini(pfdev); -diff --git a/drivers/gpu/drm/panfrost/panfrost_device.h b/drivers/gpu/drm/panfrost/panfrost_device.h -index c9468bc5573a..c30c719a8059 100644 ---- a/drivers/gpu/drm/panfrost/panfrost_device.h -+++ b/drivers/gpu/drm/panfrost/panfrost_device.h -@@ -21,6 +21,7 @@ struct panfrost_perfcnt; - - #define NUM_JOB_SLOTS 3 - #define MAX_REGULATORS 2 -+#define MAX_PM_DOMAINS 3 - - struct panfrost_features { - u16 id; -@@ -61,6 +62,13 @@ struct panfrost_compatible { - /* Supplies count and names. */ - int num_supplies; - const char * const *supply_names; -+ /* -+ * Number of power domains required, note that values 0 and 1 are -+ * handled identically, as only values > 1 need special handling. -+ */ -+ int num_pm_domains; -+ /* Only required if num_pm_domains > 1. */ -+ const char * const *pm_domain_names; - }; - - struct panfrost_device { -@@ -73,6 +81,9 @@ struct panfrost_device { - struct clk *bus_clock; - struct regulator_bulk_data regulators[MAX_REGULATORS]; - struct reset_control *rstc; -+ /* pm_domains for devices with more than one. */ -+ struct device *pm_domain_devs[MAX_PM_DOMAINS]; -+ struct device_link *pm_domain_links[MAX_PM_DOMAINS]; - - struct panfrost_features features; - const struct panfrost_compatible *comp; -diff --git a/drivers/gpu/drm/panfrost/panfrost_drv.c b/drivers/gpu/drm/panfrost/panfrost_drv.c -index 4d0850752623..a6e162236d67 100644 ---- a/drivers/gpu/drm/panfrost/panfrost_drv.c -+++ b/drivers/gpu/drm/panfrost/panfrost_drv.c -@@ -663,6 +663,8 @@ const char * const default_supplies[] = { "mali" }; - static const struct panfrost_compatible default_data = { - .num_supplies = ARRAY_SIZE(default_supplies), - .supply_names = default_supplies, -+ .num_pm_domains = 1, /* optional */ -+ .pm_domain_names = NULL, - }; - - static const struct of_device_id dt_match[] = { --- -2.17.1 - - -From 4a210ebba6b01cb060a1de524d5d000981025b5b Mon Sep 17 00:00:00 2001 -From: kbuild test robot -Date: Thu, 27 Feb 2020 09:41:46 +0800 -Subject: [PATCH] drm/panfrost: default_supplies[] can be static - -Fixes: 3e1399bccf51 ("drm/panfrost: Add support for multiple regulators") -Signed-off-by: kbuild test robot -Reviewed-by: Nicolas Boichat -Signed-off-by: Rob Herring ---- - drivers/gpu/drm/panfrost/panfrost_drv.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/drivers/gpu/drm/panfrost/panfrost_drv.c b/drivers/gpu/drm/panfrost/panfrost_drv.c -index a6e162236d67..882fecc33fdb 100644 ---- a/drivers/gpu/drm/panfrost/panfrost_drv.c -+++ b/drivers/gpu/drm/panfrost/panfrost_drv.c -@@ -659,7 +659,7 @@ static int panfrost_remove(struct platform_device *pdev) - return 0; - } - --const char * const default_supplies[] = { "mali" }; -+static const char * const default_supplies[] = { "mali" }; - static const struct panfrost_compatible default_data = { - .num_supplies = ARRAY_SIZE(default_supplies), - .supply_names = default_supplies, --- -2.17.1 - - -From 95695d5e36c49319b2cc6eabae04d32a13ca962e Mon Sep 17 00:00:00 2001 -From: Qiang Yu -Date: Sat, 22 Feb 2020 10:42:06 +0800 -Subject: [PATCH] drm/lima: save process info for debug usage - -When task fail, we can find its process with this information. - -Tested-by: Andreas Baierl -Reviewed-by: Vasily Khoruzhick -Signed-off-by: Qiang Yu ---- - drivers/gpu/drm/lima/lima_ctx.c | 3 +++ - drivers/gpu/drm/lima/lima_ctx.h | 5 +++++ - 2 files changed, 8 insertions(+) - -diff --git a/drivers/gpu/drm/lima/lima_ctx.c b/drivers/gpu/drm/lima/lima_ctx.c -index 22fff6caa961..891d5cd5019a 100644 ---- a/drivers/gpu/drm/lima/lima_ctx.c -+++ b/drivers/gpu/drm/lima/lima_ctx.c -@@ -27,6 +27,9 @@ int lima_ctx_create(struct lima_device *dev, struct lima_ctx_mgr *mgr, u32 *id) - if (err < 0) - goto err_out0; - -+ ctx->pid = task_pid_nr(current); -+ get_task_comm(ctx->pname, current); -+ - return 0; - - err_out0: -diff --git a/drivers/gpu/drm/lima/lima_ctx.h b/drivers/gpu/drm/lima/lima_ctx.h -index 6154e5c9bfe4..74e2be09090f 100644 ---- a/drivers/gpu/drm/lima/lima_ctx.h -+++ b/drivers/gpu/drm/lima/lima_ctx.h -@@ -5,6 +5,7 @@ - #define __LIMA_CTX_H__ - - #include -+#include - - #include "lima_device.h" - -@@ -13,6 +14,10 @@ struct lima_ctx { - struct lima_device *dev; - struct lima_sched_context context[lima_pipe_num]; - atomic_t guilty; -+ -+ /* debug info */ -+ char pname[TASK_COMM_LEN]; -+ pid_t pid; - }; - - struct lima_ctx_mgr { --- -2.17.1 - - -From c70385c2415949d2a8eecdb3242b0e27fcc56c25 Mon Sep 17 00:00:00 2001 -From: Qiang Yu -Date: Sat, 22 Feb 2020 10:42:07 +0800 -Subject: [PATCH] drm/lima: add max_error_tasks module parameter - -Limit error tasks to save. - -Tested-by: Andreas Baierl -Reviewed-by: Vasily Khoruzhick -Signed-off-by: Qiang Yu ---- - drivers/gpu/drm/lima/lima_drv.c | 4 ++++ - drivers/gpu/drm/lima/lima_drv.h | 1 + - 2 files changed, 5 insertions(+) - -diff --git a/drivers/gpu/drm/lima/lima_drv.c b/drivers/gpu/drm/lima/lima_drv.c -index 2daac64d8955..e235d4545b6c 100644 ---- a/drivers/gpu/drm/lima/lima_drv.c -+++ b/drivers/gpu/drm/lima/lima_drv.c -@@ -16,6 +16,7 @@ - - int lima_sched_timeout_ms; - uint lima_heap_init_nr_pages = 8; -+uint lima_max_error_tasks; - - MODULE_PARM_DESC(sched_timeout_ms, "task run timeout in ms"); - module_param_named(sched_timeout_ms, lima_sched_timeout_ms, int, 0444); -@@ -23,6 +24,9 @@ module_param_named(sched_timeout_ms, lima_sched_timeout_ms, int, 0444); - MODULE_PARM_DESC(heap_init_nr_pages, "heap buffer init number of pages"); - module_param_named(heap_init_nr_pages, lima_heap_init_nr_pages, uint, 0444); - -+MODULE_PARM_DESC(max_error_tasks, "max number of error tasks to save"); -+module_param_named(max_error_tasks, lima_max_error_tasks, uint, 0644); -+ - static int lima_ioctl_get_param(struct drm_device *dev, void *data, struct drm_file *file) - { - struct drm_lima_get_param *args = data; -diff --git a/drivers/gpu/drm/lima/lima_drv.h b/drivers/gpu/drm/lima/lima_drv.h -index f492ecc6a5d9..fdbd4077c768 100644 ---- a/drivers/gpu/drm/lima/lima_drv.h -+++ b/drivers/gpu/drm/lima/lima_drv.h -@@ -10,6 +10,7 @@ - - extern int lima_sched_timeout_ms; - extern uint lima_heap_init_nr_pages; -+extern uint lima_max_error_tasks; - - struct lima_vm; - struct lima_bo; --- -2.17.1 - - -From 3090b38955b4cb7c17b724fbdda56f5cab02e327 Mon Sep 17 00:00:00 2001 -From: Qiang Yu -Date: Sat, 7 Mar 2020 21:44:23 +0800 -Subject: [PATCH] drm/lima: save task info dump when task fail - -Save all information to start a task which can be exported to user -for debug usage. Dump file data format is specified in lima_dump.h - -v2: -Add include header to address build robot complain. - -Tested-by: Andreas Baierl -Reviewed-by: Vasily Khoruzhick -Signed-off-by: Qiang Yu ---- - drivers/gpu/drm/lima/lima_device.c | 13 +++ - drivers/gpu/drm/lima/lima_device.h | 8 ++ - drivers/gpu/drm/lima/lima_dump.h | 77 +++++++++++++++++ - drivers/gpu/drm/lima/lima_sched.c | 130 +++++++++++++++++++++++++++++ - drivers/gpu/drm/lima/lima_sched.h | 7 ++ - 5 files changed, 235 insertions(+) - create mode 100644 drivers/gpu/drm/lima/lima_dump.h - -diff --git a/drivers/gpu/drm/lima/lima_device.c b/drivers/gpu/drm/lima/lima_device.c -index 19829b543024..42a00171fea5 100644 ---- a/drivers/gpu/drm/lima/lima_device.c -+++ b/drivers/gpu/drm/lima/lima_device.c -@@ -344,6 +344,12 @@ int lima_device_init(struct lima_device *ldev) - if (err) - goto err_out5; - -+ ldev->dump.magic = LIMA_DUMP_MAGIC; -+ ldev->dump.version_major = LIMA_DUMP_MAJOR; -+ ldev->dump.version_minor = LIMA_DUMP_MINOR; -+ INIT_LIST_HEAD(&ldev->error_task_list); -+ mutex_init(&ldev->error_task_list_lock); -+ - dev_info(ldev->dev, "bus rate = %lu\n", clk_get_rate(ldev->clk_bus)); - dev_info(ldev->dev, "mod rate = %lu", clk_get_rate(ldev->clk_gpu)); - -@@ -370,6 +376,13 @@ int lima_device_init(struct lima_device *ldev) - void lima_device_fini(struct lima_device *ldev) - { - int i; -+ struct lima_sched_error_task *et, *tmp; -+ -+ list_for_each_entry_safe(et, tmp, &ldev->error_task_list, list) { -+ list_del(&et->list); -+ kvfree(et); -+ } -+ mutex_destroy(&ldev->error_task_list_lock); - - lima_fini_pp_pipe(ldev); - lima_fini_gp_pipe(ldev); -diff --git a/drivers/gpu/drm/lima/lima_device.h b/drivers/gpu/drm/lima/lima_device.h -index 31158d86271c..f17173f47f26 100644 ---- a/drivers/gpu/drm/lima/lima_device.h -+++ b/drivers/gpu/drm/lima/lima_device.h -@@ -6,8 +6,11 @@ - - #include - #include -+#include -+#include - - #include "lima_sched.h" -+#include "lima_dump.h" - - enum lima_gpu_id { - lima_gpu_mali400 = 0, -@@ -94,6 +97,11 @@ struct lima_device { - - u32 *dlbu_cpu; - dma_addr_t dlbu_dma; -+ -+ /* debug info */ -+ struct lima_dump_head dump; -+ struct list_head error_task_list; -+ struct mutex error_task_list_lock; - }; - - static inline struct lima_device * -diff --git a/drivers/gpu/drm/lima/lima_dump.h b/drivers/gpu/drm/lima/lima_dump.h -new file mode 100644 -index 000000000000..ca243d99c51b ---- /dev/null -+++ b/drivers/gpu/drm/lima/lima_dump.h -@@ -0,0 +1,77 @@ -+/* SPDX-License-Identifier: GPL-2.0 OR MIT */ -+/* Copyright 2020 Qiang Yu */ -+ -+#ifndef __LIMA_DUMP_H__ -+#define __LIMA_DUMP_H__ -+ -+#include -+ -+/** -+ * dump file format for all the information to start a lima task -+ * -+ * top level format -+ * | magic code "LIMA" | format version | num tasks | data size | -+ * | reserved | reserved | reserved | reserved | -+ * | task 1 ID | task 1 size | num chunks | reserved | task 1 data | -+ * | task 2 ID | task 2 size | num chunks | reserved | task 2 data | -+ * ... -+ * -+ * task data format -+ * | chunk 1 ID | chunk 1 size | reserved | reserved | chunk 1 data | -+ * | chunk 2 ID | chunk 2 size | reserved | reserved | chunk 2 data | -+ * ... -+ * -+ */ -+ -+#define LIMA_DUMP_MAJOR 1 -+#define LIMA_DUMP_MINOR 0 -+ -+#define LIMA_DUMP_MAGIC 0x414d494c -+ -+struct lima_dump_head { -+ __u32 magic; -+ __u16 version_major; -+ __u16 version_minor; -+ __u32 num_tasks; -+ __u32 size; -+ __u32 reserved[4]; -+}; -+ -+#define LIMA_DUMP_TASK_GP 0 -+#define LIMA_DUMP_TASK_PP 1 -+#define LIMA_DUMP_TASK_NUM 2 -+ -+struct lima_dump_task { -+ __u32 id; -+ __u32 size; -+ __u32 num_chunks; -+ __u32 reserved; -+}; -+ -+#define LIMA_DUMP_CHUNK_FRAME 0 -+#define LIMA_DUMP_CHUNK_BUFFER 1 -+#define LIMA_DUMP_CHUNK_PROCESS_NAME 2 -+#define LIMA_DUMP_CHUNK_PROCESS_ID 3 -+#define LIMA_DUMP_CHUNK_NUM 4 -+ -+struct lima_dump_chunk { -+ __u32 id; -+ __u32 size; -+ __u32 reserved[2]; -+}; -+ -+struct lima_dump_chunk_buffer { -+ __u32 id; -+ __u32 size; -+ __u32 va; -+ __u32 reserved; -+}; -+ -+struct lima_dump_chunk_pid { -+ __u32 id; -+ __u32 size; -+ __u32 pid; -+ __u32 reserved; -+}; -+ -+#endif -diff --git a/drivers/gpu/drm/lima/lima_sched.c b/drivers/gpu/drm/lima/lima_sched.c -index 3886999b4533..86192422a689 100644 ---- a/drivers/gpu/drm/lima/lima_sched.c -+++ b/drivers/gpu/drm/lima/lima_sched.c -@@ -4,6 +4,7 @@ - #include - #include - #include -+#include - - #include "lima_drv.h" - #include "lima_sched.h" -@@ -256,6 +257,133 @@ static struct dma_fence *lima_sched_run_job(struct drm_sched_job *job) - return task->fence; - } - -+static void lima_sched_build_error_task_list(struct lima_sched_task *task) -+{ -+ struct lima_sched_error_task *et; -+ struct lima_sched_pipe *pipe = to_lima_pipe(task->base.sched); -+ struct lima_ip *ip = pipe->processor[0]; -+ int pipe_id = ip->id == lima_ip_gp ? lima_pipe_gp : lima_pipe_pp; -+ struct lima_device *dev = ip->dev; -+ struct lima_sched_context *sched_ctx = -+ container_of(task->base.entity, -+ struct lima_sched_context, base); -+ struct lima_ctx *ctx = -+ container_of(sched_ctx, struct lima_ctx, context[pipe_id]); -+ struct lima_dump_task *dt; -+ struct lima_dump_chunk *chunk; -+ struct lima_dump_chunk_pid *pid_chunk; -+ struct lima_dump_chunk_buffer *buffer_chunk; -+ u32 size, task_size, mem_size; -+ int i; -+ -+ mutex_lock(&dev->error_task_list_lock); -+ -+ if (dev->dump.num_tasks >= lima_max_error_tasks) { -+ dev_info(dev->dev, "fail to save task state: error task list is full\n"); -+ goto out; -+ } -+ -+ /* frame chunk */ -+ size = sizeof(struct lima_dump_chunk) + pipe->frame_size; -+ /* process name chunk */ -+ size += sizeof(struct lima_dump_chunk) + sizeof(ctx->pname); -+ /* pid chunk */ -+ size += sizeof(struct lima_dump_chunk); -+ /* buffer chunks */ -+ for (i = 0; i < task->num_bos; i++) { -+ struct lima_bo *bo = task->bos[i]; -+ -+ size += sizeof(struct lima_dump_chunk); -+ size += bo->heap_size ? bo->heap_size : lima_bo_size(bo); -+ } -+ -+ task_size = size + sizeof(struct lima_dump_task); -+ mem_size = task_size + sizeof(*et); -+ et = kvmalloc(mem_size, GFP_KERNEL); -+ if (!et) { -+ dev_err(dev->dev, "fail to alloc task dump buffer of size %x\n", -+ mem_size); -+ goto out; -+ } -+ -+ et->data = et + 1; -+ et->size = task_size; -+ -+ dt = et->data; -+ memset(dt, 0, sizeof(*dt)); -+ dt->id = pipe_id; -+ dt->size = size; -+ -+ chunk = (struct lima_dump_chunk *)(dt + 1); -+ memset(chunk, 0, sizeof(*chunk)); -+ chunk->id = LIMA_DUMP_CHUNK_FRAME; -+ chunk->size = pipe->frame_size; -+ memcpy(chunk + 1, task->frame, pipe->frame_size); -+ dt->num_chunks++; -+ -+ chunk = (void *)(chunk + 1) + chunk->size; -+ memset(chunk, 0, sizeof(*chunk)); -+ chunk->id = LIMA_DUMP_CHUNK_PROCESS_NAME; -+ chunk->size = sizeof(ctx->pname); -+ memcpy(chunk + 1, ctx->pname, sizeof(ctx->pname)); -+ dt->num_chunks++; -+ -+ pid_chunk = (void *)(chunk + 1) + chunk->size; -+ memset(pid_chunk, 0, sizeof(*pid_chunk)); -+ pid_chunk->id = LIMA_DUMP_CHUNK_PROCESS_ID; -+ pid_chunk->pid = ctx->pid; -+ dt->num_chunks++; -+ -+ buffer_chunk = (void *)(pid_chunk + 1) + pid_chunk->size; -+ for (i = 0; i < task->num_bos; i++) { -+ struct lima_bo *bo = task->bos[i]; -+ void *data; -+ -+ memset(buffer_chunk, 0, sizeof(*buffer_chunk)); -+ buffer_chunk->id = LIMA_DUMP_CHUNK_BUFFER; -+ buffer_chunk->va = lima_vm_get_va(task->vm, bo); -+ -+ if (bo->heap_size) { -+ buffer_chunk->size = bo->heap_size; -+ -+ data = vmap(bo->base.pages, bo->heap_size >> PAGE_SHIFT, -+ VM_MAP, pgprot_writecombine(PAGE_KERNEL)); -+ if (!data) { -+ kvfree(et); -+ goto out; -+ } -+ -+ memcpy(buffer_chunk + 1, data, buffer_chunk->size); -+ -+ vunmap(data); -+ } else { -+ buffer_chunk->size = lima_bo_size(bo); -+ -+ data = drm_gem_shmem_vmap(&bo->base.base); -+ if (IS_ERR_OR_NULL(data)) { -+ kvfree(et); -+ goto out; -+ } -+ -+ memcpy(buffer_chunk + 1, data, buffer_chunk->size); -+ -+ drm_gem_shmem_vunmap(&bo->base.base, data); -+ } -+ -+ buffer_chunk = (void *)(buffer_chunk + 1) + buffer_chunk->size; -+ dt->num_chunks++; -+ } -+ -+ list_add(&et->list, &dev->error_task_list); -+ dev->dump.size += et->size; -+ dev->dump.num_tasks++; -+ -+ dev_info(dev->dev, "save error task state success\n"); -+ -+out: -+ mutex_unlock(&dev->error_task_list_lock); -+} -+ - static void lima_sched_timedout_job(struct drm_sched_job *job) - { - struct lima_sched_pipe *pipe = to_lima_pipe(job->sched); -@@ -268,6 +396,8 @@ static void lima_sched_timedout_job(struct drm_sched_job *job) - - drm_sched_increase_karma(&task->base); - -+ lima_sched_build_error_task_list(task); -+ - pipe->task_error(pipe); - - if (pipe->bcast_mmu) -diff --git a/drivers/gpu/drm/lima/lima_sched.h b/drivers/gpu/drm/lima/lima_sched.h -index d64393fb50a9..a1496cb7bc41 100644 ---- a/drivers/gpu/drm/lima/lima_sched.h -+++ b/drivers/gpu/drm/lima/lima_sched.h -@@ -5,9 +5,16 @@ - #define __LIMA_SCHED_H__ - - #include -+#include - - struct lima_vm; - -+struct lima_sched_error_task { -+ struct list_head list; -+ void *data; -+ u32 size; -+}; -+ - struct lima_sched_task { - struct drm_sched_job base; - --- -2.17.1 - - -From 3b95414439abca4e9129238481a36ee9025a8889 Mon Sep 17 00:00:00 2001 -From: Qiang Yu -Date: Sat, 22 Feb 2020 10:42:09 +0800 -Subject: [PATCH] drm/lima: add error sysfs to export error task dump - -Export /sys/class/drm/cardX/device/error sysfs for user read out -error task dump file. - -Tested-by: Andreas Baierl -Reviewed-by: Vasily Khoruzhick -Signed-off-by: Qiang Yu ---- - drivers/gpu/drm/lima/lima_drv.c | 94 +++++++++++++++++++++++++++++++++ - 1 file changed, 94 insertions(+) - -diff --git a/drivers/gpu/drm/lima/lima_drv.c b/drivers/gpu/drm/lima/lima_drv.c -index e235d4545b6c..97ed70c36340 100644 ---- a/drivers/gpu/drm/lima/lima_drv.c -+++ b/drivers/gpu/drm/lima/lima_drv.c -@@ -276,6 +276,93 @@ static struct drm_driver lima_drm_driver = { - .gem_prime_mmap = drm_gem_prime_mmap, - }; - -+struct lima_block_reader { -+ void *dst; -+ size_t base; -+ size_t count; -+ size_t off; -+ ssize_t read; -+}; -+ -+static bool lima_read_block(struct lima_block_reader *reader, -+ void *src, size_t src_size) -+{ -+ size_t max_off = reader->base + src_size; -+ -+ if (reader->off < max_off) { -+ size_t size = min_t(size_t, max_off - reader->off, -+ reader->count); -+ -+ memcpy(reader->dst, src + (reader->off - reader->base), size); -+ -+ reader->dst += size; -+ reader->off += size; -+ reader->read += size; -+ reader->count -= size; -+ } -+ -+ reader->base = max_off; -+ -+ return !!reader->count; -+} -+ -+static ssize_t lima_error_state_read(struct file *filp, struct kobject *kobj, -+ struct bin_attribute *attr, char *buf, -+ loff_t off, size_t count) -+{ -+ struct device *dev = kobj_to_dev(kobj); -+ struct lima_device *ldev = dev_get_drvdata(dev); -+ struct lima_sched_error_task *et; -+ struct lima_block_reader reader = { -+ .dst = buf, -+ .count = count, -+ .off = off, -+ }; -+ -+ mutex_lock(&ldev->error_task_list_lock); -+ -+ if (lima_read_block(&reader, &ldev->dump, sizeof(ldev->dump))) { -+ list_for_each_entry(et, &ldev->error_task_list, list) { -+ if (!lima_read_block(&reader, et->data, et->size)) -+ break; -+ } -+ } -+ -+ mutex_unlock(&ldev->error_task_list_lock); -+ return reader.read; -+} -+ -+static ssize_t lima_error_state_write(struct file *file, struct kobject *kobj, -+ struct bin_attribute *attr, char *buf, -+ loff_t off, size_t count) -+{ -+ struct device *dev = kobj_to_dev(kobj); -+ struct lima_device *ldev = dev_get_drvdata(dev); -+ struct lima_sched_error_task *et, *tmp; -+ -+ mutex_lock(&ldev->error_task_list_lock); -+ -+ list_for_each_entry_safe(et, tmp, &ldev->error_task_list, list) { -+ list_del(&et->list); -+ kvfree(et); -+ } -+ -+ ldev->dump.size = 0; -+ ldev->dump.num_tasks = 0; -+ -+ mutex_unlock(&ldev->error_task_list_lock); -+ -+ return count; -+} -+ -+static const struct bin_attribute lima_error_state_attr = { -+ .attr.name = "error", -+ .attr.mode = 0600, -+ .size = 0, -+ .read = lima_error_state_read, -+ .write = lima_error_state_write, -+}; -+ - static int lima_pdev_probe(struct platform_device *pdev) - { - struct lima_device *ldev; -@@ -318,6 +405,11 @@ static int lima_pdev_probe(struct platform_device *pdev) - if (err < 0) - goto err_out2; - -+ platform_set_drvdata(pdev, ldev); -+ -+ if (sysfs_create_bin_file(&ldev->dev->kobj, &lima_error_state_attr)) -+ dev_warn(ldev->dev, "fail to create error state sysfs\n"); -+ - return 0; - - err_out2: -@@ -334,6 +426,8 @@ static int lima_pdev_remove(struct platform_device *pdev) - struct lima_device *ldev = platform_get_drvdata(pdev); - struct drm_device *ddev = ldev->ddev; - -+ sysfs_remove_bin_file(&ldev->dev->kobj, &lima_error_state_attr); -+ platform_set_drvdata(pdev, NULL); - drm_dev_unregister(ddev); - lima_device_fini(ldev); - drm_dev_put(ddev); --- -2.17.1 - - -From e58efe898da54ddc1148539961ef3aeefe19fc80 Mon Sep 17 00:00:00 2001 -From: Qiang Yu -Date: Sat, 7 Mar 2020 21:54:38 +0800 -Subject: [PATCH] drm/lima: add trace point for tasks - -track lima task start which can be combined with -dma_fence_signal to identify task execution time. - -example command to record: - -trace-cmd record -i \ - -e "lima:lima_task_submit" -e "lima:lima_task_run" \ - -e "*fence:*fence_signaled" -e "drm:drm_vblank_event" \ - -e "drm:drm_vblank_event_queued" sleep 4 - -Reviewed-by: Vasily Khoruzhick -Signed-off-by: Qiang Yu ---- - drivers/gpu/drm/lima/Makefile | 3 +- - drivers/gpu/drm/lima/lima_sched.c | 5 +++- - drivers/gpu/drm/lima/lima_sched.h | 1 + - drivers/gpu/drm/lima/lima_trace.c | 7 +++++ - drivers/gpu/drm/lima/lima_trace.h | 50 +++++++++++++++++++++++++++++++ - 5 files changed, 64 insertions(+), 2 deletions(-) - create mode 100644 drivers/gpu/drm/lima/lima_trace.c - create mode 100644 drivers/gpu/drm/lima/lima_trace.h - -diff --git a/drivers/gpu/drm/lima/Makefile b/drivers/gpu/drm/lima/Makefile -index a85444b0a1d4..6e7b788408e8 100644 ---- a/drivers/gpu/drm/lima/Makefile -+++ b/drivers/gpu/drm/lima/Makefile -@@ -14,6 +14,7 @@ lima-y := \ - lima_sched.o \ - lima_ctx.o \ - lima_dlbu.o \ -- lima_bcast.o -+ lima_bcast.o \ -+ lima_trace.o - - obj-$(CONFIG_DRM_LIMA) += lima.o -diff --git a/drivers/gpu/drm/lima/lima_sched.c b/drivers/gpu/drm/lima/lima_sched.c -index 86192422a689..4fbf2c489507 100644 ---- a/drivers/gpu/drm/lima/lima_sched.c -+++ b/drivers/gpu/drm/lima/lima_sched.c -@@ -3,7 +3,6 @@ - - #include - #include --#include - #include - - #include "lima_drv.h" -@@ -12,6 +11,7 @@ - #include "lima_mmu.h" - #include "lima_l2_cache.h" - #include "lima_gem.h" -+#include "lima_trace.h" - - struct lima_fence { - struct dma_fence base; -@@ -177,6 +177,7 @@ struct dma_fence *lima_sched_context_queue_task(struct lima_sched_context *conte - { - struct dma_fence *fence = dma_fence_get(&task->base.s_fence->finished); - -+ trace_lima_task_submit(task); - drm_sched_entity_push_job(&task->base, &context->base); - return fence; - } -@@ -251,6 +252,8 @@ static struct dma_fence *lima_sched_run_job(struct drm_sched_job *job) - if (last_vm) - lima_vm_put(last_vm); - -+ trace_lima_task_run(task); -+ - pipe->error = false; - pipe->task_run(pipe, task); - -diff --git a/drivers/gpu/drm/lima/lima_sched.h b/drivers/gpu/drm/lima/lima_sched.h -index a1496cb7bc41..02dfa14d7083 100644 ---- a/drivers/gpu/drm/lima/lima_sched.h -+++ b/drivers/gpu/drm/lima/lima_sched.h -@@ -6,6 +6,7 @@ - - #include - #include -+#include - - struct lima_vm; - -diff --git a/drivers/gpu/drm/lima/lima_trace.c b/drivers/gpu/drm/lima/lima_trace.c -new file mode 100644 -index 000000000000..ea1c7289bebc ---- /dev/null -+++ b/drivers/gpu/drm/lima/lima_trace.c -@@ -0,0 +1,7 @@ -+// SPDX-License-Identifier: GPL-2.0 OR MIT -+/* Copyright 2020 Qiang Yu */ -+ -+#include "lima_sched.h" -+ -+#define CREATE_TRACE_POINTS -+#include "lima_trace.h" -diff --git a/drivers/gpu/drm/lima/lima_trace.h b/drivers/gpu/drm/lima/lima_trace.h -new file mode 100644 -index 000000000000..3a430e93d384 ---- /dev/null -+++ b/drivers/gpu/drm/lima/lima_trace.h -@@ -0,0 +1,50 @@ -+/* SPDX-License-Identifier: GPL-2.0 OR MIT */ -+/* Copyright 2020 Qiang Yu */ -+ -+#if !defined(_LIMA_TRACE_H) || defined(TRACE_HEADER_MULTI_READ) -+#define _LIMA_TRACE_H_ -+ -+#include -+ -+#undef TRACE_SYSTEM -+#define TRACE_SYSTEM lima -+#define TRACE_INCLUDE_FILE lima_trace -+ -+DECLARE_EVENT_CLASS(lima_task, -+ TP_PROTO(struct lima_sched_task *task), -+ TP_ARGS(task), -+ TP_STRUCT__entry( -+ __field(uint64_t, task_id) -+ __field(unsigned int, context) -+ __field(unsigned int, seqno) -+ __string(pipe, task->base.sched->name) -+ ), -+ -+ TP_fast_assign( -+ __entry->task_id = task->base.id; -+ __entry->context = task->base.s_fence->finished.context; -+ __entry->seqno = task->base.s_fence->finished.seqno; -+ __assign_str(pipe, task->base.sched->name) -+ ), -+ -+ TP_printk("task=%llu, context=%u seqno=%u pipe=%s", -+ __entry->task_id, __entry->context, __entry->seqno, -+ __get_str(pipe)) -+); -+ -+DEFINE_EVENT(lima_task, lima_task_submit, -+ TP_PROTO(struct lima_sched_task *task), -+ TP_ARGS(task) -+); -+ -+DEFINE_EVENT(lima_task, lima_task_run, -+ TP_PROTO(struct lima_sched_task *task), -+ TP_ARGS(task) -+); -+ -+#endif -+ -+/* This part must be outside protection */ -+#undef TRACE_INCLUDE_PATH -+#define TRACE_INCLUDE_PATH ../../drivers/gpu/drm/lima -+#include --- -2.17.1 - - -From f567d140f87225a04ba6c6035b4a0b79e816f9a9 Mon Sep 17 00:00:00 2001 -From: Martin Blumenstingl -Date: Thu, 19 Mar 2020 21:34:27 +0100 -Subject: [PATCH] drm/lima: Add optional devfreq and cooling device support - -Most platforms with a Mali-400 or Mali-450 GPU also have support for -changing the GPU clock frequency. Add devfreq support so the GPU clock -rate is updated based on the actual GPU usage when the -"operating-points-v2" property is present in the board.dts. - -The actual devfreq code is taken from panfrost_devfreq.c and modified so -it matches what the lima hardware needs: -- a call to dev_pm_opp_set_clkname() during initialization because there - are two clocks on Mali-4x0 IPs. "core" is the one that actually clocks - the GPU so we need to control it using devfreq. -- locking when reading or writing the devfreq statistics because (unlike - than panfrost) we have multiple PP and GP IRQs which may finish jobs - concurrently. - -Signed-off-by: Martin Blumenstingl -Signed-off-by: Qiang Yu ---- - drivers/gpu/drm/lima/Kconfig | 2 + - drivers/gpu/drm/lima/Makefile | 3 +- - drivers/gpu/drm/lima/lima_devfreq.c | 234 ++++++++++++++++++++++++++++ - drivers/gpu/drm/lima/lima_devfreq.h | 41 +++++ - drivers/gpu/drm/lima/lima_device.c | 4 + - drivers/gpu/drm/lima/lima_device.h | 3 + - drivers/gpu/drm/lima/lima_drv.c | 14 +- - drivers/gpu/drm/lima/lima_sched.c | 7 + - drivers/gpu/drm/lima/lima_sched.h | 3 + - 9 files changed, 308 insertions(+), 3 deletions(-) - create mode 100644 drivers/gpu/drm/lima/lima_devfreq.c - create mode 100644 drivers/gpu/drm/lima/lima_devfreq.h - -diff --git a/drivers/gpu/drm/lima/Kconfig b/drivers/gpu/drm/lima/Kconfig -index d589f09d04d9..fa1d4f5df31e 100644 ---- a/drivers/gpu/drm/lima/Kconfig -+++ b/drivers/gpu/drm/lima/Kconfig -@@ -10,5 +10,7 @@ config DRM_LIMA - depends on OF - select DRM_SCHED - select DRM_GEM_SHMEM_HELPER -+ select PM_DEVFREQ -+ select DEVFREQ_GOV_SIMPLE_ONDEMAND - help - DRM driver for ARM Mali 400/450 GPUs. -diff --git a/drivers/gpu/drm/lima/Makefile b/drivers/gpu/drm/lima/Makefile -index 6e7b788408e8..ca2097b8e1ad 100644 ---- a/drivers/gpu/drm/lima/Makefile -+++ b/drivers/gpu/drm/lima/Makefile -@@ -15,6 +15,7 @@ lima-y := \ - lima_ctx.o \ - lima_dlbu.o \ - lima_bcast.o \ -- lima_trace.o -+ lima_trace.o \ -+ lima_devfreq.o - - obj-$(CONFIG_DRM_LIMA) += lima.o -diff --git a/drivers/gpu/drm/lima/lima_devfreq.c b/drivers/gpu/drm/lima/lima_devfreq.c -new file mode 100644 -index 000000000000..8c4d21d07529 ---- /dev/null -+++ b/drivers/gpu/drm/lima/lima_devfreq.c -@@ -0,0 +1,234 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Copyright 2020 Martin Blumenstingl -+ * -+ * Based on panfrost_devfreq.c: -+ * Copyright 2019 Collabora ltd. -+ */ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "lima_device.h" -+#include "lima_devfreq.h" -+ -+static void lima_devfreq_update_utilization(struct lima_devfreq *devfreq) -+{ -+ ktime_t now, last; -+ -+ now = ktime_get(); -+ last = devfreq->time_last_update; -+ -+ if (devfreq->busy_count > 0) -+ devfreq->busy_time += ktime_sub(now, last); -+ else -+ devfreq->idle_time += ktime_sub(now, last); -+ -+ devfreq->time_last_update = now; -+} -+ -+static int lima_devfreq_target(struct device *dev, unsigned long *freq, -+ u32 flags) -+{ -+ struct dev_pm_opp *opp; -+ int err; -+ -+ opp = devfreq_recommended_opp(dev, freq, flags); -+ if (IS_ERR(opp)) -+ return PTR_ERR(opp); -+ dev_pm_opp_put(opp); -+ -+ err = dev_pm_opp_set_rate(dev, *freq); -+ if (err) -+ return err; -+ -+ return 0; -+} -+ -+static void lima_devfreq_reset(struct lima_devfreq *devfreq) -+{ -+ devfreq->busy_time = 0; -+ devfreq->idle_time = 0; -+ devfreq->time_last_update = ktime_get(); -+} -+ -+static int lima_devfreq_get_dev_status(struct device *dev, -+ struct devfreq_dev_status *status) -+{ -+ struct lima_device *ldev = dev_get_drvdata(dev); -+ struct lima_devfreq *devfreq = &ldev->devfreq; -+ unsigned long irqflags; -+ -+ status->current_frequency = clk_get_rate(ldev->clk_gpu); -+ -+ spin_lock_irqsave(&devfreq->lock, irqflags); -+ -+ lima_devfreq_update_utilization(devfreq); -+ -+ status->total_time = ktime_to_ns(ktime_add(devfreq->busy_time, -+ devfreq->idle_time)); -+ status->busy_time = ktime_to_ns(devfreq->busy_time); -+ -+ lima_devfreq_reset(devfreq); -+ -+ spin_unlock_irqrestore(&devfreq->lock, irqflags); -+ -+ dev_dbg(ldev->dev, "busy %lu total %lu %lu %% freq %lu MHz\n", -+ status->busy_time, status->total_time, -+ status->busy_time / (status->total_time / 100), -+ status->current_frequency / 1000 / 1000); -+ -+ return 0; -+} -+ -+static struct devfreq_dev_profile lima_devfreq_profile = { -+ .polling_ms = 50, /* ~3 frames */ -+ .target = lima_devfreq_target, -+ .get_dev_status = lima_devfreq_get_dev_status, -+}; -+ -+void lima_devfreq_fini(struct lima_device *ldev) -+{ -+ struct lima_devfreq *devfreq = &ldev->devfreq; -+ -+ if (devfreq->cooling) { -+ devfreq_cooling_unregister(devfreq->cooling); -+ devfreq->cooling = NULL; -+ } -+ -+ if (devfreq->devfreq) { -+ devm_devfreq_remove_device(&ldev->pdev->dev, -+ devfreq->devfreq); -+ devfreq->devfreq = NULL; -+ } -+ -+ if (devfreq->opp_of_table_added) { -+ dev_pm_opp_of_remove_table(&ldev->pdev->dev); -+ devfreq->opp_of_table_added = false; -+ } -+ -+ if (devfreq->regulators_opp_table) { -+ dev_pm_opp_put_regulators(devfreq->regulators_opp_table); -+ devfreq->regulators_opp_table = NULL; -+ } -+ -+ if (devfreq->clkname_opp_table) { -+ dev_pm_opp_put_clkname(devfreq->clkname_opp_table); -+ devfreq->clkname_opp_table = NULL; -+ } -+} -+ -+int lima_devfreq_init(struct lima_device *ldev) -+{ -+ struct thermal_cooling_device *cooling; -+ struct device *dev = &ldev->pdev->dev; -+ struct opp_table *opp_table; -+ struct devfreq *devfreq; -+ struct lima_devfreq *ldevfreq = &ldev->devfreq; -+ struct dev_pm_opp *opp; -+ unsigned long cur_freq; -+ int ret; -+ -+ if (!device_property_present(dev, "operating-points-v2")) -+ /* Optional, continue without devfreq */ -+ return 0; -+ -+ spin_lock_init(&ldevfreq->lock); -+ -+ opp_table = dev_pm_opp_set_clkname(dev, "core"); -+ if (IS_ERR(opp_table)) { -+ ret = PTR_ERR(opp_table); -+ goto err_fini; -+ } -+ -+ ldevfreq->clkname_opp_table = opp_table; -+ -+ opp_table = dev_pm_opp_set_regulators(dev, -+ (const char *[]){ "mali" }, -+ 1); -+ if (IS_ERR(opp_table)) { -+ ret = PTR_ERR(opp_table); -+ -+ /* Continue if the optional regulator is missing */ -+ if (ret != -ENODEV) -+ goto err_fini; -+ } else { -+ ldevfreq->regulators_opp_table = opp_table; -+ } -+ -+ ret = dev_pm_opp_of_add_table(dev); -+ if (ret) -+ goto err_fini; -+ ldevfreq->opp_of_table_added = true; -+ -+ lima_devfreq_reset(ldevfreq); -+ -+ cur_freq = clk_get_rate(ldev->clk_gpu); -+ -+ opp = devfreq_recommended_opp(dev, &cur_freq, 0); -+ if (IS_ERR(opp)) { -+ ret = PTR_ERR(opp); -+ goto err_fini; -+ } -+ -+ lima_devfreq_profile.initial_freq = cur_freq; -+ dev_pm_opp_put(opp); -+ -+ devfreq = devm_devfreq_add_device(dev, &lima_devfreq_profile, -+ DEVFREQ_GOV_SIMPLE_ONDEMAND, NULL); -+ if (IS_ERR(devfreq)) { -+ dev_err(dev, "Couldn't initialize GPU devfreq\n"); -+ ret = PTR_ERR(devfreq); -+ goto err_fini; -+ } -+ -+ ldevfreq->devfreq = devfreq; -+ -+ cooling = of_devfreq_cooling_register(dev->of_node, devfreq); -+ if (IS_ERR(cooling)) -+ dev_info(dev, "Failed to register cooling device\n"); -+ else -+ ldevfreq->cooling = cooling; -+ -+ return 0; -+ -+err_fini: -+ lima_devfreq_fini(ldev); -+ return ret; -+} -+ -+void lima_devfreq_record_busy(struct lima_devfreq *devfreq) -+{ -+ unsigned long irqflags; -+ -+ if (!devfreq->devfreq) -+ return; -+ -+ spin_lock_irqsave(&devfreq->lock, irqflags); -+ -+ lima_devfreq_update_utilization(devfreq); -+ -+ devfreq->busy_count++; -+ -+ spin_unlock_irqrestore(&devfreq->lock, irqflags); -+} -+ -+void lima_devfreq_record_idle(struct lima_devfreq *devfreq) -+{ -+ unsigned long irqflags; -+ -+ if (!devfreq->devfreq) -+ return; -+ -+ spin_lock_irqsave(&devfreq->lock, irqflags); -+ -+ lima_devfreq_update_utilization(devfreq); -+ -+ WARN_ON(--devfreq->busy_count < 0); -+ -+ spin_unlock_irqrestore(&devfreq->lock, irqflags); -+} -diff --git a/drivers/gpu/drm/lima/lima_devfreq.h b/drivers/gpu/drm/lima/lima_devfreq.h -new file mode 100644 -index 000000000000..8d71ba9fb22a ---- /dev/null -+++ b/drivers/gpu/drm/lima/lima_devfreq.h -@@ -0,0 +1,41 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* Copyright 2020 Martin Blumenstingl */ -+ -+#ifndef __LIMA_DEVFREQ_H__ -+#define __LIMA_DEVFREQ_H__ -+ -+#include -+#include -+ -+struct devfreq; -+struct opp_table; -+struct thermal_cooling_device; -+ -+struct lima_device; -+ -+struct lima_devfreq { -+ struct devfreq *devfreq; -+ struct opp_table *clkname_opp_table; -+ struct opp_table *regulators_opp_table; -+ struct thermal_cooling_device *cooling; -+ bool opp_of_table_added; -+ -+ ktime_t busy_time; -+ ktime_t idle_time; -+ ktime_t time_last_update; -+ int busy_count; -+ /* -+ * Protect busy_time, idle_time, time_last_update and busy_count -+ * because these can be updated concurrently, for example by the GP -+ * and PP interrupts. -+ */ -+ spinlock_t lock; -+}; -+ -+int lima_devfreq_init(struct lima_device *ldev); -+void lima_devfreq_fini(struct lima_device *ldev); -+ -+void lima_devfreq_record_busy(struct lima_devfreq *devfreq); -+void lima_devfreq_record_idle(struct lima_devfreq *devfreq); -+ -+#endif -diff --git a/drivers/gpu/drm/lima/lima_device.c b/drivers/gpu/drm/lima/lima_device.c -index 42a00171fea5..247f51fd40a2 100644 ---- a/drivers/gpu/drm/lima/lima_device.c -+++ b/drivers/gpu/drm/lima/lima_device.c -@@ -214,6 +214,8 @@ static int lima_init_gp_pipe(struct lima_device *dev) - struct lima_sched_pipe *pipe = dev->pipe + lima_pipe_gp; - int err; - -+ pipe->ldev = dev; -+ - err = lima_sched_pipe_init(pipe, "gp"); - if (err) - return err; -@@ -244,6 +246,8 @@ static int lima_init_pp_pipe(struct lima_device *dev) - struct lima_sched_pipe *pipe = dev->pipe + lima_pipe_pp; - int err, i; - -+ pipe->ldev = dev; -+ - err = lima_sched_pipe_init(pipe, "pp"); - if (err) - return err; -diff --git a/drivers/gpu/drm/lima/lima_device.h b/drivers/gpu/drm/lima/lima_device.h -index f17173f47f26..06fd9636dd72 100644 ---- a/drivers/gpu/drm/lima/lima_device.h -+++ b/drivers/gpu/drm/lima/lima_device.h -@@ -11,6 +11,7 @@ - - #include "lima_sched.h" - #include "lima_dump.h" -+#include "lima_devfreq.h" - - enum lima_gpu_id { - lima_gpu_mali400 = 0, -@@ -98,6 +99,8 @@ struct lima_device { - u32 *dlbu_cpu; - dma_addr_t dlbu_dma; - -+ struct lima_devfreq devfreq; -+ - /* debug info */ - struct lima_dump_head dump; - struct list_head error_task_list; -diff --git a/drivers/gpu/drm/lima/lima_drv.c b/drivers/gpu/drm/lima/lima_drv.c -index 97ed70c36340..bbbdc8455e2f 100644 ---- a/drivers/gpu/drm/lima/lima_drv.c -+++ b/drivers/gpu/drm/lima/lima_drv.c -@@ -10,6 +10,7 @@ - #include - #include - -+#include "lima_device.h" - #include "lima_drv.h" - #include "lima_gem.h" - #include "lima_vm.h" -@@ -397,13 +398,19 @@ static int lima_pdev_probe(struct platform_device *pdev) - if (err) - goto err_out1; - -+ err = lima_devfreq_init(ldev); -+ if (err) { -+ dev_err(&pdev->dev, "Fatal error during devfreq init\n"); -+ goto err_out2; -+ } -+ - /* - * Register the DRM device with the core and the connectors with - * sysfs. - */ - err = drm_dev_register(ddev, 0); - if (err < 0) -- goto err_out2; -+ goto err_out3; - - platform_set_drvdata(pdev, ldev); - -@@ -412,8 +419,10 @@ static int lima_pdev_probe(struct platform_device *pdev) - - return 0; - --err_out2: -+err_out3: - lima_device_fini(ldev); -+err_out2: -+ lima_devfreq_fini(ldev); - err_out1: - drm_dev_put(ddev); - err_out0: -@@ -429,6 +438,7 @@ static int lima_pdev_remove(struct platform_device *pdev) - sysfs_remove_bin_file(&ldev->dev->kobj, &lima_error_state_attr); - platform_set_drvdata(pdev, NULL); - drm_dev_unregister(ddev); -+ lima_devfreq_fini(ldev); - lima_device_fini(ldev); - drm_dev_put(ddev); - lima_sched_slab_fini(); -diff --git a/drivers/gpu/drm/lima/lima_sched.c b/drivers/gpu/drm/lima/lima_sched.c -index 4fbf2c489507..a2db1c937424 100644 ---- a/drivers/gpu/drm/lima/lima_sched.c -+++ b/drivers/gpu/drm/lima/lima_sched.c -@@ -5,6 +5,7 @@ - #include - #include - -+#include "lima_devfreq.h" - #include "lima_drv.h" - #include "lima_sched.h" - #include "lima_vm.h" -@@ -216,6 +217,8 @@ static struct dma_fence *lima_sched_run_job(struct drm_sched_job *job) - */ - ret = dma_fence_get(task->fence); - -+ lima_devfreq_record_busy(&pipe->ldev->devfreq); -+ - pipe->current_task = task; - - /* this is needed for MMU to work correctly, otherwise GP/PP -@@ -418,6 +421,8 @@ static void lima_sched_timedout_job(struct drm_sched_job *job) - pipe->current_vm = NULL; - pipe->current_task = NULL; - -+ lima_devfreq_record_idle(&pipe->ldev->devfreq); -+ - drm_sched_resubmit_jobs(&pipe->base); - drm_sched_start(&pipe->base, true); - } -@@ -497,5 +502,7 @@ void lima_sched_pipe_task_done(struct lima_sched_pipe *pipe) - } else { - pipe->task_fini(pipe); - dma_fence_signal(task->fence); -+ -+ lima_devfreq_record_idle(&pipe->ldev->devfreq); - } - } -diff --git a/drivers/gpu/drm/lima/lima_sched.h b/drivers/gpu/drm/lima/lima_sched.h -index 02dfa14d7083..90f03c48ef4a 100644 ---- a/drivers/gpu/drm/lima/lima_sched.h -+++ b/drivers/gpu/drm/lima/lima_sched.h -@@ -8,6 +8,7 @@ - #include - #include - -+struct lima_device; - struct lima_vm; - - struct lima_sched_error_task { -@@ -52,6 +53,8 @@ struct lima_sched_pipe { - u32 fence_seqno; - spinlock_t fence_lock; - -+ struct lima_device *ldev; -+ - struct lima_sched_task *current_task; - struct lima_vm *current_vm; - --- -2.17.1 - - -From 60e8ac9f8b772f5f3cbab5e361531d625444a320 Mon Sep 17 00:00:00 2001 -From: Robin Murphy -Date: Tue, 21 Apr 2020 23:51:36 +0100 -Subject: [PATCH] drm/lima: Clean up IRQ warnings - -Use the optional form of platform_get_irq() for blocks that legitimately -may not be present, to avoid getting an annoying barrage of spurious -warnings for non-existent PPs on configurations like Mali-450 MP2. - -Signed-off-by: Robin Murphy -Signed-off-by: Qiang Yu ---- - drivers/gpu/drm/lima/lima_device.c | 7 +++++-- - 1 file changed, 5 insertions(+), 2 deletions(-) - -diff --git a/drivers/gpu/drm/lima/lima_device.c b/drivers/gpu/drm/lima/lima_device.c -index 247f51fd40a2..c334d297796a 100644 ---- a/drivers/gpu/drm/lima/lima_device.c -+++ b/drivers/gpu/drm/lima/lima_device.c -@@ -171,8 +171,10 @@ static void lima_regulator_fini(struct lima_device *dev) - - static int lima_init_ip(struct lima_device *dev, int index) - { -+ struct platform_device *pdev = to_platform_device(dev->dev); - struct lima_ip_desc *desc = lima_ip_desc + index; - struct lima_ip *ip = dev->ip + index; -+ const char *irq_name = desc->irq_name; - int offset = desc->offset[dev->id]; - bool must = desc->must_have[dev->id]; - int err; -@@ -183,8 +185,9 @@ static int lima_init_ip(struct lima_device *dev, int index) - ip->dev = dev; - ip->id = index; - ip->iomem = dev->iomem + offset; -- if (desc->irq_name) { -- err = platform_get_irq_byname(dev->pdev, desc->irq_name); -+ if (irq_name) { -+ err = must ? platform_get_irq_byname(pdev, irq_name) : -+ platform_get_irq_byname_optional(pdev, irq_name); - if (err < 0) - goto out; - ip->irq = err; --- -2.17.1 - - -From 8bb48350b7a927e98b59299ba82c4231fef9816c Mon Sep 17 00:00:00 2001 -From: Robin Murphy -Date: Tue, 21 Apr 2020 23:51:37 +0100 -Subject: [PATCH] drm/lima: Clean up redundant pdev pointer - -There's no point explicitly tracking the platform device when it can be -trivially derived from the regular device pointer in the couple of -places it's ever used. - -Signed-off-by: Robin Murphy -Signed-off-by: Qiang Yu ---- - drivers/gpu/drm/lima/lima_devfreq.c | 7 +++---- - drivers/gpu/drm/lima/lima_device.c | 5 ++--- - drivers/gpu/drm/lima/lima_device.h | 1 - - drivers/gpu/drm/lima/lima_drv.c | 1 - - 4 files changed, 5 insertions(+), 9 deletions(-) - -diff --git a/drivers/gpu/drm/lima/lima_devfreq.c b/drivers/gpu/drm/lima/lima_devfreq.c -index 8c4d21d07529..1d479b5924fe 100644 ---- a/drivers/gpu/drm/lima/lima_devfreq.c -+++ b/drivers/gpu/drm/lima/lima_devfreq.c -@@ -101,13 +101,12 @@ void lima_devfreq_fini(struct lima_device *ldev) - } - - if (devfreq->devfreq) { -- devm_devfreq_remove_device(&ldev->pdev->dev, -- devfreq->devfreq); -+ devm_devfreq_remove_device(ldev->dev, devfreq->devfreq); - devfreq->devfreq = NULL; - } - - if (devfreq->opp_of_table_added) { -- dev_pm_opp_of_remove_table(&ldev->pdev->dev); -+ dev_pm_opp_of_remove_table(ldev->dev); - devfreq->opp_of_table_added = false; - } - -@@ -125,7 +124,7 @@ void lima_devfreq_fini(struct lima_device *ldev) - int lima_devfreq_init(struct lima_device *ldev) - { - struct thermal_cooling_device *cooling; -- struct device *dev = &ldev->pdev->dev; -+ struct device *dev = ldev->dev; - struct opp_table *opp_table; - struct devfreq *devfreq; - struct lima_devfreq *ldevfreq = &ldev->devfreq; -diff --git a/drivers/gpu/drm/lima/lima_device.c b/drivers/gpu/drm/lima/lima_device.c -index c334d297796a..29285dedd124 100644 ---- a/drivers/gpu/drm/lima/lima_device.c -+++ b/drivers/gpu/drm/lima/lima_device.c -@@ -297,8 +297,8 @@ static void lima_fini_pp_pipe(struct lima_device *dev) - - int lima_device_init(struct lima_device *ldev) - { -+ struct platform_device *pdev = to_platform_device(ldev->dev); - int err, i; -- struct resource *res; - - dma_set_coherent_mask(ldev->dev, DMA_BIT_MASK(32)); - -@@ -329,8 +329,7 @@ int lima_device_init(struct lima_device *ldev) - } else - ldev->va_end = LIMA_VA_RESERVE_END; - -- res = platform_get_resource(ldev->pdev, IORESOURCE_MEM, 0); -- ldev->iomem = devm_ioremap_resource(ldev->dev, res); -+ ldev->iomem = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(ldev->iomem)) { - dev_err(ldev->dev, "fail to ioremap iomem\n"); - err = PTR_ERR(ldev->iomem); -diff --git a/drivers/gpu/drm/lima/lima_device.h b/drivers/gpu/drm/lima/lima_device.h -index 06fd9636dd72..99b1fb147dad 100644 ---- a/drivers/gpu/drm/lima/lima_device.h -+++ b/drivers/gpu/drm/lima/lima_device.h -@@ -76,7 +76,6 @@ enum lima_pipe_id { - struct lima_device { - struct device *dev; - struct drm_device *ddev; -- struct platform_device *pdev; - - enum lima_gpu_id id; - u32 gp_version; -diff --git a/drivers/gpu/drm/lima/lima_drv.c b/drivers/gpu/drm/lima/lima_drv.c -index bbbdc8455e2f..4e5dd75822c0 100644 ---- a/drivers/gpu/drm/lima/lima_drv.c -+++ b/drivers/gpu/drm/lima/lima_drv.c -@@ -380,7 +380,6 @@ static int lima_pdev_probe(struct platform_device *pdev) - goto err_out0; - } - -- ldev->pdev = pdev; - ldev->dev = &pdev->dev; - ldev->id = (enum lima_gpu_id)of_device_get_match_data(&pdev->dev); - --- -2.17.1 - - -From 82f5f9c4e3bca70b8c6c745be7a0c794d0fded53 Mon Sep 17 00:00:00 2001 -From: Qiang Yu -Date: Tue, 21 Apr 2020 21:35:42 +0800 -Subject: [PATCH] drm/lima: use module_platform_driver helper - -Simplify module init/exit with module_platform_driver. - -Tested-by: Bhushan Shah -Reviewed-by: Vasily Khoruzhick -Signed-off-by: Qiang Yu ---- - drivers/gpu/drm/lima/lima_drv.c | 12 +----------- - 1 file changed, 1 insertion(+), 11 deletions(-) - -diff --git a/drivers/gpu/drm/lima/lima_drv.c b/drivers/gpu/drm/lima/lima_drv.c -index 4e5dd75822c0..3d63d496cfc2 100644 ---- a/drivers/gpu/drm/lima/lima_drv.c -+++ b/drivers/gpu/drm/lima/lima_drv.c -@@ -460,17 +460,7 @@ static struct platform_driver lima_platform_driver = { - }, - }; - --static int __init lima_init(void) --{ -- return platform_driver_register(&lima_platform_driver); --} --module_init(lima_init); -- --static void __exit lima_exit(void) --{ -- platform_driver_unregister(&lima_platform_driver); --} --module_exit(lima_exit); -+module_platform_driver(lima_platform_driver); - - MODULE_AUTHOR("Lima Project Developers"); - MODULE_DESCRIPTION("Lima DRM Driver"); --- -2.17.1 - - -From 2cb93a9b51b7c7105fc6baa0799c9474693c15a6 Mon Sep 17 00:00:00 2001 -From: Qiang Yu -Date: Tue, 21 Apr 2020 21:35:43 +0800 -Subject: [PATCH] drm/lima: print process name and pid when task error - -When error task list is full, print the process info where -the error task come from for debug usage. - -Tested-by: Bhushan Shah -Reviewed-by: Vasily Khoruzhick -Signed-off-by: Qiang Yu ---- - drivers/gpu/drm/lima/lima_sched.c | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/drivers/gpu/drm/lima/lima_sched.c b/drivers/gpu/drm/lima/lima_sched.c -index a2db1c937424..387f9439450a 100644 ---- a/drivers/gpu/drm/lima/lima_sched.c -+++ b/drivers/gpu/drm/lima/lima_sched.c -@@ -285,7 +285,8 @@ static void lima_sched_build_error_task_list(struct lima_sched_task *task) - mutex_lock(&dev->error_task_list_lock); - - if (dev->dump.num_tasks >= lima_max_error_tasks) { -- dev_info(dev->dev, "fail to save task state: error task list is full\n"); -+ dev_info(dev->dev, "fail to save task state from %s pid %d: " -+ "error task list is full\n", ctx->pname, ctx->pid); - goto out; - } - --- -2.17.1 - - -From 392cc15d77ef4f3dacff6b991690882051b683ad Mon Sep 17 00:00:00 2001 -From: Qiang Yu -Date: Tue, 21 Apr 2020 21:35:44 +0800 -Subject: [PATCH] drm/lima: check vm != NULL in lima_vm_put - -No need to handle this check before calling lima_vm_put. - -Tested-by: Bhushan Shah -Reviewed-by: Vasily Khoruzhick -Signed-off-by: Qiang Yu ---- - drivers/gpu/drm/lima/lima_sched.c | 7 ++----- - drivers/gpu/drm/lima/lima_vm.h | 3 ++- - 2 files changed, 4 insertions(+), 6 deletions(-) - -diff --git a/drivers/gpu/drm/lima/lima_sched.c b/drivers/gpu/drm/lima/lima_sched.c -index 387f9439450a..3ac5797e31fc 100644 ---- a/drivers/gpu/drm/lima/lima_sched.c -+++ b/drivers/gpu/drm/lima/lima_sched.c -@@ -252,8 +252,7 @@ static struct dma_fence *lima_sched_run_job(struct drm_sched_job *job) - lima_mmu_switch_vm(pipe->mmu[i], vm); - } - -- if (last_vm) -- lima_vm_put(last_vm); -+ lima_vm_put(last_vm); - - trace_lima_task_run(task); - -@@ -416,9 +415,7 @@ static void lima_sched_timedout_job(struct drm_sched_job *job) - lima_mmu_page_fault_resume(pipe->mmu[i]); - } - -- if (pipe->current_vm) -- lima_vm_put(pipe->current_vm); -- -+ lima_vm_put(pipe->current_vm); - pipe->current_vm = NULL; - pipe->current_task = NULL; - -diff --git a/drivers/gpu/drm/lima/lima_vm.h b/drivers/gpu/drm/lima/lima_vm.h -index 22aeec77d84d..3a7c74822d8b 100644 ---- a/drivers/gpu/drm/lima/lima_vm.h -+++ b/drivers/gpu/drm/lima/lima_vm.h -@@ -54,7 +54,8 @@ static inline struct lima_vm *lima_vm_get(struct lima_vm *vm) - - static inline void lima_vm_put(struct lima_vm *vm) - { -- kref_put(&vm->refcount, lima_vm_release); -+ if (vm) -+ kref_put(&vm->refcount, lima_vm_release); - } - - void lima_vm_print(struct lima_vm *vm); --- -2.17.1 - - -From 60fd3f2cb896fe4727ad7da32aaa85b4baedb097 Mon Sep 17 00:00:00 2001 -From: Qiang Yu -Date: Tue, 21 Apr 2020 21:35:45 +0800 -Subject: [PATCH] drm/lima: always set page directory when switch vm - -We need to flush TLB anyway before every task start, and the -page directory will be set to empty vm after suspend/resume, -so always set it to the task vm even no ctx switch happens. - -Tested-by: Bhushan Shah -Reviewed-by: Vasily Khoruzhick -Signed-off-by: Qiang Yu ---- - drivers/gpu/drm/lima/lima_mmu.c | 3 +-- - drivers/gpu/drm/lima/lima_sched.c | 14 ++++---------- - 2 files changed, 5 insertions(+), 12 deletions(-) - -diff --git a/drivers/gpu/drm/lima/lima_mmu.c b/drivers/gpu/drm/lima/lima_mmu.c -index f79d2af427e7..c26b751b0f9d 100644 ---- a/drivers/gpu/drm/lima/lima_mmu.c -+++ b/drivers/gpu/drm/lima/lima_mmu.c -@@ -113,8 +113,7 @@ void lima_mmu_switch_vm(struct lima_ip *ip, struct lima_vm *vm) - LIMA_MMU_STATUS, v, - v & LIMA_MMU_STATUS_STALL_ACTIVE); - -- if (vm) -- mmu_write(LIMA_MMU_DTE_ADDR, vm->pd.dma); -+ mmu_write(LIMA_MMU_DTE_ADDR, vm->pd.dma); - - /* flush the TLB */ - mmu_write(LIMA_MMU_COMMAND, LIMA_MMU_COMMAND_ZAP_CACHE); -diff --git a/drivers/gpu/drm/lima/lima_sched.c b/drivers/gpu/drm/lima/lima_sched.c -index 3ac5797e31fc..eb46db0717cd 100644 ---- a/drivers/gpu/drm/lima/lima_sched.c -+++ b/drivers/gpu/drm/lima/lima_sched.c -@@ -200,7 +200,6 @@ static struct dma_fence *lima_sched_run_job(struct drm_sched_job *job) - struct lima_sched_pipe *pipe = to_lima_pipe(job->sched); - struct lima_fence *fence; - struct dma_fence *ret; -- struct lima_vm *vm = NULL, *last_vm = NULL; - int i; - - /* after GPU reset */ -@@ -239,21 +238,16 @@ static struct dma_fence *lima_sched_run_job(struct drm_sched_job *job) - for (i = 0; i < pipe->num_l2_cache; i++) - lima_l2_cache_flush(pipe->l2_cache[i]); - -- if (task->vm != pipe->current_vm) { -- vm = lima_vm_get(task->vm); -- last_vm = pipe->current_vm; -- pipe->current_vm = task->vm; -- } -+ lima_vm_put(pipe->current_vm); -+ pipe->current_vm = lima_vm_get(task->vm); - - if (pipe->bcast_mmu) -- lima_mmu_switch_vm(pipe->bcast_mmu, vm); -+ lima_mmu_switch_vm(pipe->bcast_mmu, pipe->current_vm); - else { - for (i = 0; i < pipe->num_mmu; i++) -- lima_mmu_switch_vm(pipe->mmu[i], vm); -+ lima_mmu_switch_vm(pipe->mmu[i], pipe->current_vm); - } - -- lima_vm_put(last_vm); -- - trace_lima_task_run(task); - - pipe->error = false; --- -2.17.1 - - -From e88c2e9bf4d246ef449323208fc731aad659fc43 Mon Sep 17 00:00:00 2001 -From: Qiang Yu -Date: Tue, 21 Apr 2020 21:35:46 +0800 -Subject: [PATCH] drm/lima: add lima_devfreq_resume/suspend - -Used for device resume/suspend in the following commits. - -Tested-by: Bhushan Shah -Reviewed-by: Vasily Khoruzhick -Signed-off-by: Qiang Yu ---- - drivers/gpu/drm/lima/lima_devfreq.c | 24 ++++++++++++++++++++++++ - drivers/gpu/drm/lima/lima_devfreq.h | 3 +++ - 2 files changed, 27 insertions(+) - -diff --git a/drivers/gpu/drm/lima/lima_devfreq.c b/drivers/gpu/drm/lima/lima_devfreq.c -index 1d479b5924fe..bbe02817721b 100644 ---- a/drivers/gpu/drm/lima/lima_devfreq.c -+++ b/drivers/gpu/drm/lima/lima_devfreq.c -@@ -231,3 +231,27 @@ void lima_devfreq_record_idle(struct lima_devfreq *devfreq) - - spin_unlock_irqrestore(&devfreq->lock, irqflags); - } -+ -+int lima_devfreq_resume(struct lima_devfreq *devfreq) -+{ -+ unsigned long irqflags; -+ -+ if (!devfreq->devfreq) -+ return 0; -+ -+ spin_lock_irqsave(&devfreq->lock, irqflags); -+ -+ lima_devfreq_reset(devfreq); -+ -+ spin_unlock_irqrestore(&devfreq->lock, irqflags); -+ -+ return devfreq_resume_device(devfreq->devfreq); -+} -+ -+int lima_devfreq_suspend(struct lima_devfreq *devfreq) -+{ -+ if (!devfreq->devfreq) -+ return 0; -+ -+ return devfreq_suspend_device(devfreq->devfreq); -+} -diff --git a/drivers/gpu/drm/lima/lima_devfreq.h b/drivers/gpu/drm/lima/lima_devfreq.h -index 8d71ba9fb22a..5eed2975a375 100644 ---- a/drivers/gpu/drm/lima/lima_devfreq.h -+++ b/drivers/gpu/drm/lima/lima_devfreq.h -@@ -38,4 +38,7 @@ void lima_devfreq_fini(struct lima_device *ldev); - void lima_devfreq_record_busy(struct lima_devfreq *devfreq); - void lima_devfreq_record_idle(struct lima_devfreq *devfreq); - -+int lima_devfreq_resume(struct lima_devfreq *devfreq); -+int lima_devfreq_suspend(struct lima_devfreq *devfreq); -+ - #endif --- -2.17.1 - - -From 1f828aa538ce8def9479aec4669b655ff7e9cbf0 Mon Sep 17 00:00:00 2001 -From: Qiang Yu -Date: Tue, 21 Apr 2020 21:35:47 +0800 -Subject: [PATCH] drm/lima: power down ip blocks when pmu exit - -Prepare resume/suspend PM. - -v2: -Fix lima_pmu_wait_cmd timeout when mali400 case. - -Tested-by: Bhushan Shah -Reviewed-by: Vasily Khoruzhick -Signed-off-by: Qiang Yu ---- - drivers/gpu/drm/lima/lima_device.h | 2 ++ - drivers/gpu/drm/lima/lima_pmu.c | 53 +++++++++++++++++++++++++++++- - 2 files changed, 54 insertions(+), 1 deletion(-) - -diff --git a/drivers/gpu/drm/lima/lima_device.h b/drivers/gpu/drm/lima/lima_device.h -index 99b1fb147dad..9cd2718079bd 100644 ---- a/drivers/gpu/drm/lima/lima_device.h -+++ b/drivers/gpu/drm/lima/lima_device.h -@@ -64,6 +64,8 @@ struct lima_ip { - bool async_reset; - /* l2 cache */ - spinlock_t lock; -+ /* pmu */ -+ u32 mask; - } data; - }; - -diff --git a/drivers/gpu/drm/lima/lima_pmu.c b/drivers/gpu/drm/lima/lima_pmu.c -index 571f6d661581..d476569f2043 100644 ---- a/drivers/gpu/drm/lima/lima_pmu.c -+++ b/drivers/gpu/drm/lima/lima_pmu.c -@@ -21,7 +21,7 @@ static int lima_pmu_wait_cmd(struct lima_ip *ip) - v, v & LIMA_PMU_INT_CMD_MASK, - 100, 100000); - if (err) { -- dev_err(dev->dev, "timeout wait pmd cmd\n"); -+ dev_err(dev->dev, "timeout wait pmu cmd\n"); - return err; - } - -@@ -29,6 +29,40 @@ static int lima_pmu_wait_cmd(struct lima_ip *ip) - return 0; - } - -+static u32 lima_pmu_get_ip_mask(struct lima_ip *ip) -+{ -+ struct lima_device *dev = ip->dev; -+ u32 ret = 0; -+ int i; -+ -+ ret |= LIMA_PMU_POWER_GP0_MASK; -+ -+ if (dev->id == lima_gpu_mali400) { -+ ret |= LIMA_PMU_POWER_L2_MASK; -+ for (i = 0; i < 4; i++) { -+ if (dev->ip[lima_ip_pp0 + i].present) -+ ret |= LIMA_PMU_POWER_PP_MASK(i); -+ } -+ } else { -+ if (dev->ip[lima_ip_pp0].present) -+ ret |= LIMA450_PMU_POWER_PP0_MASK; -+ for (i = lima_ip_pp1; i <= lima_ip_pp3; i++) { -+ if (dev->ip[i].present) { -+ ret |= LIMA450_PMU_POWER_PP13_MASK; -+ break; -+ } -+ } -+ for (i = lima_ip_pp4; i <= lima_ip_pp7; i++) { -+ if (dev->ip[i].present) { -+ ret |= LIMA450_PMU_POWER_PP47_MASK; -+ break; -+ } -+ } -+ } -+ -+ return ret; -+} -+ - int lima_pmu_init(struct lima_ip *ip) - { - int err; -@@ -56,5 +90,22 @@ int lima_pmu_init(struct lima_ip *ip) - - void lima_pmu_fini(struct lima_ip *ip) - { -+ u32 stat; -+ -+ if (!ip->data.mask) -+ ip->data.mask = lima_pmu_get_ip_mask(ip); - -+ stat = ~pmu_read(LIMA_PMU_STATUS) & ip->data.mask; -+ if (stat) { -+ pmu_write(LIMA_PMU_POWER_DOWN, stat); -+ -+ /* Don't wait for interrupt on Mali400 if all domains are -+ * powered off because the HW won't generate an interrupt -+ * in this case. -+ */ -+ if (ip->dev->id == lima_gpu_mali400) -+ pmu_write(LIMA_PMU_INT_CLEAR, LIMA_PMU_INT_CMD_MASK); -+ else -+ lima_pmu_wait_cmd(ip); -+ } - } --- -2.17.1 - - -From e7a53d7606fd2e3d6f513f4d8440e2243a9968ae Mon Sep 17 00:00:00 2001 -From: Qiang Yu -Date: Tue, 21 Apr 2020 21:35:48 +0800 -Subject: [PATCH] drm/lima: add resume/suspend callback for each ip - -For called when PM do resume/suspend. - -Tested-by: Bhushan Shah -Reviewed-by: Vasily Khoruzhick -Signed-off-by: Qiang Yu ---- - drivers/gpu/drm/lima/lima_bcast.c | 25 ++++++++++++--- - drivers/gpu/drm/lima/lima_bcast.h | 2 ++ - drivers/gpu/drm/lima/lima_device.c | 4 +++ - drivers/gpu/drm/lima/lima_device.h | 2 +- - drivers/gpu/drm/lima/lima_dlbu.c | 17 +++++++++- - drivers/gpu/drm/lima/lima_dlbu.h | 2 ++ - drivers/gpu/drm/lima/lima_gp.c | 21 +++++++++++-- - drivers/gpu/drm/lima/lima_gp.h | 2 ++ - drivers/gpu/drm/lima/lima_l2_cache.c | 38 +++++++++++++++++------ - drivers/gpu/drm/lima/lima_l2_cache.h | 2 ++ - drivers/gpu/drm/lima/lima_mmu.c | 46 ++++++++++++++++++++-------- - drivers/gpu/drm/lima/lima_mmu.h | 2 ++ - drivers/gpu/drm/lima/lima_pmu.c | 24 +++++++++++++-- - drivers/gpu/drm/lima/lima_pmu.h | 2 ++ - drivers/gpu/drm/lima/lima_pp.c | 31 +++++++++++++++++-- - drivers/gpu/drm/lima/lima_pp.h | 4 +++ - 16 files changed, 187 insertions(+), 37 deletions(-) - -diff --git a/drivers/gpu/drm/lima/lima_bcast.c b/drivers/gpu/drm/lima/lima_bcast.c -index 288398027bfa..fbc43f243c54 100644 ---- a/drivers/gpu/drm/lima/lima_bcast.c -+++ b/drivers/gpu/drm/lima/lima_bcast.c -@@ -26,18 +26,33 @@ void lima_bcast_enable(struct lima_device *dev, int num_pp) - bcast_write(LIMA_BCAST_BROADCAST_MASK, mask); - } - -+static int lima_bcast_hw_init(struct lima_ip *ip) -+{ -+ bcast_write(LIMA_BCAST_BROADCAST_MASK, ip->data.mask << 16); -+ bcast_write(LIMA_BCAST_INTERRUPT_MASK, ip->data.mask); -+ return 0; -+} -+ -+int lima_bcast_resume(struct lima_ip *ip) -+{ -+ return lima_bcast_hw_init(ip); -+} -+ -+void lima_bcast_suspend(struct lima_ip *ip) -+{ -+ -+} -+ - int lima_bcast_init(struct lima_ip *ip) - { -- int i, mask = 0; -+ int i; - - for (i = lima_ip_pp0; i <= lima_ip_pp7; i++) { - if (ip->dev->ip[i].present) -- mask |= 1 << (i - lima_ip_pp0); -+ ip->data.mask |= 1 << (i - lima_ip_pp0); - } - -- bcast_write(LIMA_BCAST_BROADCAST_MASK, mask << 16); -- bcast_write(LIMA_BCAST_INTERRUPT_MASK, mask); -- return 0; -+ return lima_bcast_hw_init(ip); - } - - void lima_bcast_fini(struct lima_ip *ip) -diff --git a/drivers/gpu/drm/lima/lima_bcast.h b/drivers/gpu/drm/lima/lima_bcast.h -index c47e58563d0a..465ee587bceb 100644 ---- a/drivers/gpu/drm/lima/lima_bcast.h -+++ b/drivers/gpu/drm/lima/lima_bcast.h -@@ -6,6 +6,8 @@ - - struct lima_ip; - -+int lima_bcast_resume(struct lima_ip *ip); -+void lima_bcast_suspend(struct lima_ip *ip); - int lima_bcast_init(struct lima_ip *ip); - void lima_bcast_fini(struct lima_ip *ip); - -diff --git a/drivers/gpu/drm/lima/lima_device.c b/drivers/gpu/drm/lima/lima_device.c -index 29285dedd124..a2d4ec75b3b3 100644 ---- a/drivers/gpu/drm/lima/lima_device.c -+++ b/drivers/gpu/drm/lima/lima_device.c -@@ -25,6 +25,8 @@ struct lima_ip_desc { - - int (*init)(struct lima_ip *ip); - void (*fini)(struct lima_ip *ip); -+ int (*resume)(struct lima_ip *ip); -+ void (*suspend)(struct lima_ip *ip); - }; - - #define LIMA_IP_DESC(ipname, mst0, mst1, off0, off1, func, irq) \ -@@ -41,6 +43,8 @@ struct lima_ip_desc { - }, \ - .init = lima_##func##_init, \ - .fini = lima_##func##_fini, \ -+ .resume = lima_##func##_resume, \ -+ .suspend = lima_##func##_suspend, \ - } - - static struct lima_ip_desc lima_ip_desc[lima_ip_num] = { -diff --git a/drivers/gpu/drm/lima/lima_device.h b/drivers/gpu/drm/lima/lima_device.h -index 9cd2718079bd..d9df1b45dfa9 100644 ---- a/drivers/gpu/drm/lima/lima_device.h -+++ b/drivers/gpu/drm/lima/lima_device.h -@@ -64,7 +64,7 @@ struct lima_ip { - bool async_reset; - /* l2 cache */ - spinlock_t lock; -- /* pmu */ -+ /* pmu/bcast */ - u32 mask; - } data; - }; -diff --git a/drivers/gpu/drm/lima/lima_dlbu.c b/drivers/gpu/drm/lima/lima_dlbu.c -index 8399ceffb94b..c1d5ea35daa7 100644 ---- a/drivers/gpu/drm/lima/lima_dlbu.c -+++ b/drivers/gpu/drm/lima/lima_dlbu.c -@@ -42,7 +42,7 @@ void lima_dlbu_set_reg(struct lima_ip *ip, u32 *reg) - dlbu_write(LIMA_DLBU_START_TILE_POS, reg[3]); - } - --int lima_dlbu_init(struct lima_ip *ip) -+static int lima_dlbu_hw_init(struct lima_ip *ip) - { - struct lima_device *dev = ip->dev; - -@@ -52,6 +52,21 @@ int lima_dlbu_init(struct lima_ip *ip) - return 0; - } - -+int lima_dlbu_resume(struct lima_ip *ip) -+{ -+ return lima_dlbu_hw_init(ip); -+} -+ -+void lima_dlbu_suspend(struct lima_ip *ip) -+{ -+ -+} -+ -+int lima_dlbu_init(struct lima_ip *ip) -+{ -+ return lima_dlbu_hw_init(ip); -+} -+ - void lima_dlbu_fini(struct lima_ip *ip) - { - -diff --git a/drivers/gpu/drm/lima/lima_dlbu.h b/drivers/gpu/drm/lima/lima_dlbu.h -index 16f877984466..be71daaaee89 100644 ---- a/drivers/gpu/drm/lima/lima_dlbu.h -+++ b/drivers/gpu/drm/lima/lima_dlbu.h -@@ -12,6 +12,8 @@ void lima_dlbu_disable(struct lima_device *dev); - - void lima_dlbu_set_reg(struct lima_ip *ip, u32 *reg); - -+int lima_dlbu_resume(struct lima_ip *ip); -+void lima_dlbu_suspend(struct lima_ip *ip); - int lima_dlbu_init(struct lima_ip *ip); - void lima_dlbu_fini(struct lima_ip *ip); - -diff --git a/drivers/gpu/drm/lima/lima_gp.c b/drivers/gpu/drm/lima/lima_gp.c -index d8841c870d90..8dd501b7a3d0 100644 ---- a/drivers/gpu/drm/lima/lima_gp.c -+++ b/drivers/gpu/drm/lima/lima_gp.c -@@ -274,6 +274,23 @@ static void lima_gp_print_version(struct lima_ip *ip) - static struct kmem_cache *lima_gp_task_slab; - static int lima_gp_task_slab_refcnt; - -+static int lima_gp_hw_init(struct lima_ip *ip) -+{ -+ ip->data.async_reset = false; -+ lima_gp_soft_reset_async(ip); -+ return lima_gp_soft_reset_async_wait(ip); -+} -+ -+int lima_gp_resume(struct lima_ip *ip) -+{ -+ return lima_gp_hw_init(ip); -+} -+ -+void lima_gp_suspend(struct lima_ip *ip) -+{ -+ -+} -+ - int lima_gp_init(struct lima_ip *ip) - { - struct lima_device *dev = ip->dev; -@@ -281,9 +298,7 @@ int lima_gp_init(struct lima_ip *ip) - - lima_gp_print_version(ip); - -- ip->data.async_reset = false; -- lima_gp_soft_reset_async(ip); -- err = lima_gp_soft_reset_async_wait(ip); -+ err = lima_gp_hw_init(ip); - if (err) - return err; - -diff --git a/drivers/gpu/drm/lima/lima_gp.h b/drivers/gpu/drm/lima/lima_gp.h -index 516e5c1babbb..02ec9af78a51 100644 ---- a/drivers/gpu/drm/lima/lima_gp.h -+++ b/drivers/gpu/drm/lima/lima_gp.h -@@ -7,6 +7,8 @@ - struct lima_ip; - struct lima_device; - -+int lima_gp_resume(struct lima_ip *ip); -+void lima_gp_suspend(struct lima_ip *ip); - int lima_gp_init(struct lima_ip *ip); - void lima_gp_fini(struct lima_ip *ip); - -diff --git a/drivers/gpu/drm/lima/lima_l2_cache.c b/drivers/gpu/drm/lima/lima_l2_cache.c -index 6873a7af5a5c..c4080a02957b 100644 ---- a/drivers/gpu/drm/lima/lima_l2_cache.c -+++ b/drivers/gpu/drm/lima/lima_l2_cache.c -@@ -38,9 +38,35 @@ int lima_l2_cache_flush(struct lima_ip *ip) - return ret; - } - -+static int lima_l2_cache_hw_init(struct lima_ip *ip) -+{ -+ int err; -+ -+ err = lima_l2_cache_flush(ip); -+ if (err) -+ return err; -+ -+ l2_cache_write(LIMA_L2_CACHE_ENABLE, -+ LIMA_L2_CACHE_ENABLE_ACCESS | -+ LIMA_L2_CACHE_ENABLE_READ_ALLOCATE); -+ l2_cache_write(LIMA_L2_CACHE_MAX_READS, 0x1c); -+ -+ return 0; -+} -+ -+int lima_l2_cache_resume(struct lima_ip *ip) -+{ -+ return lima_l2_cache_hw_init(ip); -+} -+ -+void lima_l2_cache_suspend(struct lima_ip *ip) -+{ -+ -+} -+ - int lima_l2_cache_init(struct lima_ip *ip) - { -- int i, err; -+ int i; - u32 size; - struct lima_device *dev = ip->dev; - -@@ -63,15 +89,7 @@ int lima_l2_cache_init(struct lima_ip *ip) - 1 << (size & 0xff), - 1 << ((size >> 24) & 0xff)); - -- err = lima_l2_cache_flush(ip); -- if (err) -- return err; -- -- l2_cache_write(LIMA_L2_CACHE_ENABLE, -- LIMA_L2_CACHE_ENABLE_ACCESS|LIMA_L2_CACHE_ENABLE_READ_ALLOCATE); -- l2_cache_write(LIMA_L2_CACHE_MAX_READS, 0x1c); -- -- return 0; -+ return lima_l2_cache_hw_init(ip); - } - - void lima_l2_cache_fini(struct lima_ip *ip) -diff --git a/drivers/gpu/drm/lima/lima_l2_cache.h b/drivers/gpu/drm/lima/lima_l2_cache.h -index c63fb676ff14..1aeeefd53fb9 100644 ---- a/drivers/gpu/drm/lima/lima_l2_cache.h -+++ b/drivers/gpu/drm/lima/lima_l2_cache.h -@@ -6,6 +6,8 @@ - - struct lima_ip; - -+int lima_l2_cache_resume(struct lima_ip *ip); -+void lima_l2_cache_suspend(struct lima_ip *ip); - int lima_l2_cache_init(struct lima_ip *ip); - void lima_l2_cache_fini(struct lima_ip *ip); - -diff --git a/drivers/gpu/drm/lima/lima_mmu.c b/drivers/gpu/drm/lima/lima_mmu.c -index c26b751b0f9d..a1ae6c252dc2 100644 ---- a/drivers/gpu/drm/lima/lima_mmu.c -+++ b/drivers/gpu/drm/lima/lima_mmu.c -@@ -59,12 +59,44 @@ static irqreturn_t lima_mmu_irq_handler(int irq, void *data) - return IRQ_HANDLED; - } - --int lima_mmu_init(struct lima_ip *ip) -+static int lima_mmu_hw_init(struct lima_ip *ip) - { - struct lima_device *dev = ip->dev; - int err; - u32 v; - -+ mmu_write(LIMA_MMU_COMMAND, LIMA_MMU_COMMAND_HARD_RESET); -+ err = lima_mmu_send_command(LIMA_MMU_COMMAND_HARD_RESET, -+ LIMA_MMU_DTE_ADDR, v, v == 0); -+ if (err) -+ return err; -+ -+ mmu_write(LIMA_MMU_INT_MASK, -+ LIMA_MMU_INT_PAGE_FAULT | LIMA_MMU_INT_READ_BUS_ERROR); -+ mmu_write(LIMA_MMU_DTE_ADDR, dev->empty_vm->pd.dma); -+ return lima_mmu_send_command(LIMA_MMU_COMMAND_ENABLE_PAGING, -+ LIMA_MMU_STATUS, v, -+ v & LIMA_MMU_STATUS_PAGING_ENABLED); -+} -+ -+int lima_mmu_resume(struct lima_ip *ip) -+{ -+ if (ip->id == lima_ip_ppmmu_bcast) -+ return 0; -+ -+ return lima_mmu_hw_init(ip); -+} -+ -+void lima_mmu_suspend(struct lima_ip *ip) -+{ -+ -+} -+ -+int lima_mmu_init(struct lima_ip *ip) -+{ -+ struct lima_device *dev = ip->dev; -+ int err; -+ - if (ip->id == lima_ip_ppmmu_bcast) - return 0; - -@@ -74,12 +106,6 @@ int lima_mmu_init(struct lima_ip *ip) - return -EIO; - } - -- mmu_write(LIMA_MMU_COMMAND, LIMA_MMU_COMMAND_HARD_RESET); -- err = lima_mmu_send_command(LIMA_MMU_COMMAND_HARD_RESET, -- LIMA_MMU_DTE_ADDR, v, v == 0); -- if (err) -- return err; -- - err = devm_request_irq(dev->dev, ip->irq, lima_mmu_irq_handler, - IRQF_SHARED, lima_ip_name(ip), ip); - if (err) { -@@ -87,11 +113,7 @@ int lima_mmu_init(struct lima_ip *ip) - return err; - } - -- mmu_write(LIMA_MMU_INT_MASK, LIMA_MMU_INT_PAGE_FAULT | LIMA_MMU_INT_READ_BUS_ERROR); -- mmu_write(LIMA_MMU_DTE_ADDR, dev->empty_vm->pd.dma); -- return lima_mmu_send_command(LIMA_MMU_COMMAND_ENABLE_PAGING, -- LIMA_MMU_STATUS, v, -- v & LIMA_MMU_STATUS_PAGING_ENABLED); -+ return lima_mmu_hw_init(ip); - } - - void lima_mmu_fini(struct lima_ip *ip) -diff --git a/drivers/gpu/drm/lima/lima_mmu.h b/drivers/gpu/drm/lima/lima_mmu.h -index 4f8ccbebcba1..f0c97ac75ea0 100644 ---- a/drivers/gpu/drm/lima/lima_mmu.h -+++ b/drivers/gpu/drm/lima/lima_mmu.h -@@ -7,6 +7,8 @@ - struct lima_ip; - struct lima_vm; - -+int lima_mmu_resume(struct lima_ip *ip); -+void lima_mmu_suspend(struct lima_ip *ip); - int lima_mmu_init(struct lima_ip *ip); - void lima_mmu_fini(struct lima_ip *ip); - -diff --git a/drivers/gpu/drm/lima/lima_pmu.c b/drivers/gpu/drm/lima/lima_pmu.c -index d476569f2043..e397e1146e96 100644 ---- a/drivers/gpu/drm/lima/lima_pmu.c -+++ b/drivers/gpu/drm/lima/lima_pmu.c -@@ -63,7 +63,7 @@ static u32 lima_pmu_get_ip_mask(struct lima_ip *ip) - return ret; - } - --int lima_pmu_init(struct lima_ip *ip) -+static int lima_pmu_hw_init(struct lima_ip *ip) - { - int err; - u32 stat; -@@ -88,7 +88,7 @@ int lima_pmu_init(struct lima_ip *ip) - return 0; - } - --void lima_pmu_fini(struct lima_ip *ip) -+static void lima_pmu_hw_fini(struct lima_ip *ip) - { - u32 stat; - -@@ -109,3 +109,23 @@ void lima_pmu_fini(struct lima_ip *ip) - lima_pmu_wait_cmd(ip); - } - } -+ -+int lima_pmu_resume(struct lima_ip *ip) -+{ -+ return lima_pmu_hw_init(ip); -+} -+ -+void lima_pmu_suspend(struct lima_ip *ip) -+{ -+ lima_pmu_hw_fini(ip); -+} -+ -+int lima_pmu_init(struct lima_ip *ip) -+{ -+ return lima_pmu_hw_init(ip); -+} -+ -+void lima_pmu_fini(struct lima_ip *ip) -+{ -+ lima_pmu_hw_fini(ip); -+} -diff --git a/drivers/gpu/drm/lima/lima_pmu.h b/drivers/gpu/drm/lima/lima_pmu.h -index a2a18775eb07..652dc7af3047 100644 ---- a/drivers/gpu/drm/lima/lima_pmu.h -+++ b/drivers/gpu/drm/lima/lima_pmu.h -@@ -6,6 +6,8 @@ - - struct lima_ip; - -+int lima_pmu_resume(struct lima_ip *ip); -+void lima_pmu_suspend(struct lima_ip *ip); - int lima_pmu_init(struct lima_ip *ip); - void lima_pmu_fini(struct lima_ip *ip); - -diff --git a/drivers/gpu/drm/lima/lima_pp.c b/drivers/gpu/drm/lima/lima_pp.c -index 8fef224b93c8..33f01383409c 100644 ---- a/drivers/gpu/drm/lima/lima_pp.c -+++ b/drivers/gpu/drm/lima/lima_pp.c -@@ -223,6 +223,23 @@ static void lima_pp_print_version(struct lima_ip *ip) - lima_ip_name(ip), name, major, minor); - } - -+static int lima_pp_hw_init(struct lima_ip *ip) -+{ -+ ip->data.async_reset = false; -+ lima_pp_soft_reset_async(ip); -+ return lima_pp_soft_reset_async_wait(ip); -+} -+ -+int lima_pp_resume(struct lima_ip *ip) -+{ -+ return lima_pp_hw_init(ip); -+} -+ -+void lima_pp_suspend(struct lima_ip *ip) -+{ -+ -+} -+ - int lima_pp_init(struct lima_ip *ip) - { - struct lima_device *dev = ip->dev; -@@ -230,9 +247,7 @@ int lima_pp_init(struct lima_ip *ip) - - lima_pp_print_version(ip); - -- ip->data.async_reset = false; -- lima_pp_soft_reset_async(ip); -- err = lima_pp_soft_reset_async_wait(ip); -+ err = lima_pp_hw_init(ip); - if (err) - return err; - -@@ -254,6 +269,16 @@ void lima_pp_fini(struct lima_ip *ip) - - } - -+int lima_pp_bcast_resume(struct lima_ip *ip) -+{ -+ return 0; -+} -+ -+void lima_pp_bcast_suspend(struct lima_ip *ip) -+{ -+ -+} -+ - int lima_pp_bcast_init(struct lima_ip *ip) - { - struct lima_device *dev = ip->dev; -diff --git a/drivers/gpu/drm/lima/lima_pp.h b/drivers/gpu/drm/lima/lima_pp.h -index bf60c77b2633..16ec96de15a9 100644 ---- a/drivers/gpu/drm/lima/lima_pp.h -+++ b/drivers/gpu/drm/lima/lima_pp.h -@@ -7,9 +7,13 @@ - struct lima_ip; - struct lima_device; - -+int lima_pp_resume(struct lima_ip *ip); -+void lima_pp_suspend(struct lima_ip *ip); - int lima_pp_init(struct lima_ip *ip); - void lima_pp_fini(struct lima_ip *ip); - -+int lima_pp_bcast_resume(struct lima_ip *ip); -+void lima_pp_bcast_suspend(struct lima_ip *ip); - int lima_pp_bcast_init(struct lima_ip *ip); - void lima_pp_bcast_fini(struct lima_ip *ip); - --- -2.17.1 - - -From 26ee4346a85cd75c531cb31dc1fe66e43226f275 Mon Sep 17 00:00:00 2001 -From: Qiang Yu -Date: Tue, 21 Apr 2020 21:35:49 +0800 -Subject: [PATCH] drm/lima: separate clk/regulator enable/disable function - -For being used by both device init/fini and suspend/resume. - -Tested-by: Bhushan Shah -Reviewed-by: Vasily Khoruzhick -Signed-off-by: Qiang Yu ---- - drivers/gpu/drm/lima/lima_device.c | 105 +++++++++++++++++++---------- - 1 file changed, 68 insertions(+), 37 deletions(-) - -diff --git a/drivers/gpu/drm/lima/lima_device.c b/drivers/gpu/drm/lima/lima_device.c -index a2d4ec75b3b3..1d9b7f415da1 100644 ---- a/drivers/gpu/drm/lima/lima_device.c -+++ b/drivers/gpu/drm/lima/lima_device.c -@@ -81,26 +81,10 @@ const char *lima_ip_name(struct lima_ip *ip) - return lima_ip_desc[ip->id].name; - } - --static int lima_clk_init(struct lima_device *dev) -+static int lima_clk_enable(struct lima_device *dev) - { - int err; - -- dev->clk_bus = devm_clk_get(dev->dev, "bus"); -- if (IS_ERR(dev->clk_bus)) { -- err = PTR_ERR(dev->clk_bus); -- if (err != -EPROBE_DEFER) -- dev_err(dev->dev, "get bus clk failed %d\n", err); -- return err; -- } -- -- dev->clk_gpu = devm_clk_get(dev->dev, "core"); -- if (IS_ERR(dev->clk_gpu)) { -- err = PTR_ERR(dev->clk_gpu); -- if (err != -EPROBE_DEFER) -- dev_err(dev->dev, "get core clk failed %d\n", err); -- return err; -- } -- - err = clk_prepare_enable(dev->clk_bus); - if (err) - return err; -@@ -109,15 +93,7 @@ static int lima_clk_init(struct lima_device *dev) - if (err) - goto error_out0; - -- dev->reset = devm_reset_control_array_get_optional_shared(dev->dev); -- -- if (IS_ERR(dev->reset)) { -- err = PTR_ERR(dev->reset); -- if (err != -EPROBE_DEFER) -- dev_err(dev->dev, "get reset controller failed %d\n", -- err); -- goto error_out1; -- } else if (dev->reset != NULL) { -+ if (dev->reset) { - err = reset_control_deassert(dev->reset); - if (err) { - dev_err(dev->dev, -@@ -135,14 +111,76 @@ static int lima_clk_init(struct lima_device *dev) - return err; - } - --static void lima_clk_fini(struct lima_device *dev) -+static void lima_clk_disable(struct lima_device *dev) - { -- if (dev->reset != NULL) -+ if (dev->reset) - reset_control_assert(dev->reset); - clk_disable_unprepare(dev->clk_gpu); - clk_disable_unprepare(dev->clk_bus); - } - -+static int lima_clk_init(struct lima_device *dev) -+{ -+ int err; -+ -+ dev->clk_bus = devm_clk_get(dev->dev, "bus"); -+ if (IS_ERR(dev->clk_bus)) { -+ err = PTR_ERR(dev->clk_bus); -+ if (err != -EPROBE_DEFER) -+ dev_err(dev->dev, "get bus clk failed %d\n", err); -+ dev->clk_bus = NULL; -+ return err; -+ } -+ -+ dev->clk_gpu = devm_clk_get(dev->dev, "core"); -+ if (IS_ERR(dev->clk_gpu)) { -+ err = PTR_ERR(dev->clk_gpu); -+ if (err != -EPROBE_DEFER) -+ dev_err(dev->dev, "get core clk failed %d\n", err); -+ dev->clk_gpu = NULL; -+ return err; -+ } -+ -+ dev->reset = devm_reset_control_array_get_optional_shared(dev->dev); -+ if (IS_ERR(dev->reset)) { -+ err = PTR_ERR(dev->reset); -+ if (err != -EPROBE_DEFER) -+ dev_err(dev->dev, "get reset controller failed %d\n", -+ err); -+ dev->reset = NULL; -+ return err; -+ } -+ -+ return lima_clk_enable(dev); -+} -+ -+static void lima_clk_fini(struct lima_device *dev) -+{ -+ lima_clk_disable(dev); -+} -+ -+static int lima_regulator_enable(struct lima_device *dev) -+{ -+ int ret; -+ -+ if (!dev->regulator) -+ return 0; -+ -+ ret = regulator_enable(dev->regulator); -+ if (ret < 0) { -+ dev_err(dev->dev, "failed to enable regulator: %d\n", ret); -+ return ret; -+ } -+ -+ return 0; -+} -+ -+static void lima_regulator_disable(struct lima_device *dev) -+{ -+ if (dev->regulator) -+ regulator_disable(dev->regulator); -+} -+ - static int lima_regulator_init(struct lima_device *dev) - { - int ret; -@@ -158,19 +196,12 @@ static int lima_regulator_init(struct lima_device *dev) - return ret; - } - -- ret = regulator_enable(dev->regulator); -- if (ret < 0) { -- dev_err(dev->dev, "failed to enable regulator: %d\n", ret); -- return ret; -- } -- -- return 0; -+ return lima_regulator_enable(dev); - } - - static void lima_regulator_fini(struct lima_device *dev) - { -- if (dev->regulator) -- regulator_disable(dev->regulator); -+ lima_regulator_disable(dev); - } - - static int lima_init_ip(struct lima_device *dev, int index) --- -2.17.1 - - -From 90f27ceb82a87cabf926e65748bdd60cf0e191b6 Mon Sep 17 00:00:00 2001 -From: Qiang Yu -Date: Tue, 21 Apr 2020 21:35:50 +0800 -Subject: [PATCH] drm/lima: add pm resume/suspend ops - -Add driver pm system and runtime hardware resume/suspend ops. -Note this won't enable runtime pm of the device yet. - -v2: -Do clock and power gating when suspend/resume. - -Tested-by: Bhushan Shah -Reviewed-by: Vasily Khoruzhick -Signed-off-by: Qiang Yu ---- - drivers/gpu/drm/lima/lima_device.c | 90 ++++++++++++++++++++++++++++++ - drivers/gpu/drm/lima/lima_device.h | 3 + - drivers/gpu/drm/lima/lima_drv.c | 7 +++ - 3 files changed, 100 insertions(+) - -diff --git a/drivers/gpu/drm/lima/lima_device.c b/drivers/gpu/drm/lima/lima_device.c -index 1d9b7f415da1..65fdca366e41 100644 ---- a/drivers/gpu/drm/lima/lima_device.c -+++ b/drivers/gpu/drm/lima/lima_device.c -@@ -247,6 +247,27 @@ static void lima_fini_ip(struct lima_device *ldev, int index) - desc->fini(ip); - } - -+static int lima_resume_ip(struct lima_device *ldev, int index) -+{ -+ struct lima_ip_desc *desc = lima_ip_desc + index; -+ struct lima_ip *ip = ldev->ip + index; -+ int ret = 0; -+ -+ if (ip->present) -+ ret = desc->resume(ip); -+ -+ return ret; -+} -+ -+static void lima_suspend_ip(struct lima_device *ldev, int index) -+{ -+ struct lima_ip_desc *desc = lima_ip_desc + index; -+ struct lima_ip *ip = ldev->ip + index; -+ -+ if (ip->present) -+ desc->suspend(ip); -+} -+ - static int lima_init_gp_pipe(struct lima_device *dev) - { - struct lima_sched_pipe *pipe = dev->pipe + lima_pipe_gp; -@@ -441,3 +462,72 @@ void lima_device_fini(struct lima_device *ldev) - - lima_clk_fini(ldev); - } -+ -+int lima_device_resume(struct device *dev) -+{ -+ struct lima_device *ldev = dev_get_drvdata(dev); -+ int i, err; -+ -+ err = lima_clk_enable(ldev); -+ if (err) { -+ dev_err(dev, "resume clk fail %d\n", err); -+ return err; -+ } -+ -+ err = lima_regulator_enable(ldev); -+ if (err) { -+ dev_err(dev, "resume regulator fail %d\n", err); -+ goto err_out0; -+ } -+ -+ for (i = 0; i < lima_ip_num; i++) { -+ err = lima_resume_ip(ldev, i); -+ if (err) { -+ dev_err(dev, "resume ip %d fail\n", i); -+ goto err_out1; -+ } -+ } -+ -+ err = lima_devfreq_resume(&ldev->devfreq); -+ if (err) { -+ dev_err(dev, "devfreq resume fail\n"); -+ goto err_out1; -+ } -+ -+ return 0; -+ -+err_out1: -+ while (--i >= 0) -+ lima_suspend_ip(ldev, i); -+ lima_regulator_disable(ldev); -+err_out0: -+ lima_clk_disable(ldev); -+ return err; -+} -+ -+int lima_device_suspend(struct device *dev) -+{ -+ struct lima_device *ldev = dev_get_drvdata(dev); -+ int i, err; -+ -+ /* check any task running */ -+ for (i = 0; i < lima_pipe_num; i++) { -+ if (atomic_read(&ldev->pipe[i].base.hw_rq_count)) -+ return -EBUSY; -+ } -+ -+ err = lima_devfreq_suspend(&ldev->devfreq); -+ if (err) { -+ dev_err(dev, "devfreq suspend fail\n"); -+ return err; -+ } -+ -+ for (i = lima_ip_num - 1; i >= 0; i--) -+ lima_suspend_ip(ldev, i); -+ -+ lima_regulator_disable(ldev); -+ -+ lima_clk_disable(ldev); -+ -+ return 0; -+} -diff --git a/drivers/gpu/drm/lima/lima_device.h b/drivers/gpu/drm/lima/lima_device.h -index d9df1b45dfa9..41b9d7b4bcc7 100644 ---- a/drivers/gpu/drm/lima/lima_device.h -+++ b/drivers/gpu/drm/lima/lima_device.h -@@ -140,4 +140,7 @@ static inline int lima_poll_timeout(struct lima_ip *ip, lima_poll_func_t func, - return 0; - } - -+int lima_device_suspend(struct device *dev); -+int lima_device_resume(struct device *dev); -+ - #endif -diff --git a/drivers/gpu/drm/lima/lima_drv.c b/drivers/gpu/drm/lima/lima_drv.c -index 3d63d496cfc2..f3fe0a2f764b 100644 ---- a/drivers/gpu/drm/lima/lima_drv.c -+++ b/drivers/gpu/drm/lima/lima_drv.c -@@ -5,6 +5,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -451,11 +452,17 @@ static const struct of_device_id dt_match[] = { - }; - MODULE_DEVICE_TABLE(of, dt_match); - -+static const struct dev_pm_ops lima_pm_ops = { -+ SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume) -+ SET_RUNTIME_PM_OPS(lima_device_suspend, lima_device_resume, NULL) -+}; -+ - static struct platform_driver lima_platform_driver = { - .probe = lima_pdev_probe, - .remove = lima_pdev_remove, - .driver = { - .name = "lima", -+ .pm = &lima_pm_ops, - .of_match_table = dt_match, - }, - }; --- -2.17.1 - - -From 77f3ae2361292cef89c0a06e745991cefb52fcdc Mon Sep 17 00:00:00 2001 -From: Qiang Yu -Date: Tue, 21 Apr 2020 21:35:51 +0800 -Subject: [PATCH] drm/lima: enable runtime pm - -Enable runtime pm by default so GPU suspend when idle -for 200ms. This value can be changed by -autosuspend_delay_ms in device's power sysfs dir. - -On Allwinner H3 lima_device_resume takes ~40us and -lima_device_suspend takes ~20us. - -Tested-by: Bhushan Shah -Reviewed-by: Vasily Khoruzhick -Signed-off-by: Qiang Yu ---- - drivers/gpu/drm/lima/lima_drv.c | 21 ++++++++++++---- - drivers/gpu/drm/lima/lima_sched.c | 41 +++++++++++++++++++++++++++---- - 2 files changed, 52 insertions(+), 10 deletions(-) - -diff --git a/drivers/gpu/drm/lima/lima_drv.c b/drivers/gpu/drm/lima/lima_drv.c -index f3fe0a2f764b..a831565af813 100644 ---- a/drivers/gpu/drm/lima/lima_drv.c -+++ b/drivers/gpu/drm/lima/lima_drv.c -@@ -404,6 +404,12 @@ static int lima_pdev_probe(struct platform_device *pdev) - goto err_out2; - } - -+ pm_runtime_set_active(ldev->dev); -+ pm_runtime_mark_last_busy(ldev->dev); -+ pm_runtime_set_autosuspend_delay(ldev->dev, 200); -+ pm_runtime_use_autosuspend(ldev->dev); -+ pm_runtime_enable(ldev->dev); -+ - /* - * Register the DRM device with the core and the connectors with - * sysfs. -@@ -412,17 +418,16 @@ static int lima_pdev_probe(struct platform_device *pdev) - if (err < 0) - goto err_out3; - -- platform_set_drvdata(pdev, ldev); -- - if (sysfs_create_bin_file(&ldev->dev->kobj, &lima_error_state_attr)) - dev_warn(ldev->dev, "fail to create error state sysfs\n"); - - return 0; - - err_out3: -- lima_device_fini(ldev); --err_out2: -+ pm_runtime_disable(ldev->dev); - lima_devfreq_fini(ldev); -+err_out2: -+ lima_device_fini(ldev); - err_out1: - drm_dev_put(ddev); - err_out0: -@@ -436,10 +441,16 @@ static int lima_pdev_remove(struct platform_device *pdev) - struct drm_device *ddev = ldev->ddev; - - sysfs_remove_bin_file(&ldev->dev->kobj, &lima_error_state_attr); -- platform_set_drvdata(pdev, NULL); -+ - drm_dev_unregister(ddev); -+ -+ /* stop autosuspend to make sure device is in active state */ -+ pm_runtime_set_autosuspend_delay(ldev->dev, -1); -+ pm_runtime_disable(ldev->dev); -+ - lima_devfreq_fini(ldev); - lima_device_fini(ldev); -+ - drm_dev_put(ddev); - lima_sched_slab_fini(); - return 0; -diff --git a/drivers/gpu/drm/lima/lima_sched.c b/drivers/gpu/drm/lima/lima_sched.c -index eb46db0717cd..e6cefda00279 100644 ---- a/drivers/gpu/drm/lima/lima_sched.c -+++ b/drivers/gpu/drm/lima/lima_sched.c -@@ -4,6 +4,7 @@ - #include - #include - #include -+#include - - #include "lima_devfreq.h" - #include "lima_drv.h" -@@ -194,13 +195,36 @@ static struct dma_fence *lima_sched_dependency(struct drm_sched_job *job, - return NULL; - } - -+static int lima_pm_busy(struct lima_device *ldev) -+{ -+ int ret; -+ -+ /* resume GPU if it has been suspended by runtime PM */ -+ ret = pm_runtime_get_sync(ldev->dev); -+ if (ret < 0) -+ return ret; -+ -+ lima_devfreq_record_busy(&ldev->devfreq); -+ return 0; -+} -+ -+static void lima_pm_idle(struct lima_device *ldev) -+{ -+ lima_devfreq_record_idle(&ldev->devfreq); -+ -+ /* GPU can do auto runtime suspend */ -+ pm_runtime_mark_last_busy(ldev->dev); -+ pm_runtime_put_autosuspend(ldev->dev); -+} -+ - static struct dma_fence *lima_sched_run_job(struct drm_sched_job *job) - { - struct lima_sched_task *task = to_lima_task(job); - struct lima_sched_pipe *pipe = to_lima_pipe(job->sched); -+ struct lima_device *ldev = pipe->ldev; - struct lima_fence *fence; - struct dma_fence *ret; -- int i; -+ int i, err; - - /* after GPU reset */ - if (job->s_fence->finished.error < 0) -@@ -209,6 +233,13 @@ static struct dma_fence *lima_sched_run_job(struct drm_sched_job *job) - fence = lima_fence_create(pipe); - if (!fence) - return NULL; -+ -+ err = lima_pm_busy(ldev); -+ if (err < 0) { -+ dma_fence_put(&fence->base); -+ return NULL; -+ } -+ - task->fence = &fence->base; - - /* for caller usage of the fence, otherwise irq handler -@@ -216,8 +247,6 @@ static struct dma_fence *lima_sched_run_job(struct drm_sched_job *job) - */ - ret = dma_fence_get(task->fence); - -- lima_devfreq_record_busy(&pipe->ldev->devfreq); -- - pipe->current_task = task; - - /* this is needed for MMU to work correctly, otherwise GP/PP -@@ -388,6 +417,7 @@ static void lima_sched_timedout_job(struct drm_sched_job *job) - { - struct lima_sched_pipe *pipe = to_lima_pipe(job->sched); - struct lima_sched_task *task = to_lima_task(job); -+ struct lima_device *ldev = pipe->ldev; - - if (!pipe->error) - DRM_ERROR("lima job timeout\n"); -@@ -413,7 +443,7 @@ static void lima_sched_timedout_job(struct drm_sched_job *job) - pipe->current_vm = NULL; - pipe->current_task = NULL; - -- lima_devfreq_record_idle(&pipe->ldev->devfreq); -+ lima_pm_idle(ldev); - - drm_sched_resubmit_jobs(&pipe->base); - drm_sched_start(&pipe->base, true); -@@ -485,6 +515,7 @@ void lima_sched_pipe_fini(struct lima_sched_pipe *pipe) - void lima_sched_pipe_task_done(struct lima_sched_pipe *pipe) - { - struct lima_sched_task *task = pipe->current_task; -+ struct lima_device *ldev = pipe->ldev; - - if (pipe->error) { - if (task && task->recoverable) -@@ -495,6 +526,6 @@ void lima_sched_pipe_task_done(struct lima_sched_pipe *pipe) - pipe->task_fini(pipe); - dma_fence_signal(task->fence); - -- lima_devfreq_record_idle(&pipe->ldev->devfreq); -+ lima_pm_idle(ldev); - } - } --- -2.17.1 - - -From 5f88c11fbc001f7cd701af13a4a40c94572848c7 Mon Sep 17 00:00:00 2001 -From: Martin Blumenstingl -Date: Thu, 19 Mar 2020 21:34:26 +0100 -Subject: [PATCH] dt-bindings: gpu: mali-utgard: Add the #cooling-cells - property - -The GPU can be one of the big heat sources on a SoC. Allow the -"#cooling-cells" property to be specified for ARM Mali Utgard GPUs so -the GPU clock speeds (and voltages) can be reduced to prevent a SoC from -overheating. - -Signed-off-by: Martin Blumenstingl -Reviewed-by: Qiang Yu ---- - Documentation/devicetree/bindings/gpu/arm,mali-utgard.yaml | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/Documentation/devicetree/bindings/gpu/arm,mali-utgard.yaml b/Documentation/devicetree/bindings/gpu/arm,mali-utgard.yaml -index afde81be3c29..33548ca2a759 100644 ---- a/Documentation/devicetree/bindings/gpu/arm,mali-utgard.yaml -+++ b/Documentation/devicetree/bindings/gpu/arm,mali-utgard.yaml -@@ -107,6 +107,9 @@ properties: - - operating-points-v2: true - -+ "#cooling-cells": -+ const: 2 -+ - required: - - compatible - - reg -@@ -162,6 +165,7 @@ examples: - clocks = <&ccu 1>, <&ccu 2>; - clock-names = "bus", "core"; - resets = <&ccu 1>; -+ #cooling-cells = <2>; - }; - - ... --- -2.17.1 - diff --git a/patch/kernel/rk322x-current/01-linux-0011-v4l2-from-5.9.patch b/patch/kernel/rk322x-current/01-linux-0011-v4l2-from-5.9.patch new file mode 100644 index 000000000..79efdfdb0 --- /dev/null +++ b/patch/kernel/rk322x-current/01-linux-0011-v4l2-from-5.9.patch @@ -0,0 +1,1190 @@ +From 7ecb99ec97624da3354bc7702179e21309fb3a4e Mon Sep 17 00:00:00 2001 +From: Ezequiel Garcia +Date: Wed, 1 Jul 2020 15:17:30 +0200 +Subject: [PATCH] v4l2-core: Print control name in VIDIOC_S/G_(EXT)_CTRL(S) + +While debugging, it's currently really hard to identify controls +by their ID. Print the control name making the print more helpful. + +With this change, the print changes from: + +video1: VIDIOC_S_EXT_CTRLS: which=0xf010000, count=5, error_idx=4, request_fd=45, id/size=0x990ce8/1048, id/size=0x990ce9/12, id/size=0x990cea/480, id/size=0x990ceb/896, id/size=0x990cec/400 + +video1: VIDIOC_S_EXT_CTRLS: which=0xf010000, count=5, error_idx=4, request_fd=42, name=H264 Sequence Parameter Set, id/size=0x990ce8/1048, name=H264 Picture Parameter Set, id/size=0x990ce9/12, name=H264 Scaling Matrix, id/size=0x990cea/480, name=H264 Slice Parameters, id/size=0x990ceb/896, name=H264 Decode Parameters, id/size=0x990cec/400 + +For instance, this is specially helpful when the ioctl fails. Consider +the following example: + +v4l2-ctrls: prepare_ext_ctrls: video1: pointer control id 0x990cec size too small, 400 bytes but 784 bytes needed +v4l2-ctrls: try_set_ext_ctrls: video1: video1: try_set_ext_ctrls_common failed (-14) +video1: VIDIOC_S_EXT_CTRLS: error -14: which=0xf010000, count=5, error_idx=5, request_fd=39, name=H264 Sequence Parameter Set, id/size=0x990ce8/1048, name=H264 Picture Parameter Set, id/size=0x990ce9/12, name=H264 Scaling Matrix, id/size=0x990cea/480, name=H264 Slice Parameters, id/size=0x990ceb/896, name=H264 Decode Parameters, id/size=0x990cec/400 + +Signed-off-by: Ezequiel Garcia +Signed-off-by: Hans Verkuil +Signed-off-by: Mauro Carvalho Chehab +(cherry picked from commit a69a7a33268308ddcc9abf0f7d7cd61ec4300cbe) +--- + drivers/media/v4l2-core/v4l2-ioctl.c | 14 ++++++++++---- + 1 file changed, 10 insertions(+), 4 deletions(-) + +diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c +index 5e057f798a15..ccf947632a3b 100644 +--- a/drivers/media/v4l2-core/v4l2-ioctl.c ++++ b/drivers/media/v4l2-core/v4l2-ioctl.c +@@ -582,7 +582,10 @@ static void v4l_print_querymenu(const void *arg, bool write_only) + static void v4l_print_control(const void *arg, bool write_only) + { + const struct v4l2_control *p = arg; ++ const char *name = v4l2_ctrl_get_name(p->id); + ++ if (name) ++ pr_cont("name=%s, ", name); + pr_cont("id=0x%x, value=%d\n", p->id, p->value); + } + +@@ -594,12 +597,15 @@ static void v4l_print_ext_controls(const void *arg, bool write_only) + pr_cont("which=0x%x, count=%d, error_idx=%d, request_fd=%d", + p->which, p->count, p->error_idx, p->request_fd); + for (i = 0; i < p->count; i++) { ++ unsigned int id = p->controls[i].id; ++ const char *name = v4l2_ctrl_get_name(id); ++ ++ if (name) ++ pr_cont(", name=%s", name); + if (!p->controls[i].size) +- pr_cont(", id/val=0x%x/0x%x", +- p->controls[i].id, p->controls[i].value); ++ pr_cont(", id/val=0x%x/0x%x", id, p->controls[i].value); + else +- pr_cont(", id/size=0x%x/%u", +- p->controls[i].id, p->controls[i].size); ++ pr_cont(", id/size=0x%x/%u", id, p->controls[i].size); + } + pr_cont("\n"); + } + +From d524e0ef051dcccefbdff08e1023489922da198f Mon Sep 17 00:00:00 2001 +From: Ezequiel Garcia +Date: Wed, 24 Jun 2020 21:28:00 +0200 +Subject: [PATCH] media: Add V4L2_TYPE_IS_CAPTURE helper + +It's all too easy to get confused by the V4L2_TYPE_IS_OUTPUT +macro, when it's used as !V4L2_TYPE_IS_OUTPUT. + +Reduce the risk of confusion with macro to explicitly +check for the CAPTURE queue type case. + +This change does not affect functionality, and it's +only intended to make the code more readable. + +Suggested-by: Nicolas Dufresne +Signed-off-by: Ezequiel Garcia +Signed-off-by: Hans Verkuil +[hverkuil-cisco@xs4all.nl: checkpatch: align with parenthesis] +Signed-off-by: Mauro Carvalho Chehab +(cherry picked from commit b3ab1c6058fad8cd5726f24e9ed9053e43bb2af4) +--- + drivers/media/common/videobuf2/videobuf2-v4l2.c | 4 ++-- + drivers/media/platform/exynos-gsc/gsc-core.c | 2 +- + drivers/media/platform/exynos-gsc/gsc-m2m.c | 2 +- + drivers/media/platform/mtk-jpeg/mtk_jpeg_core.c | 2 +- + drivers/media/platform/mtk-mdp/mtk_mdp_m2m.c | 7 +++---- + drivers/media/platform/rcar_jpu.c | 2 +- + drivers/media/platform/sti/hva/hva-v4l2.c | 2 +- + drivers/media/platform/ti-vpe/vpe.c | 2 +- + drivers/media/test-drivers/vicodec/vicodec-core.c | 6 +++--- + drivers/media/v4l2-core/v4l2-mem2mem.c | 6 +++--- + drivers/staging/media/hantro/hantro_v4l2.c | 2 +- + drivers/staging/media/rkvdec/rkvdec.c | 2 +- + include/uapi/linux/videodev2.h | 2 ++ + 13 files changed, 21 insertions(+), 20 deletions(-) + +diff --git a/drivers/media/common/videobuf2/videobuf2-v4l2.c b/drivers/media/common/videobuf2/videobuf2-v4l2.c +index eb5d5db96552..fd32c2e64809 100644 +--- a/drivers/media/common/videobuf2/videobuf2-v4l2.c ++++ b/drivers/media/common/videobuf2/videobuf2-v4l2.c +@@ -94,7 +94,7 @@ static int __verify_length(struct vb2_buffer *vb, const struct v4l2_buffer *b) + unsigned int bytesused; + unsigned int plane; + +- if (!V4L2_TYPE_IS_OUTPUT(b->type)) ++ if (V4L2_TYPE_IS_CAPTURE(b->type)) + return 0; + + if (V4L2_TYPE_IS_MULTIPLANAR(b->type)) { +@@ -307,7 +307,7 @@ static int vb2_fill_vb2_v4l2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b + + /* Zero flags that we handle */ + vbuf->flags = b->flags & ~V4L2_BUFFER_MASK_FLAGS; +- if (!vb->vb2_queue->copy_timestamp || !V4L2_TYPE_IS_OUTPUT(b->type)) { ++ if (!vb->vb2_queue->copy_timestamp || V4L2_TYPE_IS_CAPTURE(b->type)) { + /* + * Non-COPY timestamps and non-OUTPUT queues will get + * their timestamp and timestamp source flags from the +diff --git a/drivers/media/platform/exynos-gsc/gsc-core.c b/drivers/media/platform/exynos-gsc/gsc-core.c +index f6650b45bc3d..9f41c2e7097a 100644 +--- a/drivers/media/platform/exynos-gsc/gsc-core.c ++++ b/drivers/media/platform/exynos-gsc/gsc-core.c +@@ -577,7 +577,7 @@ int gsc_try_selection(struct gsc_ctx *ctx, struct v4l2_selection *s) + v4l_bound_align_image(&tmp_w, min_w, max_w, mod_x, + &tmp_h, min_h, max_h, mod_y, 0); + +- if (!V4L2_TYPE_IS_OUTPUT(s->type) && ++ if (V4L2_TYPE_IS_CAPTURE(s->type) && + (ctx->gsc_ctrls.rotate->val == 90 || + ctx->gsc_ctrls.rotate->val == 270)) + gsc_check_crop_change(tmp_h, tmp_w, +diff --git a/drivers/media/platform/exynos-gsc/gsc-m2m.c b/drivers/media/platform/exynos-gsc/gsc-m2m.c +index e2c162635f72..27a3c92c73bc 100644 +--- a/drivers/media/platform/exynos-gsc/gsc-m2m.c ++++ b/drivers/media/platform/exynos-gsc/gsc-m2m.c +@@ -255,7 +255,7 @@ static int gsc_m2m_buf_prepare(struct vb2_buffer *vb) + if (IS_ERR(frame)) + return PTR_ERR(frame); + +- if (!V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type)) { ++ if (V4L2_TYPE_IS_CAPTURE(vb->vb2_queue->type)) { + for (i = 0; i < frame->fmt->num_planes; i++) + vb2_set_plane_payload(vb, i, frame->payload[i]); + } +diff --git a/drivers/media/platform/mtk-jpeg/mtk_jpeg_core.c b/drivers/media/platform/mtk-jpeg/mtk_jpeg_core.c +index f82a81a3bdee..61fed1e35a00 100644 +--- a/drivers/media/platform/mtk-jpeg/mtk_jpeg_core.c ++++ b/drivers/media/platform/mtk-jpeg/mtk_jpeg_core.c +@@ -731,7 +731,7 @@ static void mtk_jpeg_stop_streaming(struct vb2_queue *q) + * subsampling. Update capture queue when the stream is off. + */ + if (ctx->state == MTK_JPEG_SOURCE_CHANGE && +- !V4L2_TYPE_IS_OUTPUT(q->type)) { ++ V4L2_TYPE_IS_CAPTURE(q->type)) { + struct mtk_jpeg_src_buf *src_buf; + + vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); +diff --git a/drivers/media/platform/mtk-mdp/mtk_mdp_m2m.c b/drivers/media/platform/mtk-mdp/mtk_mdp_m2m.c +index 821f2cf325f0..a6ea22b57416 100644 +--- a/drivers/media/platform/mtk-mdp/mtk_mdp_m2m.c ++++ b/drivers/media/platform/mtk-mdp/mtk_mdp_m2m.c +@@ -193,7 +193,7 @@ static const struct mtk_mdp_fmt *mtk_mdp_try_fmt_mplane(struct mtk_mdp_ctx *ctx, + + pix_mp->field = V4L2_FIELD_NONE; + pix_mp->pixelformat = fmt->pixelformat; +- if (!V4L2_TYPE_IS_OUTPUT(f->type)) { ++ if (V4L2_TYPE_IS_CAPTURE(f->type)) { + pix_mp->colorspace = ctx->colorspace; + pix_mp->xfer_func = ctx->xfer_func; + pix_mp->ycbcr_enc = ctx->ycbcr_enc; +@@ -327,9 +327,8 @@ static int mtk_mdp_try_crop(struct mtk_mdp_ctx *ctx, u32 type, + mtk_mdp_bound_align_image(&new_w, min_w, max_w, align_w, + &new_h, min_h, max_h, align_h); + +- if (!V4L2_TYPE_IS_OUTPUT(type) && +- (ctx->ctrls.rotate->val == 90 || +- ctx->ctrls.rotate->val == 270)) ++ if (V4L2_TYPE_IS_CAPTURE(type) && ++ (ctx->ctrls.rotate->val == 90 || ctx->ctrls.rotate->val == 270)) + mtk_mdp_check_crop_change(new_h, new_w, + &r->width, &r->height); + else +diff --git a/drivers/media/platform/rcar_jpu.c b/drivers/media/platform/rcar_jpu.c +index 5250a14324e9..9b99ff368698 100644 +--- a/drivers/media/platform/rcar_jpu.c ++++ b/drivers/media/platform/rcar_jpu.c +@@ -1066,7 +1066,7 @@ static int jpu_buf_prepare(struct vb2_buffer *vb) + } + + /* decoder capture queue */ +- if (!ctx->encoder && !V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type)) ++ if (!ctx->encoder && V4L2_TYPE_IS_CAPTURE(vb->vb2_queue->type)) + vb2_set_plane_payload(vb, i, size); + } + +diff --git a/drivers/media/platform/sti/hva/hva-v4l2.c b/drivers/media/platform/sti/hva/hva-v4l2.c +index 197b99d8fd9c..bb34d6997d99 100644 +--- a/drivers/media/platform/sti/hva/hva-v4l2.c ++++ b/drivers/media/platform/sti/hva/hva-v4l2.c +@@ -1087,7 +1087,7 @@ static void hva_stop_streaming(struct vb2_queue *vq) + + if ((V4L2_TYPE_IS_OUTPUT(vq->type) && + vb2_is_streaming(&ctx->fh.m2m_ctx->cap_q_ctx.q)) || +- (!V4L2_TYPE_IS_OUTPUT(vq->type) && ++ (V4L2_TYPE_IS_CAPTURE(vq->type) && + vb2_is_streaming(&ctx->fh.m2m_ctx->out_q_ctx.q))) { + dev_dbg(dev, "%s %s out=%d cap=%d\n", + ctx->name, to_type_str(vq->type), +diff --git a/drivers/media/platform/ti-vpe/vpe.c b/drivers/media/platform/ti-vpe/vpe.c +index cff2fcd6d812..346f8212791c 100644 +--- a/drivers/media/platform/ti-vpe/vpe.c ++++ b/drivers/media/platform/ti-vpe/vpe.c +@@ -1576,7 +1576,7 @@ static int vpe_g_fmt(struct file *file, void *priv, struct v4l2_format *f) + + *f = q_data->format; + +- if (!V4L2_TYPE_IS_OUTPUT(f->type)) { ++ if (V4L2_TYPE_IS_CAPTURE(f->type)) { + struct vpe_q_data *s_q_data; + struct v4l2_pix_format_mplane *spix; + +diff --git a/drivers/media/test-drivers/vicodec/vicodec-core.c b/drivers/media/test-drivers/vicodec/vicodec-core.c +index e879290727ef..8941d73f6611 100644 +--- a/drivers/media/test-drivers/vicodec/vicodec-core.c ++++ b/drivers/media/test-drivers/vicodec/vicodec-core.c +@@ -1442,7 +1442,7 @@ static void vicodec_buf_queue(struct vb2_buffer *vb) + .u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION, + }; + +- if (!V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type) && ++ if (V4L2_TYPE_IS_CAPTURE(vb->vb2_queue->type) && + vb2_is_streaming(vb->vb2_queue) && + v4l2_m2m_dst_buf_is_last(ctx->fh.m2m_ctx)) { + unsigned int i; +@@ -1479,7 +1479,7 @@ static void vicodec_buf_queue(struct vb2_buffer *vb) + * in the compressed stream + */ + if (ctx->is_stateless || ctx->is_enc || +- !V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type)) { ++ V4L2_TYPE_IS_CAPTURE(vb->vb2_queue->type)) { + v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf); + return; + } +@@ -1574,7 +1574,7 @@ static int vicodec_start_streaming(struct vb2_queue *q, + state->gop_cnt = 0; + + if ((V4L2_TYPE_IS_OUTPUT(q->type) && !ctx->is_enc) || +- (!V4L2_TYPE_IS_OUTPUT(q->type) && ctx->is_enc)) ++ (V4L2_TYPE_IS_CAPTURE(q->type) && ctx->is_enc)) + return 0; + + if (info->id == V4L2_PIX_FMT_FWHT || +diff --git a/drivers/media/v4l2-core/v4l2-mem2mem.c b/drivers/media/v4l2-core/v4l2-mem2mem.c +index 62ac9424c92a..95a8f2dc5341 100644 +--- a/drivers/media/v4l2-core/v4l2-mem2mem.c ++++ b/drivers/media/v4l2-core/v4l2-mem2mem.c +@@ -556,7 +556,7 @@ int v4l2_m2m_querybuf(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, + ret = vb2_querybuf(vq, buf); + + /* Adjust MMAP memory offsets for the CAPTURE queue */ +- if (buf->memory == V4L2_MEMORY_MMAP && !V4L2_TYPE_IS_OUTPUT(vq->type)) { ++ if (buf->memory == V4L2_MEMORY_MMAP && V4L2_TYPE_IS_CAPTURE(vq->type)) { + if (V4L2_TYPE_IS_MULTIPLANAR(vq->type)) { + for (i = 0; i < buf->length; ++i) + buf->m.planes[i].m.mem_offset +@@ -712,7 +712,7 @@ int v4l2_m2m_qbuf(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, + int ret; + + vq = v4l2_m2m_get_vq(m2m_ctx, buf->type); +- if (!V4L2_TYPE_IS_OUTPUT(vq->type) && ++ if (V4L2_TYPE_IS_CAPTURE(vq->type) && + (buf->flags & V4L2_BUF_FLAG_REQUEST_FD)) { + dprintk("%s: requests cannot be used with capture buffers\n", + __func__); +@@ -729,7 +729,7 @@ int v4l2_m2m_qbuf(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, + * buffer as DONE with LAST flag since it won't be queued on the + * device. + */ +- if (!V4L2_TYPE_IS_OUTPUT(vq->type) && ++ if (V4L2_TYPE_IS_CAPTURE(vq->type) && + vb2_is_streaming(vq) && !vb2_start_streaming_called(vq) && + (v4l2_m2m_has_stopped(m2m_ctx) || v4l2_m2m_dst_buf_is_last(m2m_ctx))) + v4l2_m2m_force_last_buf_done(m2m_ctx, vq); +diff --git a/drivers/staging/media/hantro/hantro_v4l2.c b/drivers/staging/media/hantro/hantro_v4l2.c +index f28a94e2fa93..63859e8a0923 100644 +--- a/drivers/staging/media/hantro/hantro_v4l2.c ++++ b/drivers/staging/media/hantro/hantro_v4l2.c +@@ -237,7 +237,7 @@ static int hantro_try_fmt(const struct hantro_ctx *ctx, + enum v4l2_buf_type type) + { + const struct hantro_fmt *fmt, *vpu_fmt; +- bool capture = !V4L2_TYPE_IS_OUTPUT(type); ++ bool capture = V4L2_TYPE_IS_CAPTURE(type); + bool coded; + + coded = capture == hantro_is_encoder_ctx(ctx); +diff --git a/drivers/staging/media/rkvdec/rkvdec.c b/drivers/staging/media/rkvdec/rkvdec.c +index 225eeca73356..fd68671f0286 100644 +--- a/drivers/staging/media/rkvdec/rkvdec.c ++++ b/drivers/staging/media/rkvdec/rkvdec.c +@@ -489,7 +489,7 @@ static int rkvdec_start_streaming(struct vb2_queue *q, unsigned int count) + const struct rkvdec_coded_fmt_desc *desc; + int ret; + +- if (!V4L2_TYPE_IS_OUTPUT(q->type)) ++ if (V4L2_TYPE_IS_CAPTURE(q->type)) + return 0; + + desc = ctx->coded_fmt_desc; +diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h +index c3a1cf1c507f..6fe8822d2cb4 100644 +--- a/include/uapi/linux/videodev2.h ++++ b/include/uapi/linux/videodev2.h +@@ -171,6 +171,8 @@ enum v4l2_buf_type { + || (type) == V4L2_BUF_TYPE_SDR_OUTPUT \ + || (type) == V4L2_BUF_TYPE_META_OUTPUT) + ++#define V4L2_TYPE_IS_CAPTURE(type) (!V4L2_TYPE_IS_OUTPUT(type)) ++ + enum v4l2_tuner_type { + V4L2_TUNER_RADIO = 1, + V4L2_TUNER_ANALOG_TV = 2, + +From 728f96ea31862791706eb9390cb865e4fd8fa09d Mon Sep 17 00:00:00 2001 +From: Ezequiel Garcia +Date: Wed, 1 Jul 2020 15:16:02 +0200 +Subject: [PATCH] hantro: h264: Remove unused macro definition + +The generic H264 reference list builder moved all +the users of this macro, but left the macro. + +Remove it. + +Signed-off-by: Ezequiel Garcia +Reviewed-by: Philipp Zabel +Signed-off-by: Hans Verkuil +Signed-off-by: Mauro Carvalho Chehab +(cherry picked from commit 3ebf271b1dee6df816bd8f2135218640c478dedd) +--- + drivers/staging/media/hantro/hantro_h264.c | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/drivers/staging/media/hantro/hantro_h264.c b/drivers/staging/media/hantro/hantro_h264.c +index d561f125085a..dd935d7009bf 100644 +--- a/drivers/staging/media/hantro/hantro_h264.c ++++ b/drivers/staging/media/hantro/hantro_h264.c +@@ -22,8 +22,6 @@ + #define POC_BUFFER_SIZE 34 + #define SCALING_LIST_SIZE (6 * 16 + 2 * 64) + +-#define HANTRO_CMP(a, b) ((a) < (b) ? -1 : 1) +- + /* Data structure describing auxiliary buffer format. */ + struct hantro_h264_dec_priv_tbl { + u32 cabac_table[CABAC_INIT_BUFFER_SIZE]; + +From ad6f6337541843af2f943f603636f64a6a55e215 Mon Sep 17 00:00:00 2001 +From: Ezequiel Garcia +Date: Wed, 1 Jul 2020 15:16:03 +0200 +Subject: [PATCH] hantro: h264: Rename scaling list handling function + +Commit e17f08e31666 ("media: hantro: Do not reorder +H264 scaling list") removed the scaling list reordering, +which was wrong and not needed. + +However, the name of the function stayed, which is +confusing for anyone reading the code. Rename +from "reorder" to "assemble" which is cleaner. + +This is just a cosmetic cleanup. + +Signed-off-by: Ezequiel Garcia +Reviewed-by: Philipp Zabel +Signed-off-by: Hans Verkuil +Signed-off-by: Mauro Carvalho Chehab +(cherry picked from commit 4df3a47e3422a9de1f3ce1a4ba8a0447a73e7567) +--- + drivers/staging/media/hantro/hantro_h264.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/staging/media/hantro/hantro_h264.c b/drivers/staging/media/hantro/hantro_h264.c +index dd935d7009bf..194d05848077 100644 +--- a/drivers/staging/media/hantro/hantro_h264.c ++++ b/drivers/staging/media/hantro/hantro_h264.c +@@ -193,7 +193,7 @@ static const u32 h264_cabac_table[] = { + }; + + static void +-reorder_scaling_list(struct hantro_ctx *ctx) ++assemble_scaling_list(struct hantro_ctx *ctx) + { + const struct hantro_h264_dec_ctrls *ctrls = &ctx->h264_dec.ctrls; + const struct v4l2_ctrl_h264_scaling_matrix *scaling = ctrls->scaling; +@@ -235,7 +235,7 @@ static void prepare_table(struct hantro_ctx *ctx) + tbl->poc[32] = dec_param->top_field_order_cnt; + tbl->poc[33] = dec_param->bottom_field_order_cnt; + +- reorder_scaling_list(ctx); ++ assemble_scaling_list(ctx); + } + + static bool dpb_entry_match(const struct v4l2_h264_dpb_entry *a, + +From 63c05ac390a6fb9d4930804931732630dd0e20ac Mon Sep 17 00:00:00 2001 +From: Ezequiel Garcia +Date: Wed, 1 Jul 2020 15:16:04 +0200 +Subject: [PATCH] hantro: Rework how encoder and decoder are identified + +So far we've been using the .buf_finish hook to distinguish +decoder from encoder. This is unnecessarily obfuscated. + +Moreover, we want to move the buf_finish, so use a cleaner +scheme to distinguish the driver decoder/encoder type. + +Signed-off-by: Ezequiel Garcia +Reviewed-by: Philipp Zabel +Signed-off-by: Hans Verkuil +Signed-off-by: Mauro Carvalho Chehab +(cherry picked from commit 21f0315b7b3ee6ca909d81a963744671fb27bf71) +--- + drivers/staging/media/hantro/hantro.h | 6 ++--- + drivers/staging/media/hantro/hantro_drv.c | 9 +++---- + drivers/staging/media/hantro/hantro_v4l2.c | 28 +++++++++++----------- + 3 files changed, 20 insertions(+), 23 deletions(-) + +diff --git a/drivers/staging/media/hantro/hantro.h b/drivers/staging/media/hantro/hantro.h +index 3005207fc6fb..2284e23d8500 100644 +--- a/drivers/staging/media/hantro/hantro.h ++++ b/drivers/staging/media/hantro/hantro.h +@@ -199,6 +199,7 @@ struct hantro_dev { + * + * @dev: VPU driver data to which the context belongs. + * @fh: V4L2 file handler. ++ * @is_encoder: Decoder or encoder context? + * + * @sequence_cap: Sequence counter for capture queue + * @sequence_out: Sequence counter for output queue +@@ -223,6 +224,7 @@ struct hantro_dev { + struct hantro_ctx { + struct hantro_dev *dev; + struct v4l2_fh fh; ++ bool is_encoder; + + u32 sequence_cap; + u32 sequence_out; +@@ -399,8 +401,6 @@ static inline void hantro_reg_write_s(struct hantro_dev *vpu, + vdpu_write(vpu, vdpu_read_mask(vpu, reg, val), reg->base); + } + +-bool hantro_is_encoder_ctx(const struct hantro_ctx *ctx); +- + void *hantro_get_ctrl(struct hantro_ctx *ctx, u32 id); + dma_addr_t hantro_get_ref(struct hantro_ctx *ctx, u64 ts); + +@@ -420,7 +420,7 @@ static inline bool + hantro_needs_postproc(const struct hantro_ctx *ctx, + const struct hantro_fmt *fmt) + { +- return !hantro_is_encoder_ctx(ctx) && fmt->fourcc != V4L2_PIX_FMT_NV12; ++ return !ctx->is_encoder && fmt->fourcc != V4L2_PIX_FMT_NV12; + } + + static inline dma_addr_t +diff --git a/drivers/staging/media/hantro/hantro_drv.c b/drivers/staging/media/hantro/hantro_drv.c +index 0db8ad455160..9145d02e5d3c 100644 +--- a/drivers/staging/media/hantro/hantro_drv.c ++++ b/drivers/staging/media/hantro/hantro_drv.c +@@ -195,11 +195,6 @@ static void device_run(void *priv) + hantro_job_finish(ctx->dev, ctx, 0, VB2_BUF_STATE_ERROR); + } + +-bool hantro_is_encoder_ctx(const struct hantro_ctx *ctx) +-{ +- return ctx->buf_finish == hantro_enc_buf_finish; +-} +- + static struct v4l2_m2m_ops vpu_m2m_ops = { + .device_run = device_run, + }; +@@ -240,7 +235,7 @@ queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq) + * + * For the DMA destination buffer, we use a bounce buffer. + */ +- if (hantro_is_encoder_ctx(ctx)) { ++ if (ctx->is_encoder) { + dst_vq->mem_ops = &vb2_vmalloc_memops; + } else { + dst_vq->bidirectional = true; +@@ -420,8 +415,10 @@ static int hantro_open(struct file *filp) + if (func->id == MEDIA_ENT_F_PROC_VIDEO_ENCODER) { + allowed_codecs = vpu->variant->codec & HANTRO_ENCODERS; + ctx->buf_finish = hantro_enc_buf_finish; ++ ctx->is_encoder = true; + } else if (func->id == MEDIA_ENT_F_PROC_VIDEO_DECODER) { + allowed_codecs = vpu->variant->codec & HANTRO_DECODERS; ++ ctx->is_encoder = false; + } else { + ret = -ENODEV; + goto err_ctx_free; +diff --git a/drivers/staging/media/hantro/hantro_v4l2.c b/drivers/staging/media/hantro/hantro_v4l2.c +index 63859e8a0923..b668a82d40ad 100644 +--- a/drivers/staging/media/hantro/hantro_v4l2.c ++++ b/drivers/staging/media/hantro/hantro_v4l2.c +@@ -40,7 +40,7 @@ hantro_get_formats(const struct hantro_ctx *ctx, unsigned int *num_fmts) + { + const struct hantro_fmt *formats; + +- if (hantro_is_encoder_ctx(ctx)) { ++ if (ctx->is_encoder) { + formats = ctx->dev->variant->enc_fmts; + *num_fmts = ctx->dev->variant->num_enc_fmts; + } else { +@@ -55,7 +55,7 @@ static const struct hantro_fmt * + hantro_get_postproc_formats(const struct hantro_ctx *ctx, + unsigned int *num_fmts) + { +- if (hantro_is_encoder_ctx(ctx)) { ++ if (ctx->is_encoder) { + *num_fmts = 0; + return NULL; + } +@@ -158,7 +158,7 @@ static int vidioc_enum_fmt(struct file *file, void *priv, + * not MODE_NONE. + * - on the output side we want to filter out all MODE_NONE formats. + */ +- skip_mode_none = capture == hantro_is_encoder_ctx(ctx); ++ skip_mode_none = capture == ctx->is_encoder; + + formats = hantro_get_formats(ctx, &num_fmts); + for (i = 0; i < num_fmts; i++) { +@@ -240,7 +240,7 @@ static int hantro_try_fmt(const struct hantro_ctx *ctx, + bool capture = V4L2_TYPE_IS_CAPTURE(type); + bool coded; + +- coded = capture == hantro_is_encoder_ctx(ctx); ++ coded = capture == ctx->is_encoder; + + vpu_debug(4, "trying format %c%c%c%c\n", + (pix_mp->pixelformat & 0x7f), +@@ -257,7 +257,7 @@ static int hantro_try_fmt(const struct hantro_ctx *ctx, + if (coded) { + pix_mp->num_planes = 1; + vpu_fmt = fmt; +- } else if (hantro_is_encoder_ctx(ctx)) { ++ } else if (ctx->is_encoder) { + vpu_fmt = ctx->vpu_dst_fmt; + } else { + vpu_fmt = ctx->vpu_src_fmt; +@@ -330,7 +330,7 @@ hantro_reset_encoded_fmt(struct hantro_ctx *ctx) + + vpu_fmt = hantro_get_default_fmt(ctx, true); + +- if (hantro_is_encoder_ctx(ctx)) { ++ if (ctx->is_encoder) { + ctx->vpu_dst_fmt = vpu_fmt; + fmt = &ctx->dst_fmt; + } else { +@@ -341,7 +341,7 @@ hantro_reset_encoded_fmt(struct hantro_ctx *ctx) + hantro_reset_fmt(fmt, vpu_fmt); + fmt->width = vpu_fmt->frmsize.min_width; + fmt->height = vpu_fmt->frmsize.min_height; +- if (hantro_is_encoder_ctx(ctx)) ++ if (ctx->is_encoder) + hantro_set_fmt_cap(ctx, fmt); + else + hantro_set_fmt_out(ctx, fmt); +@@ -355,7 +355,7 @@ hantro_reset_raw_fmt(struct hantro_ctx *ctx) + + raw_vpu_fmt = hantro_get_default_fmt(ctx, false); + +- if (hantro_is_encoder_ctx(ctx)) { ++ if (ctx->is_encoder) { + ctx->vpu_src_fmt = raw_vpu_fmt; + raw_fmt = &ctx->src_fmt; + encoded_fmt = &ctx->dst_fmt; +@@ -368,7 +368,7 @@ hantro_reset_raw_fmt(struct hantro_ctx *ctx) + hantro_reset_fmt(raw_fmt, raw_vpu_fmt); + raw_fmt->width = encoded_fmt->width; + raw_fmt->width = encoded_fmt->width; +- if (hantro_is_encoder_ctx(ctx)) ++ if (ctx->is_encoder) + hantro_set_fmt_out(ctx, raw_fmt); + else + hantro_set_fmt_cap(ctx, raw_fmt); +@@ -409,7 +409,7 @@ static int hantro_set_fmt_out(struct hantro_ctx *ctx, + if (ret) + return ret; + +- if (!hantro_is_encoder_ctx(ctx)) { ++ if (!ctx->is_encoder) { + struct vb2_queue *peer_vq; + + /* +@@ -450,7 +450,7 @@ static int hantro_set_fmt_out(struct hantro_ctx *ctx, + * Note that hantro_reset_raw_fmt() also propagates size + * changes to the raw format. + */ +- if (!hantro_is_encoder_ctx(ctx)) ++ if (!ctx->is_encoder) + hantro_reset_raw_fmt(ctx); + + /* Colorimetry information are always propagated. */ +@@ -479,7 +479,7 @@ static int hantro_set_fmt_cap(struct hantro_ctx *ctx, + if (vb2_is_busy(vq)) + return -EBUSY; + +- if (hantro_is_encoder_ctx(ctx)) { ++ if (ctx->is_encoder) { + struct vb2_queue *peer_vq; + + /* +@@ -512,7 +512,7 @@ static int hantro_set_fmt_cap(struct hantro_ctx *ctx, + * Note that hantro_reset_raw_fmt() also propagates size + * changes to the raw format. + */ +- if (hantro_is_encoder_ctx(ctx)) ++ if (ctx->is_encoder) + hantro_reset_raw_fmt(ctx); + + /* Colorimetry information are always propagated. */ +@@ -655,7 +655,7 @@ static bool hantro_vq_is_coded(struct vb2_queue *q) + { + struct hantro_ctx *ctx = vb2_get_drv_priv(q); + +- return hantro_is_encoder_ctx(ctx) != V4L2_TYPE_IS_OUTPUT(q->type); ++ return ctx->is_encoder != V4L2_TYPE_IS_OUTPUT(q->type); + } + + static int hantro_start_streaming(struct vb2_queue *q, unsigned int count) + +From 9067e59021400f6924e6fe593585bb6a561ef251 Mon Sep 17 00:00:00 2001 +From: Ezequiel Garcia +Date: Wed, 1 Jul 2020 15:16:05 +0200 +Subject: [PATCH] hantro: Move hantro_enc_buf_finish to JPEG codec_ops.done + +hantro_enc_buf_finish is used only for JPEG, and so should +be moved to JPEG codec_ops.done. + +This cleanup is also taking care of addressing +a subtle issue: checking the non-NULL bounce buffer +using ctx->jpeg_enc, which is a member of a union is +confusing and error-prone. + +Note that the issue is currently innocuous because an +encoder context only supports JPEG. + +The codec_ops.done has an argument that codec-specific code +shouldn't need, so drop that as well. + +Signed-off-by: Ezequiel Garcia +Reviewed-by: Philipp Zabel +Signed-off-by: Hans Verkuil +Signed-off-by: Mauro Carvalho Chehab +(cherry picked from commit e765dba11ec26d7ea42974ec4d470b5ce00be3de) +--- + drivers/staging/media/hantro/hantro.h | 7 ---- + drivers/staging/media/hantro/hantro_drv.c | 37 ++----------------- + .../staging/media/hantro/hantro_h1_jpeg_enc.c | 17 +++++++++ + drivers/staging/media/hantro/hantro_hw.h | 3 +- + drivers/staging/media/hantro/rk3288_vpu_hw.c | 1 + + 5 files changed, 24 insertions(+), 41 deletions(-) + +diff --git a/drivers/staging/media/hantro/hantro.h b/drivers/staging/media/hantro/hantro.h +index 2284e23d8500..65f9f7ea7dcf 100644 +--- a/drivers/staging/media/hantro/hantro.h ++++ b/drivers/staging/media/hantro/hantro.h +@@ -212,9 +212,6 @@ struct hantro_dev { + * @ctrl_handler: Control handler used to register controls. + * @jpeg_quality: User-specified JPEG compression quality. + * +- * @buf_finish: Buffer finish. This depends on encoder or decoder +- * context, and it's called right before +- * calling v4l2_m2m_job_finish. + * @codec_ops: Set of operations related to codec mode. + * @postproc: Post-processing context. + * @jpeg_enc: JPEG-encoding context. +@@ -237,10 +234,6 @@ struct hantro_ctx { + struct v4l2_ctrl_handler ctrl_handler; + int jpeg_quality; + +- int (*buf_finish)(struct hantro_ctx *ctx, +- struct vb2_buffer *buf, +- unsigned int bytesused); +- + const struct hantro_codec_ops *codec_ops; + struct hantro_postproc_ctx postproc; + +diff --git a/drivers/staging/media/hantro/hantro_drv.c b/drivers/staging/media/hantro/hantro_drv.c +index 9145d02e5d3c..88b5c5989d83 100644 +--- a/drivers/staging/media/hantro/hantro_drv.c ++++ b/drivers/staging/media/hantro/hantro_drv.c +@@ -56,37 +56,12 @@ dma_addr_t hantro_get_ref(struct hantro_ctx *ctx, u64 ts) + return hantro_get_dec_buf_addr(ctx, buf); + } + +-static int +-hantro_enc_buf_finish(struct hantro_ctx *ctx, struct vb2_buffer *buf, +- unsigned int bytesused) +-{ +- size_t avail_size; +- +- avail_size = vb2_plane_size(buf, 0) - ctx->vpu_dst_fmt->header_size; +- if (bytesused > avail_size) +- return -EINVAL; +- /* +- * The bounce buffer is only for the JPEG encoder. +- * TODO: Rework the JPEG encoder to eliminate the need +- * for a bounce buffer. +- */ +- if (ctx->jpeg_enc.bounce_buffer.cpu) { +- memcpy(vb2_plane_vaddr(buf, 0) + +- ctx->vpu_dst_fmt->header_size, +- ctx->jpeg_enc.bounce_buffer.cpu, bytesused); +- } +- buf->planes[0].bytesused = +- ctx->vpu_dst_fmt->header_size + bytesused; +- return 0; +-} +- + static void hantro_job_finish(struct hantro_dev *vpu, + struct hantro_ctx *ctx, + unsigned int bytesused, + enum vb2_buffer_state result) + { + struct vb2_v4l2_buffer *src, *dst; +- int ret; + + pm_runtime_mark_last_busy(vpu->dev); + pm_runtime_put_autosuspend(vpu->dev); +@@ -103,12 +78,6 @@ static void hantro_job_finish(struct hantro_dev *vpu, + src->sequence = ctx->sequence_out++; + dst->sequence = ctx->sequence_cap++; + +- if (ctx->buf_finish) { +- ret = ctx->buf_finish(ctx, &dst->vb2_buf, bytesused); +- if (ret) +- result = VB2_BUF_STATE_ERROR; +- } +- + v4l2_m2m_buf_done_and_job_finish(ctx->dev->m2m_dev, ctx->fh.m2m_ctx, + result); + } +@@ -124,8 +93,11 @@ void hantro_irq_done(struct hantro_dev *vpu, unsigned int bytesused, + * the timeout expired. The watchdog is running, + * and will take care of finishing the job. + */ +- if (cancel_delayed_work(&vpu->watchdog_work)) ++ if (cancel_delayed_work(&vpu->watchdog_work)) { ++ if (result == VB2_BUF_STATE_DONE && ctx->codec_ops->done) ++ ctx->codec_ops->done(ctx); + hantro_job_finish(vpu, ctx, bytesused, result); ++ } + } + + void hantro_watchdog(struct work_struct *work) +@@ -414,7 +386,6 @@ static int hantro_open(struct file *filp) + ctx->dev = vpu; + if (func->id == MEDIA_ENT_F_PROC_VIDEO_ENCODER) { + allowed_codecs = vpu->variant->codec & HANTRO_ENCODERS; +- ctx->buf_finish = hantro_enc_buf_finish; + ctx->is_encoder = true; + } else if (func->id == MEDIA_ENT_F_PROC_VIDEO_DECODER) { + allowed_codecs = vpu->variant->codec & HANTRO_DECODERS; +diff --git a/drivers/staging/media/hantro/hantro_h1_jpeg_enc.c b/drivers/staging/media/hantro/hantro_h1_jpeg_enc.c +index b22418436823..b88dc4ed06db 100644 +--- a/drivers/staging/media/hantro/hantro_h1_jpeg_enc.c ++++ b/drivers/staging/media/hantro/hantro_h1_jpeg_enc.c +@@ -137,3 +137,20 @@ void hantro_h1_jpeg_enc_run(struct hantro_ctx *ctx) + + vepu_write(vpu, reg, H1_REG_ENC_CTRL); + } ++ ++void hantro_jpeg_enc_done(struct hantro_ctx *ctx) ++{ ++ struct hantro_dev *vpu = ctx->dev; ++ u32 bytesused = vepu_read(vpu, H1_REG_STR_BUF_LIMIT) / 8; ++ struct vb2_v4l2_buffer *dst_buf = hantro_get_dst_buf(ctx); ++ ++ /* ++ * TODO: Rework the JPEG encoder to eliminate the need ++ * for a bounce buffer. ++ */ ++ memcpy(vb2_plane_vaddr(&dst_buf->vb2_buf, 0) + ++ ctx->vpu_dst_fmt->header_size, ++ ctx->jpeg_enc.bounce_buffer.cpu, bytesused); ++ vb2_set_plane_payload(&dst_buf->vb2_buf, 0, ++ ctx->vpu_dst_fmt->header_size + bytesused); ++} +diff --git a/drivers/staging/media/hantro/hantro_hw.h b/drivers/staging/media/hantro/hantro_hw.h +index 4053d8710e04..2d6323cd6732 100644 +--- a/drivers/staging/media/hantro/hantro_hw.h ++++ b/drivers/staging/media/hantro/hantro_hw.h +@@ -138,7 +138,7 @@ struct hantro_codec_ops { + int (*init)(struct hantro_ctx *ctx); + void (*exit)(struct hantro_ctx *ctx); + void (*run)(struct hantro_ctx *ctx); +- void (*done)(struct hantro_ctx *ctx, enum vb2_buffer_state); ++ void (*done)(struct hantro_ctx *ctx); + void (*reset)(struct hantro_ctx *ctx); + }; + +@@ -172,6 +172,7 @@ void hantro_h1_jpeg_enc_run(struct hantro_ctx *ctx); + void rk3399_vpu_jpeg_enc_run(struct hantro_ctx *ctx); + int hantro_jpeg_enc_init(struct hantro_ctx *ctx); + void hantro_jpeg_enc_exit(struct hantro_ctx *ctx); ++void hantro_jpeg_enc_done(struct hantro_ctx *ctx); + + dma_addr_t hantro_h264_get_ref_buf(struct hantro_ctx *ctx, + unsigned int dpb_idx); +diff --git a/drivers/staging/media/hantro/rk3288_vpu_hw.c b/drivers/staging/media/hantro/rk3288_vpu_hw.c +index 2f914b37b9e5..b1cf2abb972f 100644 +--- a/drivers/staging/media/hantro/rk3288_vpu_hw.c ++++ b/drivers/staging/media/hantro/rk3288_vpu_hw.c +@@ -180,6 +180,7 @@ static const struct hantro_codec_ops rk3288_vpu_codec_ops[] = { + .run = hantro_h1_jpeg_enc_run, + .reset = rk3288_vpu_enc_reset, + .init = hantro_jpeg_enc_init, ++ .done = hantro_jpeg_enc_done, + .exit = hantro_jpeg_enc_exit, + }, + [HANTRO_MODE_H264_DEC] = { + +From 7d3bf1fa2170bacf99bd02ccd7dc0f5fdc1fbc45 Mon Sep 17 00:00:00 2001 +From: Ezequiel Garcia +Date: Wed, 1 Jul 2020 15:16:06 +0200 +Subject: [PATCH] hantro: Remove unused bytesused argument + +The driver doesn't need the bytesused argument. + +For decoders, the plane bytesused is known and therefore, +buf_prepare is used to set it. For encoders, it's +handled by the codec_ops.done hook. + +Signed-off-by: Ezequiel Garcia +Reviewed-by: Philipp Zabel +Signed-off-by: Hans Verkuil +Signed-off-by: Mauro Carvalho Chehab +(cherry picked from commit b72a6342dd240ce8e15b7acf1c38c67a0c56092b) +--- + drivers/staging/media/hantro/hantro_drv.c | 9 ++++----- + drivers/staging/media/hantro/hantro_hw.h | 2 +- + drivers/staging/media/hantro/imx8m_vpu_hw.c | 2 +- + drivers/staging/media/hantro/rk3288_vpu_hw.c | 7 +++---- + drivers/staging/media/hantro/rk3399_vpu_hw.c | 7 +++---- + 5 files changed, 12 insertions(+), 15 deletions(-) + +diff --git a/drivers/staging/media/hantro/hantro_drv.c b/drivers/staging/media/hantro/hantro_drv.c +index 88b5c5989d83..34367b169011 100644 +--- a/drivers/staging/media/hantro/hantro_drv.c ++++ b/drivers/staging/media/hantro/hantro_drv.c +@@ -58,7 +58,6 @@ dma_addr_t hantro_get_ref(struct hantro_ctx *ctx, u64 ts) + + static void hantro_job_finish(struct hantro_dev *vpu, + struct hantro_ctx *ctx, +- unsigned int bytesused, + enum vb2_buffer_state result) + { + struct vb2_v4l2_buffer *src, *dst; +@@ -82,7 +81,7 @@ static void hantro_job_finish(struct hantro_dev *vpu, + result); + } + +-void hantro_irq_done(struct hantro_dev *vpu, unsigned int bytesused, ++void hantro_irq_done(struct hantro_dev *vpu, + enum vb2_buffer_state result) + { + struct hantro_ctx *ctx = +@@ -96,7 +95,7 @@ void hantro_irq_done(struct hantro_dev *vpu, unsigned int bytesused, + if (cancel_delayed_work(&vpu->watchdog_work)) { + if (result == VB2_BUF_STATE_DONE && ctx->codec_ops->done) + ctx->codec_ops->done(ctx); +- hantro_job_finish(vpu, ctx, bytesused, result); ++ hantro_job_finish(vpu, ctx, result); + } + } + +@@ -111,7 +110,7 @@ void hantro_watchdog(struct work_struct *work) + if (ctx) { + vpu_err("frame processing timed out!\n"); + ctx->codec_ops->reset(ctx); +- hantro_job_finish(vpu, ctx, 0, VB2_BUF_STATE_ERROR); ++ hantro_job_finish(vpu, ctx, VB2_BUF_STATE_ERROR); + } + } + +@@ -164,7 +163,7 @@ static void device_run(void *priv) + return; + + err_cancel_job: +- hantro_job_finish(ctx->dev, ctx, 0, VB2_BUF_STATE_ERROR); ++ hantro_job_finish(ctx->dev, ctx, VB2_BUF_STATE_ERROR); + } + + static struct v4l2_m2m_ops vpu_m2m_ops = { +diff --git a/drivers/staging/media/hantro/hantro_hw.h b/drivers/staging/media/hantro/hantro_hw.h +index 2d6323cd6732..f066de6b592d 100644 +--- a/drivers/staging/media/hantro/hantro_hw.h ++++ b/drivers/staging/media/hantro/hantro_hw.h +@@ -163,7 +163,7 @@ extern const u32 hantro_vp8_dec_mc_filter[8][6]; + + void hantro_watchdog(struct work_struct *work); + void hantro_run(struct hantro_ctx *ctx); +-void hantro_irq_done(struct hantro_dev *vpu, unsigned int bytesused, ++void hantro_irq_done(struct hantro_dev *vpu, + enum vb2_buffer_state result); + void hantro_start_prepare_run(struct hantro_ctx *ctx); + void hantro_end_prepare_run(struct hantro_ctx *ctx); +diff --git a/drivers/staging/media/hantro/imx8m_vpu_hw.c b/drivers/staging/media/hantro/imx8m_vpu_hw.c +index cb2420c5526e..c222de075ef4 100644 +--- a/drivers/staging/media/hantro/imx8m_vpu_hw.c ++++ b/drivers/staging/media/hantro/imx8m_vpu_hw.c +@@ -143,7 +143,7 @@ static irqreturn_t imx8m_vpu_g1_irq(int irq, void *dev_id) + vdpu_write(vpu, 0, G1_REG_INTERRUPT); + vdpu_write(vpu, G1_REG_CONFIG_DEC_CLK_GATE_E, G1_REG_CONFIG); + +- hantro_irq_done(vpu, 0, state); ++ hantro_irq_done(vpu, state); + + return IRQ_HANDLED; + } +diff --git a/drivers/staging/media/hantro/rk3288_vpu_hw.c b/drivers/staging/media/hantro/rk3288_vpu_hw.c +index b1cf2abb972f..7b299ee3e93d 100644 +--- a/drivers/staging/media/hantro/rk3288_vpu_hw.c ++++ b/drivers/staging/media/hantro/rk3288_vpu_hw.c +@@ -113,17 +113,16 @@ static irqreturn_t rk3288_vepu_irq(int irq, void *dev_id) + { + struct hantro_dev *vpu = dev_id; + enum vb2_buffer_state state; +- u32 status, bytesused; ++ u32 status; + + status = vepu_read(vpu, H1_REG_INTERRUPT); +- bytesused = vepu_read(vpu, H1_REG_STR_BUF_LIMIT) / 8; + state = (status & H1_REG_INTERRUPT_FRAME_RDY) ? + VB2_BUF_STATE_DONE : VB2_BUF_STATE_ERROR; + + vepu_write(vpu, 0, H1_REG_INTERRUPT); + vepu_write(vpu, 0, H1_REG_AXI_CTRL); + +- hantro_irq_done(vpu, bytesused, state); ++ hantro_irq_done(vpu, state); + + return IRQ_HANDLED; + } +@@ -141,7 +140,7 @@ static irqreturn_t rk3288_vdpu_irq(int irq, void *dev_id) + vdpu_write(vpu, 0, G1_REG_INTERRUPT); + vdpu_write(vpu, G1_REG_CONFIG_DEC_CLK_GATE_E, G1_REG_CONFIG); + +- hantro_irq_done(vpu, 0, state); ++ hantro_irq_done(vpu, state); + + return IRQ_HANDLED; + } +diff --git a/drivers/staging/media/hantro/rk3399_vpu_hw.c b/drivers/staging/media/hantro/rk3399_vpu_hw.c +index 9ac1f2cb6a16..7a7962cf771e 100644 +--- a/drivers/staging/media/hantro/rk3399_vpu_hw.c ++++ b/drivers/staging/media/hantro/rk3399_vpu_hw.c +@@ -92,17 +92,16 @@ static irqreturn_t rk3399_vepu_irq(int irq, void *dev_id) + { + struct hantro_dev *vpu = dev_id; + enum vb2_buffer_state state; +- u32 status, bytesused; ++ u32 status; + + status = vepu_read(vpu, VEPU_REG_INTERRUPT); +- bytesused = vepu_read(vpu, VEPU_REG_STR_BUF_LIMIT) / 8; + state = (status & VEPU_REG_INTERRUPT_FRAME_READY) ? + VB2_BUF_STATE_DONE : VB2_BUF_STATE_ERROR; + + vepu_write(vpu, 0, VEPU_REG_INTERRUPT); + vepu_write(vpu, 0, VEPU_REG_AXI_CTRL); + +- hantro_irq_done(vpu, bytesused, state); ++ hantro_irq_done(vpu, state); + + return IRQ_HANDLED; + } +@@ -120,7 +119,7 @@ static irqreturn_t rk3399_vdpu_irq(int irq, void *dev_id) + vdpu_write(vpu, 0, VDPU_REG_INTERRUPT); + vdpu_write(vpu, 0, VDPU_REG_AXI_CTRL); + +- hantro_irq_done(vpu, 0, state); ++ hantro_irq_done(vpu, state); + + return IRQ_HANDLED; + } + +From 7e6a3bfc6d6ac30204d5ad0fc6496f1c263f809b Mon Sep 17 00:00:00 2001 +From: Ezequiel Garcia +Date: Wed, 1 Jul 2020 15:16:07 +0200 +Subject: [PATCH] hantro: Make sure we don't use post-processor on an encoder + +Commit 986eee3a5234 ("media: hantro: Prevent encoders from using +post-processing") fixed hantro_needs_postproc condition, +but missed one case. Encoders don't have any post-processor +hardware block, so also can't be disabled. + +Fix it. + +Fixes: 986eee3a5234 ("media: hantro: Prevent encoders from using post-processing") +Signed-off-by: Ezequiel Garcia +Reviewed-by: Philipp Zabel +Signed-off-by: Hans Verkuil +Signed-off-by: Mauro Carvalho Chehab +(cherry picked from commit 46d7aaebbe441d5381e35d8e16df784690e65ef3) +--- + drivers/staging/media/hantro/hantro_drv.c | 10 ++++++---- + 1 file changed, 6 insertions(+), 4 deletions(-) + +diff --git a/drivers/staging/media/hantro/hantro_drv.c b/drivers/staging/media/hantro/hantro_drv.c +index 34367b169011..d32b6b1ab70b 100644 +--- a/drivers/staging/media/hantro/hantro_drv.c ++++ b/drivers/staging/media/hantro/hantro_drv.c +@@ -122,10 +122,12 @@ void hantro_start_prepare_run(struct hantro_ctx *ctx) + v4l2_ctrl_request_setup(src_buf->vb2_buf.req_obj.req, + &ctx->ctrl_handler); + +- if (hantro_needs_postproc(ctx, ctx->vpu_dst_fmt)) +- hantro_postproc_enable(ctx); +- else +- hantro_postproc_disable(ctx); ++ if (!ctx->is_encoder) { ++ if (hantro_needs_postproc(ctx, ctx->vpu_dst_fmt)) ++ hantro_postproc_enable(ctx); ++ else ++ hantro_postproc_disable(ctx); ++ } + } + + void hantro_end_prepare_run(struct hantro_ctx *ctx) + +From 1f833bbde61660aabc0320b314bab5a2f7e42d10 Mon Sep 17 00:00:00 2001 +From: Ezequiel Garcia +Date: Thu, 9 Jul 2020 18:36:34 +0200 +Subject: [PATCH] rkvdec: h264: Refuse to decode unsupported bitstream + +The hardware only supports 4:2:2, 4:2:0 or 4:0:0 (monochrome), +8-bit or 10-bit depth content. + +Verify that the SPS refers to a supported bitstream, and refuse +unsupported bitstreams by failing at TRY_EXT_CTRLS time. + +The driver is currently broken on 10-bit and 4:2:2 +so disallow those as well. + +Signed-off-by: Ezequiel Garcia +Reviewed-by: Jonas Karlman +Signed-off-by: Hans Verkuil +Signed-off-by: Mauro Carvalho Chehab +(cherry picked from commit 9363aa33f6a9acfd16f98c749f17f6c65d184670) +--- + drivers/staging/media/rkvdec/rkvdec.c | 27 +++++++++++++++++++++++++++ + 1 file changed, 27 insertions(+) + +diff --git a/drivers/staging/media/rkvdec/rkvdec.c b/drivers/staging/media/rkvdec/rkvdec.c +index fd68671f0286..c8151328fb70 100644 +--- a/drivers/staging/media/rkvdec/rkvdec.c ++++ b/drivers/staging/media/rkvdec/rkvdec.c +@@ -27,6 +27,32 @@ + #include "rkvdec.h" + #include "rkvdec-regs.h" + ++static int rkvdec_try_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ if (ctrl->id == V4L2_CID_MPEG_VIDEO_H264_SPS) { ++ const struct v4l2_ctrl_h264_sps *sps = ctrl->p_new.p_h264_sps; ++ /* ++ * TODO: The hardware supports 10-bit and 4:2:2 profiles, ++ * but it's currently broken in the driver. ++ * Reject them for now, until it's fixed. ++ */ ++ if (sps->chroma_format_idc > 1) ++ /* Only 4:0:0 and 4:2:0 are supported */ ++ return -EINVAL; ++ if (sps->bit_depth_luma_minus8 != sps->bit_depth_chroma_minus8) ++ /* Luma and chroma bit depth mismatch */ ++ return -EINVAL; ++ if (sps->bit_depth_luma_minus8 != 0) ++ /* Only 8-bit is supported */ ++ return -EINVAL; ++ } ++ return 0; ++} ++ ++static const struct v4l2_ctrl_ops rkvdec_ctrl_ops = { ++ .try_ctrl = rkvdec_try_ctrl, ++}; ++ + static const struct rkvdec_ctrl_desc rkvdec_h264_ctrl_descs[] = { + { + .per_request = true, +@@ -42,6 +68,7 @@ static const struct rkvdec_ctrl_desc rkvdec_h264_ctrl_descs[] = { + .per_request = true, + .mandatory = true, + .cfg.id = V4L2_CID_MPEG_VIDEO_H264_SPS, ++ .cfg.ops = &rkvdec_ctrl_ops, + }, + { + .per_request = true, + +From c09155eb49e230da5fa16f188677120f967bbb36 Mon Sep 17 00:00:00 2001 +From: Ezequiel Garcia +Date: Thu, 9 Jul 2020 18:36:35 +0200 +Subject: [PATCH] hantro: h264: Refuse to decode unsupported bitstream + +The hardware only supports 4:2:0 or 4:0:0 (monochrome), +8-bit depth content. + +Verify that the SPS refers to a supported bitstream, and refuse +unsupported bitstreams by failing at TRY_EXT_CTRLS time. + +Given the JPEG compression level control is the only one +that needs setting, a specific ops is provided. + +Signed-off-by: Ezequiel Garcia +Reviewed-by: Philipp Zabel +Reviewed-by: Jonas Karlman +Signed-off-by: Hans Verkuil +Signed-off-by: Mauro Carvalho Chehab +(cherry picked from commit d70cca7323442026e20c474314518c446cb4766f) +--- + drivers/staging/media/hantro/hantro_drv.c | 29 ++++++++++++++++++++--- + 1 file changed, 26 insertions(+), 3 deletions(-) + +diff --git a/drivers/staging/media/hantro/hantro_drv.c b/drivers/staging/media/hantro/hantro_drv.c +index d32b6b1ab70b..34797507f214 100644 +--- a/drivers/staging/media/hantro/hantro_drv.c ++++ b/drivers/staging/media/hantro/hantro_drv.c +@@ -229,7 +229,25 @@ queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq) + return vb2_queue_init(dst_vq); + } + +-static int hantro_s_ctrl(struct v4l2_ctrl *ctrl) ++static int hantro_try_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ if (ctrl->id == V4L2_CID_MPEG_VIDEO_H264_SPS) { ++ const struct v4l2_ctrl_h264_sps *sps = ctrl->p_new.p_h264_sps; ++ ++ if (sps->chroma_format_idc > 1) ++ /* Only 4:0:0 and 4:2:0 are supported */ ++ return -EINVAL; ++ if (sps->bit_depth_luma_minus8 != sps->bit_depth_chroma_minus8) ++ /* Luma and chroma bit depth mismatch */ ++ return -EINVAL; ++ if (sps->bit_depth_luma_minus8 != 0) ++ /* Only 8-bit is supported */ ++ return -EINVAL; ++ } ++ return 0; ++} ++ ++static int hantro_jpeg_s_ctrl(struct v4l2_ctrl *ctrl) + { + struct hantro_ctx *ctx; + +@@ -250,7 +268,11 @@ static int hantro_s_ctrl(struct v4l2_ctrl *ctrl) + } + + static const struct v4l2_ctrl_ops hantro_ctrl_ops = { +- .s_ctrl = hantro_s_ctrl, ++ .try_ctrl = hantro_try_ctrl, ++}; ++ ++static const struct v4l2_ctrl_ops hantro_jpeg_ctrl_ops = { ++ .s_ctrl = hantro_jpeg_s_ctrl, + }; + + static const struct hantro_ctrl controls[] = { +@@ -262,7 +284,7 @@ static const struct hantro_ctrl controls[] = { + .max = 100, + .step = 1, + .def = 50, +- .ops = &hantro_ctrl_ops, ++ .ops = &hantro_jpeg_ctrl_ops, + }, + }, { + .codec = HANTRO_MPEG2_DECODER, +@@ -293,6 +315,7 @@ static const struct hantro_ctrl controls[] = { + .codec = HANTRO_H264_DECODER, + .cfg = { + .id = V4L2_CID_MPEG_VIDEO_H264_SPS, ++ .ops = &hantro_ctrl_ops, + }, + }, { + .codec = HANTRO_H264_DECODER, diff --git a/patch/kernel/rk322x-current/01-linux-0012-v4l2-from-next-from-list.patch b/patch/kernel/rk322x-current/01-linux-0012-v4l2-from-next-from-list.patch new file mode 100644 index 000000000..c06b7447b --- /dev/null +++ b/patch/kernel/rk322x-current/01-linux-0012-v4l2-from-next-from-list.patch @@ -0,0 +1,7852 @@ +From 337af64a63b5d8d5a60ad8302cca0bfa4d0cc4ad Mon Sep 17 00:00:00 2001 +From: Jacopo Mondi +Date: Fri, 17 Jul 2020 16:53:16 +0200 +Subject: [PATCH] media: i2c: Use the new get_mbus_config pad op + +Move the existing users of the g_mbus_config video operation to use the +newly introduced get_mbus_config pad operations. + +All the ported drivers report a static media bus configuration and do no +support s_mbus_config so the operation implementation has not changed. + +Bridge drivers needs to call the new pad operation and will receive an +-ENOICTLCMD when calling the old g_mbus_config video operation + +Signed-off-by: Jacopo Mondi +Signed-off-by: Hans Verkuil +Signed-off-by: Mauro Carvalho Chehab +--- + drivers/media/i2c/adv7180.c | 7 ++++--- + drivers/media/i2c/ml86v7667.c | 7 ++++--- + drivers/media/i2c/mt9m001.c | 7 ++++--- + drivers/media/i2c/mt9m111.c | 7 ++++--- + drivers/media/i2c/ov9640.c | 7 ++++--- + drivers/media/i2c/tc358743.c | 7 ++++--- + drivers/media/i2c/tvp5150.c | 7 ++++--- + 7 files changed, 28 insertions(+), 21 deletions(-) + +diff --git a/drivers/media/i2c/adv7180.c b/drivers/media/i2c/adv7180.c +index 00159daa6fcd..e8744efe3cf0 100644 +--- a/drivers/media/i2c/adv7180.c ++++ b/drivers/media/i2c/adv7180.c +@@ -760,8 +760,9 @@ static int adv7180_init_cfg(struct v4l2_subdev *sd, + return adv7180_set_pad_format(sd, cfg, &fmt); + } + +-static int adv7180_g_mbus_config(struct v4l2_subdev *sd, +- struct v4l2_mbus_config *cfg) ++static int adv7180_get_mbus_config(struct v4l2_subdev *sd, ++ unsigned int pad, ++ struct v4l2_mbus_config *cfg) + { + struct adv7180_state *state = to_state(sd); + +@@ -852,7 +853,6 @@ static const struct v4l2_subdev_video_ops adv7180_video_ops = { + .querystd = adv7180_querystd, + .g_input_status = adv7180_g_input_status, + .s_routing = adv7180_s_routing, +- .g_mbus_config = adv7180_g_mbus_config, + .g_pixelaspect = adv7180_g_pixelaspect, + .g_tvnorms = adv7180_g_tvnorms, + .s_stream = adv7180_s_stream, +@@ -869,6 +869,7 @@ static const struct v4l2_subdev_pad_ops adv7180_pad_ops = { + .enum_mbus_code = adv7180_enum_mbus_code, + .set_fmt = adv7180_set_pad_format, + .get_fmt = adv7180_get_pad_format, ++ .get_mbus_config = adv7180_get_mbus_config, + }; + + static const struct v4l2_subdev_sensor_ops adv7180_sensor_ops = { +diff --git a/drivers/media/i2c/ml86v7667.c b/drivers/media/i2c/ml86v7667.c +index c444bd6a0658..ff212335326a 100644 +--- a/drivers/media/i2c/ml86v7667.c ++++ b/drivers/media/i2c/ml86v7667.c +@@ -219,8 +219,9 @@ static int ml86v7667_fill_fmt(struct v4l2_subdev *sd, + return 0; + } + +-static int ml86v7667_g_mbus_config(struct v4l2_subdev *sd, +- struct v4l2_mbus_config *cfg) ++static int ml86v7667_get_mbus_config(struct v4l2_subdev *sd, ++ unsigned int pad, ++ struct v4l2_mbus_config *cfg) + { + cfg->flags = V4L2_MBUS_MASTER | V4L2_MBUS_PCLK_SAMPLE_RISING | + V4L2_MBUS_DATA_ACTIVE_HIGH; +@@ -291,13 +292,13 @@ static const struct v4l2_subdev_video_ops ml86v7667_subdev_video_ops = { + .s_std = ml86v7667_s_std, + .querystd = ml86v7667_querystd, + .g_input_status = ml86v7667_g_input_status, +- .g_mbus_config = ml86v7667_g_mbus_config, + }; + + static const struct v4l2_subdev_pad_ops ml86v7667_subdev_pad_ops = { + .enum_mbus_code = ml86v7667_enum_mbus_code, + .get_fmt = ml86v7667_fill_fmt, + .set_fmt = ml86v7667_fill_fmt, ++ .get_mbus_config = ml86v7667_get_mbus_config, + }; + + static const struct v4l2_subdev_core_ops ml86v7667_subdev_core_ops = { +diff --git a/drivers/media/i2c/mt9m001.c b/drivers/media/i2c/mt9m001.c +index 210ea76adb53..3b0ba8ed5233 100644 +--- a/drivers/media/i2c/mt9m001.c ++++ b/drivers/media/i2c/mt9m001.c +@@ -689,8 +689,9 @@ static int mt9m001_enum_mbus_code(struct v4l2_subdev *sd, + return 0; + } + +-static int mt9m001_g_mbus_config(struct v4l2_subdev *sd, +- struct v4l2_mbus_config *cfg) ++static int mt9m001_get_mbus_config(struct v4l2_subdev *sd, ++ unsigned int pad, ++ struct v4l2_mbus_config *cfg) + { + /* MT9M001 has all capture_format parameters fixed */ + cfg->flags = V4L2_MBUS_PCLK_SAMPLE_FALLING | +@@ -703,7 +704,6 @@ static int mt9m001_g_mbus_config(struct v4l2_subdev *sd, + + static const struct v4l2_subdev_video_ops mt9m001_subdev_video_ops = { + .s_stream = mt9m001_s_stream, +- .g_mbus_config = mt9m001_g_mbus_config, + }; + + static const struct v4l2_subdev_sensor_ops mt9m001_subdev_sensor_ops = { +@@ -717,6 +717,7 @@ static const struct v4l2_subdev_pad_ops mt9m001_subdev_pad_ops = { + .set_selection = mt9m001_set_selection, + .get_fmt = mt9m001_get_fmt, + .set_fmt = mt9m001_set_fmt, ++ .get_mbus_config = mt9m001_get_mbus_config, + }; + + static const struct v4l2_subdev_ops mt9m001_subdev_ops = { +diff --git a/drivers/media/i2c/mt9m111.c b/drivers/media/i2c/mt9m111.c +index 17e8253f5748..69697386ffcd 100644 +--- a/drivers/media/i2c/mt9m111.c ++++ b/drivers/media/i2c/mt9m111.c +@@ -1137,8 +1137,9 @@ static int mt9m111_init_cfg(struct v4l2_subdev *sd, + return 0; + } + +-static int mt9m111_g_mbus_config(struct v4l2_subdev *sd, +- struct v4l2_mbus_config *cfg) ++static int mt9m111_get_mbus_config(struct v4l2_subdev *sd, ++ unsigned int pad, ++ struct v4l2_mbus_config *cfg) + { + struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev); + +@@ -1155,7 +1156,6 @@ static int mt9m111_g_mbus_config(struct v4l2_subdev *sd, + } + + static const struct v4l2_subdev_video_ops mt9m111_subdev_video_ops = { +- .g_mbus_config = mt9m111_g_mbus_config, + .s_stream = mt9m111_s_stream, + .g_frame_interval = mt9m111_g_frame_interval, + .s_frame_interval = mt9m111_s_frame_interval, +@@ -1168,6 +1168,7 @@ static const struct v4l2_subdev_pad_ops mt9m111_subdev_pad_ops = { + .set_selection = mt9m111_set_selection, + .get_fmt = mt9m111_get_fmt, + .set_fmt = mt9m111_set_fmt, ++ .get_mbus_config = mt9m111_get_mbus_config, + }; + + static const struct v4l2_subdev_ops mt9m111_subdev_ops = { +diff --git a/drivers/media/i2c/ov9640.c b/drivers/media/i2c/ov9640.c +index 482609665305..0ef5af026d09 100644 +--- a/drivers/media/i2c/ov9640.c ++++ b/drivers/media/i2c/ov9640.c +@@ -648,8 +648,9 @@ static const struct v4l2_subdev_core_ops ov9640_core_ops = { + }; + + /* Request bus settings on camera side */ +-static int ov9640_g_mbus_config(struct v4l2_subdev *sd, +- struct v4l2_mbus_config *cfg) ++static int ov9640_get_mbus_config(struct v4l2_subdev *sd, ++ unsigned int pad, ++ struct v4l2_mbus_config *cfg) + { + cfg->flags = V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_MASTER | + V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_HIGH | +@@ -661,13 +662,13 @@ static int ov9640_g_mbus_config(struct v4l2_subdev *sd, + + static const struct v4l2_subdev_video_ops ov9640_video_ops = { + .s_stream = ov9640_s_stream, +- .g_mbus_config = ov9640_g_mbus_config, + }; + + static const struct v4l2_subdev_pad_ops ov9640_pad_ops = { + .enum_mbus_code = ov9640_enum_mbus_code, + .get_selection = ov9640_get_selection, + .set_fmt = ov9640_set_fmt, ++ .get_mbus_config = ov9640_get_mbus_config, + }; + + static const struct v4l2_subdev_ops ov9640_subdev_ops = { +diff --git a/drivers/media/i2c/tc358743.c b/drivers/media/i2c/tc358743.c +index dbbab75f135e..a03dcab5ce61 100644 +--- a/drivers/media/i2c/tc358743.c ++++ b/drivers/media/i2c/tc358743.c +@@ -1602,8 +1602,9 @@ static int tc358743_dv_timings_cap(struct v4l2_subdev *sd, + return 0; + } + +-static int tc358743_g_mbus_config(struct v4l2_subdev *sd, +- struct v4l2_mbus_config *cfg) ++static int tc358743_get_mbus_config(struct v4l2_subdev *sd, ++ unsigned int pad, ++ struct v4l2_mbus_config *cfg) + { + struct tc358743_state *state = to_state(sd); + +@@ -1836,7 +1837,6 @@ static const struct v4l2_subdev_video_ops tc358743_video_ops = { + .s_dv_timings = tc358743_s_dv_timings, + .g_dv_timings = tc358743_g_dv_timings, + .query_dv_timings = tc358743_query_dv_timings, +- .g_mbus_config = tc358743_g_mbus_config, + .s_stream = tc358743_s_stream, + }; + +@@ -1848,6 +1848,7 @@ static const struct v4l2_subdev_pad_ops tc358743_pad_ops = { + .set_edid = tc358743_s_edid, + .enum_dv_timings = tc358743_enum_dv_timings, + .dv_timings_cap = tc358743_dv_timings_cap, ++ .get_mbus_config = tc358743_get_mbus_config, + }; + + static const struct v4l2_subdev_ops tc358743_ops = { +diff --git a/drivers/media/i2c/tvp5150.c b/drivers/media/i2c/tvp5150.c +index 9df575238952..1c2050944b92 100644 +--- a/drivers/media/i2c/tvp5150.c ++++ b/drivers/media/i2c/tvp5150.c +@@ -1191,8 +1191,9 @@ static int tvp5150_get_selection(struct v4l2_subdev *sd, + } + } + +-static int tvp5150_g_mbus_config(struct v4l2_subdev *sd, +- struct v4l2_mbus_config *cfg) ++static int tvp5150_get_mbus_config(struct v4l2_subdev *sd, ++ unsigned int pad, ++ struct v4l2_mbus_config *cfg) + { + struct tvp5150 *decoder = to_tvp5150(sd); + +@@ -1721,7 +1722,6 @@ static const struct v4l2_subdev_video_ops tvp5150_video_ops = { + .querystd = tvp5150_querystd, + .s_stream = tvp5150_s_stream, + .s_routing = tvp5150_s_routing, +- .g_mbus_config = tvp5150_g_mbus_config, + }; + + static const struct v4l2_subdev_vbi_ops tvp5150_vbi_ops = { +@@ -1739,6 +1739,7 @@ static const struct v4l2_subdev_pad_ops tvp5150_pad_ops = { + .get_fmt = tvp5150_fill_fmt, + .get_selection = tvp5150_get_selection, + .set_selection = tvp5150_set_selection, ++ .get_mbus_config = tvp5150_get_mbus_config, + }; + + static const struct v4l2_subdev_ops tvp5150_ops = { + +From 4cc9a9a8b16549358ea377485df8fe21ea9e1bff Mon Sep 17 00:00:00 2001 +From: Jacopo Mondi +Date: Tue, 21 Jul 2020 09:53:17 +0200 +Subject: [PATCH] media: i2c: ov6650: Use new [get|set]_mbus_config ops + +Use the new get_mbus_config and set_mbus_config pad operations in place +of the video operations currently in use. + +Compared to other drivers where the same conversion has been performed, +ov6650 proved to be a bit more tricky, as the existing g_mbus_config +implementation did not report the currently applied configuration but +the set of all possible configuration options. + +Adapt the driver to support the semantic of the two newly introduced +operations: +- get_mbus_config reports the current media bus configuration +- set_mbus_config applies only changes explicitly requested and updates + the provided cfg parameter to report what has actually been applied to + the hardware. + +Compile-tested only. + +Signed-off-by: Jacopo Mondi +Signed-off-by: Hans Verkuil +Signed-off-by: Mauro Carvalho Chehab +--- + drivers/media/i2c/ov6650.c | 53 ++++++++++++++++++++++++++------------ + 1 file changed, 37 insertions(+), 16 deletions(-) + +diff --git a/drivers/media/i2c/ov6650.c b/drivers/media/i2c/ov6650.c +index 91906b94f978..48493af81198 100644 +--- a/drivers/media/i2c/ov6650.c ++++ b/drivers/media/i2c/ov6650.c +@@ -921,55 +921,74 @@ static const struct v4l2_subdev_core_ops ov6650_core_ops = { + }; + + /* Request bus settings on camera side */ +-static int ov6650_g_mbus_config(struct v4l2_subdev *sd, +- struct v4l2_mbus_config *cfg) ++static int ov6650_get_mbus_config(struct v4l2_subdev *sd, ++ unsigned int pad, ++ struct v4l2_mbus_config *cfg) + { ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ u8 comj, comf; ++ int ret; ++ ++ ret = ov6650_reg_read(client, REG_COMJ, &comj); ++ if (ret) ++ return ret; + +- cfg->flags = V4L2_MBUS_MASTER | +- V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_PCLK_SAMPLE_FALLING | +- V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_LOW | +- V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_LOW | +- V4L2_MBUS_DATA_ACTIVE_HIGH; ++ ret = ov6650_reg_read(client, REG_COMF, &comf); ++ if (ret) ++ return ret; ++ ++ cfg->flags = V4L2_MBUS_MASTER | V4L2_MBUS_DATA_ACTIVE_HIGH ++ | ((comj & COMJ_VSYNC_HIGH) ? V4L2_MBUS_VSYNC_ACTIVE_HIGH ++ : V4L2_MBUS_VSYNC_ACTIVE_LOW) ++ | ((comf & COMF_HREF_LOW) ? V4L2_MBUS_HSYNC_ACTIVE_LOW ++ : V4L2_MBUS_HSYNC_ACTIVE_HIGH) ++ | ((comj & COMJ_PCLK_RISING) ? V4L2_MBUS_PCLK_SAMPLE_RISING ++ : V4L2_MBUS_PCLK_SAMPLE_FALLING); + cfg->type = V4L2_MBUS_PARALLEL; + + return 0; + } + + /* Alter bus settings on camera side */ +-static int ov6650_s_mbus_config(struct v4l2_subdev *sd, +- const struct v4l2_mbus_config *cfg) ++static int ov6650_set_mbus_config(struct v4l2_subdev *sd, ++ unsigned int pad, ++ struct v4l2_mbus_config *cfg) + { + struct i2c_client *client = v4l2_get_subdevdata(sd); +- int ret; ++ int ret = 0; + + if (cfg->flags & V4L2_MBUS_PCLK_SAMPLE_RISING) + ret = ov6650_reg_rmw(client, REG_COMJ, COMJ_PCLK_RISING, 0); +- else ++ else if (cfg->flags & V4L2_MBUS_PCLK_SAMPLE_FALLING) + ret = ov6650_reg_rmw(client, REG_COMJ, 0, COMJ_PCLK_RISING); + if (ret) + return ret; + + if (cfg->flags & V4L2_MBUS_HSYNC_ACTIVE_LOW) + ret = ov6650_reg_rmw(client, REG_COMF, COMF_HREF_LOW, 0); +- else ++ else if (cfg->flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH) + ret = ov6650_reg_rmw(client, REG_COMF, 0, COMF_HREF_LOW); + if (ret) + return ret; + + if (cfg->flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH) + ret = ov6650_reg_rmw(client, REG_COMJ, COMJ_VSYNC_HIGH, 0); +- else ++ else if (cfg->flags & V4L2_MBUS_VSYNC_ACTIVE_LOW) + ret = ov6650_reg_rmw(client, REG_COMJ, 0, COMJ_VSYNC_HIGH); ++ if (ret) ++ return ret; + +- return ret; ++ /* ++ * Update the configuration to report what is actually applied to ++ * the hardware. ++ */ ++ return ov6650_get_mbus_config(sd, pad, cfg); + } + + static const struct v4l2_subdev_video_ops ov6650_video_ops = { + .s_stream = ov6650_s_stream, + .g_frame_interval = ov6650_g_frame_interval, + .s_frame_interval = ov6650_s_frame_interval, +- .g_mbus_config = ov6650_g_mbus_config, +- .s_mbus_config = ov6650_s_mbus_config, + }; + + static const struct v4l2_subdev_pad_ops ov6650_pad_ops = { +@@ -978,6 +997,8 @@ static const struct v4l2_subdev_pad_ops ov6650_pad_ops = { + .set_selection = ov6650_set_selection, + .get_fmt = ov6650_get_fmt, + .set_fmt = ov6650_set_fmt, ++ .get_mbus_config = ov6650_get_mbus_config, ++ .set_mbus_config = ov6650_set_mbus_config, + }; + + static const struct v4l2_subdev_ops ov6650_subdev_ops = { + +From 9b55924aa37a4ba85f84b8c4e382efffdf2b73df Mon Sep 17 00:00:00 2001 +From: Jacopo Mondi +Date: Fri, 17 Jul 2020 16:53:18 +0200 +Subject: [PATCH] media: pxa_camera: Use the new set_mbus_config op + +Move the PXA camera driver to use the new set_mbus_config pad operation. +For this platform the change is not only cosmetic, as the pxa driver is +currently the only driver in mainline to make use of the g_mbus_config +and s_mbus_config video operations. + +The existing driver semantic is the following: +- Collect all supported mbus config flags from the remote end +- Match them with the supported PXA mbus configuration flags +- If the remote subdevice allows multiple options for for VSYNC, HSYNC + and PCLK polarity, use platform data requested settings + +The semantic of the new get_mbus_config and set_mbus_config differs from +the corresponding video ops, particularly in the fact get_mbus_config +reports the current mbus configuration and not the set of supported +configuration options, with set_mbus_config always reporting the actual +mbus configuration applied to the remote subdevice. + +Adapt the driver to perform the following +- Set the remote subdevice mbus configuration according to the PXA + platform data preferences. +- If the applied configuration differs from the requested one (i.e. the + remote subdevice does not allow changing one setting) make sure that + - The remote end does not claim for DATA_ACTIVE_LOW, which seems not + supported by the platform + - The bus mastering roles match + +While at there remove a few checks performed on the media bus +configuration at get_format() time as they do not belong there. + +Compile-tested only. + +Signed-off-by: Jacopo Mondi +Signed-off-by: Hans Verkuil +Signed-off-by: Mauro Carvalho Chehab +--- + drivers/media/platform/pxa_camera.c | 189 ++++++++-------------------- + 1 file changed, 51 insertions(+), 138 deletions(-) + +diff --git a/drivers/media/platform/pxa_camera.c b/drivers/media/platform/pxa_camera.c +index 3c5fe737d36f..3a2cd28178da 100644 +--- a/drivers/media/platform/pxa_camera.c ++++ b/drivers/media/platform/pxa_camera.c +@@ -605,42 +605,6 @@ static const struct pxa_mbus_pixelfmt *pxa_mbus_get_fmtdesc( + return pxa_mbus_find_fmtdesc(code, mbus_fmt, ARRAY_SIZE(mbus_fmt)); + } + +-static unsigned int pxa_mbus_config_compatible(const struct v4l2_mbus_config *cfg, +- unsigned int flags) +-{ +- unsigned long common_flags; +- bool hsync = true, vsync = true, pclk, data, mode; +- bool mipi_lanes, mipi_clock; +- +- common_flags = cfg->flags & flags; +- +- switch (cfg->type) { +- case V4L2_MBUS_PARALLEL: +- hsync = common_flags & (V4L2_MBUS_HSYNC_ACTIVE_HIGH | +- V4L2_MBUS_HSYNC_ACTIVE_LOW); +- vsync = common_flags & (V4L2_MBUS_VSYNC_ACTIVE_HIGH | +- V4L2_MBUS_VSYNC_ACTIVE_LOW); +- /* fall through */ +- case V4L2_MBUS_BT656: +- pclk = common_flags & (V4L2_MBUS_PCLK_SAMPLE_RISING | +- V4L2_MBUS_PCLK_SAMPLE_FALLING); +- data = common_flags & (V4L2_MBUS_DATA_ACTIVE_HIGH | +- V4L2_MBUS_DATA_ACTIVE_LOW); +- mode = common_flags & (V4L2_MBUS_MASTER | V4L2_MBUS_SLAVE); +- return (!hsync || !vsync || !pclk || !data || !mode) ? +- 0 : common_flags; +- case V4L2_MBUS_CSI2_DPHY: +- mipi_lanes = common_flags & V4L2_MBUS_CSI2_LANES; +- mipi_clock = common_flags & (V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK | +- V4L2_MBUS_CSI2_CONTINUOUS_CLOCK); +- return (!mipi_lanes || !mipi_clock) ? 0 : common_flags; +- default: +- WARN_ON(1); +- return -EINVAL; +- } +- return 0; +-} +- + /** + * struct pxa_camera_format_xlate - match between host and sensor formats + * @code: code of a sensor provided format +@@ -1231,31 +1195,6 @@ static irqreturn_t pxa_camera_irq(int irq, void *data) + return IRQ_HANDLED; + } + +-static int test_platform_param(struct pxa_camera_dev *pcdev, +- unsigned char buswidth, unsigned long *flags) +-{ +- /* +- * Platform specified synchronization and pixel clock polarities are +- * only a recommendation and are only used during probing. The PXA270 +- * quick capture interface supports both. +- */ +- *flags = (pcdev->platform_flags & PXA_CAMERA_MASTER ? +- V4L2_MBUS_MASTER : V4L2_MBUS_SLAVE) | +- V4L2_MBUS_HSYNC_ACTIVE_HIGH | +- V4L2_MBUS_HSYNC_ACTIVE_LOW | +- V4L2_MBUS_VSYNC_ACTIVE_HIGH | +- V4L2_MBUS_VSYNC_ACTIVE_LOW | +- V4L2_MBUS_DATA_ACTIVE_HIGH | +- V4L2_MBUS_PCLK_SAMPLE_RISING | +- V4L2_MBUS_PCLK_SAMPLE_FALLING; +- +- /* If requested data width is supported by the platform, use it */ +- if ((1 << (buswidth - 1)) & pcdev->width_flags) +- return 0; +- +- return -EINVAL; +-} +- + static void pxa_camera_setup_cicr(struct pxa_camera_dev *pcdev, + unsigned long flags, __u32 pixfmt) + { +@@ -1598,99 +1537,78 @@ static int pxa_camera_init_videobuf2(struct pxa_camera_dev *pcdev) + */ + static int pxa_camera_set_bus_param(struct pxa_camera_dev *pcdev) + { ++ unsigned int bus_width = pcdev->current_fmt->host_fmt->bits_per_sample; + struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,}; + u32 pixfmt = pcdev->current_fmt->host_fmt->fourcc; +- unsigned long bus_flags, common_flags; ++ int mbus_config; + int ret; + +- ret = test_platform_param(pcdev, +- pcdev->current_fmt->host_fmt->bits_per_sample, +- &bus_flags); +- if (ret < 0) +- return ret; +- +- ret = sensor_call(pcdev, video, g_mbus_config, &cfg); +- if (!ret) { +- common_flags = pxa_mbus_config_compatible(&cfg, +- bus_flags); +- if (!common_flags) { +- dev_warn(pcdev_to_dev(pcdev), +- "Flags incompatible: camera 0x%x, host 0x%lx\n", +- cfg.flags, bus_flags); +- return -EINVAL; +- } +- } else if (ret != -ENOIOCTLCMD) { +- return ret; +- } else { +- common_flags = bus_flags; ++ if (!((1 << (bus_width - 1)) & pcdev->width_flags)) { ++ dev_err(pcdev_to_dev(pcdev), "Unsupported bus width %u", ++ bus_width); ++ return -EINVAL; + } + + pcdev->channels = 1; + + /* Make choices, based on platform preferences */ +- if ((common_flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH) && +- (common_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)) { +- if (pcdev->platform_flags & PXA_CAMERA_HSP) +- common_flags &= ~V4L2_MBUS_HSYNC_ACTIVE_HIGH; +- else +- common_flags &= ~V4L2_MBUS_HSYNC_ACTIVE_LOW; +- } ++ mbus_config = 0; ++ if (pcdev->platform_flags & PXA_CAMERA_MASTER) ++ mbus_config |= V4L2_MBUS_MASTER; ++ else ++ mbus_config |= V4L2_MBUS_SLAVE; + +- if ((common_flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH) && +- (common_flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)) { +- if (pcdev->platform_flags & PXA_CAMERA_VSP) +- common_flags &= ~V4L2_MBUS_VSYNC_ACTIVE_HIGH; +- else +- common_flags &= ~V4L2_MBUS_VSYNC_ACTIVE_LOW; +- } ++ if (pcdev->platform_flags & PXA_CAMERA_HSP) ++ mbus_config |= V4L2_MBUS_HSYNC_ACTIVE_HIGH; ++ else ++ mbus_config |= V4L2_MBUS_HSYNC_ACTIVE_LOW; + +- if ((common_flags & V4L2_MBUS_PCLK_SAMPLE_RISING) && +- (common_flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)) { +- if (pcdev->platform_flags & PXA_CAMERA_PCP) +- common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_RISING; +- else +- common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_FALLING; +- } ++ if (pcdev->platform_flags & PXA_CAMERA_VSP) ++ mbus_config |= V4L2_MBUS_VSYNC_ACTIVE_HIGH; ++ else ++ mbus_config |= V4L2_MBUS_VSYNC_ACTIVE_LOW; + +- cfg.flags = common_flags; +- ret = sensor_call(pcdev, video, s_mbus_config, &cfg); ++ if (pcdev->platform_flags & PXA_CAMERA_PCP) ++ mbus_config |= V4L2_MBUS_PCLK_SAMPLE_RISING; ++ else ++ mbus_config |= V4L2_MBUS_PCLK_SAMPLE_FALLING; ++ mbus_config |= V4L2_MBUS_DATA_ACTIVE_HIGH; ++ ++ cfg.flags = mbus_config; ++ ret = sensor_call(pcdev, pad, set_mbus_config, 0, &cfg); + if (ret < 0 && ret != -ENOIOCTLCMD) { +- dev_dbg(pcdev_to_dev(pcdev), +- "camera s_mbus_config(0x%lx) returned %d\n", +- common_flags, ret); ++ dev_err(pcdev_to_dev(pcdev), ++ "Failed to call set_mbus_config: %d\n", ret); + return ret; + } + +- pxa_camera_setup_cicr(pcdev, common_flags, pixfmt); +- +- return 0; +-} +- +-static int pxa_camera_try_bus_param(struct pxa_camera_dev *pcdev, +- unsigned char buswidth) +-{ +- struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,}; +- unsigned long bus_flags, common_flags; +- int ret = test_platform_param(pcdev, buswidth, &bus_flags); +- +- if (ret < 0) +- return ret; ++ /* ++ * If the requested media bus configuration has not been fully applied ++ * make sure it is supported by the platform. ++ * ++ * PXA does not support V4L2_MBUS_DATA_ACTIVE_LOW and the bus mastering ++ * roles should match. ++ */ ++ if (cfg.flags != mbus_config) { ++ unsigned int pxa_mbus_role = mbus_config & (V4L2_MBUS_MASTER | ++ V4L2_MBUS_SLAVE); ++ if (pxa_mbus_role != (cfg.flags & (V4L2_MBUS_MASTER | ++ V4L2_MBUS_SLAVE))) { ++ dev_err(pcdev_to_dev(pcdev), ++ "Unsupported mbus configuration: bus mastering\n"); ++ return -EINVAL; ++ } + +- ret = sensor_call(pcdev, video, g_mbus_config, &cfg); +- if (!ret) { +- common_flags = pxa_mbus_config_compatible(&cfg, +- bus_flags); +- if (!common_flags) { +- dev_warn(pcdev_to_dev(pcdev), +- "Flags incompatible: camera 0x%x, host 0x%lx\n", +- cfg.flags, bus_flags); ++ if (cfg.flags & V4L2_MBUS_DATA_ACTIVE_LOW) { ++ dev_err(pcdev_to_dev(pcdev), ++ "Unsupported mbus configuration: DATA_ACTIVE_LOW\n"); + return -EINVAL; + } +- } else if (ret == -ENOIOCTLCMD) { +- ret = 0; + } + +- return ret; ++ pxa_camera_setup_cicr(pcdev, cfg.flags, pixfmt); ++ ++ return 0; + } + + static const struct pxa_mbus_pixelfmt pxa_camera_formats[] = { +@@ -1738,11 +1656,6 @@ static int pxa_camera_get_formats(struct v4l2_device *v4l2_dev, + return 0; + } + +- /* This also checks support for the requested bits-per-sample */ +- ret = pxa_camera_try_bus_param(pcdev, fmt->bits_per_sample); +- if (ret < 0) +- return 0; +- + switch (code.code) { + case MEDIA_BUS_FMT_UYVY8_2X8: + formats++; + +From 562b1d8a78c8367d9809491277a6c60441565aa4 Mon Sep 17 00:00:00 2001 +From: Jacopo Mondi +Date: Fri, 17 Jul 2020 16:53:19 +0200 +Subject: [PATCH] media: v4l2-subdev: Remove [s|g]_mbus_config video ops + +With all sensor and platform drivers now converted to use the new +get_mbus_config and set_mbus_config pad operations, remove the +deprecated video operations g_mbus_config and s_mbus_config. + +Signed-off-by: Jacopo Mondi +Signed-off-by: Hans Verkuil +Signed-off-by: Mauro Carvalho Chehab +--- + include/media/v4l2-subdev.h | 10 ---------- + 1 file changed, 10 deletions(-) + +diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h +index f7fe78a6f65a..90098fb1d770 100644 +--- a/include/media/v4l2-subdev.h ++++ b/include/media/v4l2-subdev.h +@@ -402,12 +402,6 @@ struct v4l2_mbus_frame_desc { + * + * @query_dv_timings: callback for VIDIOC_QUERY_DV_TIMINGS() ioctl handler code. + * +- * @g_mbus_config: get supported mediabus configurations +- * +- * @s_mbus_config: set a certain mediabus configuration. This operation is added +- * for compatibility with soc-camera drivers and should not be used by new +- * software. +- * + * @s_rx_buffer: set a host allocated memory buffer for the subdev. The subdev + * can adjust @size to a lower value and must not write more data to the + * buffer starting at @data than the original value of @size. +@@ -435,10 +429,6 @@ struct v4l2_subdev_video_ops { + struct v4l2_dv_timings *timings); + int (*query_dv_timings)(struct v4l2_subdev *sd, + struct v4l2_dv_timings *timings); +- int (*g_mbus_config)(struct v4l2_subdev *sd, +- struct v4l2_mbus_config *cfg); +- int (*s_mbus_config)(struct v4l2_subdev *sd, +- const struct v4l2_mbus_config *cfg); + int (*s_rx_buffer)(struct v4l2_subdev *sd, void *buf, + unsigned int *size); + }; + +From 1ea27db9eaddf1eb44e533e4baa49b5b3a50900f Mon Sep 17 00:00:00 2001 +From: Jacopo Mondi +Date: Fri, 17 Jul 2020 16:53:20 +0200 +Subject: [PATCH] media: v4l2- mediabus: Add usage note for V4L2_MBUS_* + +With the removal of the legacy g_mbus_config and s_mbus_config video +operations, the sole users of V4L2_MBUS_* flags are now the newly +introduced get_mbus_config and set_mbus_config pad operations. + +As the semantic of the new operations differs from the semantic of +the legacy ones, add a usage note in the v4l2-mediabus.h header to +specify how to use the flags. + +Also add a TODO note to record that we intend to replace the existing +flags with fields, to prevent users from mixing conflicting values +in a single operation call. + +Signed-off-by: Jacopo Mondi +Signed-off-by: Hans Verkuil +Signed-off-by: Mauro Carvalho Chehab +--- + include/media/v4l2-mediabus.h | 33 +++++++++++++++++++++++++++++---- + 1 file changed, 29 insertions(+), 4 deletions(-) + +diff --git a/include/media/v4l2-mediabus.h b/include/media/v4l2-mediabus.h +index 45f88f0248c4..59b1de197114 100644 +--- a/include/media/v4l2-mediabus.h ++++ b/include/media/v4l2-mediabus.h +@@ -11,9 +11,34 @@ + #include + #include + ++/* ++ * How to use the V4L2_MBUS_* flags: ++ * Flags are defined for each of the possible states and values of a media ++ * bus configuration parameter. One and only one bit of each group of flags ++ * shall be set by the users of the v4l2_subdev_pad_ops.get_mbus_config and ++ * v4l2_subdev_pad_ops.set_mbus_config operations to ensure that no ++ * conflicting settings are specified when reporting and setting the media bus ++ * configuration with the two operations respectively. For example, it is ++ * invalid to set or clear both the V4L2_MBUS_HSYNC_ACTIVE_HIGH and the ++ * V4L2_MBUS_HSYNC_ACTIVE_LOW flag at the same time. Instead either flag ++ * V4L2_MBUS_HSYNC_ACTIVE_HIGH or flag V4L2_MBUS_HSYNC_ACTIVE_LOW shall be ++ * set. The same is true for the V4L2_MBUS_CSI2_1/2/3/4_LANE flags group: only ++ * one of these four bits shall be set. ++ * ++ * TODO: replace the existing V4L2_MBUS_* flags with structures of fields ++ * to avoid conflicting settings. ++ * ++ * In example: ++ * #define V4L2_MBUS_HSYNC_ACTIVE_HIGH BIT(2) ++ * #define V4L2_MBUS_HSYNC_ACTIVE_LOW BIT(3) ++ * will be replaced by a field whose value reports the intended active state of ++ * the signal: ++ * unsigned int v4l2_mbus_hsync_active : 1; ++ */ ++ + /* Parallel flags */ + /* +- * Can the client run in master or in slave mode. By "Master mode" an operation ++ * The client runs in master or in slave mode. By "Master mode" an operation + * mode is meant, when the client (e.g., a camera sensor) is producing + * horizontal and vertical synchronisation. In "Slave mode" the host is + * providing these signals to the slave. +@@ -45,17 +70,17 @@ + #define V4L2_MBUS_DATA_ENABLE_LOW BIT(15) + + /* Serial flags */ +-/* How many lanes the client can use */ ++/* CSI-2 D-PHY number of data lanes. */ + #define V4L2_MBUS_CSI2_1_LANE BIT(0) + #define V4L2_MBUS_CSI2_2_LANE BIT(1) + #define V4L2_MBUS_CSI2_3_LANE BIT(2) + #define V4L2_MBUS_CSI2_4_LANE BIT(3) +-/* On which channels it can send video data */ ++/* CSI-2 Virtual Channel identifiers. */ + #define V4L2_MBUS_CSI2_CHANNEL_0 BIT(4) + #define V4L2_MBUS_CSI2_CHANNEL_1 BIT(5) + #define V4L2_MBUS_CSI2_CHANNEL_2 BIT(6) + #define V4L2_MBUS_CSI2_CHANNEL_3 BIT(7) +-/* Does it support only continuous or also non-continuous clock mode */ ++/* Clock non-continuous mode support. */ + #define V4L2_MBUS_CSI2_CONTINUOUS_CLOCK BIT(8) + #define V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK BIT(9) + + +From 9aae063d84435edfb0212c7613f887105dd58009 Mon Sep 17 00:00:00 2001 +From: Jacopo Mondi +Date: Fri, 17 Jul 2020 16:53:21 +0200 +Subject: [PATCH] media: staging: media: imx: Update TODO entry + +Update the TODO entry that mentioned a potential use case for the now +removed g_mbus_config video operation. + +Signed-off-by: Jacopo Mondi +Signed-off-by: Hans Verkuil +Signed-off-by: Mauro Carvalho Chehab +--- + drivers/staging/media/imx/TODO | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/drivers/staging/media/imx/TODO b/drivers/staging/media/imx/TODO +index a371cdedcdb0..9cfc1c1e78dc 100644 +--- a/drivers/staging/media/imx/TODO ++++ b/drivers/staging/media/imx/TODO +@@ -10,6 +10,10 @@ + driver uses the parsed DT bus config method until this issue is + resolved. + ++ 2020-06: g_mbus has been removed in favour of the get_mbus_config pad ++ operation which should be used to avoid parsing the remote endpoint ++ configuration. ++ + - This media driver supports inheriting V4L2 controls to the + video capture devices, from the subdevices in the capture device's + pipeline. The controls for each capture device are updated in the + +From 33a781840365c6b8a2b86b1c6cb4aaa86941a5d6 Mon Sep 17 00:00:00 2001 +From: Jacopo Mondi +Date: Fri, 17 Jul 2020 16:53:22 +0200 +Subject: [PATCH] media: i2c: adv748x: Adjust TXA data lanes number +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +When outputting SD-Core output through the TXA MIPI CSI-2 interface, +the number of enabled data lanes should be reduced in order to guarantee +that the two video formats produced by the SD-Core (480i and 576i) +generate a MIPI CSI-2 link clock frequency compatible with the MIPI D-PHY +specifications. + +Limit the number of enabled data lanes to 2, which is guaranteed to +support 480i and 576i formats. + +Cache the number of enabled data lanes to be able to report it through +the new get_mbus_config operation. + +Reviewed-by: Kieran Bingham +Reviewed-by: Laurent Pinchart +Reviewed-by: Niklas Söderlund +Signed-off-by: Jacopo Mondi +Signed-off-by: Hans Verkuil +Signed-off-by: Mauro Carvalho Chehab +--- + drivers/media/i2c/adv748x/adv748x-core.c | 31 ++++++++++++++++++------ + drivers/media/i2c/adv748x/adv748x.h | 1 + + 2 files changed, 25 insertions(+), 7 deletions(-) + +diff --git a/drivers/media/i2c/adv748x/adv748x-core.c b/drivers/media/i2c/adv748x/adv748x-core.c +index 23e02ff27b17..1fe7f97c6d52 100644 +--- a/drivers/media/i2c/adv748x/adv748x-core.c ++++ b/drivers/media/i2c/adv748x/adv748x-core.c +@@ -241,10 +241,10 @@ static int adv748x_power_up_tx(struct adv748x_csi2 *tx) + int ret = 0; + + /* Enable n-lane MIPI */ +- adv748x_write_check(state, page, 0x00, 0x80 | tx->num_lanes, &ret); ++ adv748x_write_check(state, page, 0x00, 0x80 | tx->active_lanes, &ret); + + /* Set Auto DPHY Timing */ +- adv748x_write_check(state, page, 0x00, 0xa0 | tx->num_lanes, &ret); ++ adv748x_write_check(state, page, 0x00, 0xa0 | tx->active_lanes, &ret); + + /* ADI Required Write */ + if (tx->src == &state->hdmi.sd) { +@@ -270,7 +270,7 @@ static int adv748x_power_up_tx(struct adv748x_csi2 *tx) + usleep_range(2000, 2500); + + /* Power-up CSI-TX */ +- adv748x_write_check(state, page, 0x00, 0x20 | tx->num_lanes, &ret); ++ adv748x_write_check(state, page, 0x00, 0x20 | tx->active_lanes, &ret); + usleep_range(1000, 1500); + + /* ADI Required Writes */ +@@ -292,7 +292,7 @@ static int adv748x_power_down_tx(struct adv748x_csi2 *tx) + adv748x_write_check(state, page, 0x1e, 0x00, &ret); + + /* Enable n-lane MIPI */ +- adv748x_write_check(state, page, 0x00, 0x80 | tx->num_lanes, &ret); ++ adv748x_write_check(state, page, 0x00, 0x80 | tx->active_lanes, &ret); + + /* i2c_mipi_pll_en - 1'b1 */ + adv748x_write_check(state, page, 0xda, 0x01, &ret); +@@ -357,14 +357,29 @@ static int adv748x_link_setup(struct media_entity *entity, + if (state->afe.tx) { + /* AFE Requires TXA enabled, even when output to TXB */ + io10 |= ADV748X_IO_10_CSI4_EN; +- if (is_txa(tx)) ++ if (is_txa(tx)) { ++ /* ++ * Output from the SD-core (480i and 576i) from the TXA ++ * interface requires reducing the number of enabled ++ * data lanes in order to guarantee a valid link ++ * frequency. ++ */ ++ tx->active_lanes = min(tx->num_lanes, 2U); + io10 |= ADV748X_IO_10_CSI4_IN_SEL_AFE; +- else ++ } else { ++ /* TXB has a single data lane, no need to adjust. */ + io10 |= ADV748X_IO_10_CSI1_EN; ++ } + } + +- if (state->hdmi.tx) ++ if (state->hdmi.tx) { ++ /* ++ * Restore the number of active lanes, in case we have gone ++ * through an AFE->TXA streaming sessions. ++ */ ++ tx->active_lanes = tx->num_lanes; + io10 |= ADV748X_IO_10_CSI4_EN; ++ } + + return io_clrset(state, ADV748X_IO_10, io10_mask, io10); + } +@@ -596,6 +611,7 @@ static int adv748x_parse_csi2_lanes(struct adv748x_state *state, + } + + state->txa.num_lanes = num_lanes; ++ state->txa.active_lanes = num_lanes; + adv_dbg(state, "TXA: using %u lanes\n", state->txa.num_lanes); + } + +@@ -607,6 +623,7 @@ static int adv748x_parse_csi2_lanes(struct adv748x_state *state, + } + + state->txb.num_lanes = num_lanes; ++ state->txb.active_lanes = num_lanes; + adv_dbg(state, "TXB: using %u lanes\n", state->txb.num_lanes); + } + +diff --git a/drivers/media/i2c/adv748x/adv748x.h b/drivers/media/i2c/adv748x/adv748x.h +index fccb388ce179..1061f425ece5 100644 +--- a/drivers/media/i2c/adv748x/adv748x.h ++++ b/drivers/media/i2c/adv748x/adv748x.h +@@ -79,6 +79,7 @@ struct adv748x_csi2 { + unsigned int page; + unsigned int port; + unsigned int num_lanes; ++ unsigned int active_lanes; + + struct media_pad pads[ADV748X_CSI2_NR_PADS]; + struct v4l2_ctrl_handler ctrl_hdl; + +From 5ccfd4f056cc53beef915bd24985449b7d20affc Mon Sep 17 00:00:00 2001 +From: Jacopo Mondi +Date: Fri, 17 Jul 2020 16:53:23 +0200 +Subject: [PATCH] media: i2c: adv748x: Implement get_mbus_config +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Implement the newly introduced get_mbus_config operation to report the +number of currently used data lanes on the MIPI CSI-2 interface. + +Reviewed-by: Kieran Bingham +Reviewed-by: Niklas Söderlund +Signed-off-by: Jacopo Mondi +Signed-off-by: Hans Verkuil +Signed-off-by: Mauro Carvalho Chehab +--- + drivers/media/i2c/adv748x/adv748x-csi2.c | 31 ++++++++++++++++++++++++ + 1 file changed, 31 insertions(+) + +diff --git a/drivers/media/i2c/adv748x/adv748x-csi2.c b/drivers/media/i2c/adv748x/adv748x-csi2.c +index 2091cda50935..99bb63d05eef 100644 +--- a/drivers/media/i2c/adv748x/adv748x-csi2.c ++++ b/drivers/media/i2c/adv748x/adv748x-csi2.c +@@ -214,9 +214,40 @@ static int adv748x_csi2_set_format(struct v4l2_subdev *sd, + return ret; + } + ++static int adv748x_csi2_get_mbus_config(struct v4l2_subdev *sd, unsigned int pad, ++ struct v4l2_mbus_config *config) ++{ ++ struct adv748x_csi2 *tx = adv748x_sd_to_csi2(sd); ++ ++ if (pad != ADV748X_CSI2_SOURCE) ++ return -EINVAL; ++ ++ config->type = V4L2_MBUS_CSI2_DPHY; ++ switch (tx->active_lanes) { ++ case 1: ++ config->flags = V4L2_MBUS_CSI2_1_LANE; ++ break; ++ ++ case 2: ++ config->flags = V4L2_MBUS_CSI2_2_LANE; ++ break; ++ ++ case 3: ++ config->flags = V4L2_MBUS_CSI2_3_LANE; ++ break; ++ ++ case 4: ++ config->flags = V4L2_MBUS_CSI2_4_LANE; ++ break; ++ } ++ ++ return 0; ++} ++ + static const struct v4l2_subdev_pad_ops adv748x_csi2_pad_ops = { + .get_fmt = adv748x_csi2_get_format, + .set_fmt = adv748x_csi2_set_format, ++ .get_mbus_config = adv748x_csi2_get_mbus_config, + }; + + /* ----------------------------------------------------------------------------- + +From a7053f425fb6140bdf72c009cab1730e9d3094af Mon Sep 17 00:00:00 2001 +From: Jacopo Mondi +Date: Fri, 17 Jul 2020 16:53:24 +0200 +Subject: [PATCH] media: rcar-csi2: Negotiate data lanes number +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Use the newly introduced get_mbus_config() subdevice pad operation to +retrieve the remote subdevice MIPI CSI-2 bus configuration and configure +the number of active data lanes accordingly. + +In order to be able to call the remote subdevice operation cache the +index of the remote pad connected to the single CSI-2 input port. + +Reviewed-by: Niklas Söderlund +Signed-off-by: Jacopo Mondi +Signed-off-by: Hans Verkuil +Signed-off-by: Mauro Carvalho Chehab +--- + drivers/media/platform/rcar-vin/rcar-csi2.c | 75 +++++++++++++++++++-- + 1 file changed, 68 insertions(+), 7 deletions(-) + +diff --git a/drivers/media/platform/rcar-vin/rcar-csi2.c b/drivers/media/platform/rcar-vin/rcar-csi2.c +index 151e6a90c5fb..fe99ae00e690 100644 +--- a/drivers/media/platform/rcar-vin/rcar-csi2.c ++++ b/drivers/media/platform/rcar-vin/rcar-csi2.c +@@ -363,6 +363,7 @@ struct rcar_csi2 { + struct v4l2_async_notifier notifier; + struct v4l2_async_subdev asd; + struct v4l2_subdev *remote; ++ unsigned int remote_pad; + + struct v4l2_mbus_framefmt mf; + +@@ -408,13 +409,14 @@ static void rcsi2_exit_standby(struct rcar_csi2 *priv) + reset_control_deassert(priv->rstc); + } + +-static int rcsi2_wait_phy_start(struct rcar_csi2 *priv) ++static int rcsi2_wait_phy_start(struct rcar_csi2 *priv, ++ unsigned int lanes) + { + unsigned int timeout; + + /* Wait for the clock and data lanes to enter LP-11 state. */ + for (timeout = 0; timeout <= 20; timeout++) { +- const u32 lane_mask = (1 << priv->lanes) - 1; ++ const u32 lane_mask = (1 << lanes) - 1; + + if ((rcsi2_read(priv, PHCLM_REG) & PHCLM_STOPSTATECKL) && + (rcsi2_read(priv, PHDLM_REG) & lane_mask) == lane_mask) +@@ -446,7 +448,8 @@ static int rcsi2_set_phypll(struct rcar_csi2 *priv, unsigned int mbps) + return 0; + } + +-static int rcsi2_calc_mbps(struct rcar_csi2 *priv, unsigned int bpp) ++static int rcsi2_calc_mbps(struct rcar_csi2 *priv, unsigned int bpp, ++ unsigned int lanes) + { + struct v4l2_subdev *source; + struct v4l2_ctrl *ctrl; +@@ -471,15 +474,64 @@ static int rcsi2_calc_mbps(struct rcar_csi2 *priv, unsigned int bpp) + * bps = link_freq * 2 + */ + mbps = v4l2_ctrl_g_ctrl_int64(ctrl) * bpp; +- do_div(mbps, priv->lanes * 1000000); ++ do_div(mbps, lanes * 1000000); + + return mbps; + } + ++static int rcsi2_get_active_lanes(struct rcar_csi2 *priv, ++ unsigned int *lanes) ++{ ++ struct v4l2_mbus_config mbus_config = { 0 }; ++ unsigned int num_lanes = UINT_MAX; ++ int ret; ++ ++ *lanes = priv->lanes; ++ ++ ret = v4l2_subdev_call(priv->remote, pad, get_mbus_config, ++ priv->remote_pad, &mbus_config); ++ if (ret == -ENOIOCTLCMD) { ++ dev_dbg(priv->dev, "No remote mbus configuration available\n"); ++ return 0; ++ } ++ ++ if (ret) { ++ dev_err(priv->dev, "Failed to get remote mbus configuration\n"); ++ return ret; ++ } ++ ++ if (mbus_config.type != V4L2_MBUS_CSI2_DPHY) { ++ dev_err(priv->dev, "Unsupported media bus type %u\n", ++ mbus_config.type); ++ return -EINVAL; ++ } ++ ++ if (mbus_config.flags & V4L2_MBUS_CSI2_1_LANE) ++ num_lanes = 1; ++ else if (mbus_config.flags & V4L2_MBUS_CSI2_2_LANE) ++ num_lanes = 2; ++ else if (mbus_config.flags & V4L2_MBUS_CSI2_3_LANE) ++ num_lanes = 3; ++ else if (mbus_config.flags & V4L2_MBUS_CSI2_4_LANE) ++ num_lanes = 4; ++ ++ if (num_lanes > priv->lanes) { ++ dev_err(priv->dev, ++ "Unsupported mbus config: too many data lanes %u\n", ++ num_lanes); ++ return -EINVAL; ++ } ++ ++ *lanes = num_lanes; ++ ++ return 0; ++} ++ + static int rcsi2_start_receiver(struct rcar_csi2 *priv) + { + const struct rcar_csi2_format *format; + u32 phycnt, vcdt = 0, vcdt2 = 0, fld = 0; ++ unsigned int lanes; + unsigned int i; + int mbps, ret; + +@@ -521,10 +573,18 @@ static int rcsi2_start_receiver(struct rcar_csi2 *priv) + fld |= FLD_FLD_NUM(1); + } + ++ /* ++ * Get the number of active data lanes inspecting the remote mbus ++ * configuration. ++ */ ++ ret = rcsi2_get_active_lanes(priv, &lanes); ++ if (ret) ++ return ret; ++ + phycnt = PHYCNT_ENABLECLK; +- phycnt |= (1 << priv->lanes) - 1; ++ phycnt |= (1 << lanes) - 1; + +- mbps = rcsi2_calc_mbps(priv, format->bpp); ++ mbps = rcsi2_calc_mbps(priv, format->bpp, lanes); + if (mbps < 0) + return mbps; + +@@ -571,7 +631,7 @@ static int rcsi2_start_receiver(struct rcar_csi2 *priv) + rcsi2_write(priv, PHYCNT_REG, phycnt | PHYCNT_SHUTDOWNZ); + rcsi2_write(priv, PHYCNT_REG, phycnt | PHYCNT_SHUTDOWNZ | PHYCNT_RSTZ); + +- ret = rcsi2_wait_phy_start(priv); ++ ret = rcsi2_wait_phy_start(priv, lanes); + if (ret) + return ret; + +@@ -748,6 +808,7 @@ static int rcsi2_notify_bound(struct v4l2_async_notifier *notifier, + } + + priv->remote = subdev; ++ priv->remote_pad = pad; + + dev_dbg(priv->dev, "Bound %s pad: %d\n", subdev->name, pad); + + +From ed9092fbdad008ed58e0bd8079b6d6484839d811 Mon Sep 17 00:00:00 2001 +From: Dinghao Liu +Date: Sun, 28 Jun 2020 07:55:23 +0200 +Subject: [PATCH] media: venus: core: Fix runtime PM imbalance in venus_probe + +pm_runtime_get_sync() increments the runtime PM usage counter even +when it returns an error code. Thus a pairing decrement is needed on +the error handling path to keep the counter balanced. For other error +paths after this call, things are the same. + +Fix this by adding pm_runtime_put_noidle() after 'err_runtime_disable' +label. But in this case, the error path after pm_runtime_put_sync() +will decrease PM usage counter twice. Thus add an extra +pm_runtime_get_noresume() in this path to balance PM counter. + +Signed-off-by: Dinghao Liu +Signed-off-by: Mauro Carvalho Chehab +--- + drivers/media/platform/qcom/venus/core.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/drivers/media/platform/qcom/venus/core.c b/drivers/media/platform/qcom/venus/core.c +index 203c6538044f..b0b932bf8c02 100644 +--- a/drivers/media/platform/qcom/venus/core.c ++++ b/drivers/media/platform/qcom/venus/core.c +@@ -287,8 +287,10 @@ static int venus_probe(struct platform_device *pdev) + goto err_core_deinit; + + ret = pm_runtime_put_sync(dev); +- if (ret) ++ if (ret) { ++ pm_runtime_get_noresume(dev); + goto err_dev_unregister; ++ } + + return 0; + +@@ -299,6 +301,7 @@ static int venus_probe(struct platform_device *pdev) + err_venus_shutdown: + venus_shutdown(core); + err_runtime_disable: ++ pm_runtime_put_noidle(dev); + pm_runtime_set_suspended(dev); + pm_runtime_disable(dev); + hfi_destroy(core); + +From 757449d0037dd11f6b783bc31b27c76c5fa636c8 Mon Sep 17 00:00:00 2001 +From: Rajendra Nayak +Date: Wed, 29 Jul 2020 09:16:42 +0200 +Subject: [PATCH] media: venus: core: Fix error handling in probe + +Post a successful pm_ops->core_get, an error in probe +should exit by doing a pm_ops->core_put which seems +to be missing. So fix it. + +Signed-off-by: Rajendra Nayak +Reviewed-by: Bjorn Andersson +Signed-off-by: Stanimir Varbanov +Signed-off-by: Mauro Carvalho Chehab +--- + drivers/media/platform/qcom/venus/core.c | 15 ++++++++++----- + 1 file changed, 10 insertions(+), 5 deletions(-) + +diff --git a/drivers/media/platform/qcom/venus/core.c b/drivers/media/platform/qcom/venus/core.c +index b0b932bf8c02..321ad77cb6cf 100644 +--- a/drivers/media/platform/qcom/venus/core.c ++++ b/drivers/media/platform/qcom/venus/core.c +@@ -224,13 +224,15 @@ static int venus_probe(struct platform_device *pdev) + + ret = dma_set_mask_and_coherent(dev, core->res->dma_mask); + if (ret) +- return ret; ++ goto err_core_put; + + if (!dev->dma_parms) { + dev->dma_parms = devm_kzalloc(dev, sizeof(*dev->dma_parms), + GFP_KERNEL); +- if (!dev->dma_parms) +- return -ENOMEM; ++ if (!dev->dma_parms) { ++ ret = -ENOMEM; ++ goto err_core_put; ++ } + } + dma_set_max_seg_size(dev, DMA_BIT_MASK(32)); + +@@ -242,11 +244,11 @@ static int venus_probe(struct platform_device *pdev) + IRQF_TRIGGER_HIGH | IRQF_ONESHOT, + "venus", core); + if (ret) +- return ret; ++ goto err_core_put; + + ret = hfi_create(core, &venus_core_ops); + if (ret) +- return ret; ++ goto err_core_put; + + pm_runtime_enable(dev); + +@@ -305,6 +307,9 @@ static int venus_probe(struct platform_device *pdev) + pm_runtime_set_suspended(dev); + pm_runtime_disable(dev); + hfi_destroy(core); ++err_core_put: ++ if (core->pm_ops->core_put) ++ core->pm_ops->core_put(dev); + return ret; + } + + +From 207ffb881dd2058c1a86022671817cef37a9d273 Mon Sep 17 00:00:00 2001 +From: Rajendra Nayak +Date: Wed, 29 Jul 2020 09:16:43 +0200 +Subject: [PATCH] media: venus: core: Add support for opp tables/perf voting + +Add support to add OPP tables and perf voting on the OPP powerdomain. +This is needed so venus votes on the corresponding performance state +for the OPP powerdomain along with setting the core clock rate. + +Signed-off-by: Rajendra Nayak +Reviewed-by: Matthias Kaehlcke +Reviewed-by: Bjorn Andersson +Signed-off-by: Stanimir Varbanov +Signed-off-by: Mauro Carvalho Chehab +--- + drivers/media/platform/qcom/venus/core.c | 2 + + drivers/media/platform/qcom/venus/core.h | 5 + + .../media/platform/qcom/venus/pm_helpers.c | 92 +++++++++++++++++-- + 3 files changed, 92 insertions(+), 7 deletions(-) + +diff --git a/drivers/media/platform/qcom/venus/core.c b/drivers/media/platform/qcom/venus/core.c +index 321ad77cb6cf..5fd70f8cf857 100644 +--- a/drivers/media/platform/qcom/venus/core.c ++++ b/drivers/media/platform/qcom/venus/core.c +@@ -528,6 +528,7 @@ static const struct venus_resources sdm845_res_v2 = { + .vcodec_clks_num = 2, + .vcodec_pmdomains = { "venus", "vcodec0", "vcodec1" }, + .vcodec_pmdomains_num = 3, ++ .opp_pmdomain = (const char *[]) { "cx", NULL }, + .vcodec_num = 2, + .max_load = 3110400, /* 4096x2160@90 */ + .hfi_version = HFI_VERSION_4XX, +@@ -573,6 +574,7 @@ static const struct venus_resources sc7180_res = { + .vcodec_clks_num = 2, + .vcodec_pmdomains = { "venus", "vcodec0" }, + .vcodec_pmdomains_num = 2, ++ .opp_pmdomain = (const char *[]) { "cx", NULL }, + .vcodec_num = 1, + .hfi_version = HFI_VERSION_4XX, + .vmem_id = VIDC_RESOURCE_NONE, +diff --git a/drivers/media/platform/qcom/venus/core.h b/drivers/media/platform/qcom/venus/core.h +index 7118612673c9..b0cc544ad39f 100644 +--- a/drivers/media/platform/qcom/venus/core.h ++++ b/drivers/media/platform/qcom/venus/core.h +@@ -62,6 +62,7 @@ struct venus_resources { + unsigned int vcodec_clks_num; + const char * const vcodec_pmdomains[VIDC_PMDOMAINS_NUM_MAX]; + unsigned int vcodec_pmdomains_num; ++ const char **opp_pmdomain; + unsigned int vcodec_num; + enum hfi_version hfi_version; + u32 max_load; +@@ -145,8 +146,12 @@ struct venus_core { + struct clk *vcodec1_clks[VIDC_VCODEC_CLKS_NUM_MAX]; + struct icc_path *video_path; + struct icc_path *cpucfg_path; ++ struct opp_table *opp_table; ++ bool has_opp_table; + struct device_link *pd_dl_venus; + struct device *pmdomains[VIDC_PMDOMAINS_NUM_MAX]; ++ struct device_link *opp_dl_venus; ++ struct device *opp_pmdomain; + struct video_device *vdev_dec; + struct video_device *vdev_enc; + struct v4l2_device v4l2_dev; +diff --git a/drivers/media/platform/qcom/venus/pm_helpers.c b/drivers/media/platform/qcom/venus/pm_helpers.c +index 531e7a41658f..3127af8985cf 100644 +--- a/drivers/media/platform/qcom/venus/pm_helpers.c ++++ b/drivers/media/platform/qcom/venus/pm_helpers.c +@@ -9,6 +9,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -66,10 +67,9 @@ static void core_clks_disable(struct venus_core *core) + + static int core_clks_set_rate(struct venus_core *core, unsigned long freq) + { +- struct clk *clk = core->clks[0]; + int ret; + +- ret = clk_set_rate(clk, freq); ++ ret = dev_pm_opp_set_rate(core->dev, freq); + if (ret) + return ret; + +@@ -744,13 +744,16 @@ static int venc_power_v4(struct device *dev, int on) + + static int vcodec_domains_get(struct device *dev) + { ++ int ret; ++ struct opp_table *opp_table; ++ struct device **opp_virt_dev; + struct venus_core *core = dev_get_drvdata(dev); + const struct venus_resources *res = core->res; + struct device *pd; + unsigned int i; + + if (!res->vcodec_pmdomains_num) +- return -ENODEV; ++ goto skip_pmdomains; + + for (i = 0; i < res->vcodec_pmdomains_num; i++) { + pd = dev_pm_domain_attach_by_name(dev, +@@ -767,7 +770,41 @@ static int vcodec_domains_get(struct device *dev) + if (!core->pd_dl_venus) + return -ENODEV; + ++skip_pmdomains: ++ if (!core->has_opp_table) ++ return 0; ++ ++ /* Attach the power domain for setting performance state */ ++ opp_table = dev_pm_opp_attach_genpd(dev, res->opp_pmdomain, &opp_virt_dev); ++ if (IS_ERR(opp_table)) { ++ ret = PTR_ERR(opp_table); ++ goto opp_attach_err; ++ } ++ ++ core->opp_pmdomain = *opp_virt_dev; ++ core->opp_dl_venus = device_link_add(dev, core->opp_pmdomain, ++ DL_FLAG_RPM_ACTIVE | ++ DL_FLAG_PM_RUNTIME | ++ DL_FLAG_STATELESS); ++ if (!core->opp_dl_venus) { ++ ret = -ENODEV; ++ goto opp_dl_add_err; ++ } ++ + return 0; ++ ++opp_dl_add_err: ++ dev_pm_domain_detach(core->opp_pmdomain, true); ++opp_attach_err: ++ if (core->pd_dl_venus) { ++ device_link_del(core->pd_dl_venus); ++ for (i = 0; i < res->vcodec_pmdomains_num; i++) { ++ if (IS_ERR_OR_NULL(core->pmdomains[i])) ++ continue; ++ dev_pm_domain_detach(core->pmdomains[i], true); ++ } ++ } ++ return ret; + } + + static void vcodec_domains_put(struct device *dev) +@@ -777,7 +814,7 @@ static void vcodec_domains_put(struct device *dev) + unsigned int i; + + if (!res->vcodec_pmdomains_num) +- return; ++ goto skip_pmdomains; + + if (core->pd_dl_venus) + device_link_del(core->pd_dl_venus); +@@ -787,6 +824,15 @@ static void vcodec_domains_put(struct device *dev) + continue; + dev_pm_domain_detach(core->pmdomains[i], true); + } ++ ++skip_pmdomains: ++ if (!core->has_opp_table) ++ return; ++ ++ if (core->opp_dl_venus) ++ device_link_del(core->opp_dl_venus); ++ ++ dev_pm_domain_detach(core->opp_pmdomain, true); + } + + static int core_get_v4(struct device *dev) +@@ -815,19 +861,46 @@ static int core_get_v4(struct device *dev) + if (legacy_binding) + return 0; + ++ core->opp_table = dev_pm_opp_set_clkname(dev, "core"); ++ if (IS_ERR(core->opp_table)) ++ return PTR_ERR(core->opp_table); ++ ++ if (core->res->opp_pmdomain) { ++ ret = dev_pm_opp_of_add_table(dev); ++ if (!ret) { ++ core->has_opp_table = true; ++ } else if (ret != -ENODEV) { ++ dev_err(dev, "invalid OPP table in device tree\n"); ++ dev_pm_opp_put_clkname(core->opp_table); ++ return ret; ++ } ++ } ++ + ret = vcodec_domains_get(dev); +- if (ret) ++ if (ret) { ++ if (core->has_opp_table) ++ dev_pm_opp_of_remove_table(dev); ++ dev_pm_opp_put_clkname(core->opp_table); + return ret; ++ } + + return 0; + } + + static void core_put_v4(struct device *dev) + { ++ struct venus_core *core = dev_get_drvdata(dev); ++ + if (legacy_binding) + return; + + vcodec_domains_put(dev); ++ ++ if (core->has_opp_table) ++ dev_pm_opp_of_remove_table(dev); ++ if (core->opp_table) ++ dev_pm_opp_put_clkname(core->opp_table); ++ + } + + static int core_power_v4(struct device *dev, int on) +@@ -835,10 +908,15 @@ static int core_power_v4(struct device *dev, int on) + struct venus_core *core = dev_get_drvdata(dev); + int ret = 0; + +- if (on == POWER_ON) ++ if (on == POWER_ON) { + ret = core_clks_enable(core); +- else ++ } else { ++ /* Drop the performance state vote */ ++ if (core->opp_pmdomain) ++ dev_pm_opp_set_rate(dev, 0); ++ + core_clks_disable(core); ++ } + + return ret; + } + +From 3bf1ba10b6ac9cfff7ecd329c38dc31213e88ce1 Mon Sep 17 00:00:00 2001 +From: Ezequiel Garcia +Date: Mon, 27 Jul 2020 14:05:37 -0300 +Subject: [PATCH] hantro: h264: Get the correct fallback reference buffer + +If the bitstream and the application are incorrectly configuring +the reference pictures, the hardware will need to fallback +to using some other reference picture. + +When the post-processor is enabled, the fallback buffer +should be a shadow buffer (postproc.dec_q), and not a +CAPTURE queue buffer, since the latter is post-processed +and not really the output of the decoder core. + +Fixes: 8c2d66b036c77 ("media: hantro: Support color conversion via post-processing") +Signed-off-by: Ezequiel Garcia +--- + drivers/staging/media/hantro/hantro_h264.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/staging/media/hantro/hantro_h264.c b/drivers/staging/media/hantro/hantro_h264.c +index 194d05848077..6dcd47bd9ed3 100644 +--- a/drivers/staging/media/hantro/hantro_h264.c ++++ b/drivers/staging/media/hantro/hantro_h264.c +@@ -325,7 +325,7 @@ dma_addr_t hantro_h264_get_ref_buf(struct hantro_ctx *ctx, + */ + dst_buf = hantro_get_dst_buf(ctx); + buf = &dst_buf->vb2_buf; +- dma_addr = vb2_dma_contig_plane_dma_addr(buf, 0); ++ dma_addr = hantro_get_dec_buf_addr(ctx, buf); + } + + return dma_addr; + +From 28bebe4b9396ef9d2e4ae2a179abdb840ceddb03 Mon Sep 17 00:00:00 2001 +From: Ezequiel Garcia +Date: Mon, 27 Jul 2020 14:05:38 -0300 +Subject: [PATCH] hantro: postproc: Fix motion vector space allocation + +When the post-processor is enabled, the driver allocates +"shadow buffers" which are used for the decoder core, +and exposes the post-processed buffers to userspace. + +For this reason, extra motion vector space has to +be allocated on the shadow buffers, which the driver +wasn't doing. Fix it. + +This fix should address artifacts on high profile bitstreams. + +Fixes: 8c2d66b036c77 ("media: hantro: Support color conversion via post-processing") +Signed-off-by: Ezequiel Garcia +--- + drivers/staging/media/hantro/hantro_postproc.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/staging/media/hantro/hantro_postproc.c b/drivers/staging/media/hantro/hantro_postproc.c +index 44062ffceaea..6d2a8f2a8f0b 100644 +--- a/drivers/staging/media/hantro/hantro_postproc.c ++++ b/drivers/staging/media/hantro/hantro_postproc.c +@@ -118,7 +118,9 @@ int hantro_postproc_alloc(struct hantro_ctx *ctx) + unsigned int num_buffers = cap_queue->num_buffers; + unsigned int i, buf_size; + +- buf_size = ctx->dst_fmt.plane_fmt[0].sizeimage; ++ buf_size = ctx->dst_fmt.plane_fmt[0].sizeimage + ++ hantro_h264_mv_size(ctx->dst_fmt.width, ++ ctx->dst_fmt.height); + + for (i = 0; i < num_buffers; ++i) { + struct hantro_aux_buf *priv = &ctx->postproc.dec_q[i]; + +From be1ec3a445d13ab0bac45fd84edb30a11a2c0b8c Mon Sep 17 00:00:00 2001 +From: Jernej Skrabec +Date: Fri, 14 Aug 2020 10:36:16 -0300 +Subject: [PATCH] media: uapi: h264: Update reference lists + +When dealing with with interlaced frames, reference lists must tell if +each particular reference is meant for top or bottom field. This info +is currently not provided at all in the H264 related controls. + +Make reference lists hold a structure which will also hold an +enumerator type along index into DPB array. The enumerator must +be used to specify if reference is for top or bottom field. + +Currently the only user of these lists is Cedrus which is just compile +fixed here. Actual usage of will come in a following commit. + +Signed-off-by: Jernej Skrabec +Signed-off-by: Ezequiel Garcia +--- + .../media/v4l/ext-ctrls-codec.rst | 44 ++++++++++++++++++- + .../staging/media/sunxi/cedrus/cedrus_h264.c | 6 +-- + include/media/h264-ctrls.h | 23 +++++++--- + 3 files changed, 62 insertions(+), 11 deletions(-) + +diff --git a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst +index d0d506a444b1..b9b2617c3bda 100644 +--- a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst ++++ b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst +@@ -1843,10 +1843,10 @@ enum v4l2_mpeg_video_h264_hierarchical_coding_type - + * - __u32 + - ``slice_group_change_cycle`` + - +- * - __u8 ++ * - struct :c:type:`v4l2_h264_reference` + - ``ref_pic_list0[32]`` + - Reference picture list after applying the per-slice modifications +- * - __u8 ++ * - struct :c:type:`v4l2_h264_reference` + - ``ref_pic_list1[32]`` + - Reference picture list after applying the per-slice modifications + * - __u32 +@@ -1926,6 +1926,46 @@ enum v4l2_mpeg_video_h264_hierarchical_coding_type - + - ``chroma_offset[32][2]`` + - + ++``Picture Reference`` ++ ++.. c:type:: v4l2_h264_reference ++ ++.. cssclass:: longtable ++ ++.. flat-table:: struct v4l2_h264_reference ++ :header-rows: 0 ++ :stub-columns: 0 ++ :widths: 1 1 2 ++ ++ * - enum :c:type:`v4l2_h264_field_reference` ++ - ``reference`` ++ - Specifies how the picture is referenced. ++ * - __u8 ++ - ``index`` ++ - Index into the :c:type:`v4l2_ctrl_h264_decode_params`.dpb array. ++ ++.. c:type:: v4l2_h264_field_reference ++ ++.. cssclass:: longtable ++ ++.. flat-table:: ++ :header-rows: 0 ++ :stub-columns: 0 ++ :widths: 1 1 2 ++ ++ * - ``V4L2_H264_TOP_FIELD_REF`` ++ - 0x1 ++ - The top field in field pair is used for ++ short-term reference. ++ * - ``V4L2_H264_BOTTOM_FIELD_REF`` ++ - 0x2 ++ - The bottom field in field pair is used for ++ short-term reference. ++ * - ``V4L2_H264_FRAME_REF`` ++ - 0x3 ++ - The frame (or the top/bottom fields, if it's a field pair) ++ is used for short-term reference. ++ + ``V4L2_CID_MPEG_VIDEO_H264_DECODE_PARAMS (struct)`` + Specifies the decode parameters (as extracted from the bitstream) + for the associated H264 slice data. This includes the necessary +diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_h264.c b/drivers/staging/media/sunxi/cedrus/cedrus_h264.c +index 54ee2aa423e2..cce527bbdf86 100644 +--- a/drivers/staging/media/sunxi/cedrus/cedrus_h264.c ++++ b/drivers/staging/media/sunxi/cedrus/cedrus_h264.c +@@ -166,8 +166,8 @@ static void cedrus_write_frame_list(struct cedrus_ctx *ctx, + + static void _cedrus_write_ref_list(struct cedrus_ctx *ctx, + struct cedrus_run *run, +- const u8 *ref_list, u8 num_ref, +- enum cedrus_h264_sram_off sram) ++ const struct v4l2_h264_reference *ref_list, ++ u8 num_ref, enum cedrus_h264_sram_off sram) + { + const struct v4l2_ctrl_h264_decode_params *decode = run->h264.decode_params; + struct vb2_queue *cap_q; +@@ -188,7 +188,7 @@ static void _cedrus_write_ref_list(struct cedrus_ctx *ctx, + int buf_idx; + u8 dpb_idx; + +- dpb_idx = ref_list[i]; ++ dpb_idx = ref_list[i].index; + dpb = &decode->dpb[dpb_idx]; + + if (!(dpb->flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE)) +diff --git a/include/media/h264-ctrls.h b/include/media/h264-ctrls.h +index 080fd1293c42..5f635e8d25e2 100644 +--- a/include/media/h264-ctrls.h ++++ b/include/media/h264-ctrls.h +@@ -19,6 +19,8 @@ + */ + #define V4L2_H264_NUM_DPB_ENTRIES 16 + ++#define V4L2_H264_REF_LIST_LEN (2 * V4L2_H264_NUM_DPB_ENTRIES) ++ + /* Our pixel format isn't stable at the moment */ + #define V4L2_PIX_FMT_H264_SLICE v4l2_fourcc('S', '2', '6', '4') /* H264 parsed slices */ + +@@ -140,6 +142,19 @@ struct v4l2_h264_pred_weight_table { + #define V4L2_H264_SLICE_FLAG_DIRECT_SPATIAL_MV_PRED 0x04 + #define V4L2_H264_SLICE_FLAG_SP_FOR_SWITCH 0x08 + ++enum v4l2_h264_field_reference { ++ V4L2_H264_TOP_FIELD_REF = 0x1, ++ V4L2_H264_BOTTOM_FIELD_REF = 0x2, ++ V4L2_H264_FRAME_REF = 0x3, ++}; ++ ++struct v4l2_h264_reference { ++ enum v4l2_h264_field_reference fields; ++ ++ /* Index into v4l2_ctrl_h264_decode_params.dpb[] */ ++ __u8 index; ++}; ++ + struct v4l2_ctrl_h264_slice_params { + /* Size in bytes, including header */ + __u32 size; +@@ -178,12 +193,8 @@ struct v4l2_ctrl_h264_slice_params { + __u8 num_ref_idx_l1_active_minus1; + __u32 slice_group_change_cycle; + +- /* +- * Entries on each list are indices into +- * v4l2_ctrl_h264_decode_params.dpb[]. +- */ +- __u8 ref_pic_list0[32]; +- __u8 ref_pic_list1[32]; ++ struct v4l2_h264_reference ref_pic_list0[V4L2_H264_REF_LIST_LEN]; ++ struct v4l2_h264_reference ref_pic_list1[V4L2_H264_REF_LIST_LEN]; + + __u32 flags; + }; + +From 9e30508e5834c1a37aa07836bf7fc78f96559f82 Mon Sep 17 00:00:00 2001 +From: Ezequiel Garcia +Date: Fri, 14 Aug 2020 10:36:17 -0300 +Subject: [PATCH] media: uapi: h264: Further clarify scaling lists order + +Commit 0b0393d59eb4a ("media: uapi: h264: clarify +expected scaling_list_4x4/8x8 order") improved the +documentation on H264 scaling lists order. + +This commit improves the documentation by clarifying +that the lists themselves are expected in raster scan order. + +Signed-off-by: Ezequiel Garcia +--- + Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst +index b9b2617c3bda..694037ce888a 100644 +--- a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst ++++ b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst +@@ -1725,12 +1725,14 @@ enum v4l2_mpeg_video_h264_hierarchical_coding_type - + - ``scaling_list_4x4[6][16]`` + - Scaling matrix after applying the inverse scanning process. + Expected list order is Intra Y, Intra Cb, Intra Cr, Inter Y, +- Inter Cb, Inter Cr. ++ Inter Cb, Inter Cr. The values on each scaling list are ++ expected in raster scan order. + * - __u8 + - ``scaling_list_8x8[6][64]`` + - Scaling matrix after applying the inverse scanning process. + Expected list order is Intra Y, Inter Y, Intra Cb, Inter Cb, +- Intra Cr, Inter Cr. ++ Intra Cr, Inter Cr. The values on each scaling list are ++ expected in raster scan order. + + ``V4L2_CID_MPEG_VIDEO_H264_SLICE_PARAMS (struct)`` + Specifies the slice parameters (as extracted from the bitstream) + +From da0e200cf7bd3c42b97c8fa8e941a756ffdbfb26 Mon Sep 17 00:00:00 2001 +From: Ezequiel Garcia +Date: Fri, 14 Aug 2020 10:36:18 -0300 +Subject: [PATCH] media: uapi: h264: Split prediction weight parameters + +The prediction weight parameters are only required under +certain conditions, which depend on slice header parameters. + +As specified in section 7.3.3 Slice header syntax, the prediction +weight table is present if: + +((weighted_pred_flag && (slice_type == P || slice_type == SP)) || \ +(weighted_bipred_idc == 1 && slice_type == B)) + +Given its size, it makes sense to move this table to its control, +so applications can avoid passing it if the slice doesn't specify it. + +Before this change struct v4l2_ctrl_h264_slice_params was 960 bytes. +With this change, it's 188 bytes and struct v4l2_ctrl_h264_pred_weight +is 772 bytes. + +Signed-off-by: Ezequiel Garcia +--- + .../media/v4l/ext-ctrls-codec.rst | 19 ++++++++++++------- + drivers/media/v4l2-core/v4l2-ctrls.c | 8 ++++++++ + drivers/staging/media/sunxi/cedrus/cedrus.c | 7 +++++++ + drivers/staging/media/sunxi/cedrus/cedrus.h | 1 + + .../staging/media/sunxi/cedrus/cedrus_dec.c | 2 ++ + .../staging/media/sunxi/cedrus/cedrus_h264.c | 12 +++--------- + include/media/h264-ctrls.h | 12 ++++++++++-- + include/media/v4l2-ctrls.h | 2 ++ + 8 files changed, 45 insertions(+), 18 deletions(-) + +diff --git a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst +index 694037ce888a..ddf9c6af7d0a 100644 +--- a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst ++++ b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst +@@ -1879,18 +1879,23 @@ enum v4l2_mpeg_video_h264_hierarchical_coding_type - + - 0x00000008 + - + +-``Prediction Weight Table`` ++``V4L2_CID_MPEG_VIDEO_H264_PRED_WEIGHTS (struct)`` ++ Prediction weight table defined according to :ref:`h264`, ++ section 7.4.3.2 "Prediction Weight Table Semantics". ++ The prediction weight table must be passed by applications ++ under the conditions explained in section 7.3.3 "Slice header ++ syntax". + +- The bitstream parameters are defined according to :ref:`h264`, +- section 7.4.3.2 "Prediction Weight Table Semantics". For further +- documentation, refer to the above specification, unless there is +- an explicit comment stating otherwise. ++ .. note:: ++ ++ This compound control is not yet part of the public kernel API and ++ it is expected to change. + +-.. c:type:: v4l2_h264_pred_weight_table ++.. c:type:: v4l2_ctrl_h264_pred_weights + + .. cssclass:: longtable + +-.. flat-table:: struct v4l2_h264_pred_weight_table ++.. flat-table:: struct v4l2_ctrl_h264_pred_weights + :header-rows: 0 + :stub-columns: 0 + :widths: 1 1 2 +diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c +index 3f3fbcd60cc6..76c8dc8fb31c 100644 +--- a/drivers/media/v4l2-core/v4l2-ctrls.c ++++ b/drivers/media/v4l2-core/v4l2-ctrls.c +@@ -897,6 +897,7 @@ const char *v4l2_ctrl_get_name(u32 id) + case V4L2_CID_MPEG_VIDEO_H264_DECODE_PARAMS: return "H264 Decode Parameters"; + case V4L2_CID_MPEG_VIDEO_H264_DECODE_MODE: return "H264 Decode Mode"; + case V4L2_CID_MPEG_VIDEO_H264_START_CODE: return "H264 Start Code"; ++ case V4L2_CID_MPEG_VIDEO_H264_PRED_WEIGHTS: return "H264 Prediction Weight Table"; + case V4L2_CID_MPEG_VIDEO_MPEG2_LEVEL: return "MPEG2 Level"; + case V4L2_CID_MPEG_VIDEO_MPEG2_PROFILE: return "MPEG2 Profile"; + case V4L2_CID_MPEG_VIDEO_MPEG4_I_FRAME_QP: return "MPEG4 I-Frame QP Value"; +@@ -1412,6 +1413,9 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type, + case V4L2_CID_MPEG_VIDEO_H264_DECODE_PARAMS: + *type = V4L2_CTRL_TYPE_H264_DECODE_PARAMS; + break; ++ case V4L2_CID_MPEG_VIDEO_H264_PRED_WEIGHTS: ++ *type = V4L2_CTRL_TYPE_H264_PRED_WEIGHTS; ++ break; + case V4L2_CID_MPEG_VIDEO_VP8_FRAME_HEADER: + *type = V4L2_CTRL_TYPE_VP8_FRAME_HEADER; + break; +@@ -1790,6 +1794,7 @@ static int std_validate_compound(const struct v4l2_ctrl *ctrl, u32 idx, + case V4L2_CTRL_TYPE_H264_SPS: + case V4L2_CTRL_TYPE_H264_PPS: + case V4L2_CTRL_TYPE_H264_SCALING_MATRIX: ++ case V4L2_CTRL_TYPE_H264_PRED_WEIGHTS: + case V4L2_CTRL_TYPE_H264_SLICE_PARAMS: + case V4L2_CTRL_TYPE_H264_DECODE_PARAMS: + break; +@@ -2553,6 +2558,9 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl, + case V4L2_CTRL_TYPE_H264_DECODE_PARAMS: + elem_size = sizeof(struct v4l2_ctrl_h264_decode_params); + break; ++ case V4L2_CTRL_TYPE_H264_PRED_WEIGHTS: ++ elem_size = sizeof(struct v4l2_ctrl_h264_pred_weights); ++ break; + case V4L2_CTRL_TYPE_VP8_FRAME_HEADER: + elem_size = sizeof(struct v4l2_ctrl_vp8_frame_header); + break; +diff --git a/drivers/staging/media/sunxi/cedrus/cedrus.c b/drivers/staging/media/sunxi/cedrus/cedrus.c +index bc27f9430eeb..826324faad7e 100644 +--- a/drivers/staging/media/sunxi/cedrus/cedrus.c ++++ b/drivers/staging/media/sunxi/cedrus/cedrus.c +@@ -78,6 +78,13 @@ static const struct cedrus_control cedrus_controls[] = { + .codec = CEDRUS_CODEC_H264, + .required = true, + }, ++ { ++ .cfg = { ++ .id = V4L2_CID_MPEG_VIDEO_H264_PRED_WEIGHTS, ++ }, ++ .codec = CEDRUS_CODEC_H264, ++ .required = false, ++ }, + { + .cfg = { + .id = V4L2_CID_MPEG_VIDEO_H264_DECODE_MODE, +diff --git a/drivers/staging/media/sunxi/cedrus/cedrus.h b/drivers/staging/media/sunxi/cedrus/cedrus.h +index 96765555ab8a..93c843ae14bb 100644 +--- a/drivers/staging/media/sunxi/cedrus/cedrus.h ++++ b/drivers/staging/media/sunxi/cedrus/cedrus.h +@@ -62,6 +62,7 @@ struct cedrus_h264_run { + const struct v4l2_ctrl_h264_scaling_matrix *scaling_matrix; + const struct v4l2_ctrl_h264_slice_params *slice_params; + const struct v4l2_ctrl_h264_sps *sps; ++ const struct v4l2_ctrl_h264_pred_weights *pred_weights; + }; + + struct cedrus_mpeg2_run { +diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_dec.c b/drivers/staging/media/sunxi/cedrus/cedrus_dec.c +index 58c48e4fdfe9..6385026d1b6b 100644 +--- a/drivers/staging/media/sunxi/cedrus/cedrus_dec.c ++++ b/drivers/staging/media/sunxi/cedrus/cedrus_dec.c +@@ -57,6 +57,8 @@ void cedrus_device_run(void *priv) + V4L2_CID_MPEG_VIDEO_H264_SLICE_PARAMS); + run.h264.sps = cedrus_find_control_data(ctx, + V4L2_CID_MPEG_VIDEO_H264_SPS); ++ run.h264.pred_weights = cedrus_find_control_data(ctx, ++ V4L2_CID_MPEG_VIDEO_H264_PRED_WEIGHTS); + break; + + case V4L2_PIX_FMT_HEVC_SLICE: +diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_h264.c b/drivers/staging/media/sunxi/cedrus/cedrus_h264.c +index cce527bbdf86..d5636dbbb622 100644 +--- a/drivers/staging/media/sunxi/cedrus/cedrus_h264.c ++++ b/drivers/staging/media/sunxi/cedrus/cedrus_h264.c +@@ -256,10 +256,8 @@ static void cedrus_write_scaling_lists(struct cedrus_ctx *ctx, + static void cedrus_write_pred_weight_table(struct cedrus_ctx *ctx, + struct cedrus_run *run) + { +- const struct v4l2_ctrl_h264_slice_params *slice = +- run->h264.slice_params; +- const struct v4l2_h264_pred_weight_table *pred_weight = +- &slice->pred_weight_table; ++ const struct v4l2_ctrl_h264_pred_weights *pred_weight = ++ run->h264.pred_weights; + struct cedrus_dev *dev = ctx->dev; + int i, j, k; + +@@ -367,11 +365,7 @@ static void cedrus_set_params(struct cedrus_ctx *ctx, + + cedrus_skip_bits(dev, slice->header_bit_size); + +- if (((pps->flags & V4L2_H264_PPS_FLAG_WEIGHTED_PRED) && +- (slice->slice_type == V4L2_H264_SLICE_TYPE_P || +- slice->slice_type == V4L2_H264_SLICE_TYPE_SP)) || +- (pps->weighted_bipred_idc == 1 && +- slice->slice_type == V4L2_H264_SLICE_TYPE_B)) ++ if (V4L2_H264_CTRL_PRED_WEIGHTS_REQUIRED(pps, slice)) + cedrus_write_pred_weight_table(ctx, run); + + if ((slice->slice_type == V4L2_H264_SLICE_TYPE_P) || +diff --git a/include/media/h264-ctrls.h b/include/media/h264-ctrls.h +index 5f635e8d25e2..d995614be159 100644 +--- a/include/media/h264-ctrls.h ++++ b/include/media/h264-ctrls.h +@@ -36,6 +36,7 @@ + #define V4L2_CID_MPEG_VIDEO_H264_DECODE_PARAMS (V4L2_CID_MPEG_BASE+1004) + #define V4L2_CID_MPEG_VIDEO_H264_DECODE_MODE (V4L2_CID_MPEG_BASE+1005) + #define V4L2_CID_MPEG_VIDEO_H264_START_CODE (V4L2_CID_MPEG_BASE+1006) ++#define V4L2_CID_MPEG_VIDEO_H264_PRED_WEIGHTS (V4L2_CID_MPEG_BASE+1007) + + /* enum v4l2_ctrl_type type values */ + #define V4L2_CTRL_TYPE_H264_SPS 0x0110 +@@ -43,6 +44,7 @@ + #define V4L2_CTRL_TYPE_H264_SCALING_MATRIX 0x0112 + #define V4L2_CTRL_TYPE_H264_SLICE_PARAMS 0x0113 + #define V4L2_CTRL_TYPE_H264_DECODE_PARAMS 0x0114 ++#define V4L2_CTRL_TYPE_H264_PRED_WEIGHTS 0x0115 + + enum v4l2_mpeg_video_h264_decode_mode { + V4L2_MPEG_VIDEO_H264_DECODE_MODE_SLICE_BASED, +@@ -125,7 +127,14 @@ struct v4l2_h264_weight_factors { + __s16 chroma_offset[32][2]; + }; + +-struct v4l2_h264_pred_weight_table { ++#define V4L2_H264_CTRL_PRED_WEIGHTS_REQUIRED(pps, slice) \ ++ ((((pps)->flags & V4L2_H264_PPS_FLAG_WEIGHTED_PRED) && \ ++ ((slice)->slice_type == V4L2_H264_SLICE_TYPE_P || \ ++ (slice)->slice_type == V4L2_H264_SLICE_TYPE_SP)) || \ ++ ((pps)->weighted_bipred_idc == 1 && \ ++ (slice)->slice_type == V4L2_H264_SLICE_TYPE_B)) ++ ++struct v4l2_ctrl_h264_pred_weights { + __u16 luma_log2_weight_denom; + __u16 chroma_log2_weight_denom; + struct v4l2_h264_weight_factors weight_factors[2]; +@@ -177,7 +186,6 @@ struct v4l2_ctrl_h264_slice_params { + __s32 delta_pic_order_cnt0; + __s32 delta_pic_order_cnt1; + +- struct v4l2_h264_pred_weight_table pred_weight_table; + /* Size in bits of dec_ref_pic_marking() syntax element. */ + __u32 dec_ref_pic_marking_bit_size; + /* Size in bits of pic order count syntax. */ +diff --git a/include/media/v4l2-ctrls.h b/include/media/v4l2-ctrls.h +index f40e2cbb21d3..cb25f345e9ad 100644 +--- a/include/media/v4l2-ctrls.h ++++ b/include/media/v4l2-ctrls.h +@@ -51,6 +51,7 @@ struct video_device; + * @p_h264_scaling_matrix: Pointer to a struct v4l2_ctrl_h264_scaling_matrix. + * @p_h264_slice_params: Pointer to a struct v4l2_ctrl_h264_slice_params. + * @p_h264_decode_params: Pointer to a struct v4l2_ctrl_h264_decode_params. ++ * @p_h264_pred_weights: Pointer to a struct v4l2_ctrl_h264_pred_weights. + * @p_vp8_frame_header: Pointer to a VP8 frame header structure. + * @p_hevc_sps: Pointer to an HEVC sequence parameter set structure. + * @p_hevc_pps: Pointer to an HEVC picture parameter set structure. +@@ -74,6 +75,7 @@ union v4l2_ctrl_ptr { + struct v4l2_ctrl_h264_scaling_matrix *p_h264_scaling_matrix; + struct v4l2_ctrl_h264_slice_params *p_h264_slice_params; + struct v4l2_ctrl_h264_decode_params *p_h264_decode_params; ++ struct v4l2_ctrl_h264_pred_weights *p_h264_pred_weights; + struct v4l2_ctrl_vp8_frame_header *p_vp8_frame_header; + struct v4l2_ctrl_hevc_sps *p_hevc_sps; + struct v4l2_ctrl_hevc_pps *p_hevc_pps; + +From 82c12e79f57d0b51b81efb2bb87a91288988d958 Mon Sep 17 00:00:00 2001 +From: Philipp Zabel +Date: Fri, 14 Aug 2020 10:36:19 -0300 +Subject: [PATCH] media: uapi: h264: Clarify pic_order_cnt_bit_size field + +Since pic_order_cnt_bit_size is not a syntax element itself, explicitly +state that it is the total size in bits of the pic_order_cnt_lsb, +delta_pic_order_cnt_bottom, delta_pic_order_cnt[0], and +delta_pic_order_cnt[1] syntax elements contained in the slice. + +Signed-off-by: Philipp Zabel +[Ezequiel: rebase] +Signed-off-by: Ezequiel Garcia +Reviewed-by: Nicolas Dufresne +--- + Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst +index ddf9c6af7d0a..32f3cebf16e5 100644 +--- a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst ++++ b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst +@@ -1815,7 +1815,9 @@ enum v4l2_mpeg_video_h264_hierarchical_coding_type - + - Size in bits of the dec_ref_pic_marking() syntax element. + * - __u32 + - ``pic_order_cnt_bit_size`` +- - ++ - Combined size in bits of the picture order count related syntax ++ elements: pic_order_cnt_lsb, delta_pic_order_cnt_bottom, ++ delta_pic_order_cnt0, and delta_pic_order_cnt1. + * - __u8 + - ``cabac_init_idc`` + - + +From fced897398d6228473f01df99fd09fd4410f623d Mon Sep 17 00:00:00 2001 +From: Ezequiel Garcia +Date: Fri, 14 Aug 2020 10:36:20 -0300 +Subject: [PATCH] media: uapi: h264: Increase size of 'first_mb_in_slice' field + +Slice header syntax element 'first_mb_in_slice' can point +to the last macroblock, currently the field can only reference +65536 macroblocks which is insufficient for 8K videos. + +Although unlikely, a 8192x4320 video (where macroblocks are 16x16), +would contain 138240 macroblocks on a frame. + +As per the H264 specification, 'first_mb_in_slice' can be up to +PicSizeInMbs - 1, so increase the size of the field to 32-bits. + +Note that v4l2_ctrl_h264_slice_params struct will be modified +in a follow-up commit, and so we defer its 64-bit padding. + +Signed-off-by: Ezequiel Garcia +--- + Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst | 2 +- + include/media/h264-ctrls.h | 3 ++- + 2 files changed, 3 insertions(+), 2 deletions(-) + +diff --git a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst +index 32f3cebf16e5..714a8d9ae6a0 100644 +--- a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst ++++ b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst +@@ -1774,7 +1774,7 @@ enum v4l2_mpeg_video_h264_hierarchical_coding_type - + * - __u32 + - ``header_bit_size`` + - +- * - __u16 ++ * - __u32 + - ``first_mb_in_slice`` + - + * - __u8 +diff --git a/include/media/h264-ctrls.h b/include/media/h264-ctrls.h +index d995614be159..9ff085fdc9ab 100644 +--- a/include/media/h264-ctrls.h ++++ b/include/media/h264-ctrls.h +@@ -174,7 +174,8 @@ struct v4l2_ctrl_h264_slice_params { + /* Offset in bits to slice_data() from the beginning of this slice. */ + __u32 header_bit_size; + +- __u16 first_mb_in_slice; ++ __u32 first_mb_in_slice; ++ + __u8 slice_type; + __u8 pic_parameter_set_id; + __u8 colour_plane_id; + +From 52266e3675e9359f13aa4d44a4ab392fd1f079c0 Mon Sep 17 00:00:00 2001 +From: Ezequiel Garcia +Date: Fri, 14 Aug 2020 10:36:21 -0300 +Subject: [PATCH] media: uapi: h264: Clean DPB entry interface + +As discussed recently, the current interface for the +Decoded Picture Buffer is not enough to properly +support field coding. + +This commit introduces enough semantics to support +frame and field coding, and to signal how DPB entries +are "used for reference". + +Signed-off-by: Ezequiel Garcia +--- + .../media/v4l/ext-ctrls-codec.rst | 24 ++++++------------- + drivers/media/v4l2-core/v4l2-h264.c | 4 ++-- + drivers/staging/media/rkvdec/rkvdec-h264.c | 17 ++++++------- + include/media/h264-ctrls.h | 2 +- + 4 files changed, 19 insertions(+), 28 deletions(-) + +diff --git a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst +index 714a8d9ae6a0..d14da8325382 100644 +--- a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst ++++ b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst +@@ -2063,6 +2063,9 @@ enum v4l2_mpeg_video_h264_hierarchical_coding_type - + * - __s32 + - ``bottom_field_order_cnt`` + - ++ * - enum :c:type:`v4l2_h264_field_reference` ++ - ``reference`` ++ - Specifies how the DPB entry is referenced. + * - __u32 + - ``flags`` + - See :ref:`DPB Entry Flags ` +@@ -2080,29 +2083,16 @@ enum v4l2_mpeg_video_h264_hierarchical_coding_type - + + * - ``V4L2_H264_DPB_ENTRY_FLAG_VALID`` + - 0x00000001 +- - The DPB entry is valid and should be considered ++ - The DPB entry is valid (non-empty) and should be considered. + * - ``V4L2_H264_DPB_ENTRY_FLAG_ACTIVE`` + - 0x00000002 +- - The DPB entry is currently being used as a reference frame ++ - The DPB entry is used for reference. + * - ``V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM`` + - 0x00000004 +- - The DPB entry is a long term reference frame ++ - The DPB entry is used for long-term reference. + * - ``V4L2_H264_DPB_ENTRY_FLAG_FIELD`` + - 0x00000008 +- - The DPB entry is a field reference, which means only one of the field +- will be used when decoding the new frame/field. When not set the DPB +- entry is a frame reference (both fields will be used). Note that this +- flag does not say anything about the number of fields contained in the +- reference frame, it just describes the one used to decode the new +- field/frame +- * - ``V4L2_H264_DPB_ENTRY_FLAG_BOTTOM_FIELD`` +- - 0x00000010 +- - The DPB entry is a bottom field reference (only the bottom field of the +- reference frame is needed to decode the new frame/field). Only valid if +- V4L2_H264_DPB_ENTRY_FLAG_FIELD is set. When +- V4L2_H264_DPB_ENTRY_FLAG_FIELD is set but +- V4L2_H264_DPB_ENTRY_FLAG_BOTTOM_FIELD is not, that means the +- DPB entry is a top field reference ++ - The DPB entry is a single field or a complementary field pair. + + ``V4L2_CID_MPEG_VIDEO_H264_DECODE_MODE (enum)`` + Specifies the decoding mode to use. Currently exposes slice-based and +diff --git a/drivers/media/v4l2-core/v4l2-h264.c b/drivers/media/v4l2-core/v4l2-h264.c +index edf6225f0522..12b751c09016 100644 +--- a/drivers/media/v4l2-core/v4l2-h264.c ++++ b/drivers/media/v4l2-core/v4l2-h264.c +@@ -66,10 +66,10 @@ v4l2_h264_init_reflist_builder(struct v4l2_h264_reflist_builder *b, + else + b->refs[i].frame_num = dpb[i].frame_num; + +- if (!(dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_FIELD)) ++ if (dpb[i].reference == V4L2_H264_FRAME_REF) + pic_order_count = min(dpb[i].top_field_order_cnt, + dpb[i].bottom_field_order_cnt); +- else if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_BOTTOM_FIELD) ++ else if (dpb[i].reference & V4L2_H264_BOTTOM_FIELD_REF) + pic_order_count = dpb[i].bottom_field_order_cnt; + else + pic_order_count = dpb[i].top_field_order_cnt; +diff --git a/drivers/staging/media/rkvdec/rkvdec-h264.c b/drivers/staging/media/rkvdec/rkvdec-h264.c +index 7b66e2743a4f..07a80e9a9df2 100644 +--- a/drivers/staging/media/rkvdec/rkvdec-h264.c ++++ b/drivers/staging/media/rkvdec/rkvdec-h264.c +@@ -949,16 +949,17 @@ static void config_registers(struct rkvdec_ctx *ctx, + for (i = 0; i < ARRAY_SIZE(dec_params->dpb); i++) { + struct vb2_buffer *vb_buf = get_ref_buf(ctx, run, i); + +- refer_addr = vb2_dma_contig_plane_dma_addr(vb_buf, 0) | +- RKVDEC_COLMV_USED_FLAG_REF; ++ refer_addr = vb2_dma_contig_plane_dma_addr(vb_buf, 0); + +- if (!(dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_FIELD)) +- refer_addr |= RKVDEC_TOPFIELD_USED_REF | +- RKVDEC_BOTFIELD_USED_REF; +- else if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_BOTTOM_FIELD) +- refer_addr |= RKVDEC_BOTFIELD_USED_REF; +- else ++ if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE) ++ refer_addr |= RKVDEC_COLMV_USED_FLAG_REF; ++ if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_FIELD) ++ refer_addr |= RKVDEC_FIELD_REF; ++ ++ if (dpb[i].reference & V4L2_H264_TOP_FIELD_REF) + refer_addr |= RKVDEC_TOPFIELD_USED_REF; ++ if (dpb[i].reference & V4L2_H264_BOTTOM_FIELD_REF) ++ refer_addr |= RKVDEC_BOTFIELD_USED_REF; + + writel_relaxed(dpb[i].top_field_order_cnt, + rkvdec->regs + poc_reg_tbl_top_field[i]); +diff --git a/include/media/h264-ctrls.h b/include/media/h264-ctrls.h +index 9ff085fdc9ab..4447697e9465 100644 +--- a/include/media/h264-ctrls.h ++++ b/include/media/h264-ctrls.h +@@ -212,7 +212,6 @@ struct v4l2_ctrl_h264_slice_params { + #define V4L2_H264_DPB_ENTRY_FLAG_ACTIVE 0x02 + #define V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM 0x04 + #define V4L2_H264_DPB_ENTRY_FLAG_FIELD 0x08 +-#define V4L2_H264_DPB_ENTRY_FLAG_BOTTOM_FIELD 0x10 + + struct v4l2_h264_dpb_entry { + __u64 reference_ts; +@@ -221,6 +220,7 @@ struct v4l2_h264_dpb_entry { + /* Note that field is indicated by v4l2_buffer.field */ + __s32 top_field_order_cnt; + __s32 bottom_field_order_cnt; ++ enum v4l2_h264_field_reference reference; + __u32 flags; /* V4L2_H264_DPB_ENTRY_FLAG_* */ + }; + + +From cd2980d0ab75400656f854ac48a147ef07b9f9ba Mon Sep 17 00:00:00 2001 +From: Ezequiel Garcia +Date: Fri, 14 Aug 2020 10:36:22 -0300 +Subject: [PATCH] media: uapi: h264: Increase size of DPB entry pic_num + +DPB entry PicNum maximum value is 2*MaxFrameNum for interlaced +content (field_pic_flag=1). + +As specified, MaxFrameNum is 2^(log2_max_frame_num_minus4 + 4) +and log2_max_frame_num_minus4 is in the range of 0 to 12, +which means pic_num should be a 32-bit field. + +The v4l2_h264_dpb_entry struct needs to be padded to avoid a hole, +which might be also useful to allow future uAPI extensions. + +Signed-off-by: Ezequiel Garcia +--- + .../userspace-api/media/v4l/ext-ctrls-codec.rst | 5 ++++- + drivers/media/v4l2-core/v4l2-ctrls.c | 13 +++++++++++++ + include/media/h264-ctrls.h | 3 ++- + include/media/v4l2-h264.h | 2 +- + 4 files changed, 20 insertions(+), 3 deletions(-) + +diff --git a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst +index d14da8325382..c0ae7fda803e 100644 +--- a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst ++++ b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst +@@ -2054,7 +2054,10 @@ enum v4l2_mpeg_video_h264_hierarchical_coding_type - + * - __u16 + - ``frame_num`` + - +- * - __u16 ++ * - __u8 ++ - ``reserved[2]`` ++ - Applications and drivers must set this to zero. ++ * - __u32 + - ``pic_num`` + - + * - __s32 +diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c +index 76c8dc8fb31c..b9457789fa55 100644 +--- a/drivers/media/v4l2-core/v4l2-ctrls.c ++++ b/drivers/media/v4l2-core/v4l2-ctrls.c +@@ -1725,6 +1725,8 @@ static void std_log(const struct v4l2_ctrl *ctrl) + + #define zero_padding(s) \ + memset(&(s).padding, 0, sizeof((s).padding)) ++#define zero_reserved(s) \ ++ memset(&(s).reserved, 0, sizeof((s).reserved)) + + /* + * Compound controls validation requires setting unused fields/flags to zero +@@ -1735,6 +1737,7 @@ static int std_validate_compound(const struct v4l2_ctrl *ctrl, u32 idx, + { + struct v4l2_ctrl_mpeg2_slice_params *p_mpeg2_slice_params; + struct v4l2_ctrl_vp8_frame_header *p_vp8_frame_header; ++ struct v4l2_ctrl_h264_decode_params *p_h264_dec_params; + struct v4l2_ctrl_hevc_sps *p_hevc_sps; + struct v4l2_ctrl_hevc_pps *p_hevc_pps; + struct v4l2_ctrl_hevc_slice_params *p_hevc_slice_params; +@@ -1796,7 +1799,17 @@ static int std_validate_compound(const struct v4l2_ctrl *ctrl, u32 idx, + case V4L2_CTRL_TYPE_H264_SCALING_MATRIX: + case V4L2_CTRL_TYPE_H264_PRED_WEIGHTS: + case V4L2_CTRL_TYPE_H264_SLICE_PARAMS: ++ break; ++ + case V4L2_CTRL_TYPE_H264_DECODE_PARAMS: ++ p_h264_dec_params = p; ++ ++ for (i = 0; i < V4L2_H264_NUM_DPB_ENTRIES; i++) { ++ struct v4l2_h264_dpb_entry *dpb_entry = ++ &p_h264_dec_params->dpb[i]; ++ ++ zero_reserved(*dpb_entry); ++ } + break; + + case V4L2_CTRL_TYPE_VP8_FRAME_HEADER: +diff --git a/include/media/h264-ctrls.h b/include/media/h264-ctrls.h +index 4447697e9465..d178d7ad53b6 100644 +--- a/include/media/h264-ctrls.h ++++ b/include/media/h264-ctrls.h +@@ -216,7 +216,8 @@ struct v4l2_ctrl_h264_slice_params { + struct v4l2_h264_dpb_entry { + __u64 reference_ts; + __u16 frame_num; +- __u16 pic_num; ++ __u8 reserved[2]; ++ __u32 pic_num; + /* Note that field is indicated by v4l2_buffer.field */ + __s32 top_field_order_cnt; + __s32 bottom_field_order_cnt; +diff --git a/include/media/v4l2-h264.h b/include/media/v4l2-h264.h +index bc9ebb560ccf..1a5f26fc2a9a 100644 +--- a/include/media/v4l2-h264.h ++++ b/include/media/v4l2-h264.h +@@ -33,7 +33,7 @@ struct v4l2_h264_reflist_builder { + struct { + s32 pic_order_count; + int frame_num; +- u16 pic_num; ++ u32 pic_num; + u16 longterm : 1; + } refs[V4L2_H264_NUM_DPB_ENTRIES]; + s32 cur_pic_order_count; + +From c380a6c41ab18183ff5d6342d8dc6cf7f22e6ed5 Mon Sep 17 00:00:00 2001 +From: Ezequiel Garcia +Date: Fri, 14 Aug 2020 10:36:23 -0300 +Subject: [PATCH] media: uapi: h264: Drop SLICE_PARAMS 'size' field + +The SLICE_PARAMS control is intended for slice-based +devices. In this mode, the OUTPUT buffer contains +a single slice, and so the buffer's plane payload size +can be used to query the slice size. + +To reduce the API surface drop the size from the +SLICE_PARAMS control. + +A follow-up change will remove other members in SLICE_PARAMS +so we don't need to add padding fields here. + +Signed-off-by: Ezequiel Garcia +--- + Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst | 3 --- + drivers/staging/media/sunxi/cedrus/cedrus_h264.c | 7 +++---- + include/media/h264-ctrls.h | 3 --- + 3 files changed, 3 insertions(+), 10 deletions(-) + +diff --git a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst +index c0ae7fda803e..e88c207d945b 100644 +--- a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst ++++ b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst +@@ -1760,9 +1760,6 @@ enum v4l2_mpeg_video_h264_hierarchical_coding_type - + :stub-columns: 0 + :widths: 1 1 2 + +- * - __u32 +- - ``size`` +- - + * - __u32 + - ``start_byte_offset`` + Offset (in bytes) from the beginning of the OUTPUT buffer to the start +diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_h264.c b/drivers/staging/media/sunxi/cedrus/cedrus_h264.c +index d5636dbbb622..7d9bd5860a1b 100644 +--- a/drivers/staging/media/sunxi/cedrus/cedrus_h264.c ++++ b/drivers/staging/media/sunxi/cedrus/cedrus_h264.c +@@ -324,17 +324,16 @@ static void cedrus_set_params(struct cedrus_ctx *ctx, + struct vb2_buffer *src_buf = &run->src->vb2_buf; + struct cedrus_dev *dev = ctx->dev; + dma_addr_t src_buf_addr; +- u32 len = slice->size * 8; ++ size_t slice_bytes = vb2_get_plane_payload(src_buf, 0); + unsigned int pic_width_in_mbs; + bool mbaff_pic; + u32 reg; + +- cedrus_write(dev, VE_H264_VLD_LEN, len); ++ cedrus_write(dev, VE_H264_VLD_LEN, slice_bytes * 8); + cedrus_write(dev, VE_H264_VLD_OFFSET, 0); + + src_buf_addr = vb2_dma_contig_plane_dma_addr(src_buf, 0); +- cedrus_write(dev, VE_H264_VLD_END, +- src_buf_addr + vb2_get_plane_payload(src_buf, 0)); ++ cedrus_write(dev, VE_H264_VLD_END, src_buf_addr + slice_bytes); + cedrus_write(dev, VE_H264_VLD_ADDR, + VE_H264_VLD_ADDR_VAL(src_buf_addr) | + VE_H264_VLD_ADDR_FIRST | VE_H264_VLD_ADDR_VALID | +diff --git a/include/media/h264-ctrls.h b/include/media/h264-ctrls.h +index d178d7ad53b6..afcae3052085 100644 +--- a/include/media/h264-ctrls.h ++++ b/include/media/h264-ctrls.h +@@ -165,9 +165,6 @@ struct v4l2_h264_reference { + }; + + struct v4l2_ctrl_h264_slice_params { +- /* Size in bytes, including header */ +- __u32 size; +- + /* Offset in bytes to the start of slice in the OUTPUT buffer. */ + __u32 start_byte_offset; + + +From 37293295255bb5ad4063fe1ca6945a6890c65cd4 Mon Sep 17 00:00:00 2001 +From: Ezequiel Garcia +Date: Fri, 14 Aug 2020 10:36:24 -0300 +Subject: [PATCH] media: uapi: h264: Clarify SLICE_BASED mode + +Currently, the SLICE_BASED and FRAME_BASED modes documentation +is misleading and not matching the intended use-cases. + +Drop non-required fields SLICE_PARAMS 'start_byte_offset' and +DECODE_PARAMS 'num_slices' and clarify the decoding modes in the +documentation. + +On SLICE_BASED mode, a single slice is expected per OUTPUT buffer, +and therefore 'start_byte_offset' is not needed (since the offset +to the slice is the start of the buffer). + +This mode requires the use of CAPTURE buffer holding, and so +the number of slices shall not be required. + +On FRAME_BASED mode, the devices are expected to take care of slice +parsing. Neither SLICE_PARAMS are required (and shouldn't be +exposed by frame-based drivers), nor the number of slices. + +Signed-off-by: Ezequiel Garcia +--- + .../media/v4l/ext-ctrls-codec.rst | 39 +++++-------------- + include/media/h264-ctrls.h | 4 -- + 2 files changed, 10 insertions(+), 33 deletions(-) + +diff --git a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst +index e88c207d945b..90caf6a0d5a0 100644 +--- a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst ++++ b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst +@@ -1748,9 +1748,6 @@ enum v4l2_mpeg_video_h264_hierarchical_coding_type - + This compound control is not yet part of the public kernel API + and it is expected to change. + +- This structure is expected to be passed as an array, with one +- entry for each slice included in the bitstream buffer. +- + .. c:type:: v4l2_ctrl_h264_slice_params + + .. cssclass:: longtable +@@ -1760,17 +1757,9 @@ enum v4l2_mpeg_video_h264_hierarchical_coding_type - + :stub-columns: 0 + :widths: 1 1 2 + +- * - __u32 +- - ``start_byte_offset`` +- Offset (in bytes) from the beginning of the OUTPUT buffer to the start +- of the slice. If the slice starts with a start code, then this is the +- offset to such start code. When operating in slice-based decoding mode +- (see :c:type:`v4l2_mpeg_video_h264_decode_mode`), this field should +- be set to 0. When operating in frame-based decoding mode, this field +- should be 0 for the first slice. + * - __u32 + - ``header_bit_size`` +- - ++ - Offset in bits to slice_data() from the beginning of this slice. + * - __u32 + - ``first_mb_in_slice`` + - +@@ -1998,12 +1987,6 @@ enum v4l2_mpeg_video_h264_hierarchical_coding_type - + * - struct :c:type:`v4l2_h264_dpb_entry` + - ``dpb[16]`` + - +- * - __u16 +- - ``num_slices`` +- - Number of slices needed to decode the current frame/field. When +- operating in slice-based decoding mode (see +- :c:type:`v4l2_mpeg_video_h264_decode_mode`), this field +- should always be set to one. + * - __u16 + - ``nal_ref_idc`` + - NAL reference ID value coming from the NAL Unit header +@@ -2121,22 +2104,20 @@ enum v4l2_mpeg_video_h264_hierarchical_coding_type - + * - ``V4L2_MPEG_VIDEO_H264_DECODE_MODE_SLICE_BASED`` + - 0 + - Decoding is done at the slice granularity. +- In this mode, ``num_slices`` field in struct +- :c:type:`v4l2_ctrl_h264_decode_params` should be set to 1, +- and ``start_byte_offset`` in struct +- :c:type:`v4l2_ctrl_h264_slice_params` should be set to 0. + The OUTPUT buffer must contain a single slice. ++ When this mode is selected, the ``V4L2_CID_MPEG_VIDEO_H264_SLICE_PARAMS`` ++ control shall be set. When multiple slices compose a frame, ++ use of ``V4L2_BUF_CAP_SUPPORTS_M2M_HOLD_CAPTURE_BUF`` flag ++ is required. + * - ``V4L2_MPEG_VIDEO_H264_DECODE_MODE_FRAME_BASED`` + - 1 +- - Decoding is done at the frame granularity. +- In this mode, ``num_slices`` field in struct +- :c:type:`v4l2_ctrl_h264_decode_params` should be set to the number +- of slices in the frame, and ``start_byte_offset`` in struct +- :c:type:`v4l2_ctrl_h264_slice_params` should be set accordingly +- for each slice. For the first slice, ``start_byte_offset`` should +- be zero. ++ - Decoding is done at the frame granularity, + The OUTPUT buffer must contain all slices needed to decode the + frame. The OUTPUT buffer must also contain both fields. ++ This mode will be supported by devices that ++ parse the slice(s) header(s) in hardware. When this mode is ++ selected, the ``V4L2_CID_MPEG_VIDEO_H264_SLICE_PARAMS`` ++ control shall not be set. + + ``V4L2_CID_MPEG_VIDEO_H264_START_CODE (enum)`` + Specifies the H264 slice start code expected for each slice. +diff --git a/include/media/h264-ctrls.h b/include/media/h264-ctrls.h +index afcae3052085..e180501e6385 100644 +--- a/include/media/h264-ctrls.h ++++ b/include/media/h264-ctrls.h +@@ -165,9 +165,6 @@ struct v4l2_h264_reference { + }; + + struct v4l2_ctrl_h264_slice_params { +- /* Offset in bytes to the start of slice in the OUTPUT buffer. */ +- __u32 start_byte_offset; +- + /* Offset in bits to slice_data() from the beginning of this slice. */ + __u32 header_bit_size; + +@@ -226,7 +223,6 @@ struct v4l2_h264_dpb_entry { + + struct v4l2_ctrl_h264_decode_params { + struct v4l2_h264_dpb_entry dpb[V4L2_H264_NUM_DPB_ENTRIES]; +- __u16 num_slices; + __u16 nal_ref_idc; + __s32 top_field_order_cnt; + __s32 bottom_field_order_cnt; + +From ff81175260cd33feaa7d0407ef50186422215fae Mon Sep 17 00:00:00 2001 +From: Ezequiel Garcia +Date: Fri, 14 Aug 2020 10:36:25 -0300 +Subject: [PATCH] media: uapi: h264: Clean slice invariants syntax elements + +The H.264 specification requires in section 7.4.3 "Slice header semantics", +that the following values shall be the same in all slice headers: + + pic_parameter_set_id + frame_num + field_pic_flag + bottom_field_flag + idr_pic_id + pic_order_cnt_lsb + delta_pic_order_cnt_bottom + delta_pic_order_cnt[ 0 ] + delta_pic_order_cnt[ 1 ] + sp_for_switch_flag + slice_group_change_cycle + +These bitstream fields are part of the slice header, and therefore +passed redundantly on each slice. The purpose of the redundancy +is to make the codec fault-tolerant in network scenarios. + +This is of course not needed to be reflected in the V4L2 controls, +given the bitstream has already been parsed by applications. +Therefore, move the redundant fields to the per-frame decode +parameters control (DECODE_PARAMS). + +Field 'pic_parameter_set_id' is simply removed in this case, +because the PPS control must currently contain the active PPS. + +Syntax elements dec_ref_pic_marking() and those related +to pic order count, remain invariant as well, and therefore, +the fields dec_ref_pic_marking_bit_size and pic_order_cnt_bit_size +are also common to all slices. + +Signed-off-by: Ezequiel Garcia +Reviewed-by: Nicolas Dufresne +--- + .../media/v4l/ext-ctrls-codec.rst | 86 +++++++++---------- + drivers/media/v4l2-core/v4l2-ctrls.c | 7 ++ + drivers/media/v4l2-core/v4l2-h264.c | 8 +- + .../staging/media/hantro/hantro_g1_h264_dec.c | 21 +++-- + drivers/staging/media/hantro/hantro_h264.c | 3 +- + drivers/staging/media/rkvdec/rkvdec-h264.c | 6 +- + .../staging/media/sunxi/cedrus/cedrus_h264.c | 9 +- + include/media/h264-ctrls.h | 39 +++++---- + include/media/v4l2-h264.h | 1 - + 9 files changed, 90 insertions(+), 90 deletions(-) + +diff --git a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst +index 90caf6a0d5a0..69dd3961b99b 100644 +--- a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst ++++ b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst +@@ -1766,44 +1766,12 @@ enum v4l2_mpeg_video_h264_hierarchical_coding_type - + * - __u8 + - ``slice_type`` + - +- * - __u8 +- - ``pic_parameter_set_id`` +- - + * - __u8 + - ``colour_plane_id`` + - + * - __u8 + - ``redundant_pic_cnt`` + - +- * - __u16 +- - ``frame_num`` +- - +- * - __u16 +- - ``idr_pic_id`` +- - +- * - __u16 +- - ``pic_order_cnt_lsb`` +- - +- * - __s32 +- - ``delta_pic_order_cnt_bottom`` +- - +- * - __s32 +- - ``delta_pic_order_cnt0`` +- - +- * - __s32 +- - ``delta_pic_order_cnt1`` +- - +- * - struct :c:type:`v4l2_h264_pred_weight_table` +- - ``pred_weight_table`` +- - +- * - __u32 +- - ``dec_ref_pic_marking_bit_size`` +- - Size in bits of the dec_ref_pic_marking() syntax element. +- * - __u32 +- - ``pic_order_cnt_bit_size`` +- - Combined size in bits of the picture order count related syntax +- elements: pic_order_cnt_lsb, delta_pic_order_cnt_bottom, +- delta_pic_order_cnt0, and delta_pic_order_cnt1. + * - __u8 + - ``cabac_init_idc`` + - +@@ -1830,9 +1798,9 @@ enum v4l2_mpeg_video_h264_hierarchical_coding_type - + - ``num_ref_idx_l1_active_minus1`` + - If num_ref_idx_active_override_flag is not set, this field must be + set to the value of num_ref_idx_l1_default_active_minus1. +- * - __u32 +- - ``slice_group_change_cycle`` +- - ++ * - __u8 ++ - ``reserved`` ++ - Applications and drivers must set this to zero. + * - struct :c:type:`v4l2_h264_reference` + - ``ref_pic_list0[32]`` + - Reference picture list after applying the per-slice modifications +@@ -1854,17 +1822,11 @@ enum v4l2_mpeg_video_h264_hierarchical_coding_type - + :stub-columns: 0 + :widths: 1 1 2 + +- * - ``V4L2_H264_SLICE_FLAG_FIELD_PIC`` +- - 0x00000001 +- - +- * - ``V4L2_H264_SLICE_FLAG_BOTTOM_FIELD`` +- - 0x00000002 +- - + * - ``V4L2_H264_SLICE_FLAG_DIRECT_SPATIAL_MV_PRED`` +- - 0x00000004 ++ - 0x00000001 + - + * - ``V4L2_H264_SLICE_FLAG_SP_FOR_SWITCH`` +- - 0x00000008 ++ - 0x00000002 + - + + ``V4L2_CID_MPEG_VIDEO_H264_PRED_WEIGHTS (struct)`` +@@ -1990,12 +1952,44 @@ enum v4l2_mpeg_video_h264_hierarchical_coding_type - + * - __u16 + - ``nal_ref_idc`` + - NAL reference ID value coming from the NAL Unit header ++ * - __u16 ++ - ``frame_num`` ++ - + * - __s32 + - ``top_field_order_cnt`` + - Picture Order Count for the coded top field + * - __s32 + - ``bottom_field_order_cnt`` + - Picture Order Count for the coded bottom field ++ * - __u16 ++ - ``idr_pic_id`` ++ - ++ * - __u16 ++ - ``pic_order_cnt_lsb`` ++ - ++ * - __s32 ++ - ``delta_pic_order_cnt_bottom`` ++ - ++ * - __s32 ++ - ``delta_pic_order_cnt0`` ++ - ++ * - __s32 ++ - ``delta_pic_order_cnt1`` ++ - ++ * - __u32 ++ - ``dec_ref_pic_marking_bit_size`` ++ - Size in bits of the dec_ref_pic_marking() syntax element. ++ * - __u32 ++ - ``pic_order_cnt_bit_size`` ++ - Combined size in bits of the picture order count related syntax ++ elements: pic_order_cnt_lsb, delta_pic_order_cnt_bottom, ++ delta_pic_order_cnt0, and delta_pic_order_cnt1. ++ * - __u32 ++ - ``slice_group_change_cycle`` ++ - ++ * - __u32 ++ - ``reserved`` ++ - Applications and drivers must set this to zero. + * - __u32 + - ``flags`` + - See :ref:`Decode Parameters Flags ` +@@ -2014,6 +2008,12 @@ enum v4l2_mpeg_video_h264_hierarchical_coding_type - + * - ``V4L2_H264_DECODE_PARAM_FLAG_IDR_PIC`` + - 0x00000001 + - That picture is an IDR picture ++ * - ``V4L2_H264_DECODE_PARAM_FLAG_FIELD_PIC`` ++ - 0x00000002 ++ - ++ * - ``V4L2_H264_DECODE_PARAM_FLAG_BOTTOM_FIELD`` ++ - 0x00000004 ++ - + + .. c:type:: v4l2_h264_dpb_entry + +diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c +index b9457789fa55..b846f5b089c9 100644 +--- a/drivers/media/v4l2-core/v4l2-ctrls.c ++++ b/drivers/media/v4l2-core/v4l2-ctrls.c +@@ -1737,6 +1737,7 @@ static int std_validate_compound(const struct v4l2_ctrl *ctrl, u32 idx, + { + struct v4l2_ctrl_mpeg2_slice_params *p_mpeg2_slice_params; + struct v4l2_ctrl_vp8_frame_header *p_vp8_frame_header; ++ struct v4l2_ctrl_h264_slice_params *p_h264_slice_params; + struct v4l2_ctrl_h264_decode_params *p_h264_dec_params; + struct v4l2_ctrl_hevc_sps *p_hevc_sps; + struct v4l2_ctrl_hevc_pps *p_hevc_pps; +@@ -1798,7 +1799,12 @@ static int std_validate_compound(const struct v4l2_ctrl *ctrl, u32 idx, + case V4L2_CTRL_TYPE_H264_PPS: + case V4L2_CTRL_TYPE_H264_SCALING_MATRIX: + case V4L2_CTRL_TYPE_H264_PRED_WEIGHTS: ++ break; ++ + case V4L2_CTRL_TYPE_H264_SLICE_PARAMS: ++ p_h264_slice_params = p; ++ ++ zero_reserved(*p_h264_slice_params); + break; + + case V4L2_CTRL_TYPE_H264_DECODE_PARAMS: +@@ -1810,6 +1816,7 @@ static int std_validate_compound(const struct v4l2_ctrl *ctrl, u32 idx, + + zero_reserved(*dpb_entry); + } ++ zero_reserved(*p_h264_dec_params); + break; + + case V4L2_CTRL_TYPE_VP8_FRAME_HEADER: +diff --git a/drivers/media/v4l2-core/v4l2-h264.c b/drivers/media/v4l2-core/v4l2-h264.c +index 12b751c09016..101fdeabfb06 100644 +--- a/drivers/media/v4l2-core/v4l2-h264.c ++++ b/drivers/media/v4l2-core/v4l2-h264.c +@@ -18,14 +18,12 @@ + * + * @b: the builder context to initialize + * @dec_params: decode parameters control +- * @slice_params: first slice parameters control + * @sps: SPS control + * @dpb: DPB to use when creating the reference list + */ + void + v4l2_h264_init_reflist_builder(struct v4l2_h264_reflist_builder *b, + const struct v4l2_ctrl_h264_decode_params *dec_params, +- const struct v4l2_ctrl_h264_slice_params *slice_params, + const struct v4l2_ctrl_h264_sps *sps, + const struct v4l2_h264_dpb_entry dpb[V4L2_H264_NUM_DPB_ENTRIES]) + { +@@ -33,13 +31,13 @@ v4l2_h264_init_reflist_builder(struct v4l2_h264_reflist_builder *b, + unsigned int i; + + max_frame_num = 1 << (sps->log2_max_frame_num_minus4 + 4); +- cur_frame_num = slice_params->frame_num; ++ cur_frame_num = dec_params->frame_num; + + memset(b, 0, sizeof(*b)); +- if (!(slice_params->flags & V4L2_H264_SLICE_FLAG_FIELD_PIC)) ++ if (!(dec_params->flags & V4L2_H264_DECODE_PARAM_FLAG_FIELD_PIC)) + b->cur_pic_order_count = min(dec_params->bottom_field_order_cnt, + dec_params->top_field_order_cnt); +- else if (slice_params->flags & V4L2_H264_SLICE_FLAG_BOTTOM_FIELD) ++ else if (dec_params->flags & V4L2_H264_DECODE_PARAM_FLAG_BOTTOM_FIELD) + b->cur_pic_order_count = dec_params->bottom_field_order_cnt; + else + b->cur_pic_order_count = dec_params->top_field_order_cnt; +diff --git a/drivers/staging/media/hantro/hantro_g1_h264_dec.c b/drivers/staging/media/hantro/hantro_g1_h264_dec.c +index 424c648ce9fc..f9839e9c6da5 100644 +--- a/drivers/staging/media/hantro/hantro_g1_h264_dec.c ++++ b/drivers/staging/media/hantro/hantro_g1_h264_dec.c +@@ -23,7 +23,6 @@ static void set_params(struct hantro_ctx *ctx) + { + const struct hantro_h264_dec_ctrls *ctrls = &ctx->h264_dec.ctrls; + const struct v4l2_ctrl_h264_decode_params *dec_param = ctrls->decode; +- const struct v4l2_ctrl_h264_slice_params *slices = ctrls->slices; + const struct v4l2_ctrl_h264_sps *sps = ctrls->sps; + const struct v4l2_ctrl_h264_pps *pps = ctrls->pps; + struct vb2_v4l2_buffer *src_buf = hantro_get_src_buf(ctx); +@@ -42,11 +41,11 @@ static void set_params(struct hantro_ctx *ctx) + + if (!(sps->flags & V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY) && + (sps->flags & V4L2_H264_SPS_FLAG_MB_ADAPTIVE_FRAME_FIELD || +- slices[0].flags & V4L2_H264_SLICE_FLAG_FIELD_PIC)) ++ dec_param->flags & V4L2_H264_DECODE_PARAM_FLAG_FIELD_PIC)) + reg |= G1_REG_DEC_CTRL0_PIC_INTERLACE_E; +- if (slices[0].flags & V4L2_H264_SLICE_FLAG_FIELD_PIC) ++ if (dec_param->flags & V4L2_H264_DECODE_PARAM_FLAG_FIELD_PIC) + reg |= G1_REG_DEC_CTRL0_PIC_FIELDMODE_E; +- if (!(slices[0].flags & V4L2_H264_SLICE_FLAG_BOTTOM_FIELD)) ++ if (!(dec_param->flags & V4L2_H264_DECODE_PARAM_FLAG_BOTTOM_FIELD)) + reg |= G1_REG_DEC_CTRL0_PIC_TOPFIELD_E; + vdpu_write_relaxed(vpu, reg, G1_REG_DEC_CTRL0); + +@@ -75,7 +74,7 @@ static void set_params(struct hantro_ctx *ctx) + + /* Decoder control register 4. */ + reg = G1_REG_DEC_CTRL4_FRAMENUM_LEN(sps->log2_max_frame_num_minus4 + 4) | +- G1_REG_DEC_CTRL4_FRAMENUM(slices[0].frame_num) | ++ G1_REG_DEC_CTRL4_FRAMENUM(dec_param->frame_num) | + G1_REG_DEC_CTRL4_WEIGHT_BIPR_IDC(pps->weighted_bipred_idc); + if (pps->flags & V4L2_H264_PPS_FLAG_ENTROPY_CODING_MODE) + reg |= G1_REG_DEC_CTRL4_CABAC_E; +@@ -88,8 +87,8 @@ static void set_params(struct hantro_ctx *ctx) + vdpu_write_relaxed(vpu, reg, G1_REG_DEC_CTRL4); + + /* Decoder control register 5. */ +- reg = G1_REG_DEC_CTRL5_REFPIC_MK_LEN(slices[0].dec_ref_pic_marking_bit_size) | +- G1_REG_DEC_CTRL5_IDR_PIC_ID(slices[0].idr_pic_id); ++ reg = G1_REG_DEC_CTRL5_REFPIC_MK_LEN(dec_param->dec_ref_pic_marking_bit_size) | ++ G1_REG_DEC_CTRL5_IDR_PIC_ID(dec_param->idr_pic_id); + if (pps->flags & V4L2_H264_PPS_FLAG_CONSTRAINED_INTRA_PRED) + reg |= G1_REG_DEC_CTRL5_CONST_INTRA_E; + if (pps->flags & V4L2_H264_PPS_FLAG_DEBLOCKING_FILTER_CONTROL_PRESENT) +@@ -103,10 +102,10 @@ static void set_params(struct hantro_ctx *ctx) + vdpu_write_relaxed(vpu, reg, G1_REG_DEC_CTRL5); + + /* Decoder control register 6. */ +- reg = G1_REG_DEC_CTRL6_PPS_ID(slices[0].pic_parameter_set_id) | ++ reg = G1_REG_DEC_CTRL6_PPS_ID(pps->pic_parameter_set_id) | + G1_REG_DEC_CTRL6_REFIDX0_ACTIVE(pps->num_ref_idx_l0_default_active_minus1 + 1) | + G1_REG_DEC_CTRL6_REFIDX1_ACTIVE(pps->num_ref_idx_l1_default_active_minus1 + 1) | +- G1_REG_DEC_CTRL6_POC_LENGTH(slices[0].pic_order_cnt_bit_size); ++ G1_REG_DEC_CTRL6_POC_LENGTH(dec_param->pic_order_cnt_bit_size); + vdpu_write_relaxed(vpu, reg, G1_REG_DEC_CTRL6); + + /* Error concealment register. */ +@@ -246,7 +245,7 @@ static void set_buffers(struct hantro_ctx *ctx) + /* Destination (decoded frame) buffer. */ + dst_dma = hantro_get_dec_buf_addr(ctx, &dst_buf->vb2_buf); + /* Adjust dma addr to start at second line for bottom field */ +- if (ctrls->slices[0].flags & V4L2_H264_SLICE_FLAG_BOTTOM_FIELD) ++ if (ctrls->decode->flags & V4L2_H264_DECODE_PARAM_FLAG_BOTTOM_FIELD) + offset = ALIGN(ctx->src_fmt.width, MB_DIM); + vdpu_write_relaxed(vpu, dst_dma + offset, G1_REG_ADDR_DST); + +@@ -265,7 +264,7 @@ static void set_buffers(struct hantro_ctx *ctx) + * DMV buffer is split in two for field encoded frames, + * adjust offset for bottom field + */ +- if (ctrls->slices[0].flags & V4L2_H264_SLICE_FLAG_BOTTOM_FIELD) ++ if (ctrls->decode->flags & V4L2_H264_DECODE_PARAM_FLAG_BOTTOM_FIELD) + offset += 32 * MB_WIDTH(ctx->src_fmt.width) * + MB_HEIGHT(ctx->src_fmt.height); + vdpu_write_relaxed(vpu, dst_dma + offset, G1_REG_ADDR_DIR_MV); +diff --git a/drivers/staging/media/hantro/hantro_h264.c b/drivers/staging/media/hantro/hantro_h264.c +index 6dcd47bd9ed3..7578a4fc1b16 100644 +--- a/drivers/staging/media/hantro/hantro_h264.c ++++ b/drivers/staging/media/hantro/hantro_h264.c +@@ -372,8 +372,7 @@ int hantro_h264_dec_prepare_run(struct hantro_ctx *ctx) + + /* Build the P/B{0,1} ref lists. */ + v4l2_h264_init_reflist_builder(&reflist_builder, ctrls->decode, +- &ctrls->slices[0], ctrls->sps, +- ctx->h264_dec.dpb); ++ ctrls->sps, ctx->h264_dec.dpb); + v4l2_h264_build_p_ref_list(&reflist_builder, h264_ctx->reflists.p); + v4l2_h264_build_b_ref_lists(&reflist_builder, h264_ctx->reflists.b0, + h264_ctx->reflists.b1); +diff --git a/drivers/staging/media/rkvdec/rkvdec-h264.c b/drivers/staging/media/rkvdec/rkvdec-h264.c +index 07a80e9a9df2..70752e30b3a3 100644 +--- a/drivers/staging/media/rkvdec/rkvdec-h264.c ++++ b/drivers/staging/media/rkvdec/rkvdec-h264.c +@@ -730,7 +730,6 @@ static void assemble_hw_rps(struct rkvdec_ctx *ctx, + struct rkvdec_h264_run *run) + { + const struct v4l2_ctrl_h264_decode_params *dec_params = run->decode_params; +- const struct v4l2_ctrl_h264_slice_params *sl_params = &run->slices_params[0]; + const struct v4l2_h264_dpb_entry *dpb = dec_params->dpb; + struct rkvdec_h264_ctx *h264_ctx = ctx->priv; + const struct v4l2_ctrl_h264_sps *sps = run->sps; +@@ -754,7 +753,7 @@ static void assemble_hw_rps(struct rkvdec_ctx *ctx, + continue; + + if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM || +- dpb[i].frame_num < sl_params->frame_num) { ++ dpb[i].frame_num < dec_params->frame_num) { + p[i] = dpb[i].frame_num; + continue; + } +@@ -1094,8 +1093,7 @@ static int rkvdec_h264_run(struct rkvdec_ctx *ctx) + + /* Build the P/B{0,1} ref lists. */ + v4l2_h264_init_reflist_builder(&reflist_builder, run.decode_params, +- &run.slices_params[0], run.sps, +- run.decode_params->dpb); ++ run.sps, run.decode_params->dpb); + h264_ctx->reflists.num_valid = reflist_builder.num_valid; + v4l2_h264_build_p_ref_list(&reflist_builder, h264_ctx->reflists.p); + v4l2_h264_build_b_ref_lists(&reflist_builder, h264_ctx->reflists.b0, +diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_h264.c b/drivers/staging/media/sunxi/cedrus/cedrus_h264.c +index 7d9bd5860a1b..c8f626fdd3dd 100644 +--- a/drivers/staging/media/sunxi/cedrus/cedrus_h264.c ++++ b/drivers/staging/media/sunxi/cedrus/cedrus_h264.c +@@ -95,7 +95,6 @@ static void cedrus_write_frame_list(struct cedrus_ctx *ctx, + { + struct cedrus_h264_sram_ref_pic pic_list[CEDRUS_H264_FRAME_NUM]; + const struct v4l2_ctrl_h264_decode_params *decode = run->h264.decode_params; +- const struct v4l2_ctrl_h264_slice_params *slice = run->h264.slice_params; + const struct v4l2_ctrl_h264_sps *sps = run->h264.sps; + struct vb2_queue *cap_q; + struct cedrus_buffer *output_buf; +@@ -144,7 +143,7 @@ static void cedrus_write_frame_list(struct cedrus_ctx *ctx, + output_buf = vb2_to_cedrus_buffer(&run->dst->vb2_buf); + output_buf->codec.h264.position = position; + +- if (slice->flags & V4L2_H264_SLICE_FLAG_FIELD_PIC) ++ if (decode->flags & V4L2_H264_DECODE_PARAM_FLAG_FIELD_PIC) + output_buf->codec.h264.pic_type = CEDRUS_H264_PIC_TYPE_FIELD; + else if (sps->flags & V4L2_H264_SPS_FLAG_MB_ADAPTIVE_FRAME_FIELD) + output_buf->codec.h264.pic_type = CEDRUS_H264_PIC_TYPE_MBAFF; +@@ -407,7 +406,7 @@ static void cedrus_set_params(struct cedrus_ctx *ctx, + reg |= VE_H264_SPS_DIRECT_8X8_INFERENCE; + cedrus_write(dev, VE_H264_SPS, reg); + +- mbaff_pic = !(slice->flags & V4L2_H264_SLICE_FLAG_FIELD_PIC) && ++ mbaff_pic = !(decode->flags & V4L2_H264_DECODE_PARAM_FLAG_FIELD_PIC) && + (sps->flags & V4L2_H264_SPS_FLAG_MB_ADAPTIVE_FRAME_FIELD); + pic_width_in_mbs = sps->pic_width_in_mbs_minus1 + 1; + +@@ -421,9 +420,9 @@ static void cedrus_set_params(struct cedrus_ctx *ctx, + reg |= slice->cabac_init_idc & 0x3; + if (ctx->fh.m2m_ctx->new_frame) + reg |= VE_H264_SHS_FIRST_SLICE_IN_PIC; +- if (slice->flags & V4L2_H264_SLICE_FLAG_FIELD_PIC) ++ if (decode->flags & V4L2_H264_DECODE_PARAM_FLAG_FIELD_PIC) + reg |= VE_H264_SHS_FIELD_PIC; +- if (slice->flags & V4L2_H264_SLICE_FLAG_BOTTOM_FIELD) ++ if (decode->flags & V4L2_H264_DECODE_PARAM_FLAG_BOTTOM_FIELD) + reg |= VE_H264_SHS_BOTTOM_FIELD; + if (slice->flags & V4L2_H264_SLICE_FLAG_DIRECT_SPATIAL_MV_PRED) + reg |= VE_H264_SHS_DIRECT_SPATIAL_MV_PRED; +diff --git a/include/media/h264-ctrls.h b/include/media/h264-ctrls.h +index e180501e6385..1217b706128e 100644 +--- a/include/media/h264-ctrls.h ++++ b/include/media/h264-ctrls.h +@@ -146,10 +146,8 @@ struct v4l2_ctrl_h264_pred_weights { + #define V4L2_H264_SLICE_TYPE_SP 3 + #define V4L2_H264_SLICE_TYPE_SI 4 + +-#define V4L2_H264_SLICE_FLAG_FIELD_PIC 0x01 +-#define V4L2_H264_SLICE_FLAG_BOTTOM_FIELD 0x02 +-#define V4L2_H264_SLICE_FLAG_DIRECT_SPATIAL_MV_PRED 0x04 +-#define V4L2_H264_SLICE_FLAG_SP_FOR_SWITCH 0x08 ++#define V4L2_H264_SLICE_FLAG_DIRECT_SPATIAL_MV_PRED 0x01 ++#define V4L2_H264_SLICE_FLAG_SP_FOR_SWITCH 0x02 + + enum v4l2_h264_field_reference { + V4L2_H264_TOP_FIELD_REF = 0x1, +@@ -171,21 +169,8 @@ struct v4l2_ctrl_h264_slice_params { + __u32 first_mb_in_slice; + + __u8 slice_type; +- __u8 pic_parameter_set_id; + __u8 colour_plane_id; + __u8 redundant_pic_cnt; +- __u16 frame_num; +- __u16 idr_pic_id; +- __u16 pic_order_cnt_lsb; +- __s32 delta_pic_order_cnt_bottom; +- __s32 delta_pic_order_cnt0; +- __s32 delta_pic_order_cnt1; +- +- /* Size in bits of dec_ref_pic_marking() syntax element. */ +- __u32 dec_ref_pic_marking_bit_size; +- /* Size in bits of pic order count syntax. */ +- __u32 pic_order_cnt_bit_size; +- + __u8 cabac_init_idc; + __s8 slice_qp_delta; + __s8 slice_qs_delta; +@@ -194,7 +179,8 @@ struct v4l2_ctrl_h264_slice_params { + __s8 slice_beta_offset_div2; + __u8 num_ref_idx_l0_active_minus1; + __u8 num_ref_idx_l1_active_minus1; +- __u32 slice_group_change_cycle; ++ ++ __u8 reserved; + + struct v4l2_h264_reference ref_pic_list0[V4L2_H264_REF_LIST_LEN]; + struct v4l2_h264_reference ref_pic_list1[V4L2_H264_REF_LIST_LEN]; +@@ -219,13 +205,28 @@ struct v4l2_h264_dpb_entry { + __u32 flags; /* V4L2_H264_DPB_ENTRY_FLAG_* */ + }; + +-#define V4L2_H264_DECODE_PARAM_FLAG_IDR_PIC 0x01 ++#define V4L2_H264_DECODE_PARAM_FLAG_IDR_PIC 0x01 ++#define V4L2_H264_DECODE_PARAM_FLAG_FIELD_PIC 0x02 ++#define V4L2_H264_DECODE_PARAM_FLAG_BOTTOM_FIELD 0x04 + + struct v4l2_ctrl_h264_decode_params { + struct v4l2_h264_dpb_entry dpb[V4L2_H264_NUM_DPB_ENTRIES]; + __u16 nal_ref_idc; ++ __u16 frame_num; + __s32 top_field_order_cnt; + __s32 bottom_field_order_cnt; ++ __u16 idr_pic_id; ++ __u16 pic_order_cnt_lsb; ++ __s32 delta_pic_order_cnt_bottom; ++ __s32 delta_pic_order_cnt0; ++ __s32 delta_pic_order_cnt1; ++ /* Size in bits of dec_ref_pic_marking() syntax element. */ ++ __u32 dec_ref_pic_marking_bit_size; ++ /* Size in bits of pic order count syntax. */ ++ __u32 pic_order_cnt_bit_size; ++ __u32 slice_group_change_cycle; ++ ++ __u32 reserved; + __u32 flags; /* V4L2_H264_DECODE_PARAM_FLAG_* */ + }; + +diff --git a/include/media/v4l2-h264.h b/include/media/v4l2-h264.h +index 1a5f26fc2a9a..f08ba181263d 100644 +--- a/include/media/v4l2-h264.h ++++ b/include/media/v4l2-h264.h +@@ -44,7 +44,6 @@ struct v4l2_h264_reflist_builder { + void + v4l2_h264_init_reflist_builder(struct v4l2_h264_reflist_builder *b, + const struct v4l2_ctrl_h264_decode_params *dec_params, +- const struct v4l2_ctrl_h264_slice_params *slice_params, + const struct v4l2_ctrl_h264_sps *sps, + const struct v4l2_h264_dpb_entry dpb[V4L2_H264_NUM_DPB_ENTRIES]); + + +From c94048bd00c4faa5bf1be0b3b01d3cc41cb475bb Mon Sep 17 00:00:00 2001 +From: Ezequiel Garcia +Date: Fri, 14 Aug 2020 10:36:26 -0300 +Subject: [PATCH] media: uapi: h264: Rename and clarify + PPS_FLAG_SCALING_MATRIX_PRESENT + +Applications are expected to fill V4L2_CID_MPEG_VIDEO_H264_SCALING_MATRIX +if a non-flat scaling matrix applies to the picture. This is the case if +SPS scaling_matrix_present_flag or PPS pic_scaling_matrix_present_flag +are set, and should be handled by applications. + +On one hand, the PPS bitstream syntax element signals the presence of a +Picture scaling matrix modifying the Sequence (SPS) scaling matrix. +On the other hand, our flag should indicate if the scaling matrix +V4L2 control is applicable to this request. + +Rename the flag from PPS_FLAG_PIC_SCALING_MATRIX_PRESENT to +PPS_FLAG_SCALING_MATRIX_PRESENT, to avoid mixing this flag with +bitstream syntax element pic_scaling_matrix_present_flag, +and clarify the meaning of our flag. + +Signed-off-by: Ezequiel Garcia +--- + Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst | 5 +++-- + include/media/h264-ctrls.h | 2 +- + 2 files changed, 4 insertions(+), 3 deletions(-) + +diff --git a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst +index 69dd3961b99b..03ce87aa5488 100644 +--- a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst ++++ b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst +@@ -1695,9 +1695,10 @@ enum v4l2_mpeg_video_h264_hierarchical_coding_type - + * - ``V4L2_H264_PPS_FLAG_TRANSFORM_8X8_MODE`` + - 0x00000040 + - +- * - ``V4L2_H264_PPS_FLAG_PIC_SCALING_MATRIX_PRESENT`` ++ * - ``V4L2_H264_PPS_FLAG_SCALING_MATRIX_PRESENT`` + - 0x00000080 +- - ++ - Indicates that ``V4L2_CID_MPEG_VIDEO_H264_SCALING_MATRIX`` ++ must be used for this picture. + + ``V4L2_CID_MPEG_VIDEO_H264_SCALING_MATRIX (struct)`` + Specifies the scaling matrix (as extracted from the bitstream) for +diff --git a/include/media/h264-ctrls.h b/include/media/h264-ctrls.h +index 1217b706128e..070b9499d7bc 100644 +--- a/include/media/h264-ctrls.h ++++ b/include/media/h264-ctrls.h +@@ -99,7 +99,7 @@ struct v4l2_ctrl_h264_sps { + #define V4L2_H264_PPS_FLAG_CONSTRAINED_INTRA_PRED 0x0010 + #define V4L2_H264_PPS_FLAG_REDUNDANT_PIC_CNT_PRESENT 0x0020 + #define V4L2_H264_PPS_FLAG_TRANSFORM_8X8_MODE 0x0040 +-#define V4L2_H264_PPS_FLAG_PIC_SCALING_MATRIX_PRESENT 0x0080 ++#define V4L2_H264_PPS_FLAG_SCALING_MATRIX_PRESENT 0x0080 + + struct v4l2_ctrl_h264_pps { + __u8 pic_parameter_set_id; + +From 2344f270ec7a9f9559e6d1e57a124c6a89ce0602 Mon Sep 17 00:00:00 2001 +From: Ezequiel Garcia +Date: Fri, 14 Aug 2020 10:36:27 -0300 +Subject: [PATCH] media: hantro: Don't require unneeded H264_SLICE_PARAMS + +Now that slice invariant parameters have been moved, +the driver no longer needs this control, so drop it. + +Signed-off-by: Ezequiel Garcia +--- + drivers/staging/media/hantro/hantro_drv.c | 5 ----- + drivers/staging/media/hantro/hantro_h264.c | 5 ----- + drivers/staging/media/hantro/hantro_hw.h | 2 -- + 3 files changed, 12 deletions(-) + +diff --git a/drivers/staging/media/hantro/hantro_drv.c b/drivers/staging/media/hantro/hantro_drv.c +index 34797507f214..3cd00cc0a364 100644 +--- a/drivers/staging/media/hantro/hantro_drv.c ++++ b/drivers/staging/media/hantro/hantro_drv.c +@@ -306,11 +306,6 @@ static const struct hantro_ctrl controls[] = { + .cfg = { + .id = V4L2_CID_MPEG_VIDEO_H264_DECODE_PARAMS, + }, +- }, { +- .codec = HANTRO_H264_DECODER, +- .cfg = { +- .id = V4L2_CID_MPEG_VIDEO_H264_SLICE_PARAMS, +- }, + }, { + .codec = HANTRO_H264_DECODER, + .cfg = { +diff --git a/drivers/staging/media/hantro/hantro_h264.c b/drivers/staging/media/hantro/hantro_h264.c +index 7578a4fc1b16..089bfa9c625b 100644 +--- a/drivers/staging/media/hantro/hantro_h264.c ++++ b/drivers/staging/media/hantro/hantro_h264.c +@@ -349,11 +349,6 @@ int hantro_h264_dec_prepare_run(struct hantro_ctx *ctx) + if (WARN_ON(!ctrls->decode)) + return -EINVAL; + +- ctrls->slices = +- hantro_get_ctrl(ctx, V4L2_CID_MPEG_VIDEO_H264_SLICE_PARAMS); +- if (WARN_ON(!ctrls->slices)) +- return -EINVAL; +- + ctrls->sps = + hantro_get_ctrl(ctx, V4L2_CID_MPEG_VIDEO_H264_SPS); + if (WARN_ON(!ctrls->sps)) +diff --git a/drivers/staging/media/hantro/hantro_hw.h b/drivers/staging/media/hantro/hantro_hw.h +index f066de6b592d..219283a06f52 100644 +--- a/drivers/staging/media/hantro/hantro_hw.h ++++ b/drivers/staging/media/hantro/hantro_hw.h +@@ -56,14 +56,12 @@ struct hantro_jpeg_enc_hw_ctx { + * struct hantro_h264_dec_ctrls + * @decode: Decode params + * @scaling: Scaling info +- * @slice: Slice params + * @sps: SPS info + * @pps: PPS info + */ + struct hantro_h264_dec_ctrls { + const struct v4l2_ctrl_h264_decode_params *decode; + const struct v4l2_ctrl_h264_scaling_matrix *scaling; +- const struct v4l2_ctrl_h264_slice_params *slices; + const struct v4l2_ctrl_h264_sps *sps; + const struct v4l2_ctrl_h264_pps *pps; + }; + +From 419ccc9852409f2553c92ee3be909afa53d24d1d Mon Sep 17 00:00:00 2001 +From: Ezequiel Garcia +Date: Fri, 14 Aug 2020 10:36:28 -0300 +Subject: [PATCH] media: rkvdec: Don't require unneeded H264_SLICE_PARAMS + +Now that slice invariant parameters have been moved, +the driver no longer needs this control, so drop it. + +Signed-off-by: Ezequiel Garcia +Reviewed-by: Jonas Karlman +--- + drivers/staging/media/rkvdec/rkvdec-h264.c | 4 ---- + drivers/staging/media/rkvdec/rkvdec.c | 5 ----- + 2 files changed, 9 deletions(-) + +diff --git a/drivers/staging/media/rkvdec/rkvdec-h264.c b/drivers/staging/media/rkvdec/rkvdec-h264.c +index 70752e30b3a3..584e0d5c493b 100644 +--- a/drivers/staging/media/rkvdec/rkvdec-h264.c ++++ b/drivers/staging/media/rkvdec/rkvdec-h264.c +@@ -109,7 +109,6 @@ struct rkvdec_h264_reflists { + struct rkvdec_h264_run { + struct rkvdec_run base; + const struct v4l2_ctrl_h264_decode_params *decode_params; +- const struct v4l2_ctrl_h264_slice_params *slices_params; + const struct v4l2_ctrl_h264_sps *sps; + const struct v4l2_ctrl_h264_pps *pps; + const struct v4l2_ctrl_h264_scaling_matrix *scaling_matrix; +@@ -1066,9 +1065,6 @@ static void rkvdec_h264_run_preamble(struct rkvdec_ctx *ctx, + ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl, + V4L2_CID_MPEG_VIDEO_H264_DECODE_PARAMS); + run->decode_params = ctrl ? ctrl->p_cur.p : NULL; +- ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl, +- V4L2_CID_MPEG_VIDEO_H264_SLICE_PARAMS); +- run->slices_params = ctrl ? ctrl->p_cur.p : NULL; + ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl, + V4L2_CID_MPEG_VIDEO_H264_SPS); + run->sps = ctrl ? ctrl->p_cur.p : NULL; +diff --git a/drivers/staging/media/rkvdec/rkvdec.c b/drivers/staging/media/rkvdec/rkvdec.c +index c8151328fb70..7c5129593921 100644 +--- a/drivers/staging/media/rkvdec/rkvdec.c ++++ b/drivers/staging/media/rkvdec/rkvdec.c +@@ -59,11 +59,6 @@ static const struct rkvdec_ctrl_desc rkvdec_h264_ctrl_descs[] = { + .mandatory = true, + .cfg.id = V4L2_CID_MPEG_VIDEO_H264_DECODE_PARAMS, + }, +- { +- .per_request = true, +- .mandatory = true, +- .cfg.id = V4L2_CID_MPEG_VIDEO_H264_SLICE_PARAMS, +- }, + { + .per_request = true, + .mandatory = true, + +From 85567a00727331d7a3269bd76319a048ef1ed505 Mon Sep 17 00:00:00 2001 +From: Jernej Skrabec +Date: Fri, 14 Aug 2020 10:36:29 -0300 +Subject: [PATCH] media: cedrus: h264: Properly configure reference field + +When interlaced H264 content is being decoded, references must indicate +which field is being referenced. Currently this was done by checking +capture buffer flags. However, that is not correct because capture +buffer may hold both fields. + +Fix this by checking newly introduced flags in reference lists. + +Signed-off-by: Jernej Skrabec +Reviewed-by: Nicolas Dufresne +--- + drivers/staging/media/sunxi/cedrus/cedrus_h264.c | 6 ++---- + 1 file changed, 2 insertions(+), 4 deletions(-) + +diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_h264.c b/drivers/staging/media/sunxi/cedrus/cedrus_h264.c +index c8f626fdd3dd..1e89a8438f36 100644 +--- a/drivers/staging/media/sunxi/cedrus/cedrus_h264.c ++++ b/drivers/staging/media/sunxi/cedrus/cedrus_h264.c +@@ -182,7 +182,6 @@ static void _cedrus_write_ref_list(struct cedrus_ctx *ctx, + for (i = 0; i < num_ref; i++) { + const struct v4l2_h264_dpb_entry *dpb; + const struct cedrus_buffer *cedrus_buf; +- const struct vb2_v4l2_buffer *ref_buf; + unsigned int position; + int buf_idx; + u8 dpb_idx; +@@ -197,12 +196,11 @@ static void _cedrus_write_ref_list(struct cedrus_ctx *ctx, + if (buf_idx < 0) + continue; + +- ref_buf = to_vb2_v4l2_buffer(cap_q->bufs[buf_idx]); +- cedrus_buf = vb2_v4l2_to_cedrus_buffer(ref_buf); ++ cedrus_buf = vb2_to_cedrus_buffer(cap_q->bufs[buf_idx]); + position = cedrus_buf->codec.h264.position; + + sram_array[i] |= position << 1; +- if (ref_buf->field == V4L2_FIELD_BOTTOM) ++ if (ref_list[i].fields & V4L2_H264_BOTTOM_FIELD_REF) + sram_array[i] |= BIT(0); + } + + +From 102efa220abfcf3c08ceaf0a7c3ac5f88db5bc0c Mon Sep 17 00:00:00 2001 +From: Jernej Skrabec +Date: Fri, 14 Aug 2020 10:36:30 -0300 +Subject: [PATCH] media: cedrus: h264: Fix frame list construction + +Current frame list construction algorithm assumes that decoded image +will be output into its own buffer. That is true for progressive content +but not for interlaced where each field is decoded separately into same +buffer. + +Fix that by checking if capture buffer is listed in DPB. If it is, reuse +it. + +Signed-off-by: Jernej Skrabec +--- + drivers/staging/media/sunxi/cedrus/cedrus_h264.c | 15 +++++++++------ + 1 file changed, 9 insertions(+), 6 deletions(-) + +diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_h264.c b/drivers/staging/media/sunxi/cedrus/cedrus_h264.c +index 1e89a8438f36..fe041b444385 100644 +--- a/drivers/staging/media/sunxi/cedrus/cedrus_h264.c ++++ b/drivers/staging/media/sunxi/cedrus/cedrus_h264.c +@@ -101,7 +101,7 @@ static void cedrus_write_frame_list(struct cedrus_ctx *ctx, + struct cedrus_dev *dev = ctx->dev; + unsigned long used_dpbs = 0; + unsigned int position; +- unsigned int output = 0; ++ int output = -1; + unsigned int i; + + cap_q = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); +@@ -124,6 +124,11 @@ static void cedrus_write_frame_list(struct cedrus_ctx *ctx, + position = cedrus_buf->codec.h264.position; + used_dpbs |= BIT(position); + ++ if (run->dst->vb2_buf.timestamp == dpb->reference_ts) { ++ output = position; ++ continue; ++ } ++ + if (!(dpb->flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE)) + continue; + +@@ -131,13 +136,11 @@ static void cedrus_write_frame_list(struct cedrus_ctx *ctx, + dpb->top_field_order_cnt, + dpb->bottom_field_order_cnt, + &pic_list[position]); +- +- output = max(position, output); + } + +- position = find_next_zero_bit(&used_dpbs, CEDRUS_H264_FRAME_NUM, +- output); +- if (position >= CEDRUS_H264_FRAME_NUM) ++ if (output >= 0) ++ position = output; ++ else + position = find_first_zero_bit(&used_dpbs, CEDRUS_H264_FRAME_NUM); + + output_buf = vb2_to_cedrus_buffer(&run->dst->vb2_buf); + +From 47f1224e5d7f2d3d566d1da9df0f72ee0564a0d1 Mon Sep 17 00:00:00 2001 +From: Ezequiel Garcia +Date: Wed, 19 Aug 2020 11:37:55 -0300 +Subject: [PATCH] media: rkvdec: Drop unneeded per_request driver-specific + control flag + +Currently, the drivers makes no distinction between per_request +and mandatory, as both are used in the same request validate check. + +The driver only cares to know if a given control is +required to be part of a request, so only one flag is needed. + +Signed-off-by: Ezequiel Garcia +--- + drivers/staging/media/rkvdec/rkvdec.c | 8 +------- + drivers/staging/media/rkvdec/rkvdec.h | 1 - + 2 files changed, 1 insertion(+), 8 deletions(-) + +diff --git a/drivers/staging/media/rkvdec/rkvdec.c b/drivers/staging/media/rkvdec/rkvdec.c +index 7c5129593921..9f59dfb62d3f 100644 +--- a/drivers/staging/media/rkvdec/rkvdec.c ++++ b/drivers/staging/media/rkvdec/rkvdec.c +@@ -55,35 +55,29 @@ static const struct v4l2_ctrl_ops rkvdec_ctrl_ops = { + + static const struct rkvdec_ctrl_desc rkvdec_h264_ctrl_descs[] = { + { +- .per_request = true, + .mandatory = true, + .cfg.id = V4L2_CID_MPEG_VIDEO_H264_DECODE_PARAMS, + }, + { +- .per_request = true, + .mandatory = true, + .cfg.id = V4L2_CID_MPEG_VIDEO_H264_SPS, + .cfg.ops = &rkvdec_ctrl_ops, + }, + { +- .per_request = true, + .mandatory = true, + .cfg.id = V4L2_CID_MPEG_VIDEO_H264_PPS, + }, + { +- .per_request = true, + .mandatory = true, + .cfg.id = V4L2_CID_MPEG_VIDEO_H264_SCALING_MATRIX, + }, + { +- .mandatory = true, + .cfg.id = V4L2_CID_MPEG_VIDEO_H264_DECODE_MODE, + .cfg.min = V4L2_MPEG_VIDEO_H264_DECODE_MODE_FRAME_BASED, + .cfg.max = V4L2_MPEG_VIDEO_H264_DECODE_MODE_FRAME_BASED, + .cfg.def = V4L2_MPEG_VIDEO_H264_DECODE_MODE_FRAME_BASED, + }, + { +- .mandatory = true, + .cfg.id = V4L2_CID_MPEG_VIDEO_H264_START_CODE, + .cfg.min = V4L2_MPEG_VIDEO_H264_START_CODE_ANNEX_B, + .cfg.def = V4L2_MPEG_VIDEO_H264_START_CODE_ANNEX_B, +@@ -615,7 +609,7 @@ static int rkvdec_request_validate(struct media_request *req) + u32 id = ctrls->ctrls[i].cfg.id; + struct v4l2_ctrl *ctrl; + +- if (!ctrls->ctrls[i].per_request || !ctrls->ctrls[i].mandatory) ++ if (!ctrls->ctrls[i].mandatory) + continue; + + ctrl = v4l2_ctrl_request_hdl_ctrl_find(hdl, id); +diff --git a/drivers/staging/media/rkvdec/rkvdec.h b/drivers/staging/media/rkvdec/rkvdec.h +index 2fc9f46b6910..77a137cca88e 100644 +--- a/drivers/staging/media/rkvdec/rkvdec.h ++++ b/drivers/staging/media/rkvdec/rkvdec.h +@@ -25,7 +25,6 @@ + struct rkvdec_ctx; + + struct rkvdec_ctrl_desc { +- u32 per_request : 1; + u32 mandatory : 1; + struct v4l2_ctrl_config cfg; + }; + +From 90ea71bc465216778ac6fda4ca151f324df4d516 Mon Sep 17 00:00:00 2001 +From: Ezequiel Garcia +Date: Fri, 14 Aug 2020 10:36:32 -0300 +Subject: [PATCH] media: rkvdec: Use H264_SCALING_MATRIX only when required + +Baseline, Main and Extended profiles are specified to +not support a scaling matrix. Also, High profiles +can optionally specify a scaling matrix, using +SPS and PPS NAL units. + +To meet this expectation, applications are required to +set the V4L2_CID_MPEG_VIDEO_H264_SCALING_MATRIX control +and set the V4L2_H264_PPS_FLAG_SCALING_MATRIX_PRESENT +flag only when a scaling matrix is specified for a picture. + +Implement this on rkvdec, which has hardware support for this +case. + +Signed-off-by: Ezequiel Garcia +--- + drivers/staging/media/rkvdec/rkvdec-h264.c | 10 +++++++--- + drivers/staging/media/rkvdec/rkvdec.c | 1 - + 2 files changed, 7 insertions(+), 4 deletions(-) + +diff --git a/drivers/staging/media/rkvdec/rkvdec-h264.c b/drivers/staging/media/rkvdec/rkvdec-h264.c +index 584e0d5c493b..9233260e14c1 100644 +--- a/drivers/staging/media/rkvdec/rkvdec-h264.c ++++ b/drivers/staging/media/rkvdec/rkvdec-h264.c +@@ -708,9 +708,9 @@ static void assemble_hw_pps(struct rkvdec_ctx *ctx, + WRITE_PPS(pps->second_chroma_qp_index_offset, + SECOND_CHROMA_QP_INDEX_OFFSET); + +- /* always use the matrix sent from userspace */ +- WRITE_PPS(1, SCALING_LIST_ENABLE_FLAG); +- ++ WRITE_PPS(!!(pps->flags & V4L2_H264_PPS_FLAG_SCALING_MATRIX_PRESENT), ++ SCALING_LIST_ENABLE_FLAG); ++ /* To be on the safe side, program the scaling matrix address */ + scaling_distance = offsetof(struct rkvdec_h264_priv_tbl, scaling_list); + scaling_list_address = h264_ctx->priv_tbl.dma + scaling_distance; + WRITE_PPS(scaling_list_address, SCALING_LIST_ADDRESS); +@@ -792,9 +792,13 @@ static void assemble_hw_scaling_list(struct rkvdec_ctx *ctx, + struct rkvdec_h264_run *run) + { + const struct v4l2_ctrl_h264_scaling_matrix *scaling = run->scaling_matrix; ++ const struct v4l2_ctrl_h264_pps *pps = run->pps; + struct rkvdec_h264_ctx *h264_ctx = ctx->priv; + struct rkvdec_h264_priv_tbl *tbl = h264_ctx->priv_tbl.cpu; + ++ if (!(pps->flags & V4L2_H264_PPS_FLAG_SCALING_MATRIX_PRESENT)) ++ return; ++ + BUILD_BUG_ON(sizeof(tbl->scaling_list.scaling_list_4x4) != + sizeof(scaling->scaling_list_4x4)); + BUILD_BUG_ON(sizeof(tbl->scaling_list.scaling_list_8x8) != +diff --git a/drivers/staging/media/rkvdec/rkvdec.c b/drivers/staging/media/rkvdec/rkvdec.c +index 9f59dfb62d3f..d25c4a37e2af 100644 +--- a/drivers/staging/media/rkvdec/rkvdec.c ++++ b/drivers/staging/media/rkvdec/rkvdec.c +@@ -68,7 +68,6 @@ static const struct rkvdec_ctrl_desc rkvdec_h264_ctrl_descs[] = { + .cfg.id = V4L2_CID_MPEG_VIDEO_H264_PPS, + }, + { +- .mandatory = true, + .cfg.id = V4L2_CID_MPEG_VIDEO_H264_SCALING_MATRIX, + }, + { + +From 70d39439f485d511c9c929934a26341ef3b736ef Mon Sep 17 00:00:00 2001 +From: Ezequiel Garcia +Date: Fri, 14 Aug 2020 10:36:33 -0300 +Subject: [PATCH] media: hantro: Use H264_SCALING_MATRIX only when required + +Baseline, Main and Extended profiles are specified to +not support a scaling matrix. Also, High profiles +can optionally specify a scaling matrix, using +SPS and PPS NAL units. + +To meet this expectation, applications are required to +set the V4L2_CID_MPEG_VIDEO_H264_SCALING_MATRIX control +and set the V4L2_H264_PPS_FLAG_SCALING_MATRIX_PRESENT +flag only when a scaling matrix is specified for a picture. + +Implement this on hantro, which has hardware support for this +case. + +Signed-off-by: Ezequiel Garcia +--- + drivers/staging/media/hantro/hantro_g1_h264_dec.c | 5 ++--- + drivers/staging/media/hantro/hantro_h264.c | 4 ++++ + 2 files changed, 6 insertions(+), 3 deletions(-) + +diff --git a/drivers/staging/media/hantro/hantro_g1_h264_dec.c b/drivers/staging/media/hantro/hantro_g1_h264_dec.c +index f9839e9c6da5..845bef73d218 100644 +--- a/drivers/staging/media/hantro/hantro_g1_h264_dec.c ++++ b/drivers/staging/media/hantro/hantro_g1_h264_dec.c +@@ -59,9 +59,8 @@ static void set_params(struct hantro_ctx *ctx) + reg = G1_REG_DEC_CTRL2_CH_QP_OFFSET(pps->chroma_qp_index_offset) | + G1_REG_DEC_CTRL2_CH_QP_OFFSET2(pps->second_chroma_qp_index_offset); + +- /* always use the matrix sent from userspace */ +- reg |= G1_REG_DEC_CTRL2_TYPE1_QUANT_E; +- ++ if (pps->flags & V4L2_H264_PPS_FLAG_SCALING_MATRIX_PRESENT) ++ reg |= G1_REG_DEC_CTRL2_TYPE1_QUANT_E; + if (!(sps->flags & V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY)) + reg |= G1_REG_DEC_CTRL2_FIELDPIC_FLAG_E; + vdpu_write_relaxed(vpu, reg, G1_REG_DEC_CTRL2); +diff --git a/drivers/staging/media/hantro/hantro_h264.c b/drivers/staging/media/hantro/hantro_h264.c +index 089bfa9c625b..b1bdc00ac262 100644 +--- a/drivers/staging/media/hantro/hantro_h264.c ++++ b/drivers/staging/media/hantro/hantro_h264.c +@@ -197,6 +197,7 @@ assemble_scaling_list(struct hantro_ctx *ctx) + { + const struct hantro_h264_dec_ctrls *ctrls = &ctx->h264_dec.ctrls; + const struct v4l2_ctrl_h264_scaling_matrix *scaling = ctrls->scaling; ++ const struct v4l2_ctrl_h264_pps *pps = ctrls->pps; + const size_t num_list_4x4 = ARRAY_SIZE(scaling->scaling_list_4x4); + const size_t list_len_4x4 = ARRAY_SIZE(scaling->scaling_list_4x4[0]); + const size_t list_len_8x8 = ARRAY_SIZE(scaling->scaling_list_8x8[0]); +@@ -205,6 +206,9 @@ assemble_scaling_list(struct hantro_ctx *ctx) + const u32 *src; + int i, j; + ++ if (!(pps->flags & V4L2_H264_PPS_FLAG_SCALING_MATRIX_PRESENT)) ++ return; ++ + for (i = 0; i < num_list_4x4; i++) { + src = (u32 *)&scaling->scaling_list_4x4[i]; + for (j = 0; j < list_len_4x4 / 4; j++) + +From 6390458815944ce231b6282771e2a6c3fc6f2fa6 Mon Sep 17 00:00:00 2001 +From: Ezequiel Garcia +Date: Fri, 14 Aug 2020 10:36:34 -0300 +Subject: [PATCH] media: cedrus: Use H264_SCALING_MATRIX only when required + +Baseline, Main and Extended profiles are specified to +not support a scaling matrix. Also, High profiles +can optionally specify a scaling matrix, using +SPS and PPS NAL units. + +To meet this expectation, applications are required to +set the V4L2_CID_MPEG_VIDEO_H264_SCALING_MATRIX control +and set the V4L2_H264_PPS_FLAG_SCALING_MATRIX_PRESENT +flag only when a scaling matrix is specified for a picture. + +Implement this on cedrus, which has hardware support for this +case. + +Signed-off-by: Ezequiel Garcia +--- + drivers/staging/media/sunxi/cedrus/cedrus.c | 2 +- + drivers/staging/media/sunxi/cedrus/cedrus_h264.c | 6 ++++++ + 2 files changed, 7 insertions(+), 1 deletion(-) + +diff --git a/drivers/staging/media/sunxi/cedrus/cedrus.c b/drivers/staging/media/sunxi/cedrus/cedrus.c +index 826324faad7e..6ebb39e0c0ce 100644 +--- a/drivers/staging/media/sunxi/cedrus/cedrus.c ++++ b/drivers/staging/media/sunxi/cedrus/cedrus.c +@@ -76,7 +76,7 @@ static const struct cedrus_control cedrus_controls[] = { + .id = V4L2_CID_MPEG_VIDEO_H264_SCALING_MATRIX, + }, + .codec = CEDRUS_CODEC_H264, +- .required = true, ++ .required = false, + }, + { + .cfg = { +diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_h264.c b/drivers/staging/media/sunxi/cedrus/cedrus_h264.c +index fe041b444385..28319351e909 100644 +--- a/drivers/staging/media/sunxi/cedrus/cedrus_h264.c ++++ b/drivers/staging/media/sunxi/cedrus/cedrus_h264.c +@@ -238,8 +238,12 @@ static void cedrus_write_scaling_lists(struct cedrus_ctx *ctx, + { + const struct v4l2_ctrl_h264_scaling_matrix *scaling = + run->h264.scaling_matrix; ++ const struct v4l2_ctrl_h264_pps *pps = run->h264.pps; + struct cedrus_dev *dev = ctx->dev; + ++ if (!(pps->flags & V4L2_H264_PPS_FLAG_SCALING_MATRIX_PRESENT)) ++ return; ++ + cedrus_h264_write_sram(dev, CEDRUS_SRAM_H264_SCALING_LIST_8x8_0, + scaling->scaling_list_8x8[0], + sizeof(scaling->scaling_list_8x8[0])); +@@ -442,6 +446,8 @@ static void cedrus_set_params(struct cedrus_ctx *ctx, + reg |= (pps->second_chroma_qp_index_offset & 0x3f) << 16; + reg |= (pps->chroma_qp_index_offset & 0x3f) << 8; + reg |= (pps->pic_init_qp_minus26 + 26 + slice->slice_qp_delta) & 0x3f; ++ if (pps->flags & V4L2_H264_PPS_FLAG_SCALING_MATRIX_PRESENT) ++ reg |= VE_H264_SHS_QP_SCALING_MATRIX_DEFAULT; + cedrus_write(dev, VE_H264_SHS_QP, reg); + + // clear status flags + +From 711f57301ef4368ba23f70f6596994b7242803cc Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Mon, 6 Jul 2020 21:54:33 +0000 +Subject: [PATCH] media: rkvdec: h264: Fix reference frame_num wrap for second + field + +When decoding the second field in a complementary field pair the second +field is sharing the same frame_num with the first field. + +Currently the frame_num for the first field is wrapped when it matches the +field being decoded, this cause issues to decode the second field in a +complementary field pair. + +Fix this by using inclusive comparison, less than or equal. + +Signed-off-by: Jonas Karlman +Reviewed-by: Ezequiel Garcia +--- + drivers/staging/media/rkvdec/rkvdec-h264.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/staging/media/rkvdec/rkvdec-h264.c b/drivers/staging/media/rkvdec/rkvdec-h264.c +index 9233260e14c1..8fab0151b884 100644 +--- a/drivers/staging/media/rkvdec/rkvdec-h264.c ++++ b/drivers/staging/media/rkvdec/rkvdec-h264.c +@@ -752,7 +752,7 @@ static void assemble_hw_rps(struct rkvdec_ctx *ctx, + continue; + + if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM || +- dpb[i].frame_num < dec_params->frame_num) { ++ dpb[i].frame_num <= dec_params->frame_num) { + p[i] = dpb[i].frame_num; + continue; + } + +From a957b522403e98c67b8c184fa3b7709c6e874d40 Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Mon, 6 Jul 2020 21:54:34 +0000 +Subject: [PATCH] media: rkvdec: Ensure decoded resolution fit coded resolution + +Ensure decoded CAPTURE buffer resolution is larger or equal to the coded +OPTUPT buffer resolution. + +Signed-off-by: Jonas Karlman +--- + drivers/staging/media/rkvdec/rkvdec.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/staging/media/rkvdec/rkvdec.c b/drivers/staging/media/rkvdec/rkvdec.c +index d25c4a37e2af..b3e067031c83 100644 +--- a/drivers/staging/media/rkvdec/rkvdec.c ++++ b/drivers/staging/media/rkvdec/rkvdec.c +@@ -223,6 +223,8 @@ static int rkvdec_try_capture_fmt(struct file *file, void *priv, + pix_mp->pixelformat = coded_desc->decoded_fmts[0]; + + /* Always apply the frmsize constraint of the coded end. */ ++ pix_mp->width = max(pix_mp->width, ctx->coded_fmt.fmt.pix_mp.width); ++ pix_mp->height = max(pix_mp->height, ctx->coded_fmt.fmt.pix_mp.height); + v4l2_apply_frmsize_constraints(&pix_mp->width, + &pix_mp->height, + &coded_desc->frmsize); + +From 7c3bb86b8d315c1939a35c4dfe31e120758e5395 Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Mon, 6 Jul 2020 21:54:34 +0000 +Subject: [PATCH] media: rkvdec: h264: Validate and use pic width and height in + mbs + +The width and height in mbs is currently configured based on OUTPUT buffer +resolution, this works for frame pictures but can cause issues for field +pictures. + +When frame_mbs_only_flag is 0 the height in mbs should be height of +the field instead of height of frame. + +Validate pic_width_in_mbs_minus1 and pic_height_in_map_units_minus1 +against OUTPUT buffer resolution and use these values to configure HW. + +Signed-off-by: Jonas Karlman +--- + drivers/staging/media/rkvdec/rkvdec-h264.c | 4 ++-- + drivers/staging/media/rkvdec/rkvdec.c | 10 ++++++++++ + 2 files changed, 12 insertions(+), 2 deletions(-) + +diff --git a/drivers/staging/media/rkvdec/rkvdec-h264.c b/drivers/staging/media/rkvdec/rkvdec-h264.c +index 8fab0151b884..20a783a1bcc7 100644 +--- a/drivers/staging/media/rkvdec/rkvdec-h264.c ++++ b/drivers/staging/media/rkvdec/rkvdec-h264.c +@@ -671,8 +671,8 @@ static void assemble_hw_pps(struct rkvdec_ctx *ctx, + LOG2_MAX_PIC_ORDER_CNT_LSB_MINUS4); + WRITE_PPS(!!(sps->flags & V4L2_H264_SPS_FLAG_DELTA_PIC_ORDER_ALWAYS_ZERO), + DELTA_PIC_ORDER_ALWAYS_ZERO_FLAG); +- WRITE_PPS(DIV_ROUND_UP(ctx->coded_fmt.fmt.pix_mp.width, 16), PIC_WIDTH_IN_MBS); +- WRITE_PPS(DIV_ROUND_UP(ctx->coded_fmt.fmt.pix_mp.height, 16), PIC_HEIGHT_IN_MBS); ++ WRITE_PPS(sps->pic_width_in_mbs_minus1 + 1, PIC_WIDTH_IN_MBS); ++ WRITE_PPS(sps->pic_height_in_map_units_minus1 + 1, PIC_HEIGHT_IN_MBS); + WRITE_PPS(!!(sps->flags & V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY), + FRAME_MBS_ONLY_FLAG); + WRITE_PPS(!!(sps->flags & V4L2_H264_SPS_FLAG_MB_ADAPTIVE_FRAME_FIELD), +diff --git a/drivers/staging/media/rkvdec/rkvdec.c b/drivers/staging/media/rkvdec/rkvdec.c +index b3e067031c83..06fc58440cd3 100644 +--- a/drivers/staging/media/rkvdec/rkvdec.c ++++ b/drivers/staging/media/rkvdec/rkvdec.c +@@ -29,8 +29,11 @@ + + static int rkvdec_try_ctrl(struct v4l2_ctrl *ctrl) + { ++ struct rkvdec_ctx *ctx = container_of(ctrl->handler, struct rkvdec_ctx, ctrl_hdl); ++ + if (ctrl->id == V4L2_CID_MPEG_VIDEO_H264_SPS) { + const struct v4l2_ctrl_h264_sps *sps = ctrl->p_new.p_h264_sps; ++ unsigned int width, height; + /* + * TODO: The hardware supports 10-bit and 4:2:2 profiles, + * but it's currently broken in the driver. +@@ -45,6 +48,13 @@ static int rkvdec_try_ctrl(struct v4l2_ctrl *ctrl) + if (sps->bit_depth_luma_minus8 != 0) + /* Only 8-bit is supported */ + return -EINVAL; ++ ++ width = (sps->pic_width_in_mbs_minus1 + 1) * 16; ++ height = (sps->pic_height_in_map_units_minus1 + 1) * 16; ++ ++ if (width > ctx->coded_fmt.fmt.pix_mp.width || ++ height > ctx->coded_fmt.fmt.pix_mp.height) ++ return -EINVAL; + } + return 0; + } + +From f28529ac6fd75419e2b1806777158b5912ea0cb4 Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Mon, 6 Jul 2020 21:54:35 +0000 +Subject: [PATCH] media: rkvdec: h264: Fix bit depth wrap in pps packet + +The luma and chroma bit depth fields in the pps packet is 3 bits wide. +8 is wrongly added to the bit depth value written to these 3-bit fields. +Because only the 3 LSB is written the hardware is configured correctly. + +Correct this by not adding 8 to the luma and chroma bit depth value. + +Signed-off-by: Jonas Karlman +Reviewed-by: Ezequiel Garcia +--- + drivers/staging/media/rkvdec/rkvdec-h264.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/staging/media/rkvdec/rkvdec-h264.c b/drivers/staging/media/rkvdec/rkvdec-h264.c +index 20a783a1bcc7..f4b61dd45e7f 100644 +--- a/drivers/staging/media/rkvdec/rkvdec-h264.c ++++ b/drivers/staging/media/rkvdec/rkvdec-h264.c +@@ -661,8 +661,8 @@ static void assemble_hw_pps(struct rkvdec_ctx *ctx, + WRITE_PPS(0xff, PROFILE_IDC); + WRITE_PPS(1, CONSTRAINT_SET3_FLAG); + WRITE_PPS(sps->chroma_format_idc, CHROMA_FORMAT_IDC); +- WRITE_PPS(sps->bit_depth_luma_minus8 + 8, BIT_DEPTH_LUMA); +- WRITE_PPS(sps->bit_depth_chroma_minus8 + 8, BIT_DEPTH_CHROMA); ++ WRITE_PPS(sps->bit_depth_luma_minus8, BIT_DEPTH_LUMA); ++ WRITE_PPS(sps->bit_depth_chroma_minus8, BIT_DEPTH_CHROMA); + WRITE_PPS(0, QPPRIME_Y_ZERO_TRANSFORM_BYPASS_FLAG); + WRITE_PPS(sps->log2_max_frame_num_minus4, LOG2_MAX_FRAME_NUM_MINUS4); + WRITE_PPS(sps->max_num_ref_frames, MAX_NUM_REF_FRAMES); + +From a0de7efadd3058c3837714fd1c71e31dd00b9eac Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Mon, 6 Jul 2020 21:54:35 +0000 +Subject: [PATCH] media: rkvdec: h264: Do not override output buffer sizeimage + +The output buffer sizeimage is currently forced to 2 bytes per pixel, this +can lead to high memory usage for 4K content when multiple output buffers +is created by userspace. + +Do not override output buffer sizeimage and let userspace have control of +output buffer sizeimage by only setting sizeimage if none is provided. + +Signed-off-by: Jonas Karlman +--- + drivers/staging/media/rkvdec/rkvdec-h264.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/drivers/staging/media/rkvdec/rkvdec-h264.c b/drivers/staging/media/rkvdec/rkvdec-h264.c +index f4b61dd45e7f..2e7749bac417 100644 +--- a/drivers/staging/media/rkvdec/rkvdec-h264.c ++++ b/drivers/staging/media/rkvdec/rkvdec-h264.c +@@ -1015,8 +1015,9 @@ static int rkvdec_h264_adjust_fmt(struct rkvdec_ctx *ctx, + struct v4l2_pix_format_mplane *fmt = &f->fmt.pix_mp; + + fmt->num_planes = 1; +- fmt->plane_fmt[0].sizeimage = fmt->width * fmt->height * +- RKVDEC_H264_MAX_DEPTH_IN_BYTES; ++ if (!fmt->plane_fmt[0].sizeimage) ++ fmt->plane_fmt[0].sizeimage = fmt->width * fmt->height * ++ RKVDEC_H264_MAX_DEPTH_IN_BYTES; + return 0; + } + + +From 2fd027124722012155dda6bf4af57d978ce0655c Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Mon, 6 Jul 2020 21:54:35 +0000 +Subject: [PATCH] media: v4l2-common: Add helpers to calculate bytesperline and + sizeimage + +Add helper functions to calculate plane bytesperline and sizeimage, these +new helpers consider block width and height when calculating plane +bytesperline and sizeimage. + +This prepare support for new pixel formats added in next patch that make +use of block width and height. + +Signed-off-by: Jonas Karlman +--- + drivers/media/v4l2-core/v4l2-common.c | 77 +++++++++++++-------------- + 1 file changed, 38 insertions(+), 39 deletions(-) + +diff --git a/drivers/media/v4l2-core/v4l2-common.c b/drivers/media/v4l2-core/v4l2-common.c +index 3dc17ebe14fa..4102c373b48a 100644 +--- a/drivers/media/v4l2-core/v4l2-common.c ++++ b/drivers/media/v4l2-core/v4l2-common.c +@@ -333,6 +333,33 @@ static inline unsigned int v4l2_format_block_height(const struct v4l2_format_inf + return info->block_h[plane]; + } + ++static inline unsigned int v4l2_format_plane_width(const struct v4l2_format_info *info, int plane, ++ unsigned int width) ++{ ++ unsigned int hdiv = plane ? info->hdiv : 1; ++ unsigned int bytes = DIV_ROUND_UP(width * info->bpp[plane], ++ v4l2_format_block_width(info, plane) * ++ v4l2_format_block_height(info, plane)); ++ ++ return DIV_ROUND_UP(bytes, hdiv); ++} ++ ++static inline unsigned int v4l2_format_plane_height(const struct v4l2_format_info *info, int plane, ++ unsigned int height) ++{ ++ unsigned int vdiv = plane ? info->vdiv : 1; ++ unsigned int lines = ALIGN(height, v4l2_format_block_height(info, plane)); ++ ++ return DIV_ROUND_UP(lines, vdiv); ++} ++ ++static inline unsigned int v4l2_format_plane_size(const struct v4l2_format_info *info, int plane, ++ unsigned int width, unsigned int height) ++{ ++ return v4l2_format_plane_width(info, plane, width) * ++ v4l2_format_plane_height(info, plane, height); ++} ++ + void v4l2_apply_frmsize_constraints(u32 *width, u32 *height, + const struct v4l2_frmsize_stepwise *frmsize) + { +@@ -368,37 +395,19 @@ int v4l2_fill_pixfmt_mp(struct v4l2_pix_format_mplane *pixfmt, + + if (info->mem_planes == 1) { + plane = &pixfmt->plane_fmt[0]; +- plane->bytesperline = ALIGN(width, v4l2_format_block_width(info, 0)) * info->bpp[0]; ++ plane->bytesperline = v4l2_format_plane_width(info, 0, width); + plane->sizeimage = 0; + +- for (i = 0; i < info->comp_planes; i++) { +- unsigned int hdiv = (i == 0) ? 1 : info->hdiv; +- unsigned int vdiv = (i == 0) ? 1 : info->vdiv; +- unsigned int aligned_width; +- unsigned int aligned_height; +- +- aligned_width = ALIGN(width, v4l2_format_block_width(info, i)); +- aligned_height = ALIGN(height, v4l2_format_block_height(info, i)); +- +- plane->sizeimage += info->bpp[i] * +- DIV_ROUND_UP(aligned_width, hdiv) * +- DIV_ROUND_UP(aligned_height, vdiv); +- } ++ for (i = 0; i < info->comp_planes; i++) ++ plane->sizeimage += ++ v4l2_format_plane_size(info, i, width, height); + } else { + for (i = 0; i < info->comp_planes; i++) { +- unsigned int hdiv = (i == 0) ? 1 : info->hdiv; +- unsigned int vdiv = (i == 0) ? 1 : info->vdiv; +- unsigned int aligned_width; +- unsigned int aligned_height; +- +- aligned_width = ALIGN(width, v4l2_format_block_width(info, i)); +- aligned_height = ALIGN(height, v4l2_format_block_height(info, i)); +- + plane = &pixfmt->plane_fmt[i]; + plane->bytesperline = +- info->bpp[i] * DIV_ROUND_UP(aligned_width, hdiv); +- plane->sizeimage = +- plane->bytesperline * DIV_ROUND_UP(aligned_height, vdiv); ++ v4l2_format_plane_width(info, i, width); ++ plane->sizeimage = plane->bytesperline * ++ v4l2_format_plane_height(info, i, height); + } + } + return 0; +@@ -422,22 +431,12 @@ int v4l2_fill_pixfmt(struct v4l2_pix_format *pixfmt, u32 pixelformat, + pixfmt->width = width; + pixfmt->height = height; + pixfmt->pixelformat = pixelformat; +- pixfmt->bytesperline = ALIGN(width, v4l2_format_block_width(info, 0)) * info->bpp[0]; ++ pixfmt->bytesperline = v4l2_format_plane_width(info, 0, width); + pixfmt->sizeimage = 0; + +- for (i = 0; i < info->comp_planes; i++) { +- unsigned int hdiv = (i == 0) ? 1 : info->hdiv; +- unsigned int vdiv = (i == 0) ? 1 : info->vdiv; +- unsigned int aligned_width; +- unsigned int aligned_height; +- +- aligned_width = ALIGN(width, v4l2_format_block_width(info, i)); +- aligned_height = ALIGN(height, v4l2_format_block_height(info, i)); +- +- pixfmt->sizeimage += info->bpp[i] * +- DIV_ROUND_UP(aligned_width, hdiv) * +- DIV_ROUND_UP(aligned_height, vdiv); +- } ++ for (i = 0; i < info->comp_planes; i++) ++ pixfmt->sizeimage += ++ v4l2_format_plane_size(info, i, width, height); + return 0; + } + EXPORT_SYMBOL_GPL(v4l2_fill_pixfmt); + +From 889f4693a0947c22188ca643ed9ba3579f0abc66 Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Mon, 6 Jul 2020 21:54:36 +0000 +Subject: [PATCH] media: v4l2: Add NV15 and NV20 pixel formats + +Add NV15 and NV20 pixel formats used by the Rockchip Video Decoder for +10-bit buffers. + +NV15 and NV20 is a packed 10-bit 4:2:0/4:2:2 semi-planar Y/CbCr format +similar to P010 and P210 but has no padding between components. Instead, +luminance and chrominance samples are grouped into 4s so that each group is +packed into an integer number of bytes: + +YYYY = UVUV = 4 * 10 bits = 40 bits = 5 bytes + +The '15' and '20' suffix refers to the optimum effective bits per pixel +which is achieved when the total number of luminance samples is a multiple +of 8 for NV15 and 4 for NV20. + +Signed-off-by: Jonas Karlman +--- + .../userspace-api/media/v4l/pixfmt-nv15.rst | 101 ++++++++++++++++++ + .../userspace-api/media/v4l/pixfmt-nv20.rst | 99 +++++++++++++++++ + .../userspace-api/media/v4l/yuv-formats.rst | 2 + + drivers/media/v4l2-core/v4l2-common.c | 3 + + drivers/media/v4l2-core/v4l2-ioctl.c | 2 + + include/uapi/linux/videodev2.h | 3 + + 6 files changed, 210 insertions(+) + create mode 100644 Documentation/userspace-api/media/v4l/pixfmt-nv15.rst + create mode 100644 Documentation/userspace-api/media/v4l/pixfmt-nv20.rst + +diff --git a/Documentation/userspace-api/media/v4l/pixfmt-nv15.rst b/Documentation/userspace-api/media/v4l/pixfmt-nv15.rst +new file mode 100644 +index 000000000000..d059db58c6e0 +--- /dev/null ++++ b/Documentation/userspace-api/media/v4l/pixfmt-nv15.rst +@@ -0,0 +1,101 @@ ++.. Permission is granted to copy, distribute and/or modify this ++.. document under the terms of the GNU Free Documentation License, ++.. Version 1.1 or any later version published by the Free Software ++.. Foundation, with no Invariant Sections, no Front-Cover Texts ++.. and no Back-Cover Texts. A copy of the license is included at ++.. Documentation/userspace-api/media/fdl-appendix.rst. ++.. ++.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections ++ ++.. _V4L2-PIX-FMT-NV15: ++ ++************************** ++V4L2_PIX_FMT_NV15 ('NV15') ++************************** ++ ++Format with ½ horizontal and vertical chroma resolution, also known as ++YUV 4:2:0. One luminance and one chrominance plane with alternating ++chroma samples similar to ``V4L2_PIX_FMT_NV12`` but with 10-bit samples ++that are grouped into four and packed into five bytes. ++ ++The '15' suffix refers to the optimum effective bits per pixel which is ++achieved when the total number of luminance samples is a multiple of 8. ++ ++ ++Description ++=========== ++ ++This is a packed 10-bit two-plane version of the YUV 4:2:0 format. The ++three components are separated into two sub-images or planes. The Y plane ++is first. The Y plane has five bytes per each group of four pixels. A ++combined CbCr plane immediately follows the Y plane in memory. The CbCr ++plane is the same width, in bytes, as the Y plane (and of the image), but ++is half as tall in pixels. Each CbCr pair belongs to four pixels. For ++example, Cb\ :sub:`00`/Cr\ :sub:`00` belongs to Y'\ :sub:`00`, ++Y'\ :sub:`01`, Y'\ :sub:`10`, Y'\ :sub:`11`. ++ ++If the Y plane has pad bytes after each row, then the CbCr plane has as ++many pad bytes after its rows. ++ ++**Byte Order.** ++Little endian. Each cell is one byte. Pixels cross the byte boundary. ++ ++ ++.. flat-table:: ++ :header-rows: 0 ++ :stub-columns: 0 ++ ++ * - start + 0: ++ - Y'\ :sub:`00[7:0]` ++ - Y'\ :sub:`01[5:0]`\ Y'\ :sub:`00[9:8]` ++ - Y'\ :sub:`02[3:0]`\ Y'\ :sub:`01[9:6]` ++ - Y'\ :sub:`03[1:0]`\ Y'\ :sub:`02[9:4]` ++ - Y'\ :sub:`03[9:2]` ++ * - start + 5: ++ - Y'\ :sub:`10[7:0]` ++ - Y'\ :sub:`11[5:0]`\ Y'\ :sub:`10[9:8]` ++ - Y'\ :sub:`12[3:0]`\ Y'\ :sub:`11[9:6]` ++ - Y'\ :sub:`13[1:0]`\ Y'\ :sub:`12[9:4]` ++ - Y'\ :sub:`13[9:2]` ++ * - start + 10: ++ - Cb'\ :sub:`00[7:0]` ++ - Cr'\ :sub:`00[5:0]`\ Cb'\ :sub:`00[9:8]` ++ - Cb'\ :sub:`01[3:0]`\ Cr'\ :sub:`00[9:6]` ++ - Cr'\ :sub:`01[1:0]`\ Cb'\ :sub:`01[9:4]` ++ - Cr'\ :sub:`01[9:2]` ++ ++ ++**Color Sample Location:** ++ ++.. flat-table:: ++ :header-rows: 0 ++ :stub-columns: 0 ++ ++ * - ++ - 0 ++ - ++ - 1 ++ - 2 ++ - ++ - 3 ++ * - 0 ++ - Y ++ - ++ - Y ++ - Y ++ - ++ - Y ++ * - ++ - ++ - C ++ - ++ - ++ - C ++ - ++ * - 1 ++ - Y ++ - ++ - Y ++ - Y ++ - ++ - Y +diff --git a/Documentation/userspace-api/media/v4l/pixfmt-nv20.rst b/Documentation/userspace-api/media/v4l/pixfmt-nv20.rst +new file mode 100644 +index 000000000000..a8123be0baa3 +--- /dev/null ++++ b/Documentation/userspace-api/media/v4l/pixfmt-nv20.rst +@@ -0,0 +1,99 @@ ++.. Permission is granted to copy, distribute and/or modify this ++.. document under the terms of the GNU Free Documentation License, ++.. Version 1.1 or any later version published by the Free Software ++.. Foundation, with no Invariant Sections, no Front-Cover Texts ++.. and no Back-Cover Texts. A copy of the license is included at ++.. Documentation/userspace-api/media/fdl-appendix.rst. ++.. ++.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections ++ ++.. _V4L2-PIX-FMT-NV20: ++ ++************************** ++V4L2_PIX_FMT_NV20 ('NV20') ++************************** ++ ++Format with ½ horizontal chroma resolution, also known as YUV 4:2:2. ++One luminance and one chrominance plane with alternating chroma samples ++similar to ``V4L2_PIX_FMT_NV16`` but with 10-bit samples ++that are grouped into four and packed into five bytes. ++ ++The '20' suffix refers to the optimum effective bits per pixel which is ++achieved when the total number of luminance samples is a multiple of 4. ++ ++ ++Description ++=========== ++ ++This is a packed 10-bit two-plane version of the YUV 4:2:2 format. The ++three components are separated into two sub-images or planes. The Y plane ++is first. The Y plane has five bytes per each group of four pixels. A ++combined CbCr plane immediately follows the Y plane in memory. The CbCr ++plane is the same width and height, in bytes, as the Y plane (and of the ++image). Each CbCr pair belongs to two pixels. For example, ++Cb\ :sub:`00`/Cr\ :sub:`00` belongs to Y'\ :sub:`00`, Y'\ :sub:`01`. ++ ++If the Y plane has pad bytes after each row, then the CbCr plane has as ++many pad bytes after its rows. ++ ++**Byte Order.** ++Little endian. Each cell is one byte. Pixels cross the byte boundary. ++ ++ ++.. flat-table:: ++ :header-rows: 0 ++ :stub-columns: 0 ++ ++ * - start + 0: ++ - Y'\ :sub:`00[7:0]` ++ - Y'\ :sub:`01[5:0]`\ Y'\ :sub:`00[9:8]` ++ - Y'\ :sub:`02[3:0]`\ Y'\ :sub:`01[9:6]` ++ - Y'\ :sub:`03[1:0]`\ Y'\ :sub:`02[9:4]` ++ - Y'\ :sub:`03[9:2]` ++ * - start + 5: ++ - Y'\ :sub:`10[7:0]` ++ - Y'\ :sub:`11[5:0]`\ Y'\ :sub:`10[9:8]` ++ - Y'\ :sub:`12[3:0]`\ Y'\ :sub:`11[9:6]` ++ - Y'\ :sub:`13[1:0]`\ Y'\ :sub:`12[9:4]` ++ - Y'\ :sub:`13[9:2]` ++ * - start + 10: ++ - Cb'\ :sub:`00[7:0]` ++ - Cr'\ :sub:`00[5:0]`\ Cb'\ :sub:`00[9:8]` ++ - Cb'\ :sub:`01[3:0]`\ Cr'\ :sub:`00[9:6]` ++ - Cr'\ :sub:`01[1:0]`\ Cb'\ :sub:`01[9:4]` ++ - Cr'\ :sub:`01[9:2]` ++ * - start + 15: ++ - Cb'\ :sub:`10[7:0]` ++ - Cr'\ :sub:`10[5:0]`\ Cb'\ :sub:`10[9:8]` ++ - Cb'\ :sub:`11[3:0]`\ Cr'\ :sub:`10[9:6]` ++ - Cr'\ :sub:`11[1:0]`\ Cb'\ :sub:`11[9:4]` ++ - Cr'\ :sub:`11[9:2]` ++ ++ ++**Color Sample Location:** ++ ++.. flat-table:: ++ :header-rows: 0 ++ :stub-columns: 0 ++ ++ * - ++ - 0 ++ - ++ - 1 ++ - 2 ++ - ++ - 3 ++ * - 0 ++ - Y ++ - C ++ - Y ++ - Y ++ - C ++ - Y ++ * - 1 ++ - Y ++ - C ++ - Y ++ - Y ++ - C ++ - Y +diff --git a/Documentation/userspace-api/media/v4l/yuv-formats.rst b/Documentation/userspace-api/media/v4l/yuv-formats.rst +index 8ee92d0cd769..7cca883f178a 100644 +--- a/Documentation/userspace-api/media/v4l/yuv-formats.rst ++++ b/Documentation/userspace-api/media/v4l/yuv-formats.rst +@@ -61,4 +61,6 @@ to brightness information. + pixfmt-nv16 + pixfmt-nv16m + pixfmt-nv24 ++ pixfmt-nv15 ++ pixfmt-nv20 + pixfmt-m420 +diff --git a/drivers/media/v4l2-core/v4l2-common.c b/drivers/media/v4l2-core/v4l2-common.c +index 4102c373b48a..0caac755d303 100644 +--- a/drivers/media/v4l2-core/v4l2-common.c ++++ b/drivers/media/v4l2-core/v4l2-common.c +@@ -267,6 +267,9 @@ const struct v4l2_format_info *v4l2_format_info(u32 format) + { .format = V4L2_PIX_FMT_NV24, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, .hdiv = 1, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_NV42, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, .hdiv = 1, .vdiv = 1 }, + ++ { .format = V4L2_PIX_FMT_NV15, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 2, .bpp = { 5, 5, 0, 0 }, .hdiv = 2, .vdiv = 2, .block_w = { 4, 2, 0, 0 }, .block_h = { 1, 1, 0, 0 } }, ++ { .format = V4L2_PIX_FMT_NV20, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 2, .bpp = { 5, 5, 0, 0 }, .hdiv = 2, .vdiv = 1, .block_w = { 4, 2, 0, 0 }, .block_h = { 1, 1, 0, 0 } }, ++ + { .format = V4L2_PIX_FMT_YUV410, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 3, .bpp = { 1, 1, 1, 0 }, .hdiv = 4, .vdiv = 4 }, + { .format = V4L2_PIX_FMT_YVU410, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 3, .bpp = { 1, 1, 1, 0 }, .hdiv = 4, .vdiv = 4 }, + { .format = V4L2_PIX_FMT_YUV411P, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 3, .bpp = { 1, 1, 1, 0 }, .hdiv = 4, .vdiv = 1 }, +diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c +index ccf947632a3b..53de49087938 100644 +--- a/drivers/media/v4l2-core/v4l2-ioctl.c ++++ b/drivers/media/v4l2-core/v4l2-ioctl.c +@@ -1321,6 +1321,8 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt) + case V4L2_PIX_FMT_NV61: descr = "Y/CrCb 4:2:2"; break; + case V4L2_PIX_FMT_NV24: descr = "Y/CbCr 4:4:4"; break; + case V4L2_PIX_FMT_NV42: descr = "Y/CrCb 4:4:4"; break; ++ case V4L2_PIX_FMT_NV15: descr = "10-bit Y/CbCr 4:2:0 (Packed)"; break; ++ case V4L2_PIX_FMT_NV20: descr = "10-bit Y/CbCr 4:2:2 (Packed)"; break; + case V4L2_PIX_FMT_NV12M: descr = "Y/CbCr 4:2:0 (N-C)"; break; + case V4L2_PIX_FMT_NV21M: descr = "Y/CrCb 4:2:0 (N-C)"; break; + case V4L2_PIX_FMT_NV16M: descr = "Y/CbCr 4:2:2 (N-C)"; break; +diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h +index 6fe8822d2cb4..c8d7148cd9ae 100644 +--- a/include/uapi/linux/videodev2.h ++++ b/include/uapi/linux/videodev2.h +@@ -610,6 +610,9 @@ struct v4l2_pix_format { + #define V4L2_PIX_FMT_NV24 v4l2_fourcc('N', 'V', '2', '4') /* 24 Y/CbCr 4:4:4 */ + #define V4L2_PIX_FMT_NV42 v4l2_fourcc('N', 'V', '4', '2') /* 24 Y/CrCb 4:4:4 */ + ++#define V4L2_PIX_FMT_NV15 v4l2_fourcc('N', 'V', '1', '5') /* 15 Y/CbCr 4:2:0 10-bit packed */ ++#define V4L2_PIX_FMT_NV20 v4l2_fourcc('N', 'V', '2', '0') /* 20 Y/CbCr 4:2:2 10-bit packed */ ++ + /* two non contiguous planes - one Y, one Cr + Cb interleaved */ + #define V4L2_PIX_FMT_NV12M v4l2_fourcc('N', 'M', '1', '2') /* 12 Y/CbCr 4:2:0 */ + #define V4L2_PIX_FMT_NV21M v4l2_fourcc('N', 'M', '2', '1') /* 21 Y/CrCb 4:2:0 */ + +From d09e5dfbcc096eddf5c5d11744d53bae5f1f7d00 Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Mon, 6 Jul 2020 21:54:36 +0000 +Subject: [PATCH] media: rkvdec: h264: Use bytesperline and buffer height to + calculate stride + +Use bytesperline and buffer height to calculate the strides configured. + +This does not really change anything other than ensuring the bytesperline +that is signaled to userspace matches what is configured in HW. + +Signed-off-by: Jonas Karlman +--- + drivers/staging/media/rkvdec/rkvdec-h264.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/drivers/staging/media/rkvdec/rkvdec-h264.c b/drivers/staging/media/rkvdec/rkvdec-h264.c +index 2e7749bac417..d33fccc92205 100644 +--- a/drivers/staging/media/rkvdec/rkvdec-h264.c ++++ b/drivers/staging/media/rkvdec/rkvdec-h264.c +@@ -893,9 +893,9 @@ static void config_registers(struct rkvdec_ctx *ctx, + dma_addr_t rlc_addr; + dma_addr_t refer_addr; + u32 rlc_len; +- u32 hor_virstride = 0; +- u32 ver_virstride = 0; +- u32 y_virstride = 0; ++ u32 hor_virstride; ++ u32 ver_virstride; ++ u32 y_virstride; + u32 yuv_virstride = 0; + u32 offset; + dma_addr_t dst_addr; +@@ -906,8 +906,8 @@ static void config_registers(struct rkvdec_ctx *ctx, + + f = &ctx->decoded_fmt; + dst_fmt = &f->fmt.pix_mp; +- hor_virstride = (sps->bit_depth_luma_minus8 + 8) * dst_fmt->width / 8; +- ver_virstride = round_up(dst_fmt->height, 16); ++ hor_virstride = dst_fmt->plane_fmt[0].bytesperline; ++ ver_virstride = dst_fmt->height; + y_virstride = hor_virstride * ver_virstride; + + if (sps->chroma_format_idc == 0) + +From f0e873d66825fcd9ea314dcdab0d214226b2b8b4 Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Mon, 6 Jul 2020 21:54:37 +0000 +Subject: [PATCH] media: rkvdec: Extract rkvdec_fill_decoded_pixfmt helper + method + +This extract setting decoded pixfmt into a helper method, current code is +replaced with a call to the new helper method. + +The helper method is also called from a new function in next patch. + +Signed-off-by: Jonas Karlman +--- + drivers/staging/media/rkvdec/rkvdec.c | 29 ++++++++++++++------------- + 1 file changed, 15 insertions(+), 14 deletions(-) + +diff --git a/drivers/staging/media/rkvdec/rkvdec.c b/drivers/staging/media/rkvdec/rkvdec.c +index 06fc58440cd3..dc16bf8d57a9 100644 +--- a/drivers/staging/media/rkvdec/rkvdec.c ++++ b/drivers/staging/media/rkvdec/rkvdec.c +@@ -27,6 +27,17 @@ + #include "rkvdec.h" + #include "rkvdec-regs.h" + ++static void rkvdec_fill_decoded_pixfmt(struct rkvdec_ctx *ctx, ++ struct v4l2_pix_format_mplane *pix_mp) ++{ ++ v4l2_fill_pixfmt_mp(pix_mp, pix_mp->pixelformat, ++ pix_mp->width, pix_mp->height); ++ pix_mp->plane_fmt[0].sizeimage += 128 * ++ DIV_ROUND_UP(pix_mp->width, 16) * ++ DIV_ROUND_UP(pix_mp->height, 16); ++ pix_mp->field = V4L2_FIELD_NONE; ++} ++ + static int rkvdec_try_ctrl(struct v4l2_ctrl *ctrl) + { + struct rkvdec_ctx *ctx = container_of(ctrl->handler, struct rkvdec_ctx, ctrl_hdl); +@@ -167,13 +178,9 @@ static void rkvdec_reset_decoded_fmt(struct rkvdec_ctx *ctx) + + rkvdec_reset_fmt(ctx, f, ctx->coded_fmt_desc->decoded_fmts[0]); + f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; +- v4l2_fill_pixfmt_mp(&f->fmt.pix_mp, +- ctx->coded_fmt_desc->decoded_fmts[0], +- ctx->coded_fmt.fmt.pix_mp.width, +- ctx->coded_fmt.fmt.pix_mp.height); +- f->fmt.pix_mp.plane_fmt[0].sizeimage += 128 * +- DIV_ROUND_UP(f->fmt.pix_mp.width, 16) * +- DIV_ROUND_UP(f->fmt.pix_mp.height, 16); ++ f->fmt.pix_mp.width = ctx->coded_fmt.fmt.pix_mp.width; ++ f->fmt.pix_mp.height = ctx->coded_fmt.fmt.pix_mp.height; ++ rkvdec_fill_decoded_pixfmt(ctx, &f->fmt.pix_mp); + } + + static int rkvdec_enum_framesizes(struct file *file, void *priv, +@@ -239,13 +246,7 @@ static int rkvdec_try_capture_fmt(struct file *file, void *priv, + &pix_mp->height, + &coded_desc->frmsize); + +- v4l2_fill_pixfmt_mp(pix_mp, pix_mp->pixelformat, +- pix_mp->width, pix_mp->height); +- pix_mp->plane_fmt[0].sizeimage += +- 128 * +- DIV_ROUND_UP(pix_mp->width, 16) * +- DIV_ROUND_UP(pix_mp->height, 16); +- pix_mp->field = V4L2_FIELD_NONE; ++ rkvdec_fill_decoded_pixfmt(ctx, pix_mp); + + return 0; + } + +From 7743a31004da67bfd0f6246deaa59e670230c84e Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Mon, 6 Jul 2020 21:54:37 +0000 +Subject: [PATCH] media: rkvdec: Lock capture pixel format in s_ctrl and s_fmt + +Add an optional valid_fmt operation that should return the valid +pixelformat of CAPTURE buffers. + +This is used in next patch to ensure correct pixelformat is used for 10-bit +and 4:2:2 content. + +Signed-off-by: Jonas Karlman +--- + drivers/staging/media/rkvdec/rkvdec.c | 59 ++++++++++++++++++++++++--- + drivers/staging/media/rkvdec/rkvdec.h | 2 + + 2 files changed, 55 insertions(+), 6 deletions(-) + +diff --git a/drivers/staging/media/rkvdec/rkvdec.c b/drivers/staging/media/rkvdec/rkvdec.c +index dc16bf8d57a9..6b2a2f4164b2 100644 +--- a/drivers/staging/media/rkvdec/rkvdec.c ++++ b/drivers/staging/media/rkvdec/rkvdec.c +@@ -38,6 +38,16 @@ static void rkvdec_fill_decoded_pixfmt(struct rkvdec_ctx *ctx, + pix_mp->field = V4L2_FIELD_NONE; + } + ++static u32 rkvdec_valid_fmt(struct rkvdec_ctx *ctx, struct v4l2_ctrl *ctrl) ++{ ++ const struct rkvdec_coded_fmt_desc *coded_desc = ctx->coded_fmt_desc; ++ ++ if (coded_desc->ops->valid_fmt) ++ return coded_desc->ops->valid_fmt(ctx, ctrl); ++ ++ return ctx->valid_fmt; ++} ++ + static int rkvdec_try_ctrl(struct v4l2_ctrl *ctrl) + { + struct rkvdec_ctx *ctx = container_of(ctrl->handler, struct rkvdec_ctx, ctrl_hdl); +@@ -60,6 +70,10 @@ static int rkvdec_try_ctrl(struct v4l2_ctrl *ctrl) + /* Only 8-bit is supported */ + return -EINVAL; + ++ if (ctx->valid_fmt && ctx->valid_fmt != rkvdec_valid_fmt(ctx, ctrl)) ++ /* Only current valid format */ ++ return -EINVAL; ++ + width = (sps->pic_width_in_mbs_minus1 + 1) * 16; + height = (sps->pic_height_in_map_units_minus1 + 1) * 16; + +@@ -70,8 +84,27 @@ static int rkvdec_try_ctrl(struct v4l2_ctrl *ctrl) + return 0; + } + ++static int rkvdec_s_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ struct rkvdec_ctx *ctx = container_of(ctrl->handler, struct rkvdec_ctx, ctrl_hdl); ++ ++ if (ctrl->id == V4L2_CID_MPEG_VIDEO_H264_SPS && !ctx->valid_fmt) { ++ ctx->valid_fmt = rkvdec_valid_fmt(ctx, ctrl); ++ if (ctx->valid_fmt) { ++ struct v4l2_pix_format_mplane *pix_mp; ++ ++ pix_mp = &ctx->decoded_fmt.fmt.pix_mp; ++ pix_mp->pixelformat = ctx->valid_fmt; ++ rkvdec_fill_decoded_pixfmt(ctx, pix_mp); ++ } ++ } ++ ++ return 0; ++} ++ + static const struct v4l2_ctrl_ops rkvdec_ctrl_ops = { + .try_ctrl = rkvdec_try_ctrl, ++ .s_ctrl = rkvdec_s_ctrl, + }; + + static const struct rkvdec_ctrl_desc rkvdec_h264_ctrl_descs[] = { +@@ -176,6 +209,7 @@ static void rkvdec_reset_decoded_fmt(struct rkvdec_ctx *ctx) + { + struct v4l2_format *f = &ctx->decoded_fmt; + ++ ctx->valid_fmt = 0; + rkvdec_reset_fmt(ctx, f, ctx->coded_fmt_desc->decoded_fmts[0]); + f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + f->fmt.pix_mp.width = ctx->coded_fmt.fmt.pix_mp.width; +@@ -231,13 +265,17 @@ static int rkvdec_try_capture_fmt(struct file *file, void *priv, + if (WARN_ON(!coded_desc)) + return -EINVAL; + +- for (i = 0; i < coded_desc->num_decoded_fmts; i++) { +- if (coded_desc->decoded_fmts[i] == pix_mp->pixelformat) +- break; +- } ++ if (ctx->valid_fmt) { ++ pix_mp->pixelformat = ctx->valid_fmt; ++ } else { ++ for (i = 0; i < coded_desc->num_decoded_fmts; i++) { ++ if (coded_desc->decoded_fmts[i] == pix_mp->pixelformat) ++ break; ++ } + +- if (i == coded_desc->num_decoded_fmts) +- pix_mp->pixelformat = coded_desc->decoded_fmts[0]; ++ if (i == coded_desc->num_decoded_fmts) ++ pix_mp->pixelformat = coded_desc->decoded_fmts[0]; ++ } + + /* Always apply the frmsize constraint of the coded end. */ + pix_mp->width = max(pix_mp->width, ctx->coded_fmt.fmt.pix_mp.width); +@@ -312,6 +350,7 @@ static int rkvdec_s_capture_fmt(struct file *file, void *priv, + return ret; + + ctx->decoded_fmt = *f; ++ ctx->valid_fmt = f->fmt.pix_mp.pixelformat; + return 0; + } + +@@ -401,6 +440,14 @@ static int rkvdec_enum_capture_fmt(struct file *file, void *priv, + if (WARN_ON(!ctx->coded_fmt_desc)) + return -EINVAL; + ++ if (ctx->valid_fmt) { ++ if (f->index) ++ return -EINVAL; ++ ++ f->pixelformat = ctx->valid_fmt; ++ return 0; ++ } ++ + if (f->index >= ctx->coded_fmt_desc->num_decoded_fmts) + return -EINVAL; + +diff --git a/drivers/staging/media/rkvdec/rkvdec.h b/drivers/staging/media/rkvdec/rkvdec.h +index 77a137cca88e..e95c52e3168a 100644 +--- a/drivers/staging/media/rkvdec/rkvdec.h ++++ b/drivers/staging/media/rkvdec/rkvdec.h +@@ -63,6 +63,7 @@ vb2_to_rkvdec_decoded_buf(struct vb2_buffer *buf) + struct rkvdec_coded_fmt_ops { + int (*adjust_fmt)(struct rkvdec_ctx *ctx, + struct v4l2_format *f); ++ u32 (*valid_fmt)(struct rkvdec_ctx *ctx, struct v4l2_ctrl *ctrl); + int (*start)(struct rkvdec_ctx *ctx); + void (*stop)(struct rkvdec_ctx *ctx); + int (*run)(struct rkvdec_ctx *ctx); +@@ -96,6 +97,7 @@ struct rkvdec_ctx { + struct v4l2_fh fh; + struct v4l2_format coded_fmt; + struct v4l2_format decoded_fmt; ++ u32 valid_fmt; + const struct rkvdec_coded_fmt_desc *coded_fmt_desc; + struct v4l2_ctrl_handler ctrl_hdl; + struct rkvdec_dev *dev; + +From 15bb8d006a05aecc371e530769f06bf52c2c65bc Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Mon, 6 Jul 2020 21:54:37 +0000 +Subject: [PATCH] media: rkvdec: h264: Support High 10 and 4:2:2 profiles + +Add support and enable decoding of H264 High 10 and 4:2:2 profiles. + +Decoded CAPTURE buffer width is aligned to 64 pixels to accommodate HW +requirement on 10-bit format buffers. + +The new valid_fmt operation is implemented and return a valid pixelformat +for the provided SPS control. + +Signed-off-by: Jonas Karlman +--- + drivers/staging/media/rkvdec/rkvdec-h264.c | 20 ++++++++++++++++++++ + drivers/staging/media/rkvdec/rkvdec.c | 19 +++++++++---------- + 2 files changed, 29 insertions(+), 10 deletions(-) + +diff --git a/drivers/staging/media/rkvdec/rkvdec-h264.c b/drivers/staging/media/rkvdec/rkvdec-h264.c +index d33fccc92205..afc695d32186 100644 +--- a/drivers/staging/media/rkvdec/rkvdec-h264.c ++++ b/drivers/staging/media/rkvdec/rkvdec-h264.c +@@ -1021,6 +1021,25 @@ static int rkvdec_h264_adjust_fmt(struct rkvdec_ctx *ctx, + return 0; + } + ++static u32 rkvdec_h264_valid_fmt(struct rkvdec_ctx *ctx, struct v4l2_ctrl *ctrl) ++{ ++ const struct v4l2_ctrl_h264_sps *sps = ctrl->p_new.p_h264_sps; ++ ++ if (sps->bit_depth_luma_minus8 == 0) { ++ if (sps->chroma_format_idc == 2) ++ return V4L2_PIX_FMT_NV16; ++ else ++ return V4L2_PIX_FMT_NV12; ++ } else if (sps->bit_depth_luma_minus8 == 2) { ++ if (sps->chroma_format_idc == 2) ++ return V4L2_PIX_FMT_NV20; ++ else ++ return V4L2_PIX_FMT_NV15; ++ } ++ ++ return 0; ++} ++ + static int rkvdec_h264_start(struct rkvdec_ctx *ctx) + { + struct rkvdec_dev *rkvdec = ctx->dev; +@@ -1124,6 +1143,7 @@ static int rkvdec_h264_run(struct rkvdec_ctx *ctx) + + const struct rkvdec_coded_fmt_ops rkvdec_h264_fmt_ops = { + .adjust_fmt = rkvdec_h264_adjust_fmt, ++ .valid_fmt = rkvdec_h264_valid_fmt, + .start = rkvdec_h264_start, + .stop = rkvdec_h264_stop, + .run = rkvdec_h264_run, +diff --git a/drivers/staging/media/rkvdec/rkvdec.c b/drivers/staging/media/rkvdec/rkvdec.c +index 6b2a2f4164b2..bd8ec2915fe9 100644 +--- a/drivers/staging/media/rkvdec/rkvdec.c ++++ b/drivers/staging/media/rkvdec/rkvdec.c +@@ -31,7 +31,7 @@ static void rkvdec_fill_decoded_pixfmt(struct rkvdec_ctx *ctx, + struct v4l2_pix_format_mplane *pix_mp) + { + v4l2_fill_pixfmt_mp(pix_mp, pix_mp->pixelformat, +- pix_mp->width, pix_mp->height); ++ ALIGN(pix_mp->width, 64), pix_mp->height); + pix_mp->plane_fmt[0].sizeimage += 128 * + DIV_ROUND_UP(pix_mp->width, 16) * + DIV_ROUND_UP(pix_mp->height, 16); +@@ -55,19 +55,15 @@ static int rkvdec_try_ctrl(struct v4l2_ctrl *ctrl) + if (ctrl->id == V4L2_CID_MPEG_VIDEO_H264_SPS) { + const struct v4l2_ctrl_h264_sps *sps = ctrl->p_new.p_h264_sps; + unsigned int width, height; +- /* +- * TODO: The hardware supports 10-bit and 4:2:2 profiles, +- * but it's currently broken in the driver. +- * Reject them for now, until it's fixed. +- */ +- if (sps->chroma_format_idc > 1) +- /* Only 4:0:0 and 4:2:0 are supported */ ++ ++ if (sps->chroma_format_idc > 2) ++ /* Only 4:0:0, 4:2:0 and 4:2:2 are supported */ + return -EINVAL; + if (sps->bit_depth_luma_minus8 != sps->bit_depth_chroma_minus8) + /* Luma and chroma bit depth mismatch */ + return -EINVAL; +- if (sps->bit_depth_luma_minus8 != 0) +- /* Only 8-bit is supported */ ++ if (sps->bit_depth_luma_minus8 != 0 && sps->bit_depth_luma_minus8 != 2) ++ /* Only 8-bit and 10-bit is supported */ + return -EINVAL; + + if (ctx->valid_fmt && ctx->valid_fmt != rkvdec_valid_fmt(ctx, ctrl)) +@@ -145,6 +141,9 @@ static const struct rkvdec_ctrls rkvdec_h264_ctrls = { + + static const u32 rkvdec_h264_decoded_fmts[] = { + V4L2_PIX_FMT_NV12, ++ V4L2_PIX_FMT_NV15, ++ V4L2_PIX_FMT_NV16, ++ V4L2_PIX_FMT_NV20, + }; + + static const struct rkvdec_coded_fmt_desc rkvdec_coded_fmts[] = { + +From 26aca7fda4117f4bff16e3fb5349878fb322410b Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Mon, 6 Jul 2020 21:54:38 +0000 +Subject: [PATCH] media: rkvdec: h264: Support profile and level controls + +The Rockchip Video Decoder used in RK3399 supports H.264 profiles from +Baseline to High 4:2:2 up to Level 5.1, except for the Extended profile. + +Expose the V4L2_CID_MPEG_VIDEO_H264_PROFILE and the +V4L2_CID_MPEG_VIDEO_H264_LEVEL control, so that userspace can query the +driver for the list of supported profiles and level. + +Signed-off-by: Jonas Karlman +Reviewed-by: Ezequiel Garcia +--- + drivers/staging/media/rkvdec/rkvdec.c | 13 +++++++++++++ + 1 file changed, 13 insertions(+) + +diff --git a/drivers/staging/media/rkvdec/rkvdec.c b/drivers/staging/media/rkvdec/rkvdec.c +index bd8ec2915fe9..87987a782d75 100644 +--- a/drivers/staging/media/rkvdec/rkvdec.c ++++ b/drivers/staging/media/rkvdec/rkvdec.c +@@ -132,6 +132,19 @@ static const struct rkvdec_ctrl_desc rkvdec_h264_ctrl_descs[] = { + .cfg.def = V4L2_MPEG_VIDEO_H264_START_CODE_ANNEX_B, + .cfg.max = V4L2_MPEG_VIDEO_H264_START_CODE_ANNEX_B, + }, ++ { ++ .cfg.id = V4L2_CID_MPEG_VIDEO_H264_PROFILE, ++ .cfg.min = V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE, ++ .cfg.max = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_422, ++ .cfg.menu_skip_mask = ++ BIT(V4L2_MPEG_VIDEO_H264_PROFILE_EXTENDED), ++ .cfg.def = V4L2_MPEG_VIDEO_H264_PROFILE_MAIN, ++ }, ++ { ++ .cfg.id = V4L2_CID_MPEG_VIDEO_H264_LEVEL, ++ .cfg.min = V4L2_MPEG_VIDEO_H264_LEVEL_1_0, ++ .cfg.max = V4L2_MPEG_VIDEO_H264_LEVEL_5_1, ++ }, + }; + + static const struct rkvdec_ctrls rkvdec_h264_ctrls = { + +From 272e8a34d1803cc88e74de99b10330cd57d18f26 Mon Sep 17 00:00:00 2001 +From: Ezequiel Garcia +Date: Mon, 18 May 2020 14:40:09 -0300 +Subject: [PATCH] media: rkvdec: Fix .buf_prepare + +The driver should only set the payload on .buf_prepare +if the buffer is CAPTURE type, or if an OUTPUT buffer +has a zeroed payload. + +Fix it. + +Fixes: cd33c830448ba ("media: rkvdec: Add the rkvdec driver") +Signed-off-by: Ezequiel Garcia +--- + drivers/staging/media/rkvdec/rkvdec.c | 10 +++++++++- + 1 file changed, 9 insertions(+), 1 deletion(-) + +diff --git a/drivers/staging/media/rkvdec/rkvdec.c b/drivers/staging/media/rkvdec/rkvdec.c +index 87987a782d75..91f8a1bb6176 100644 +--- a/drivers/staging/media/rkvdec/rkvdec.c ++++ b/drivers/staging/media/rkvdec/rkvdec.c +@@ -543,7 +543,15 @@ static int rkvdec_buf_prepare(struct vb2_buffer *vb) + if (vb2_plane_size(vb, i) < sizeimage) + return -EINVAL; + } +- vb2_set_plane_payload(vb, 0, f->fmt.pix_mp.plane_fmt[0].sizeimage); ++ ++ /* ++ * Buffer's bytesused is written by the driver for CAPTURE buffers, ++ * or if the application passed zero bytesused on an OUTPUT buffer. ++ */ ++ if (!V4L2_TYPE_IS_OUTPUT(vq->type) || ++ (V4L2_TYPE_IS_OUTPUT(vq->type) && !vb2_get_plane_payload(vb, 0))) ++ vb2_set_plane_payload(vb, 0, ++ f->fmt.pix_mp.plane_fmt[0].sizeimage); + return 0; + } + + +From 6e771db436797df6146b1fe0ec94d4138bdaa2bc Mon Sep 17 00:00:00 2001 +From: Boris Brezillon +Date: Mon, 18 May 2020 14:40:10 -0300 +Subject: [PATCH] media: uapi: Add VP9 stateless decoder controls + +Add the VP9 stateless decoder controls plus the documentation that goes +with it. + +Signed-off-by: Boris Brezillon +Signed-off-by: Ezequiel Garcia +--- + .../userspace-api/media/v4l/biblio.rst | 10 + + .../media/v4l/ext-ctrls-codec.rst | 550 ++++++++++++++++++ + drivers/media/v4l2-core/v4l2-ctrls.c | 239 ++++++++ + drivers/media/v4l2-core/v4l2-ioctl.c | 1 + + include/media/v4l2-ctrls.h | 1 + + include/media/vp9-ctrls.h | 485 +++++++++++++++ + 6 files changed, 1286 insertions(+) + create mode 100644 include/media/vp9-ctrls.h + +diff --git a/Documentation/userspace-api/media/v4l/biblio.rst b/Documentation/userspace-api/media/v4l/biblio.rst +index 3c9634173e82..e09102e572fd 100644 +--- a/Documentation/userspace-api/media/v4l/biblio.rst ++++ b/Documentation/userspace-api/media/v4l/biblio.rst +@@ -414,3 +414,13 @@ VP8 + :title: RFC 6386: "VP8 Data Format and Decoding Guide" + + :author: J. Bankoski et al. ++ ++.. _vp9: ++ ++VP9 ++=== ++ ++ ++:title: VP9 Bitstream & Decoding Process Specification ++ ++:author: Adrian Grange (Google), Peter de Rivaz (Argon Design), Jonathan Hunt (Argon Design) +diff --git a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst +index 03ce87aa5488..ca13b141d8c2 100644 +--- a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst ++++ b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst +@@ -2689,6 +2689,556 @@ enum v4l2_mpeg_video_h264_hierarchical_coding_type - + - ``padding[3]`` + - Applications and drivers must set this to zero. + ++.. _v4l2-mpeg-vp9: ++ ++``V4L2_CID_MPEG_VIDEO_VP9_FRAME_CONTEXT(0..3) (struct)`` ++ Stores VP9 probabilities attached to a specific frame context. The VP9 ++ specification allows using a maximum of 4 contexts. Each frame being ++ decoded refers to one of those context. See section '7.1.2 Refresh ++ probs semantics' section of :ref:`vp9` for more details about these ++ contexts. ++ ++ This control is bi-directional: ++ ++ * all 4 contexts must be initialized by userspace just after the ++ stream is started and before the first decoding request is submitted. ++ * the referenced context might be read by the kernel when a decoding ++ request is submitted, and will be updated after the decoder is done ++ decoding the frame if the `V4L2_VP9_FRAME_FLAG_REFRESH_FRAME_CTX` flag ++ is set. ++ * contexts will be read back by user space before each decoding request ++ to retrieve the updated probabilities. ++ * userspace will re-initialize the context to their default values when ++ a reset context is required. ++ ++ .. note:: ++ ++ This compound control is not yet part of the public kernel API and ++ it is expected to change. ++ ++.. c:type:: v4l2_ctrl_vp9_frame_ctx ++ ++.. cssclass:: longtable ++ ++.. tabularcolumns:: |p{5.8cm}|p{4.8cm}|p{6.6cm}| ++ ++.. flat-table:: struct v4l2_ctrl_vp9_frame_ctx ++ :header-rows: 0 ++ :stub-columns: 0 ++ :widths: 1 1 2 ++ ++ * - struct :c:type:`v4l2_vp9_probabilities` ++ - ``probs`` ++ - Structure with VP9 probabilities attached to the context. ++ ++.. c:type:: v4l2_vp9_probabilities ++ ++.. cssclass:: longtable ++ ++.. tabularcolumns:: |p{1.5cm}|p{6.3cm}|p{9.4cm}| ++ ++.. flat-table:: struct v4l2_vp9_probabilities ++ :header-rows: 0 ++ :stub-columns: 0 ++ :widths: 1 1 2 ++ ++ * - __u8 ++ - ``tx8[2][1]`` ++ - TX 8x8 probabilities. ++ * - __u8 ++ - ``tx16[2][2]`` ++ - TX 16x16 probabilities. ++ * - __u8 ++ - ``tx32[2][3]`` ++ - TX 32x32 probabilities. ++ * - __u8 ++ - ``coef[4][2][2][6][6][3]`` ++ - Coefficient probabilities. ++ * - __u8 ++ - ``skip[3]`` ++ - Skip probabilities. ++ * - __u8 ++ - ``inter_mode[7][3]`` ++ - Inter prediction mode probabilities. ++ * - __u8 ++ - ``interp_filter[4][2]`` ++ - Interpolation filter probabilities. ++ * - __u8 ++ - ``is_inter[4]`` ++ - Is inter-block probabilities. ++ * - __u8 ++ - ``comp_mode[5]`` ++ - Compound prediction mode probabilities. ++ * - __u8 ++ - ``single_ref[5][2]`` ++ - Single reference probabilities. ++ * - __u8 ++ - ``comp_mode[5]`` ++ - Compound reference probabilities. ++ * - __u8 ++ - ``y_mode[4][9]`` ++ - Y prediction mode probabilities. ++ * - __u8 ++ - ``uv_mode[10][9]`` ++ - UV prediction mode probabilities. ++ * - __u8 ++ - ``partition[16][3]`` ++ - Partition probabilities. ++ * - __u8 ++ - ``mv.joint[3]`` ++ - Motion vector joint probabilities. ++ * - __u8 ++ - ``mv.sign[2]`` ++ - Motion vector sign probabilities. ++ * - __u8 ++ - ``mv.class[2][10]`` ++ - Motion vector class probabilities. ++ * - __u8 ++ - ``mv.class0_bit[2]`` ++ - Motion vector class0 bit probabilities. ++ * - __u8 ++ - ``mv.bits[2][10]`` ++ - Motion vector bits probabilities. ++ * - __u8 ++ - ``mv.class0_fr[2][2][3]`` ++ - Motion vector class0 fractional bit probabilities. ++ * - __u8 ++ - ``mv.fr[2][3]`` ++ - Motion vector fractional bit probabilities. ++ * - __u8 ++ - ``mv.class0_hp[2]`` ++ - Motion vector class0 high precision fractional bit probabilities. ++ * - __u8 ++ - ``mv.hp[2]`` ++ - Motion vector high precision fractional bit probabilities. ++ ++``V4L2_CID_MPEG_VIDEO_VP9_FRAME_DECODE_PARAMS (struct)`` ++ Specifies the frame parameters for the associated VP9 frame decode request. ++ This includes the necessary parameters for configuring a stateless hardware ++ decoding pipeline for VP9. The bitstream parameters are defined according ++ to :ref:`vp9`. ++ ++ .. note:: ++ ++ This compound control is not yet part of the public kernel API and ++ it is expected to change. ++ ++.. c:type:: v4l2_ctrl_vp9_frame_decode_params ++ ++.. cssclass:: longtable ++ ++.. tabularcolumns:: |p{1.5cm}|p{6.3cm}|p{9.4cm}| ++ ++.. flat-table:: struct v4l2_ctrl_vp9_frame_decode_params ++ :header-rows: 0 ++ :stub-columns: 0 ++ :widths: 1 1 2 ++ ++ * - __u32 ++ - ``flags`` ++ - Combination of V4L2_VP9_FRAME_FLAG_* flags. See ++ :c:type:`v4l2_vp9_frame_flags`. ++ * - __u16 ++ - ``compressed_header_size`` ++ - Compressed header size in bytes. ++ * - __u16 ++ - ``uncompressed_header_size`` ++ - Uncompressed header size in bytes. ++ * - __u8 ++ - ``profile`` ++ - VP9 profile. Can be 0, 1, 2 or 3. ++ * - __u8 ++ - ``reset_frame_context`` ++ - Frame context that should be used/updated when decoding the frame. ++ * - __u8 ++ - ``bit_depth`` ++ - Component depth in bits. Must be 8 for profile 0 and 1. Must 10 or 12 ++ for profile 2 and 3. ++ * - __u8 ++ - ``interpolation_filter`` ++ - Specifies the filter selection used for performing inter prediction. See ++ :c:type:`v4l2_vp9_interpolation_filter`. ++ * - __u8 ++ - ``tile_cols_log2`` ++ - Specifies the base 2 logarithm of the width of each tile (where the ++ width is measured in units of 8x8 blocks). Shall be less than or equal ++ to 6. ++ * - __u8 ++ - ``tile_rows_log2`` ++ - Specifies the base 2 logarithm of the height of each tile (where the ++ height is measured in units of 8x8 blocks) ++ * - __u8 ++ - ``tx_mode`` ++ - Specifies the TX mode. See :c:type:`v4l2_vp9_tx_mode`. ++ * - __u8 ++ - ``reference_mode`` ++ - Specifies the type of inter prediction to be used. See ++ :c:type:`v4l2_vp9_reference_mode`. ++ * - __u8 ++ - ``padding`` ++ - Needed to make this struct 64 bit aligned. Shall be filled with zeroes. ++ * - __u16 ++ - ``frame_width_minus_1`` ++ - Add 1 to get the frame width expressed in pixels. ++ * - __u16 ++ - ``frame_height_minus_1`` ++ - Add 1 to to get the frame height expressed in pixels. ++ * - __u16 ++ - ``frame_width_minus_1`` ++ - Add 1 to to get the expected render width expressed in pixels. This is ++ not used during the decoding process but might be used by HW scalers to ++ prepare a frame that's ready for scanout. ++ * - __u16 ++ - frame_height_minus_1 ++ - Add 1 to get the expected render height expressed in pixels. This is ++ not used during the decoding process but might be used by HW scalers to ++ prepare a frame that's ready for scanout. ++ * - __u64 ++ - ``refs[3]`` ++ - Array of reference frame timestamps. ++ * - struct :c:type:`v4l2_vp9_loop_filter` ++ - ``lf`` ++ - Loop filter parameters. See struct :c:type:`v4l2_vp9_loop_filter`. ++ * - struct :c:type:`v4l2_vp9_quantization` ++ - ``quant`` ++ - Quantization parameters. See :c:type:`v4l2_vp9_quantization`. ++ * - struct :c:type:`v4l2_vp9_segmentation` ++ - ``seg`` ++ - Segmentation parameters. See :c:type:`v4l2_vp9_segmentation`. ++ * - struct :c:type:`v4l2_vp9_probabilities` ++ - ``probs`` ++ - Probabilities. See :c:type:`v4l2_vp9_probabilities`. ++ ++.. c:type:: v4l2_vp9_frame_flags ++ ++.. cssclass:: longtable ++ ++.. tabularcolumns:: |p{1.5cm}|p{6.3cm}|p{9.4cm}| ++ ++.. flat-table:: enum v4l2_vp9_frame_flags ++ :header-rows: 0 ++ :stub-columns: 0 ++ :widths: 1 2 ++ ++ * - ``V4L2_VP9_FRAME_FLAG_KEY_FRAME`` ++ - The frame is a key frame. ++ * - ``V4L2_VP9_FRAME_FLAG_SHOW_FRAME`` ++ - The frame should be displayed. ++ * - ``V4L2_VP9_FRAME_FLAG_ERROR_RESILIENT`` ++ - The decoding should be error resilient. ++ * - ``V4L2_VP9_FRAME_FLAG_INTRA_ONLY`` ++ - The frame does not reference other frames. ++ * - ``V4L2_VP9_FRAME_FLAG_ALLOW_HIGH_PREC_MV`` ++ - the frame might can high precision motion vectors. ++ * - ``V4L2_VP9_FRAME_FLAG_REFRESH_FRAME_CTX`` ++ - Frame context should be updated after decoding. ++ * - ``V4L2_VP9_FRAME_FLAG_PARALLEL_DEC_MODE`` ++ - Parallel decoding is used. ++ * - ``V4L2_VP9_FRAME_FLAG_X_SUBSAMPLING`` ++ - Vertical subsampling is enabled. ++ * - ``V4L2_VP9_FRAME_FLAG_Y_SUBSAMPLING`` ++ - Horizontal subsampling is enabled. ++ * - ``V4L2_VP9_FRAME_FLAG_COLOR_RANGE_FULL_SWING`` ++ - The full UV range is used. ++ ++.. c:type:: v4l2_vp9_ref_id ++ ++.. cssclass:: longtable ++ ++.. tabularcolumns:: |p{1.5cm}|p{6.3cm}|p{9.4cm}| ++ ++.. flat-table:: enum v4l2_vp9_ref_id ++ :header-rows: 0 ++ :stub-columns: 0 ++ :widths: 1 2 ++ ++ * - ``V4L2_REF_ID_LAST`` ++ - Last reference frame. ++ * - ``V4L2_REF_ID_GOLDEN`` ++ - Golden reference frame. ++ * - ``V4L2_REF_ID_ALTREF`` ++ - Alternative reference frame. ++ * - ``V4L2_REF_ID_CNT`` ++ - Number of reference frames. ++ ++.. c:type:: v4l2_vp9_tx_mode ++ ++.. cssclass:: longtable ++ ++.. tabularcolumns:: |p{1.5cm}|p{6.3cm}|p{9.4cm}| ++ ++.. flat-table:: enum v4l2_vp9_tx_mode ++ :header-rows: 0 ++ :stub-columns: 0 ++ :widths: 1 2 ++ ++ * - ``V4L2_VP9_TX_MODE_ONLY_4X4`` ++ - Transform size is 4x4. ++ * - ``V4L2_VP9_TX_MODE_ALLOW_8X8`` ++ - Transform size can be up to 8x8. ++ * - ``V4L2_VP9_TX_MODE_ALLOW_16X16`` ++ - Transform size can be up to 16x16. ++ * - ``V4L2_VP9_TX_MODE_ALLOW_32X32`` ++ - transform size can be up to 32x32. ++ * - ``V4L2_VP9_TX_MODE_SELECT`` ++ - Bitstream contains transform size for each block. ++ ++.. c:type:: v4l2_vp9_reference_mode ++ ++.. cssclass:: longtable ++ ++.. tabularcolumns:: |p{1.5cm}|p{6.3cm}|p{9.4cm}| ++ ++.. flat-table:: enum v4l2_vp9_reference_mode ++ :header-rows: 0 ++ :stub-columns: 0 ++ :widths: 1 2 ++ ++ * - ``V4L2_VP9_REF_MODE_SINGLE`` ++ - Indicates that all the inter blocks use only a single reference frame ++ to generate motion compensated prediction. ++ * - ``V4L2_VP9_REF_MODE_COMPOUND`` ++ - Requires all the inter blocks to use compound mode. Single reference ++ frame prediction is not allowed. ++ * - ``V4L2_VP9_REF_MODE_SELECT`` ++ - Allows each individual inter block to select between single and ++ compound prediction modes. ++ ++.. c:type:: v4l2_vp9_interpolation_filter ++ ++.. cssclass:: longtable ++ ++.. tabularcolumns:: |p{1.5cm}|p{6.3cm}|p{9.4cm}| ++ ++.. flat-table:: enum v4l2_vp9_interpolation_filter ++ :header-rows: 0 ++ :stub-columns: 0 ++ :widths: 1 2 ++ ++ * - ``V4L2_VP9_INTERP_FILTER_8TAP`` ++ - Height tap filter. ++ * - ``V4L2_VP9_INTERP_FILTER_8TAP_SMOOTH`` ++ - Height tap smooth filter. ++ * - ``V4L2_VP9_INTERP_FILTER_8TAP_SHARP`` ++ - Height tap sharp filter. ++ * - ``V4L2_VP9_INTERP_FILTER_BILINEAR`` ++ - Bilinear filter. ++ * - ``V4L2_VP9_INTERP_FILTER_SWITCHABLE`` ++ - Filter selection is signaled at the block level. ++ ++.. c:type:: v4l2_vp9_reset_frame_context ++ ++.. cssclass:: longtable ++ ++.. tabularcolumns:: |p{1.5cm}|p{6.3cm}|p{9.4cm}| ++ ++.. flat-table:: enum v4l2_vp9_reset_frame_context ++ :header-rows: 0 ++ :stub-columns: 0 ++ :widths: 1 2 ++ ++ * - ``V4L2_VP9_RESET_FRAME_CTX_NONE`` ++ - Do not reset any frame context. ++ * - ``V4L2_VP9_RESET_FRAME_CTX_SPEC`` ++ - Reset the frame context pointed by ++ :c:type:`v4l2_ctrl_vp9_frame_decode_params`.frame_context_idx. ++ * - ``V4L2_VP9_RESET_FRAME_CTX_ALL`` ++ - Reset all frame contexts. ++ ++.. c:type:: v4l2_vp9_intra_prediction_mode ++ ++.. cssclass:: longtable ++ ++.. tabularcolumns:: |p{1.5cm}|p{6.3cm}|p{9.4cm}| ++ ++.. flat-table:: enum v4l2_vp9_intra_prediction_mode ++ :header-rows: 0 ++ :stub-columns: 0 ++ :widths: 1 2 ++ ++ * - ``V4L2_VP9_INTRA_PRED_DC`` ++ - DC intra prediction. ++ * - ``V4L2_VP9_INTRA_PRED_MODE_V`` ++ - Vertical intra prediction. ++ * - ``V4L2_VP9_INTRA_PRED_MODE_H`` ++ - Horizontal intra prediction. ++ * - ``V4L2_VP9_INTRA_PRED_MODE_D45`` ++ - D45 intra prediction. ++ * - ``V4L2_VP9_INTRA_PRED_MODE_D135`` ++ - D135 intra prediction. ++ * - ``V4L2_VP9_INTRA_PRED_MODE_D117`` ++ - D117 intra prediction. ++ * - ``V4L2_VP9_INTRA_PRED_MODE_D153`` ++ - D153 intra prediction. ++ * - ``V4L2_VP9_INTRA_PRED_MODE_D207`` ++ - D207 intra prediction. ++ * - ``V4L2_VP9_INTRA_PRED_MODE_D63`` ++ - D63 intra prediction. ++ * - ``V4L2_VP9_INTRA_PRED_MODE_TM`` ++ - True motion intra prediction. ++ ++.. c:type:: v4l2_vp9_segmentation ++ ++.. cssclass:: longtable ++ ++.. tabularcolumns:: |p{1.5cm}|p{6.3cm}|p{9.4cm}| ++ ++.. flat-table:: struct v4l2_vp9_segmentation ++ :header-rows: 0 ++ :stub-columns: 0 ++ :widths: 1 1 2 ++ ++ * - __u8 ++ - ``flags`` ++ - Combination of V4L2_VP9_SEGMENTATION_FLAG_* flags. See ++ :c:type:`v4l2_vp9_segmentation_flags`. ++ * - __u8 ++ - ``tree_probs[7]`` ++ - Specifies the probability values to be used when decoding a Segment-ID. ++ See '5.15. Segmentation map' section of :ref:`vp9` for more details. ++ * - __u8 ++ - ``pred_prob[3]`` ++ - Specifies the probability values to be used when decoding a ++ Predicted-Segment-ID. See '6.4.14. Get segment id syntax' ++ section of :ref:`vp9` for more details. ++ * - __u8 ++ - ``padding[5]`` ++ - Used to align this struct on 64 bit. Shall be filled with zeroes. ++ * - __u8 ++ - ``feature_enabled[8]`` ++ - Bitmask defining which features are enabled in each segment. ++ * - __u8 ++ - ``feature_data[8][4]`` ++ - Data attached to each feature. Data entry is only valid if the feature ++ is enabled. ++ ++.. c:type:: v4l2_vp9_segment_feature ++ ++.. cssclass:: longtable ++ ++.. tabularcolumns:: |p{1.5cm}|p{6.3cm}|p{9.4cm}| ++ ++.. flat-table:: enum v4l2_vp9_segment_feature ++ :header-rows: 0 ++ :stub-columns: 0 ++ :widths: 1 2 ++ ++ * - ``V4L2_VP9_SEGMENT_FEATURE_QP_DELTA`` ++ - QP delta segment feature. ++ * - ``V4L2_VP9_SEGMENT_FEATURE_LF`` ++ - Loop filter segment feature. ++ * - ``V4L2_VP9_SEGMENT_FEATURE_REF_FRAME`` ++ - Reference frame segment feature. ++ * - ``V4L2_VP9_SEGMENT_FEATURE_SKIP`` ++ - Skip segment feature. ++ * - ``V4L2_VP9_SEGMENT_FEATURE_CNT`` ++ - Number of segment features. ++ ++.. c:type:: v4l2_vp9_segmentation_flags ++ ++.. cssclass:: longtable ++ ++.. tabularcolumns:: |p{1.5cm}|p{6.3cm}|p{9.4cm}| ++ ++.. flat-table:: enum v4l2_vp9_segmentation_flags ++ :header-rows: 0 ++ :stub-columns: 0 ++ :widths: 1 2 ++ ++ * - ``V4L2_VP9_SEGMENTATION_FLAG_ENABLED`` ++ - Indicates that this frame makes use of the segmentation tool. ++ * - ``V4L2_VP9_SEGMENTATION_FLAG_UPDATE_MAP`` ++ - Indicates that the segmentation map should be updated during the ++ decoding of this frame. ++ * - ``V4L2_VP9_SEGMENTATION_FLAG_TEMPORAL_UPDATE`` ++ - Indicates that the updates to the segmentation map are coded ++ relative to the existing segmentation map. ++ * - ``V4L2_VP9_SEGMENTATION_FLAG_UPDATE_DATA`` ++ - Indicates that new parameters are about to be specified for each ++ segment. ++ * - ``V4L2_VP9_SEGMENTATION_FLAG_ABS_OR_DELTA_UPDATE`` ++ - Indicates that the segmentation parameters represent the actual values ++ to be used. ++ ++.. c:type:: v4l2_vp9_quantization ++ ++.. cssclass:: longtable ++ ++.. tabularcolumns:: |p{1.5cm}|p{6.3cm}|p{9.4cm}| ++ ++.. flat-table:: struct v4l2_vp9_quantization ++ :header-rows: 0 ++ :stub-columns: 0 ++ :widths: 1 1 2 ++ ++ * - __u8 ++ - ``base_q_idx`` ++ - Indicates the base frame qindex. ++ * - __s8 ++ - ``delta_q_y_dc`` ++ - Indicates the Y DC quantizer relative to base_q_idx. ++ * - __s8 ++ - ``delta_q_uv_dc`` ++ - Indicates the UV DC quantizer relative to base_q_idx. ++ * - __s8 ++ - ``delta_q_uv_ac`` ++ - Indicates the UV AC quantizer relative to base_q_idx. ++ * - __u8 ++ - ``padding[4]`` ++ - Padding bytes used to align this struct on 64 bit. Must be set to 0. ++ ++.. c:type:: v4l2_vp9_loop_filter ++ ++.. cssclass:: longtable ++ ++.. tabularcolumns:: |p{1.5cm}|p{6.3cm}|p{9.4cm}| ++ ++.. flat-table:: struct v4l2_vp9_loop_filter ++ :header-rows: 0 ++ :stub-columns: 0 ++ :widths: 1 1 2 ++ ++ * - __u8 ++ - ``flags`` ++ - Combination of V4L2_VP9_LOOP_FILTER_FLAG_* flags. ++ See :c:type:`v4l2_vp9_loop_filter_flags`. ++ * - __u8 ++ - ``level`` ++ - Indicates the loop filter strength. ++ * - __u8 ++ - ``sharpness`` ++ - Indicates the sharpness level. ++ * - __s8 ++ - ``ref_deltas[4]`` ++ - Contains the adjustment needed for the filter level based on the chosen ++ reference frame. ++ * - __s8 ++ - ``mode_deltas[2]`` ++ - Contains the adjustment needed for the filter level based on the chosen ++ mode ++ * - __u8 ++ - ``level_lookup[8][4][2]`` ++ - Level lookup table. ++ ++ ++.. c:type:: v4l2_vp9_loop_filter_flags ++ ++.. cssclass:: longtable ++ ++.. tabularcolumns:: |p{1.5cm}|p{6.3cm}|p{9.4cm}| ++ ++.. flat-table:: enum v4l2_vp9_loop_filter_flags ++ :header-rows: 0 ++ :stub-columns: 0 ++ :widths: 1 2 ++ ++ * - ``V4L2_VP9_LOOP_FILTER_FLAG_DELTA_ENABLED`` ++ - When set, the filter level depends on the mode and reference frame used ++ to predict a block. ++ * - ``V4L2_VP9_LOOP_FILTER_FLAG_DELTA_UPDATE`` ++ - When set, the bitstream contains additional syntax elements that ++ specify which mode and reference frame deltas are to be updated. ++ + .. raw:: latex + + \normalsize +diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c +index b846f5b089c9..5913088cbc6f 100644 +--- a/drivers/media/v4l2-core/v4l2-ctrls.c ++++ b/drivers/media/v4l2-core/v4l2-ctrls.c +@@ -940,6 +940,11 @@ const char *v4l2_ctrl_get_name(u32 id) + case V4L2_CID_MPEG_VIDEO_VP8_PROFILE: return "VP8 Profile"; + case V4L2_CID_MPEG_VIDEO_VP9_PROFILE: return "VP9 Profile"; + case V4L2_CID_MPEG_VIDEO_VP8_FRAME_HEADER: return "VP8 Frame Header"; ++ case V4L2_CID_MPEG_VIDEO_VP9_FRAME_DECODE_PARAMS: return "VP9 Frame Decode Parameters"; ++ case V4L2_CID_MPEG_VIDEO_VP9_FRAME_CONTEXT(0): return "VP9 Frame Context 0"; ++ case V4L2_CID_MPEG_VIDEO_VP9_FRAME_CONTEXT(1): return "VP9 Frame Context 1"; ++ case V4L2_CID_MPEG_VIDEO_VP9_FRAME_CONTEXT(2): return "VP9 Frame Context 2"; ++ case V4L2_CID_MPEG_VIDEO_VP9_FRAME_CONTEXT(3): return "VP9 Frame Context 3"; + + /* HEVC controls */ + case V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_QP: return "HEVC I-Frame QP Value"; +@@ -1419,6 +1424,15 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type, + case V4L2_CID_MPEG_VIDEO_VP8_FRAME_HEADER: + *type = V4L2_CTRL_TYPE_VP8_FRAME_HEADER; + break; ++ case V4L2_CID_MPEG_VIDEO_VP9_FRAME_DECODE_PARAMS: ++ *type = V4L2_CTRL_TYPE_VP9_FRAME_DECODE_PARAMS; ++ break; ++ case V4L2_CID_MPEG_VIDEO_VP9_FRAME_CONTEXT(0): ++ case V4L2_CID_MPEG_VIDEO_VP9_FRAME_CONTEXT(1): ++ case V4L2_CID_MPEG_VIDEO_VP9_FRAME_CONTEXT(2): ++ case V4L2_CID_MPEG_VIDEO_VP9_FRAME_CONTEXT(3): ++ *type = V4L2_CTRL_TYPE_VP9_FRAME_CONTEXT; ++ break; + case V4L2_CID_MPEG_VIDEO_HEVC_SPS: + *type = V4L2_CTRL_TYPE_HEVC_SPS; + break; +@@ -1721,6 +1735,219 @@ static void std_log(const struct v4l2_ctrl *ctrl) + 0; \ + }) + ++static int ++validate_vp9_lf_params(struct v4l2_vp9_loop_filter *lf) ++{ ++ unsigned int i, j, k; ++ ++ if (lf->flags & ++ ~(V4L2_VP9_LOOP_FILTER_FLAG_DELTA_ENABLED | ++ V4L2_VP9_LOOP_FILTER_FLAG_DELTA_UPDATE)) ++ return -EINVAL; ++ ++ /* ++ * V4L2_VP9_LOOP_FILTER_FLAG_DELTA_ENABLED implies ++ * V4L2_VP9_LOOP_FILTER_FLAG_DELTA_UPDATE. ++ */ ++ if (lf->flags & V4L2_VP9_LOOP_FILTER_FLAG_DELTA_UPDATE && ++ !(lf->flags & V4L2_VP9_LOOP_FILTER_FLAG_DELTA_ENABLED)) ++ return -EINVAL; ++ ++ /* That all values are in the accepted range. */ ++ if (lf->level > GENMASK(5, 0)) ++ return -EINVAL; ++ ++ if (lf->sharpness > GENMASK(2, 0)) ++ return -EINVAL; ++ ++ for (i = 0; i < ARRAY_SIZE(lf->ref_deltas); i++) { ++ if (lf->ref_deltas[i] < -63 || lf->ref_deltas[i] > 63) ++ return -EINVAL; ++ } ++ ++ for (i = 0; i < ARRAY_SIZE(lf->mode_deltas); i++) { ++ if (lf->mode_deltas[i] < -63 || lf->mode_deltas[i] > 63) ++ return -EINVAL; ++ } ++ ++ for (i = 0; i < ARRAY_SIZE(lf->level_lookup); i++) { ++ for (j = 0; j < ARRAY_SIZE(lf->level_lookup[0]); j++) { ++ for (k = 0; k < ARRAY_SIZE(lf->level_lookup[0][0]); k++) { ++ if (lf->level_lookup[i][j][k] > 63) ++ return -EINVAL; ++ } ++ } ++ } ++ ++ return 0; ++} ++ ++static int ++validate_vp9_quant_params(struct v4l2_vp9_quantization *quant) ++{ ++ if (quant->delta_q_y_dc < -15 || quant->delta_q_y_dc > 15 || ++ quant->delta_q_uv_dc < -15 || quant->delta_q_uv_dc > 15 || ++ quant->delta_q_uv_ac < -15 || quant->delta_q_uv_ac > 15) ++ return -EINVAL; ++ ++ memset(quant->padding, 0, sizeof(quant->padding)); ++ return 0; ++} ++ ++static int ++validate_vp9_seg_params(struct v4l2_vp9_segmentation *seg) ++{ ++ unsigned int i, j; ++ ++ if (seg->flags & ++ ~(V4L2_VP9_SEGMENTATION_FLAG_ENABLED | ++ V4L2_VP9_SEGMENTATION_FLAG_UPDATE_MAP | ++ V4L2_VP9_SEGMENTATION_FLAG_TEMPORAL_UPDATE | ++ V4L2_VP9_SEGMENTATION_FLAG_UPDATE_DATA | ++ V4L2_VP9_SEGMENTATION_FLAG_ABS_OR_DELTA_UPDATE)) ++ return -EINVAL; ++ ++ /* ++ * V4L2_VP9_SEGMENTATION_FLAG_UPDATE_MAP and ++ * V4L2_VP9_SEGMENTATION_FLAG_UPDATE_DATA imply ++ * V4L2_VP9_SEGMENTATION_FLAG_ENABLED. ++ */ ++ if ((seg->flags & ++ (V4L2_VP9_SEGMENTATION_FLAG_UPDATE_MAP | ++ V4L2_VP9_SEGMENTATION_FLAG_UPDATE_DATA)) && ++ !(seg->flags & V4L2_VP9_SEGMENTATION_FLAG_ENABLED)) ++ return -EINVAL; ++ ++ /* ++ * V4L2_VP9_SEGMENTATION_FLAG_TEMPORAL_UPDATE implies ++ * V4L2_VP9_SEGMENTATION_FLAG_UPDATE_MAP. ++ */ ++ if (seg->flags & V4L2_VP9_SEGMENTATION_FLAG_TEMPORAL_UPDATE && ++ !(seg->flags & V4L2_VP9_SEGMENTATION_FLAG_UPDATE_MAP)) ++ return -EINVAL; ++ ++ /* ++ * V4L2_VP9_SEGMENTATION_FLAG_ABS_OR_DELTA_UPDATE implies ++ * V4L2_VP9_SEGMENTATION_FLAG_UPDATE_DATA. ++ */ ++ if (seg->flags & V4L2_VP9_SEGMENTATION_FLAG_ABS_OR_DELTA_UPDATE && ++ !(seg->flags & V4L2_VP9_SEGMENTATION_FLAG_UPDATE_DATA)) ++ return -EINVAL; ++ ++ for (i = 0; i < ARRAY_SIZE(seg->feature_enabled); i++) { ++ if (seg->feature_enabled[i] & ++ ~(V4L2_VP9_SEGMENT_FEATURE_QP_DELTA | ++ V4L2_VP9_SEGMENT_FEATURE_LF | ++ V4L2_VP9_SEGMENT_FEATURE_REF_FRAME | ++ V4L2_VP9_SEGMENT_FEATURE_SKIP)) ++ return -EINVAL; ++ } ++ ++ for (i = 0; i < ARRAY_SIZE(seg->feature_data); i++) { ++ const int range[] = {255, 63, 3, 0}; ++ ++ for (j = 0; j < ARRAY_SIZE(seg->feature_data[j]); j++) { ++ if (seg->feature_data[i][j] < -range[j] || ++ seg->feature_data[i][j] > range[j]) ++ return -EINVAL; ++ } ++ } ++ ++ memset(seg->padding, 0, sizeof(seg->padding)); ++ return 0; ++} ++ ++static int ++validate_vp9_frame_decode_params(struct v4l2_ctrl_vp9_frame_decode_params *dec_params) ++{ ++ int ret; ++ ++ /* Make sure we're not passed invalid flags. */ ++ if (dec_params->flags & ++ ~(V4L2_VP9_FRAME_FLAG_KEY_FRAME | ++ V4L2_VP9_FRAME_FLAG_SHOW_FRAME | ++ V4L2_VP9_FRAME_FLAG_ERROR_RESILIENT | ++ V4L2_VP9_FRAME_FLAG_INTRA_ONLY | ++ V4L2_VP9_FRAME_FLAG_ALLOW_HIGH_PREC_MV | ++ V4L2_VP9_FRAME_FLAG_REFRESH_FRAME_CTX | ++ V4L2_VP9_FRAME_FLAG_PARALLEL_DEC_MODE | ++ V4L2_VP9_FRAME_FLAG_X_SUBSAMPLING | ++ V4L2_VP9_FRAME_FLAG_Y_SUBSAMPLING | ++ V4L2_VP9_FRAME_FLAG_COLOR_RANGE_FULL_SWING)) ++ return -EINVAL; ++ ++ /* ++ * The refresh context and error resilient flags are mutually exclusive. ++ * Same goes for parallel decoding and error resilient modes. ++ */ ++ if (dec_params->flags & V4L2_VP9_FRAME_FLAG_ERROR_RESILIENT && ++ dec_params->flags & ++ (V4L2_VP9_FRAME_FLAG_REFRESH_FRAME_CTX | ++ V4L2_VP9_FRAME_FLAG_PARALLEL_DEC_MODE)) ++ return -EINVAL; ++ ++ if (dec_params->profile > V4L2_VP9_PROFILE_MAX) ++ return -EINVAL; ++ ++ if (dec_params->reset_frame_context > V4L2_VP9_RESET_FRAME_CTX_ALL) ++ return -EINVAL; ++ ++ if (dec_params->frame_context_idx >= V4L2_VP9_NUM_FRAME_CTX) ++ return -EINVAL; ++ ++ /* ++ * Profiles 0 and 1 only support 8-bit depth, profiles 2 and 3 only 10 ++ * and 12 bit depths. ++ */ ++ if ((dec_params->profile < 2 && dec_params->bit_depth != 8) || ++ (dec_params->profile >= 2 && ++ (dec_params->bit_depth != 10 && dec_params->bit_depth != 12))) ++ return -EINVAL; ++ ++ /* Profile 0 and 2 only accept YUV 4:2:0. */ ++ if ((dec_params->profile == 0 || dec_params->profile == 2) && ++ (!(dec_params->flags & V4L2_VP9_FRAME_FLAG_X_SUBSAMPLING) || ++ !(dec_params->flags & V4L2_VP9_FRAME_FLAG_Y_SUBSAMPLING))) ++ return -EINVAL; ++ ++ /* Profile 1 and 3 only accept YUV 4:2:2, 4:4:0 and 4:4:4. */ ++ if ((dec_params->profile == 1 || dec_params->profile == 3) && ++ ((dec_params->flags & V4L2_VP9_FRAME_FLAG_X_SUBSAMPLING) && ++ (dec_params->flags & V4L2_VP9_FRAME_FLAG_Y_SUBSAMPLING))) ++ return -EINVAL; ++ ++ if (dec_params->interpolation_filter > V4L2_VP9_INTERP_FILTER_SWITCHABLE) ++ return -EINVAL; ++ ++ /* ++ * According to the spec, tile_cols_log2 shall be less than or equal ++ * to 6. ++ */ ++ if (dec_params->tile_cols_log2 > 6) ++ return -EINVAL; ++ ++ if (dec_params->tx_mode > V4L2_VP9_TX_MODE_SELECT) ++ return -EINVAL; ++ ++ if (dec_params->reference_mode > V4L2_VP9_REF_MODE_SELECT) ++ return -EINVAL; ++ ++ ret = validate_vp9_lf_params(&dec_params->lf); ++ if (ret) ++ return ret; ++ ++ ret = validate_vp9_quant_params(&dec_params->quant); ++ if (ret) ++ return ret; ++ ++ ret = validate_vp9_seg_params(&dec_params->seg); ++ if (ret) ++ return ret; ++ ++ memset(dec_params->padding, 0, sizeof(dec_params->padding)); ++ return 0; ++} ++ + /* Validate a new control */ + + #define zero_padding(s) \ +@@ -1838,6 +2065,12 @@ static int std_validate_compound(const struct v4l2_ctrl *ctrl, u32 idx, + zero_padding(p_vp8_frame_header->coder_state); + break; + ++ case V4L2_CTRL_TYPE_VP9_FRAME_DECODE_PARAMS: ++ return validate_vp9_frame_decode_params(p); ++ ++ case V4L2_CTRL_TYPE_VP9_FRAME_CONTEXT: ++ break; ++ + case V4L2_CTRL_TYPE_HEVC_SPS: + p_hevc_sps = p; + +@@ -2584,6 +2817,12 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl, + case V4L2_CTRL_TYPE_VP8_FRAME_HEADER: + elem_size = sizeof(struct v4l2_ctrl_vp8_frame_header); + break; ++ case V4L2_CTRL_TYPE_VP9_FRAME_CONTEXT: ++ elem_size = sizeof(struct v4l2_ctrl_vp9_frame_ctx); ++ break; ++ case V4L2_CTRL_TYPE_VP9_FRAME_DECODE_PARAMS: ++ elem_size = sizeof(struct v4l2_ctrl_vp9_frame_decode_params); ++ break; + case V4L2_CTRL_TYPE_HEVC_SPS: + elem_size = sizeof(struct v4l2_ctrl_hevc_sps); + break; +diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c +index 53de49087938..22eab942c8d4 100644 +--- a/drivers/media/v4l2-core/v4l2-ioctl.c ++++ b/drivers/media/v4l2-core/v4l2-ioctl.c +@@ -1431,6 +1431,7 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt) + case V4L2_PIX_FMT_VP8: descr = "VP8"; break; + case V4L2_PIX_FMT_VP8_FRAME: descr = "VP8 Frame"; break; + case V4L2_PIX_FMT_VP9: descr = "VP9"; break; ++ case V4L2_PIX_FMT_VP9_FRAME: descr = "VP9 Frame"; break; + case V4L2_PIX_FMT_HEVC: descr = "HEVC"; break; /* aka H.265 */ + case V4L2_PIX_FMT_HEVC_SLICE: descr = "HEVC Parsed Slice Data"; break; + case V4L2_PIX_FMT_FWHT: descr = "FWHT"; break; /* used in vicodec */ +diff --git a/include/media/v4l2-ctrls.h b/include/media/v4l2-ctrls.h +index cb25f345e9ad..c427acc964b9 100644 +--- a/include/media/v4l2-ctrls.h ++++ b/include/media/v4l2-ctrls.h +@@ -21,6 +21,7 @@ + #include + #include + #include ++#include + #include + + /* forward references */ +diff --git a/include/media/vp9-ctrls.h b/include/media/vp9-ctrls.h +new file mode 100644 +index 000000000000..0cdea8a18b72 +--- /dev/null ++++ b/include/media/vp9-ctrls.h +@@ -0,0 +1,485 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * These are the VP9 state controls for use with stateless VP9 ++ * codec drivers. ++ * ++ * It turns out that these structs are not stable yet and will undergo ++ * more changes. So keep them private until they are stable and ready to ++ * become part of the official public API. ++ */ ++ ++#ifndef _VP9_CTRLS_H_ ++#define _VP9_CTRLS_H_ ++ ++#include ++ ++#define V4L2_PIX_FMT_VP9_FRAME v4l2_fourcc('V', 'P', '9', 'F') ++ ++#define V4L2_CID_MPEG_VIDEO_VP9_FRAME_CONTEXT(i) (V4L2_CID_MPEG_BASE + 4000 + (i)) ++#define V4L2_CID_MPEG_VIDEO_VP9_FRAME_DECODE_PARAMS (V4L2_CID_MPEG_BASE + 4004) ++#define V4L2_CTRL_TYPE_VP9_FRAME_CONTEXT 0x400 ++#define V4L2_CTRL_TYPE_VP9_FRAME_DECODE_PARAMS 0x404 ++ ++/** ++ * enum v4l2_vp9_loop_filter_flags - VP9 loop filter flags ++ * ++ * @V4L2_VP9_LOOP_FILTER_FLAG_DELTA_ENABLED: the filter level depends on ++ * the mode and reference frame used ++ * to predict a block ++ * @V4L2_VP9_LOOP_FILTER_FLAG_DELTA_UPDATE: the bitstream contains additional ++ * syntax elements that specify which ++ * mode and reference frame deltas ++ * are to be updated ++ * ++ * Those are the flags you should pass to &v4l2_vp9_loop_filter.flags. See ++ * section '7.2.8 Loop filter semantics' of the VP9 specification for more ++ * details. ++ */ ++enum v4l2_vp9_loop_filter_flags { ++ V4L2_VP9_LOOP_FILTER_FLAG_DELTA_ENABLED = 1 << 0, ++ V4L2_VP9_LOOP_FILTER_FLAG_DELTA_UPDATE = 1 << 1, ++}; ++ ++/** ++ * struct v4l2_vp9_loop_filter - VP9 loop filter parameters ++ * ++ * @flags: combination of V4L2_VP9_LOOP_FILTER_FLAG_* flags ++ * @level: indicates the loop filter strength ++ * @sharpness: indicates the sharpness level ++ * @ref_deltas: contains the adjustment needed for the filter level based on ++ * the chosen reference frame ++ * @mode_deltas: contains the adjustment needed for the filter level based on ++ * the chosen mode ++ * @level_lookup: level lookup table ++ * ++ * This structure contains all loop filter related parameters. See sections ++ * '7.2.8 Loop filter semantics' and '8.8.1 Loop filter frame init process' ++ * of the VP9 specification for more details. ++ */ ++struct v4l2_vp9_loop_filter { ++ __u8 flags; ++ __u8 level; ++ __u8 sharpness; ++ __s8 ref_deltas[4]; ++ __s8 mode_deltas[2]; ++ __u8 level_lookup[8][4][2]; ++}; ++ ++/** ++ * struct v4l2_vp9_quantization - VP9 quantization parameters ++ * ++ * @base_q_idx: indicates the base frame qindex ++ * @delta_q_y_dc: indicates the Y DC quantizer relative to base_q_idx ++ * @delta_q_uv_dc: indicates the UV DC quantizer relative to base_q_idx ++ * @delta_q_uv_ac indicates the UV AC quantizer relative to base_q_idx ++ * @padding: padding bytes to align things on 64 bits. Must be set to 0 ++ * ++ * Encodes the quantization parameters. See section '7.2.9 Quantization params ++ * syntax' of the VP9 specification for more details. ++ */ ++struct v4l2_vp9_quantization { ++ __u8 base_q_idx; ++ __s8 delta_q_y_dc; ++ __s8 delta_q_uv_dc; ++ __s8 delta_q_uv_ac; ++ __u8 padding[4]; ++}; ++ ++/** ++ * enum v4l2_vp9_segmentation_flags - VP9 segmentation flags ++ * ++ * @V4L2_VP9_SEGMENTATION_FLAG_ENABLED: indicates that this frame makes use of ++ * the segmentation tool ++ * @V4L2_VP9_SEGMENTATION_FLAG_UPDATE_MAP: indicates that the segmentation map ++ * should be updated during the ++ * decoding of this frame ++ * @V4L2_VP9_SEGMENTATION_FLAG_TEMPORAL_UPDATE: indicates that the updates to ++ * the segmentation map are coded ++ * relative to the existing ++ * segmentation map ++ * @V4L2_VP9_SEGMENTATION_FLAG_UPDATE_DATA: indicates that new parameters are ++ * about to be specified for each ++ * segment ++ * @V4L2_VP9_SEGMENTATION_FLAG_ABS_OR_DELTA_UPDATE: indicates that the ++ * segmentation parameters ++ * represent the actual values ++ * to be used ++ * ++ * Those are the flags you should pass to &v4l2_vp9_segmentation.flags. See ++ * section '7.2.10 Segmentation params syntax' of the VP9 specification for ++ * more details. ++ */ ++enum v4l2_vp9_segmentation_flags { ++ V4L2_VP9_SEGMENTATION_FLAG_ENABLED = 1 << 0, ++ V4L2_VP9_SEGMENTATION_FLAG_UPDATE_MAP = 1 << 1, ++ V4L2_VP9_SEGMENTATION_FLAG_TEMPORAL_UPDATE = 1 << 2, ++ V4L2_VP9_SEGMENTATION_FLAG_UPDATE_DATA = 1 << 3, ++ V4L2_VP9_SEGMENTATION_FLAG_ABS_OR_DELTA_UPDATE = 1 << 4, ++}; ++ ++#define V4L2_VP9_SEGMENT_FEATURE_ENABLED(id) (1 << (id)) ++#define V4L2_VP9_SEGMENT_FEATURE_ENABLED_MASK 0xf ++ ++/** ++ * enum v4l2_vp9_segment_feature - VP9 segment feature IDs ++ * ++ * @V4L2_VP9_SEGMENT_FEATURE_QP_DELTA: QP delta segment feature ++ * @V4L2_VP9_SEGMENT_FEATURE_LF: loop filter segment feature ++ * @V4L2_VP9_SEGMENT_FEATURE_REF_FRAME: reference frame segment feature ++ * @V4L2_VP9_SEGMENT_FEATURE_SKIP: skip segment feature ++ * @V4L2_VP9_SEGMENT_FEATURE_CNT: number of segment features ++ * ++ * Segment feature IDs. See section '7.2.10 Segmentation params syntax' of the ++ * VP9 specification for more details. ++ */ ++enum v4l2_vp9_segment_feature { ++ V4L2_VP9_SEGMENT_FEATURE_QP_DELTA, ++ V4L2_VP9_SEGMENT_FEATURE_LF, ++ V4L2_VP9_SEGMENT_FEATURE_REF_FRAME, ++ V4L2_VP9_SEGMENT_FEATURE_SKIP, ++ V4L2_VP9_SEGMENT_FEATURE_CNT, ++}; ++ ++/** ++ * struct v4l2_vp9_segmentation - VP9 segmentation parameters ++ * ++ * @flags: combination of V4L2_VP9_SEGMENTATION_FLAG_* flags ++ * @tree_probs: specifies the probability values to be used when ++ * decoding a Segment-ID. See '5.15. Segmentation map' ++ * section of the VP9 specification for more details. ++ * @pred_prob: specifies the probability values to be used when decoding a ++ * Predicted-Segment-ID. See '6.4.14. Get segment id syntax' ++ * section of :ref:`vp9` for more details.. ++ * @padding: padding used to make things aligned on 64 bits. Shall be zero ++ * filled ++ * @feature_enabled: bitmask defining which features are enabled in each ++ * segment ++ * @feature_data: data attached to each feature. Data entry is only valid if ++ * the feature is enabled ++ * ++ * Encodes the quantization parameters. See section '7.2.10 Segmentation ++ * params syntax' of the VP9 specification for more details. ++ */ ++struct v4l2_vp9_segmentation { ++ __u8 flags; ++ __u8 tree_probs[7]; ++ __u8 pred_probs[3]; ++ __u8 padding[5]; ++ __u8 feature_enabled[8]; ++ __s16 feature_data[8][4]; ++}; ++ ++/** ++ * enum v4l2_vp9_intra_prediction_mode - VP9 Intra prediction modes ++ * ++ * @V4L2_VP9_INTRA_PRED_DC: DC intra prediction ++ * @V4L2_VP9_INTRA_PRED_MODE_V: vertical intra prediction ++ * @V4L2_VP9_INTRA_PRED_MODE_H: horizontal intra prediction ++ * @V4L2_VP9_INTRA_PRED_MODE_D45: D45 intra prediction ++ * @V4L2_VP9_INTRA_PRED_MODE_D135: D135 intra prediction ++ * @V4L2_VP9_INTRA_PRED_MODE_D117: D117 intra prediction ++ * @V4L2_VP9_INTRA_PRED_MODE_D153: D153 intra prediction ++ * @V4L2_VP9_INTRA_PRED_MODE_D207: D207 intra prediction ++ * @V4L2_VP9_INTRA_PRED_MODE_D63: D63 intra prediction ++ * @V4L2_VP9_INTRA_PRED_MODE_TM: True Motion intra prediction ++ * ++ * See section '7.4.5 Intra frame mode info semantics' for more details. ++ */ ++enum v4l2_vp9_intra_prediction_mode { ++ V4L2_VP9_INTRA_PRED_MODE_DC, ++ V4L2_VP9_INTRA_PRED_MODE_V, ++ V4L2_VP9_INTRA_PRED_MODE_H, ++ V4L2_VP9_INTRA_PRED_MODE_D45, ++ V4L2_VP9_INTRA_PRED_MODE_D135, ++ V4L2_VP9_INTRA_PRED_MODE_D117, ++ V4L2_VP9_INTRA_PRED_MODE_D153, ++ V4L2_VP9_INTRA_PRED_MODE_D207, ++ V4L2_VP9_INTRA_PRED_MODE_D63, ++ V4L2_VP9_INTRA_PRED_MODE_TM, ++}; ++ ++/** ++ * struct v4l2_vp9_mv_probabilities - VP9 Motion vector probabilities ++ * @joint: motion vector joint probabilities ++ * @sign: motion vector sign probabilities ++ * @class: motion vector class probabilities ++ * @class0_bit: motion vector class0 bit probabilities ++ * @bits: motion vector bits probabilities ++ * @class0_fr: motion vector class0 fractional bit probabilities ++ * @fr: motion vector fractional bit probabilities ++ * @class0_hp: motion vector class0 high precision fractional bit probabilities ++ * @hp: motion vector high precision fractional bit probabilities ++ */ ++struct v4l2_vp9_mv_probabilities { ++ __u8 joint[3]; ++ __u8 sign[2]; ++ __u8 class[2][10]; ++ __u8 class0_bit[2]; ++ __u8 bits[2][10]; ++ __u8 class0_fr[2][2][3]; ++ __u8 fr[2][3]; ++ __u8 class0_hp[2]; ++ __u8 hp[2]; ++}; ++ ++/** ++ * struct v4l2_vp9_probabilities - VP9 Probabilities ++ * ++ * @tx8: TX 8x8 probabilities ++ * @tx16: TX 16x16 probabilities ++ * @tx32: TX 32x32 probabilities ++ * @coef: coefficient probabilities ++ * @skip: skip probabilities ++ * @inter_mode: inter mode probabilities ++ * @interp_filter: interpolation filter probabilities ++ * @is_inter: is inter-block probabilities ++ * @comp_mode: compound prediction mode probabilities ++ * @single_ref: single ref probabilities ++ * @comp_ref: compound ref probabilities ++ * @y_mode: Y prediction mode probabilities ++ * @uv_mode: UV prediction mode probabilities ++ * @partition: partition probabilities ++ * @mv: motion vector probabilities ++ * ++ * Structure containing most VP9 probabilities. See the VP9 specification ++ * for more details. ++ */ ++struct v4l2_vp9_probabilities { ++ __u8 tx8[2][1]; ++ __u8 tx16[2][2]; ++ __u8 tx32[2][3]; ++ __u8 coef[4][2][2][6][6][3]; ++ __u8 skip[3]; ++ __u8 inter_mode[7][3]; ++ __u8 interp_filter[4][2]; ++ __u8 is_inter[4]; ++ __u8 comp_mode[5]; ++ __u8 single_ref[5][2]; ++ __u8 comp_ref[5]; ++ __u8 y_mode[4][9]; ++ __u8 uv_mode[10][9]; ++ __u8 partition[16][3]; ++ ++ struct v4l2_vp9_mv_probabilities mv; ++}; ++ ++/** ++ * enum v4l2_vp9_reset_frame_context - Valid values for ++ * &v4l2_ctrl_vp9_frame_decode_params->reset_frame_context ++ * ++ * @V4L2_VP9_RESET_FRAME_CTX_NONE: don't reset any frame context ++ * @V4L2_VP9_RESET_FRAME_CTX_SPEC: reset the frame context pointed by ++ * &v4l2_ctrl_vp9_frame_decode_params.frame_context_idx ++ * @V4L2_VP9_RESET_FRAME_CTX_ALL: reset all frame contexts ++ * ++ * See section '7.2 Uncompressed header semantics' of the VP9 specification ++ * for more details. ++ */ ++enum v4l2_vp9_reset_frame_context { ++ V4L2_VP9_RESET_FRAME_CTX_NONE, ++ V4L2_VP9_RESET_FRAME_CTX_SPEC, ++ V4L2_VP9_RESET_FRAME_CTX_ALL, ++}; ++ ++/** ++ * enum v4l2_vp9_interpolation_filter - VP9 interpolation filter types ++ * ++ * @V4L2_VP9_INTERP_FILTER_8TAP: height tap filter ++ * @V4L2_VP9_INTERP_FILTER_8TAP_SMOOTH: height tap smooth filter ++ * @V4L2_VP9_INTERP_FILTER_8TAP_SHARP: height tap sharp filter ++ * @V4L2_VP9_INTERP_FILTER_BILINEAR: bilinear filter ++ * @V4L2_VP9_INTERP_FILTER_SWITCHABLE: filter selection is signaled at the ++ * block level ++ * ++ * See section '7.2.7 Interpolation filter semantics' of the VP9 specification ++ * for more details. ++ */ ++enum v4l2_vp9_interpolation_filter { ++ V4L2_VP9_INTERP_FILTER_8TAP, ++ V4L2_VP9_INTERP_FILTER_8TAP_SMOOTH, ++ V4L2_VP9_INTERP_FILTER_8TAP_SHARP, ++ V4L2_VP9_INTERP_FILTER_BILINEAR, ++ V4L2_VP9_INTERP_FILTER_SWITCHABLE, ++}; ++ ++/** ++ * enum v4l2_vp9_reference_mode - VP9 reference modes ++ * ++ * @V4L2_VP9_REF_MODE_SINGLE: indicates that all the inter blocks use only a ++ * single reference frame to generate motion ++ * compensated prediction ++ * @V4L2_VP9_REF_MODE_COMPOUND: requires all the inter blocks to use compound ++ * mode. Single reference frame prediction is not ++ * allowed ++ * @V4L2_VP9_REF_MODE_SELECT: allows each individual inter block to select ++ * between single and compound prediction modes ++ * ++ * See section '7.3.6 Frame reference mode semantics' of the VP9 specification ++ * for more details. ++ */ ++enum v4l2_vp9_reference_mode { ++ V4L2_VP9_REF_MODE_SINGLE, ++ V4L2_VP9_REF_MODE_COMPOUND, ++ V4L2_VP9_REF_MODE_SELECT, ++}; ++ ++/** ++ * enum v4l2_vp9_tx_mode - VP9 TX modes ++ * ++ * @V4L2_VP9_TX_MODE_ONLY_4X4: transform size is 4x4 ++ * @V4L2_VP9_TX_MODE_ALLOW_8X8: transform size can be up to 8x8 ++ * @V4L2_VP9_TX_MODE_ALLOW_16X16: transform size can be up to 16x16 ++ * @V4L2_VP9_TX_MODE_ALLOW_32X32: transform size can be up to 32x32 ++ * @V4L2_VP9_TX_MODE_SELECT: bitstream contains transform size for each block ++ * ++ * See section '7.3.1 Tx mode semantics' of the VP9 specification for more ++ * details. ++ */ ++enum v4l2_vp9_tx_mode { ++ V4L2_VP9_TX_MODE_ONLY_4X4, ++ V4L2_VP9_TX_MODE_ALLOW_8X8, ++ V4L2_VP9_TX_MODE_ALLOW_16X16, ++ V4L2_VP9_TX_MODE_ALLOW_32X32, ++ V4L2_VP9_TX_MODE_SELECT, ++}; ++ ++/** ++ * enum v4l2_vp9_ref_id - VP9 Reference frame IDs ++ * ++ * @V4L2_REF_ID_LAST: last reference frame ++ * @V4L2_REF_ID_GOLDEN: golden reference frame ++ * @V4L2_REF_ID_ALTREF: alternative reference frame ++ * @V4L2_REF_ID_CNT: number of reference frames ++ * ++ * See section '7.4.12 Ref frames semantics' of the VP9 specification for more ++ * details. ++ */ ++enum v4l2_vp9_ref_id { ++ V4L2_REF_ID_LAST, ++ V4L2_REF_ID_GOLDEN, ++ V4L2_REF_ID_ALTREF, ++ V4L2_REF_ID_CNT, ++}; ++ ++/** ++ * enum v4l2_vp9_frame_flags - VP9 frame flags ++ * @V4L2_VP9_FRAME_FLAG_KEY_FRAME: the frame is a key frame ++ * @V4L2_VP9_FRAME_FLAG_SHOW_FRAME: the frame should be displayed ++ * @V4L2_VP9_FRAME_FLAG_ERROR_RESILIENT: the decoding should be error resilient ++ * @V4L2_VP9_FRAME_FLAG_INTRA_ONLY: the frame does not reference other frames ++ * @V4L2_VP9_FRAME_FLAG_ALLOW_HIGH_PREC_MV: the frame might can high precision ++ * motion vectors ++ * @V4L2_VP9_FRAME_FLAG_REFRESH_FRAME_CTX: frame context should be updated ++ * after decoding ++ * @V4L2_VP9_FRAME_FLAG_PARALLEL_DEC_MODE: parallel decoding is used ++ * @V4L2_VP9_FRAME_FLAG_X_SUBSAMPLING: vertical subsampling is enabled ++ * @V4L2_VP9_FRAME_FLAG_Y_SUBSAMPLING: horizontal subsampling is enabled ++ * @V4L2_VP9_FRAME_FLAG_COLOR_RANGE_FULL_SWING: full UV range is used ++ * ++ * Check the VP9 specification for more details. ++ */ ++enum v4l2_vp9_frame_flags { ++ V4L2_VP9_FRAME_FLAG_KEY_FRAME = 1 << 0, ++ V4L2_VP9_FRAME_FLAG_SHOW_FRAME = 1 << 1, ++ V4L2_VP9_FRAME_FLAG_ERROR_RESILIENT = 1 << 2, ++ V4L2_VP9_FRAME_FLAG_INTRA_ONLY = 1 << 3, ++ V4L2_VP9_FRAME_FLAG_ALLOW_HIGH_PREC_MV = 1 << 4, ++ V4L2_VP9_FRAME_FLAG_REFRESH_FRAME_CTX = 1 << 5, ++ V4L2_VP9_FRAME_FLAG_PARALLEL_DEC_MODE = 1 << 6, ++ V4L2_VP9_FRAME_FLAG_X_SUBSAMPLING = 1 << 7, ++ V4L2_VP9_FRAME_FLAG_Y_SUBSAMPLING = 1 << 8, ++ V4L2_VP9_FRAME_FLAG_COLOR_RANGE_FULL_SWING = 1 << 9, ++}; ++ ++#define V4L2_VP9_PROFILE_MAX 3 ++ ++/** ++ * struct v4l2_ctrl_vp9_frame_decode_params - VP9 frame decoding control ++ * ++ * @flags: combination of V4L2_VP9_FRAME_FLAG_* flags ++ * @compressed_header_size: compressed header size in bytes ++ * @uncompressed_header_size: uncompressed header size in bytes ++ * @profile: VP9 profile. Can be 0, 1, 2 or 3 ++ * @reset_frame_context: specifies whether the frame context should be reset ++ * to default values. See &v4l2_vp9_reset_frame_context ++ * for more details ++ * @frame_context_idx: frame context that should be used/updated ++ * @bit_depth: bits per components. Can be 8, 10 or 12. Note that not all ++ * profiles support 10 and/or 12 bits depths ++ * @interpolation_filter: specifies the filter selection used for performing ++ * inter prediction. See &v4l2_vp9_interpolation_filter ++ * for more details ++ * @tile_cols_log2: specifies the base 2 logarithm of the width of each tile ++ * (where the width is measured in units of 8x8 blocks). ++ * Shall be less than or equal to 6 ++ * @tile_rows_log2: specifies the base 2 logarithm of the height of each tile ++ * (where the height is measured in units of 8x8 blocks) ++ * @tx_mode: specifies the TX mode. See &v4l2_vp9_tx_mode for more details ++ * @reference_mode: specifies the type of inter prediction to be used. See ++ * &v4l2_vp9_reference_mode for more details ++ * @padding: needed to make this struct 64 bit aligned. Shall be filled with ++ * zeros ++ * @frame_width_minus_1: add 1 to it and you'll get the frame width expressed ++ * in pixels ++ * @frame_height_minus_1: add 1 to it and you'll get the frame height expressed ++ * in pixels ++ * @frame_width_minus_1: add 1 to it and you'll get the expected render width ++ * expressed in pixels. This is not used during the ++ * decoding process but might be used by HW scalers to ++ * prepare a frame that's ready for scanout ++ * @frame_height_minus_1: add 1 to it and you'll get the expected render height ++ * expressed in pixels. This is not used during the ++ * decoding process but might be used by HW scalers to ++ * prepare a frame that's ready for scanout ++ * @refs: array of reference frames. See &v4l2_vp9_ref_id for more details ++ * @lf: loop filter parameters. See &v4l2_vp9_loop_filter for more details ++ * @quant: quantization parameters. See &v4l2_vp9_quantization for more details ++ * @seg: segmentation parameters. See &v4l2_vp9_segmentation for more details ++ * @probs: probabilities. See &v4l2_vp9_probabilities for more details ++ */ ++struct v4l2_ctrl_vp9_frame_decode_params { ++ __u32 flags; ++ __u16 compressed_header_size; ++ __u16 uncompressed_header_size; ++ __u8 profile; ++ __u8 reset_frame_context; ++ __u8 frame_context_idx; ++ __u8 bit_depth; ++ __u8 interpolation_filter; ++ __u8 tile_cols_log2; ++ __u8 tile_rows_log2; ++ __u8 tx_mode; ++ __u8 reference_mode; ++ __u8 padding[6]; ++ __u16 frame_width_minus_1; ++ __u16 frame_height_minus_1; ++ __u16 render_width_minus_1; ++ __u16 render_height_minus_1; ++ __u64 refs[V4L2_REF_ID_CNT]; ++ struct v4l2_vp9_loop_filter lf; ++ struct v4l2_vp9_quantization quant; ++ struct v4l2_vp9_segmentation seg; ++ struct v4l2_vp9_probabilities probs; ++}; ++ ++#define V4L2_VP9_NUM_FRAME_CTX 4 ++ ++/** ++ * struct v4l2_ctrl_vp9_frame_ctx - VP9 frame context control ++ * ++ * @probs: VP9 probabilities ++ * ++ * This control is accessed in both direction. The user should initialize the ++ * 4 contexts with default values just after starting the stream. Then before ++ * decoding a frame it should query the current frame context (the one passed ++ * through &v4l2_ctrl_vp9_frame_decode_params.frame_context_idx) to initialize ++ * &v4l2_ctrl_vp9_frame_decode_params.probs. The probs are then adjusted based ++ * on the bitstream info and passed to the kernel. The codec should update ++ * the frame context after the frame has been decoded, so that next time ++ * userspace query this context it contains the updated probabilities. ++ */ ++struct v4l2_ctrl_vp9_frame_ctx { ++ struct v4l2_vp9_probabilities probs; ++}; ++ ++#endif /* _VP9_CTRLS_H_ */ + +From 3e089d23e73a5eb2b070f875845ff423a492f3ba Mon Sep 17 00:00:00 2001 +From: Boris Brezillon +Date: Mon, 18 May 2020 14:40:11 -0300 +Subject: [PATCH] media: rkvdec: Add the VP9 backend + +The Rockchip VDEC supports VP9 profile 0 up to 4096x2304@30fps. Add +a backend for this new format. + +Signed-off-by: Boris Brezillon +Signed-off-by: Ezequiel Garcia +--- + drivers/staging/media/rkvdec/Makefile | 2 +- + drivers/staging/media/rkvdec/rkvdec-vp9.c | 1577 +++++++++++++++++++++ + drivers/staging/media/rkvdec/rkvdec.c | 54 + + drivers/staging/media/rkvdec/rkvdec.h | 6 + + 4 files changed, 1638 insertions(+), 1 deletion(-) + create mode 100644 drivers/staging/media/rkvdec/rkvdec-vp9.c + +diff --git a/drivers/staging/media/rkvdec/Makefile b/drivers/staging/media/rkvdec/Makefile +index c08fed0a39f9..cb86b429cfaa 100644 +--- a/drivers/staging/media/rkvdec/Makefile ++++ b/drivers/staging/media/rkvdec/Makefile +@@ -1,3 +1,3 @@ + obj-$(CONFIG_VIDEO_ROCKCHIP_VDEC) += rockchip-vdec.o + +-rockchip-vdec-y += rkvdec.o rkvdec-h264.o ++rockchip-vdec-y += rkvdec.o rkvdec-h264.o rkvdec-vp9.o +diff --git a/drivers/staging/media/rkvdec/rkvdec-vp9.c b/drivers/staging/media/rkvdec/rkvdec-vp9.c +new file mode 100644 +index 000000000000..37d0ea4e3570 +--- /dev/null ++++ b/drivers/staging/media/rkvdec/rkvdec-vp9.c +@@ -0,0 +1,1577 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Rockchip Video Decoder VP9 backend ++ * ++ * Copyright (C) 2019 Collabora, Ltd. ++ * Boris Brezillon ++ * ++ * Copyright (C) 2016 Rockchip Electronics Co., Ltd. ++ * Alpha Lin ++ */ ++ ++#include ++#include ++#include ++ ++#include "rkvdec.h" ++#include "rkvdec-regs.h" ++ ++#define RKVDEC_VP9_PROBE_SIZE 4864 ++#define RKVDEC_VP9_COUNT_SIZE 13232 ++#define RKVDEC_VP9_MAX_SEGMAP_SIZE 73728 ++ ++struct rkvdec_vp9_intra_mode_probs { ++ u8 y_mode[105]; ++ u8 uv_mode[23]; ++}; ++ ++struct rkvdec_vp9_intra_only_frame_probs { ++ u8 coef_intra[4][2][128]; ++ struct rkvdec_vp9_intra_mode_probs intra_mode[10]; ++}; ++ ++struct rkvdec_vp9_inter_frame_probs { ++ u8 y_mode[4][9]; ++ u8 comp_mode[5]; ++ u8 comp_ref[5]; ++ u8 single_ref[5][2]; ++ u8 inter_mode[7][3]; ++ u8 interp_filter[4][2]; ++ u8 padding0[11]; ++ u8 coef[2][4][2][128]; ++ u8 uv_mode_0_2[3][9]; ++ u8 padding1[5]; ++ u8 uv_mode_3_5[3][9]; ++ u8 padding2[5]; ++ u8 uv_mode_6_8[3][9]; ++ u8 padding3[5]; ++ u8 uv_mode_9[9]; ++ u8 padding4[7]; ++ u8 padding5[16]; ++ struct { ++ u8 joint[3]; ++ u8 sign[2]; ++ u8 class[2][10]; ++ u8 class0_bit[2]; ++ u8 bits[2][10]; ++ u8 class0_fr[2][2][3]; ++ u8 fr[2][3]; ++ u8 class0_hp[2]; ++ u8 hp[2]; ++ } mv; ++}; ++ ++struct rkvdec_vp9_probs { ++ u8 partition[16][3]; ++ u8 pred[3]; ++ u8 tree[7]; ++ u8 skip[3]; ++ u8 tx32[2][3]; ++ u8 tx16[2][2]; ++ u8 tx8[2][1]; ++ u8 is_inter[4]; ++ /* 128 bit alignment */ ++ u8 padding0[3]; ++ union { ++ struct rkvdec_vp9_inter_frame_probs inter; ++ struct rkvdec_vp9_intra_only_frame_probs intra_only; ++ }; ++}; ++ ++/* Data structure describing auxiliary buffer format. */ ++struct rkvdec_vp9_priv_tbl { ++ struct rkvdec_vp9_probs probs; ++ u8 segmap[2][RKVDEC_VP9_MAX_SEGMAP_SIZE]; ++}; ++ ++struct rkvdec_vp9_refs_counts { ++ u32 eob[2]; ++ u32 coeff[3]; ++}; ++ ++struct rkvdec_vp9_inter_frame_symbol_counts { ++ u32 partition[16][4]; ++ u32 skip[3][2]; ++ u32 inter[4][2]; ++ u32 tx32p[2][4]; ++ u32 tx16p[2][4]; ++ u32 tx8p[2][2]; ++ u32 y_mode[4][10]; ++ u32 uv_mode[10][10]; ++ u32 comp[5][2]; ++ u32 comp_ref[5][2]; ++ u32 single_ref[5][2][2]; ++ u32 mv_mode[7][4]; ++ u32 filter[4][3]; ++ u32 mv_joint[4]; ++ u32 sign[2][2]; ++ /* add 1 element for align */ ++ u32 classes[2][11 + 1]; ++ u32 class0[2][2]; ++ u32 bits[2][10][2]; ++ u32 class0_fp[2][2][4]; ++ u32 fp[2][4]; ++ u32 class0_hp[2][2]; ++ u32 hp[2][2]; ++ struct rkvdec_vp9_refs_counts ref_cnt[2][4][2][6][6]; ++}; ++ ++struct rkvdec_vp9_intra_frame_symbol_counts { ++ u32 partition[4][4][4]; ++ u32 skip[3][2]; ++ u32 intra[4][2]; ++ u32 tx32p[2][4]; ++ u32 tx16p[2][4]; ++ u32 tx8p[2][2]; ++ struct rkvdec_vp9_refs_counts ref_cnt[2][4][2][6][6]; ++}; ++ ++struct rkvdec_vp9_run { ++ struct rkvdec_run base; ++ const struct v4l2_ctrl_vp9_frame_decode_params *decode_params; ++}; ++ ++struct rkvdec_vp9_frame_info { ++ u32 valid : 1; ++ u32 segmapid : 1; ++ u32 frame_context_idx : 2; ++ u32 reference_mode : 2; ++ u32 tx_mode : 3; ++ u32 interpolation_filter : 3; ++ u32 flags; ++ u64 timestamp; ++ struct v4l2_vp9_segmentation seg; ++ struct v4l2_vp9_loop_filter lf; ++}; ++ ++struct rkvdec_vp9_ctx { ++ struct rkvdec_aux_buf priv_tbl; ++ struct rkvdec_aux_buf count_tbl; ++ struct v4l2_ctrl_vp9_frame_ctx frame_context; ++ struct rkvdec_vp9_frame_info cur; ++ struct rkvdec_vp9_frame_info last; ++}; ++ ++static u32 rkvdec_fastdiv(u32 dividend, u16 divisor) ++{ ++#define DIV_INV(d) (u32)(((1ULL << 32) + ((d) - 1)) / (d)) ++#define DIVS_INV(d0, d1, d2, d3, d4, d5, d6, d7, d8, d9) \ ++ DIV_INV(d0), DIV_INV(d1), DIV_INV(d2), DIV_INV(d3), \ ++ DIV_INV(d4), DIV_INV(d5), DIV_INV(d6), DIV_INV(d7), \ ++ DIV_INV(d8), DIV_INV(d9) ++ ++ static const u32 inv[] = { ++ DIV_INV(2), DIV_INV(3), DIV_INV(4), DIV_INV(5), ++ DIV_INV(6), DIV_INV(7), DIV_INV(8), DIV_INV(9), ++ DIVS_INV(10, 11, 12, 13, 14, 15, 16, 17, 18, 19), ++ DIVS_INV(20, 21, 22, 23, 24, 25, 26, 27, 28, 29), ++ DIVS_INV(30, 31, 32, 33, 34, 35, 36, 37, 38, 39), ++ DIVS_INV(40, 41, 42, 43, 44, 45, 46, 47, 48, 49), ++ DIVS_INV(50, 51, 52, 53, 54, 55, 56, 57, 58, 59), ++ DIVS_INV(60, 61, 62, 63, 64, 65, 66, 67, 68, 69), ++ DIVS_INV(70, 71, 72, 73, 74, 75, 76, 77, 78, 79), ++ DIVS_INV(80, 81, 82, 83, 84, 85, 86, 87, 88, 89), ++ DIVS_INV(90, 91, 92, 93, 94, 95, 96, 97, 98, 99), ++ DIVS_INV(100, 101, 102, 103, 104, 105, 106, 107, 108, 109), ++ DIVS_INV(110, 111, 112, 113, 114, 115, 116, 117, 118, 119), ++ DIVS_INV(120, 121, 122, 123, 124, 125, 126, 127, 128, 129), ++ DIVS_INV(130, 131, 132, 133, 134, 135, 136, 137, 138, 139), ++ DIVS_INV(140, 141, 142, 143, 144, 145, 146, 147, 148, 149), ++ DIVS_INV(150, 151, 152, 153, 154, 155, 156, 157, 158, 159), ++ DIVS_INV(160, 161, 162, 163, 164, 165, 166, 167, 168, 169), ++ DIVS_INV(170, 171, 172, 173, 174, 175, 176, 177, 178, 179), ++ DIVS_INV(180, 181, 182, 183, 184, 185, 186, 187, 188, 189), ++ DIVS_INV(190, 191, 192, 193, 194, 195, 196, 197, 198, 199), ++ DIVS_INV(200, 201, 202, 203, 204, 205, 206, 207, 208, 209), ++ DIVS_INV(210, 211, 212, 213, 214, 215, 216, 217, 218, 219), ++ DIVS_INV(220, 221, 222, 223, 224, 225, 226, 227, 228, 229), ++ DIVS_INV(230, 231, 232, 233, 234, 235, 236, 237, 238, 239), ++ DIVS_INV(240, 241, 242, 243, 244, 245, 246, 247, 248, 249), ++ DIV_INV(250), DIV_INV(251), DIV_INV(252), DIV_INV(253), ++ DIV_INV(254), DIV_INV(255), DIV_INV(256), ++ }; ++ ++ if (divisor == 0) ++ return 0; ++ else if (divisor == 1) ++ return dividend; ++ ++ if (WARN_ON(divisor - 2 >= ARRAY_SIZE(inv))) ++ return dividend; ++ ++ return ((u64)dividend * inv[divisor - 2]) >> 32; ++} ++ ++static const u8 vp9_kf_y_mode_prob[10][10][9] = { ++ { ++ /* above = dc */ ++ { 137, 30, 42, 148, 151, 207, 70, 52, 91 },/*left = dc */ ++ { 92, 45, 102, 136, 116, 180, 74, 90, 100 },/*left = v */ ++ { 73, 32, 19, 187, 222, 215, 46, 34, 100 },/*left = h */ ++ { 91, 30, 32, 116, 121, 186, 93, 86, 94 },/*left = d45 */ ++ { 72, 35, 36, 149, 68, 206, 68, 63, 105 },/*left = d135*/ ++ { 73, 31, 28, 138, 57, 124, 55, 122, 151 },/*left = d117*/ ++ { 67, 23, 21, 140, 126, 197, 40, 37, 171 },/*left = d153*/ ++ { 86, 27, 28, 128, 154, 212, 45, 43, 53 },/*left = d207*/ ++ { 74, 32, 27, 107, 86, 160, 63, 134, 102 },/*left = d63 */ ++ { 59, 67, 44, 140, 161, 202, 78, 67, 119 } /*left = tm */ ++ }, { /* above = v */ ++ { 63, 36, 126, 146, 123, 158, 60, 90, 96 },/*left = dc */ ++ { 43, 46, 168, 134, 107, 128, 69, 142, 92 },/*left = v */ ++ { 44, 29, 68, 159, 201, 177, 50, 57, 77 },/*left = h */ ++ { 58, 38, 76, 114, 97, 172, 78, 133, 92 },/*left = d45 */ ++ { 46, 41, 76, 140, 63, 184, 69, 112, 57 },/*left = d135*/ ++ { 38, 32, 85, 140, 46, 112, 54, 151, 133 },/*left = d117*/ ++ { 39, 27, 61, 131, 110, 175, 44, 75, 136 },/*left = d153*/ ++ { 52, 30, 74, 113, 130, 175, 51, 64, 58 },/*left = d207*/ ++ { 47, 35, 80, 100, 74, 143, 64, 163, 74 },/*left = d63 */ ++ { 36, 61, 116, 114, 128, 162, 80, 125, 82 } /*left = tm */ ++ }, { /* above = h */ ++ { 82, 26, 26, 171, 208, 204, 44, 32, 105 },/*left = dc */ ++ { 55, 44, 68, 166, 179, 192, 57, 57, 108 },/*left = v */ ++ { 42, 26, 11, 199, 241, 228, 23, 15, 85 },/*left = h */ ++ { 68, 42, 19, 131, 160, 199, 55, 52, 83 },/*left = d45 */ ++ { 58, 50, 25, 139, 115, 232, 39, 52, 118 },/*left = d135*/ ++ { 50, 35, 33, 153, 104, 162, 64, 59, 131 },/*left = d117*/ ++ { 44, 24, 16, 150, 177, 202, 33, 19, 156 },/*left = d153*/ ++ { 55, 27, 12, 153, 203, 218, 26, 27, 49 },/*left = d207*/ ++ { 53, 49, 21, 110, 116, 168, 59, 80, 76 },/*left = d63 */ ++ { 38, 72, 19, 168, 203, 212, 50, 50, 107 } /*left = tm */ ++ }, { /* above = d45 */ ++ { 103, 26, 36, 129, 132, 201, 83, 80, 93 },/*left = dc */ ++ { 59, 38, 83, 112, 103, 162, 98, 136, 90 },/*left = v */ ++ { 62, 30, 23, 158, 200, 207, 59, 57, 50 },/*left = h */ ++ { 67, 30, 29, 84, 86, 191, 102, 91, 59 },/*left = d45 */ ++ { 60, 32, 33, 112, 71, 220, 64, 89, 104 },/*left = d135*/ ++ { 53, 26, 34, 130, 56, 149, 84, 120, 103 },/*left = d117*/ ++ { 53, 21, 23, 133, 109, 210, 56, 77, 172 },/*left = d153*/ ++ { 77, 19, 29, 112, 142, 228, 55, 66, 36 },/*left = d207*/ ++ { 61, 29, 29, 93, 97, 165, 83, 175, 162 },/*left = d63 */ ++ { 47, 47, 43, 114, 137, 181, 100, 99, 95 } /*left = tm */ ++ }, { /* above = d135 */ ++ { 69, 23, 29, 128, 83, 199, 46, 44, 101 },/*left = dc */ ++ { 53, 40, 55, 139, 69, 183, 61, 80, 110 },/*left = v */ ++ { 40, 29, 19, 161, 180, 207, 43, 24, 91 },/*left = h */ ++ { 60, 34, 19, 105, 61, 198, 53, 64, 89 },/*left = d45 */ ++ { 52, 31, 22, 158, 40, 209, 58, 62, 89 },/*left = d135*/ ++ { 44, 31, 29, 147, 46, 158, 56, 102, 198 },/*left = d117*/ ++ { 35, 19, 12, 135, 87, 209, 41, 45, 167 },/*left = d153*/ ++ { 55, 25, 21, 118, 95, 215, 38, 39, 66 },/*left = d207*/ ++ { 51, 38, 25, 113, 58, 164, 70, 93, 97 },/*left = d63 */ ++ { 47, 54, 34, 146, 108, 203, 72, 103, 151 } /*left = tm */ ++ }, { /* above = d117 */ ++ { 64, 19, 37, 156, 66, 138, 49, 95, 133 },/*left = dc */ ++ { 46, 27, 80, 150, 55, 124, 55, 121, 135 },/*left = v */ ++ { 36, 23, 27, 165, 149, 166, 54, 64, 118 },/*left = h */ ++ { 53, 21, 36, 131, 63, 163, 60, 109, 81 },/*left = d45 */ ++ { 40, 26, 35, 154, 40, 185, 51, 97, 123 },/*left = d135*/ ++ { 35, 19, 34, 179, 19, 97, 48, 129, 124 },/*left = d117*/ ++ { 36, 20, 26, 136, 62, 164, 33, 77, 154 },/*left = d153*/ ++ { 45, 18, 32, 130, 90, 157, 40, 79, 91 },/*left = d207*/ ++ { 45, 26, 28, 129, 45, 129, 49, 147, 123 },/*left = d63 */ ++ { 38, 44, 51, 136, 74, 162, 57, 97, 121 } /*left = tm */ ++ }, { /* above = d153 */ ++ { 75, 17, 22, 136, 138, 185, 32, 34, 166 },/*left = dc */ ++ { 56, 39, 58, 133, 117, 173, 48, 53, 187 },/*left = v */ ++ { 35, 21, 12, 161, 212, 207, 20, 23, 145 },/*left = h */ ++ { 56, 29, 19, 117, 109, 181, 55, 68, 112 },/*left = d45 */ ++ { 47, 29, 17, 153, 64, 220, 59, 51, 114 },/*left = d135*/ ++ { 46, 16, 24, 136, 76, 147, 41, 64, 172 },/*left = d117*/ ++ { 34, 17, 11, 108, 152, 187, 13, 15, 209 },/*left = d153*/ ++ { 51, 24, 14, 115, 133, 209, 32, 26, 104 },/*left = d207*/ ++ { 55, 30, 18, 122, 79, 179, 44, 88, 116 },/*left = d63 */ ++ { 37, 49, 25, 129, 168, 164, 41, 54, 148 } /*left = tm */ ++ }, { /* above = d207 */ ++ { 82, 22, 32, 127, 143, 213, 39, 41, 70 },/*left = dc */ ++ { 62, 44, 61, 123, 105, 189, 48, 57, 64 },/*left = v */ ++ { 47, 25, 17, 175, 222, 220, 24, 30, 86 },/*left = h */ ++ { 68, 36, 17, 106, 102, 206, 59, 74, 74 },/*left = d45 */ ++ { 57, 39, 23, 151, 68, 216, 55, 63, 58 },/*left = d135*/ ++ { 49, 30, 35, 141, 70, 168, 82, 40, 115 },/*left = d117*/ ++ { 51, 25, 15, 136, 129, 202, 38, 35, 139 },/*left = d153*/ ++ { 68, 26, 16, 111, 141, 215, 29, 28, 28 },/*left = d207*/ ++ { 59, 39, 19, 114, 75, 180, 77, 104, 42 },/*left = d63 */ ++ { 40, 61, 26, 126, 152, 206, 61, 59, 93 } /*left = tm */ ++ }, { /* above = d63 */ ++ { 78, 23, 39, 111, 117, 170, 74, 124, 94 },/*left = dc */ ++ { 48, 34, 86, 101, 92, 146, 78, 179, 134 },/*left = v */ ++ { 47, 22, 24, 138, 187, 178, 68, 69, 59 },/*left = h */ ++ { 56, 25, 33, 105, 112, 187, 95, 177, 129 },/*left = d45 */ ++ { 48, 31, 27, 114, 63, 183, 82, 116, 56 },/*left = d135*/ ++ { 43, 28, 37, 121, 63, 123, 61, 192, 169 },/*left = d117*/ ++ { 42, 17, 24, 109, 97, 177, 56, 76, 122 },/*left = d153*/ ++ { 58, 18, 28, 105, 139, 182, 70, 92, 63 },/*left = d207*/ ++ { 46, 23, 32, 74, 86, 150, 67, 183, 88 },/*left = d63 */ ++ { 36, 38, 48, 92, 122, 165, 88, 137, 91 } /*left = tm */ ++ }, { /* above = tm */ ++ { 65, 70, 60, 155, 159, 199, 61, 60, 81 },/*left = dc */ ++ { 44, 78, 115, 132, 119, 173, 71, 112, 93 },/*left = v */ ++ { 39, 38, 21, 184, 227, 206, 42, 32, 64 },/*left = h */ ++ { 58, 47, 36, 124, 137, 193, 80, 82, 78 },/*left = d45 */ ++ { 49, 50, 35, 144, 95, 205, 63, 78, 59 },/*left = d135*/ ++ { 41, 53, 52, 148, 71, 142, 65, 128, 51 },/*left = d117*/ ++ { 40, 36, 28, 143, 143, 202, 40, 55, 137 },/*left = d153*/ ++ { 52, 34, 29, 129, 183, 227, 42, 35, 43 },/*left = d207*/ ++ { 42, 44, 44, 104, 105, 164, 64, 130, 80 },/*left = d63 */ ++ { 43, 81, 53, 140, 169, 204, 68, 84, 72 } /*left = tm */ ++ } ++}; ++ ++static const u8 kf_partition_probs[16][3] = { ++ /* 8x8 -> 4x4 */ ++ { 158, 97, 94 }, /* a/l both not split */ ++ { 93, 24, 99 }, /* a split, l not split */ ++ { 85, 119, 44 }, /* l split, a not split */ ++ { 62, 59, 67 }, /* a/l both split */ ++ /* 16x16 -> 8x8 */ ++ { 149, 53, 53 }, /* a/l both not split */ ++ { 94, 20, 48 }, /* a split, l not split */ ++ { 83, 53, 24 }, /* l split, a not split */ ++ { 52, 18, 18 }, /* a/l both split */ ++ /* 32x32 -> 16x16 */ ++ { 150, 40, 39 }, /* a/l both not split */ ++ { 78, 12, 26 }, /* a split, l not split */ ++ { 67, 33, 11 }, /* l split, a not split */ ++ { 24, 7, 5 }, /* a/l both split */ ++ /* 64x64 -> 32x32 */ ++ { 174, 35, 49 }, /* a/l both not split */ ++ { 68, 11, 27 }, /* a split, l not split */ ++ { 57, 15, 9 }, /* l split, a not split */ ++ { 12, 3, 3 }, /* a/l both split */ ++}; ++ ++static const u8 kf_uv_mode_prob[10][9] = { ++ { 144, 11, 54, 157, 195, 130, 46, 58, 108 }, /* y = dc */ ++ { 118, 15, 123, 148, 131, 101, 44, 93, 131 }, /* y = v */ ++ { 113, 12, 23, 188, 226, 142, 26, 32, 125 }, /* y = h */ ++ { 120, 11, 50, 123, 163, 135, 64, 77, 103 }, /* y = d45 */ ++ { 113, 9, 36, 155, 111, 157, 32, 44, 161 }, /* y = d135 */ ++ { 116, 9, 55, 176, 76, 96, 37, 61, 149 }, /* y = d117 */ ++ { 115, 9, 28, 141, 161, 167, 21, 25, 193 }, /* y = d153 */ ++ { 120, 12, 32, 145, 195, 142, 32, 38, 86 }, /* y = d207 */ ++ { 116, 12, 64, 120, 140, 125, 49, 115, 121 }, /* y = d63 */ ++ { 102, 19, 66, 162, 182, 122, 35, 59, 128 } /* y = tm */ ++}; ++ ++static void write_coeff_plane(const u8 coef[6][6][3], u8 *coeff_plane) ++{ ++ unsigned int idx = 0; ++ u8 byte_count = 0, p; ++ s32 k, m, n; ++ ++ for (k = 0; k < 6; k++) { ++ for (m = 0; m < 6; m++) { ++ for (n = 0; n < 3; n++) { ++ p = coef[k][m][n]; ++ coeff_plane[idx++] = p; ++ byte_count++; ++ if (byte_count == 27) { ++ idx += 5; ++ byte_count = 0; ++ } ++ } ++ } ++ } ++} ++ ++static void init_intra_only_probs(struct rkvdec_ctx *ctx, ++ const struct rkvdec_vp9_run *run) ++{ ++ const struct v4l2_ctrl_vp9_frame_decode_params *dec_params; ++ struct rkvdec_vp9_ctx *vp9_ctx = ctx->priv; ++ struct rkvdec_vp9_priv_tbl *tbl = vp9_ctx->priv_tbl.cpu; ++ struct rkvdec_vp9_intra_only_frame_probs *rkprobs; ++ const struct v4l2_vp9_probabilities *probs; ++ unsigned int i, j, k, m; ++ ++ rkprobs = &tbl->probs.intra_only; ++ dec_params = run->decode_params; ++ probs = &dec_params->probs; ++ ++ /* ++ * intra only 149 x 128 bits ,aligned to 152 x 128 bits coeff related ++ * prob 64 x 128 bits ++ */ ++ for (i = 0; i < ARRAY_SIZE(probs->coef); i++) { ++ for (j = 0; j < ARRAY_SIZE(probs->coef[0]); j++) ++ write_coeff_plane(probs->coef[i][j][0], ++ rkprobs->coef_intra[i][j]); ++ } ++ ++ /* intra mode prob 80 x 128 bits */ ++ for (i = 0; i < ARRAY_SIZE(vp9_kf_y_mode_prob); i++) { ++ u32 byte_count = 0; ++ int idx = 0; ++ ++ /* vp9_kf_y_mode_prob */ ++ for (j = 0; j < ARRAY_SIZE(vp9_kf_y_mode_prob[0]); j++) { ++ for (k = 0; k < ARRAY_SIZE(vp9_kf_y_mode_prob[0][0]); ++ k++) { ++ u8 val = vp9_kf_y_mode_prob[i][j][k]; ++ ++ rkprobs->intra_mode[i].y_mode[idx++] = val; ++ byte_count++; ++ if (byte_count == 27) { ++ byte_count = 0; ++ idx += 5; ++ } ++ } ++ } ++ ++ idx = 0; ++ if (i < 4) { ++ for (m = 0; m < (i < 3 ? 23 : 21); m++) { ++ const u8 *ptr = (const u8 *)kf_uv_mode_prob; ++ ++ rkprobs->intra_mode[i].uv_mode[idx++] = ptr[i * 23 + m]; ++ } ++ } ++ } ++} ++ ++static void init_inter_probs(struct rkvdec_ctx *ctx, ++ const struct rkvdec_vp9_run *run) ++{ ++ const struct v4l2_ctrl_vp9_frame_decode_params *dec_params; ++ struct rkvdec_vp9_ctx *vp9_ctx = ctx->priv; ++ struct rkvdec_vp9_priv_tbl *tbl = vp9_ctx->priv_tbl.cpu; ++ struct rkvdec_vp9_inter_frame_probs *rkprobs; ++ const struct v4l2_vp9_probabilities *probs; ++ unsigned int i, j, k; ++ ++ rkprobs = &tbl->probs.inter; ++ dec_params = run->decode_params; ++ probs = &dec_params->probs; ++ ++ /* ++ * inter probs ++ * 151 x 128 bits, aligned to 152 x 128 bits ++ * inter only ++ * intra_y_mode & inter_block info 6 x 128 bits ++ */ ++ ++ memcpy(rkprobs->y_mode, probs->y_mode, sizeof(rkprobs->y_mode)); ++ memcpy(rkprobs->comp_mode, probs->comp_mode, ++ sizeof(rkprobs->comp_mode)); ++ memcpy(rkprobs->comp_ref, probs->comp_ref, ++ sizeof(rkprobs->comp_ref)); ++ memcpy(rkprobs->single_ref, probs->single_ref, ++ sizeof(rkprobs->single_ref)); ++ memcpy(rkprobs->inter_mode, probs->inter_mode, ++ sizeof(rkprobs->inter_mode)); ++ memcpy(rkprobs->interp_filter, probs->interp_filter, ++ sizeof(rkprobs->interp_filter)); ++ ++ /* 128 x 128 bits coeff related */ ++ for (i = 0; i < ARRAY_SIZE(probs->coef); i++) { ++ for (j = 0; j < ARRAY_SIZE(probs->coef[0]); j++) { ++ for (k = 0; k < ARRAY_SIZE(probs->coef[0][0]); k++) ++ write_coeff_plane(probs->coef[i][j][k], ++ rkprobs->coef[k][i][j]); ++ } ++ } ++ ++ /* intra uv mode 6 x 128 */ ++ memcpy(rkprobs->uv_mode_0_2, &probs->uv_mode[0], ++ sizeof(rkprobs->uv_mode_0_2)); ++ memcpy(rkprobs->uv_mode_3_5, &probs->uv_mode[3], ++ sizeof(rkprobs->uv_mode_3_5)); ++ memcpy(rkprobs->uv_mode_6_8, &probs->uv_mode[6], ++ sizeof(rkprobs->uv_mode_6_8)); ++ memcpy(rkprobs->uv_mode_9, &probs->uv_mode[9], ++ sizeof(rkprobs->uv_mode_9)); ++ ++ /* mv related 6 x 128 */ ++ memcpy(rkprobs->mv.joint, probs->mv.joint, ++ sizeof(rkprobs->mv.joint)); ++ memcpy(rkprobs->mv.sign, probs->mv.sign, ++ sizeof(rkprobs->mv.sign)); ++ memcpy(rkprobs->mv.class, probs->mv.class, ++ sizeof(rkprobs->mv.class)); ++ memcpy(rkprobs->mv.class0_bit, probs->mv.class0_bit, ++ sizeof(rkprobs->mv.class0_bit)); ++ memcpy(rkprobs->mv.bits, probs->mv.bits, ++ sizeof(rkprobs->mv.bits)); ++ memcpy(rkprobs->mv.class0_fr, probs->mv.class0_fr, ++ sizeof(rkprobs->mv.class0_fr)); ++ memcpy(rkprobs->mv.fr, probs->mv.fr, ++ sizeof(rkprobs->mv.fr)); ++ memcpy(rkprobs->mv.class0_hp, probs->mv.class0_hp, ++ sizeof(rkprobs->mv.class0_hp)); ++ memcpy(rkprobs->mv.hp, probs->mv.hp, ++ sizeof(rkprobs->mv.hp)); ++} ++ ++static void init_probs(struct rkvdec_ctx *ctx, ++ const struct rkvdec_vp9_run *run) ++{ ++ const struct v4l2_ctrl_vp9_frame_decode_params *dec_params; ++ struct rkvdec_vp9_ctx *vp9_ctx = ctx->priv; ++ struct rkvdec_vp9_priv_tbl *tbl = vp9_ctx->priv_tbl.cpu; ++ struct rkvdec_vp9_probs *rkprobs = &tbl->probs; ++ const struct v4l2_vp9_segmentation *seg; ++ const struct v4l2_vp9_probabilities *probs; ++ bool intra_only; ++ ++ dec_params = run->decode_params; ++ probs = &dec_params->probs; ++ seg = &dec_params->seg; ++ ++ memset(rkprobs, 0, sizeof(*rkprobs)); ++ ++ intra_only = !!(dec_params->flags & ++ (V4L2_VP9_FRAME_FLAG_KEY_FRAME | ++ V4L2_VP9_FRAME_FLAG_INTRA_ONLY)); ++ ++ /* sb info 5 x 128 bit */ ++ memcpy(rkprobs->partition, ++ intra_only ? kf_partition_probs : probs->partition, ++ sizeof(rkprobs->partition)); ++ ++ memcpy(rkprobs->pred, seg->pred_probs, sizeof(rkprobs->pred)); ++ memcpy(rkprobs->tree, seg->tree_probs, sizeof(rkprobs->tree)); ++ memcpy(rkprobs->skip, probs->skip, sizeof(rkprobs->skip)); ++ memcpy(rkprobs->tx32, probs->tx32, sizeof(rkprobs->tx32)); ++ memcpy(rkprobs->tx16, probs->tx16, sizeof(rkprobs->tx16)); ++ memcpy(rkprobs->tx8, probs->tx8, sizeof(rkprobs->tx8)); ++ memcpy(rkprobs->is_inter, probs->is_inter, sizeof(rkprobs->is_inter)); ++ ++ if (intra_only) ++ init_intra_only_probs(ctx, run); ++ else ++ init_inter_probs(ctx, run); ++} ++ ++struct vp9d_ref_config { ++ u32 reg_frm_size; ++ u32 reg_hor_stride; ++ u32 reg_y_stride; ++ u32 reg_yuv_stride; ++ u32 reg_ref_base; ++}; ++ ++static struct vp9d_ref_config ref_config[3] = { ++ { ++ .reg_frm_size = RKVDEC_REG_VP9_FRAME_SIZE(0), ++ .reg_hor_stride = RKVDEC_VP9_HOR_VIRSTRIDE(0), ++ .reg_y_stride = RKVDEC_VP9_LAST_FRAME_YSTRIDE, ++ .reg_yuv_stride = RKVDEC_VP9_LAST_FRAME_YUVSTRIDE, ++ .reg_ref_base = RKVDEC_REG_VP9_LAST_FRAME_BASE, ++ }, ++ { ++ .reg_frm_size = RKVDEC_REG_VP9_FRAME_SIZE(1), ++ .reg_hor_stride = RKVDEC_VP9_HOR_VIRSTRIDE(1), ++ .reg_y_stride = RKVDEC_VP9_GOLDEN_FRAME_YSTRIDE, ++ .reg_yuv_stride = 0, ++ .reg_ref_base = RKVDEC_REG_VP9_GOLDEN_FRAME_BASE, ++ }, ++ { ++ .reg_frm_size = RKVDEC_REG_VP9_FRAME_SIZE(2), ++ .reg_hor_stride = RKVDEC_VP9_HOR_VIRSTRIDE(2), ++ .reg_y_stride = RKVDEC_VP9_ALTREF_FRAME_YSTRIDE, ++ .reg_yuv_stride = 0, ++ .reg_ref_base = RKVDEC_REG_VP9_ALTREF_FRAME_BASE, ++ } ++}; ++ ++static struct rkvdec_decoded_buffer * ++get_ref_buf(struct rkvdec_ctx *ctx, struct vb2_v4l2_buffer *dst, u64 timestamp) ++{ ++ struct v4l2_m2m_ctx *m2m_ctx = ctx->fh.m2m_ctx; ++ struct vb2_queue *cap_q = &m2m_ctx->cap_q_ctx.q; ++ int buf_idx; ++ ++ /* ++ * If a ref is unused or invalid, address of current destination ++ * buffer is returned. ++ */ ++ buf_idx = vb2_find_timestamp(cap_q, timestamp, 0); ++ if (buf_idx < 0) ++ return vb2_to_rkvdec_decoded_buf(&dst->vb2_buf); ++ ++ return vb2_to_rkvdec_decoded_buf(vb2_get_buffer(cap_q, buf_idx)); ++} ++ ++static dma_addr_t get_mv_base_addr(struct rkvdec_decoded_buffer *buf) ++{ ++ u32 aligned_pitch, aligned_height, yuv_len; ++ ++ aligned_height = round_up(buf->vp9.height, 64); ++ aligned_pitch = round_up(buf->vp9.width * buf->vp9.bit_depth, 512) / 8; ++ yuv_len = (aligned_height * aligned_pitch * 3) / 2; ++ ++ return vb2_dma_contig_plane_dma_addr(&buf->base.vb.vb2_buf, 0) + ++ yuv_len; ++} ++ ++static void ++config_ref_registers(struct rkvdec_ctx *ctx, ++ const struct rkvdec_vp9_run *run, ++ struct rkvdec_decoded_buffer **ref_bufs, ++ enum v4l2_vp9_ref_id id) ++{ ++ u32 aligned_pitch, aligned_height, y_len, yuv_len; ++ struct rkvdec_decoded_buffer *buf = ref_bufs[id]; ++ struct rkvdec_dev *rkvdec = ctx->dev; ++ ++ aligned_height = round_up(buf->vp9.height, 64); ++ writel_relaxed(RKVDEC_VP9_FRAMEWIDTH(buf->vp9.width) | ++ RKVDEC_VP9_FRAMEHEIGHT(buf->vp9.height), ++ rkvdec->regs + ref_config[id].reg_frm_size); ++ ++ writel_relaxed(vb2_dma_contig_plane_dma_addr(&buf->base.vb.vb2_buf, 0), ++ rkvdec->regs + ref_config[id].reg_ref_base); ++ ++ if (&buf->base.vb == run->base.bufs.dst) ++ return; ++ ++ aligned_pitch = round_up(buf->vp9.width * buf->vp9.bit_depth, 512) / 8; ++ y_len = aligned_height * aligned_pitch; ++ yuv_len = (y_len * 3) / 2; ++ ++ writel_relaxed(RKVDEC_HOR_Y_VIRSTRIDE(aligned_pitch / 16) | ++ RKVDEC_HOR_UV_VIRSTRIDE(aligned_pitch / 16), ++ rkvdec->regs + ref_config[id].reg_hor_stride); ++ writel_relaxed(RKVDEC_VP9_REF_YSTRIDE(y_len / 16), ++ rkvdec->regs + ref_config[id].reg_y_stride); ++ ++ if (!ref_config[id].reg_yuv_stride) ++ return; ++ ++ writel_relaxed(RKVDEC_VP9_REF_YUVSTRIDE(yuv_len / 16), ++ rkvdec->regs + ref_config[id].reg_yuv_stride); ++} ++ ++static bool seg_featured_enabled(const struct v4l2_vp9_segmentation *seg, ++ enum v4l2_vp9_segment_feature feature, ++ unsigned int segid) ++{ ++ u8 mask = V4L2_VP9_SEGMENT_FEATURE_ENABLED(feature); ++ ++ return !!(seg->feature_enabled[segid] & mask); ++} ++ ++static void ++config_seg_registers(struct rkvdec_ctx *ctx, ++ unsigned int segid) ++{ ++ struct rkvdec_vp9_ctx *vp9_ctx = ctx->priv; ++ const struct v4l2_vp9_segmentation *seg; ++ struct rkvdec_dev *rkvdec = ctx->dev; ++ s16 feature_val; ++ u8 feature_id; ++ u32 val = 0; ++ ++ seg = vp9_ctx->last.valid ? &vp9_ctx->last.seg : &vp9_ctx->cur.seg; ++ feature_id = V4L2_VP9_SEGMENT_FEATURE_QP_DELTA; ++ if (seg_featured_enabled(seg, feature_id, segid)) { ++ feature_val = seg->feature_data[segid][feature_id]; ++ val |= RKVDEC_SEGID_FRAME_QP_DELTA_EN(1) | ++ RKVDEC_SEGID_FRAME_QP_DELTA(feature_val); ++ } ++ ++ feature_id = V4L2_VP9_SEGMENT_FEATURE_LF; ++ if (seg_featured_enabled(seg, feature_id, segid)) { ++ feature_val = seg->feature_data[segid][feature_id]; ++ val |= RKVDEC_SEGID_FRAME_LOOPFILTER_VALUE_EN(1) | ++ RKVDEC_SEGID_FRAME_LOOPFILTER_VALUE(feature_val); ++ } ++ ++ feature_id = V4L2_VP9_SEGMENT_FEATURE_REF_FRAME; ++ if (seg_featured_enabled(seg, feature_id, segid)) { ++ feature_val = seg->feature_data[segid][feature_id]; ++ val |= RKVDEC_SEGID_REFERINFO_EN(1) | ++ RKVDEC_SEGID_REFERINFO(feature_val); ++ } ++ ++ feature_id = V4L2_VP9_SEGMENT_FEATURE_SKIP; ++ if (seg_featured_enabled(seg, feature_id, segid)) ++ val |= RKVDEC_SEGID_FRAME_SKIP_EN(1); ++ ++ if (!segid && ++ (seg->flags & V4L2_VP9_SEGMENTATION_FLAG_ABS_OR_DELTA_UPDATE)) ++ val |= RKVDEC_SEGID_ABS_DELTA(1); ++ ++ writel_relaxed(val, rkvdec->regs + RKVDEC_VP9_SEGID_GRP(segid)); ++} ++ ++static void ++update_dec_buf_info(struct rkvdec_decoded_buffer *buf, ++ const struct v4l2_ctrl_vp9_frame_decode_params *dec_params) ++{ ++ buf->vp9.width = dec_params->frame_width_minus_1 + 1; ++ buf->vp9.height = dec_params->frame_height_minus_1 + 1; ++ buf->vp9.bit_depth = dec_params->bit_depth; ++} ++ ++static void ++update_ctx_cur_info(struct rkvdec_vp9_ctx *vp9_ctx, ++ struct rkvdec_decoded_buffer *buf, ++ const struct v4l2_ctrl_vp9_frame_decode_params *dec_params) ++{ ++ vp9_ctx->cur.valid = true; ++ vp9_ctx->cur.frame_context_idx = dec_params->frame_context_idx; ++ vp9_ctx->cur.reference_mode = dec_params->reference_mode; ++ vp9_ctx->cur.tx_mode = dec_params->tx_mode; ++ vp9_ctx->cur.interpolation_filter = dec_params->interpolation_filter; ++ vp9_ctx->cur.flags = dec_params->flags; ++ vp9_ctx->cur.timestamp = buf->base.vb.vb2_buf.timestamp; ++ vp9_ctx->cur.seg = dec_params->seg; ++ vp9_ctx->cur.lf = dec_params->lf; ++} ++ ++static void ++update_ctx_last_info(struct rkvdec_vp9_ctx *vp9_ctx) ++{ ++ vp9_ctx->last = vp9_ctx->cur; ++} ++ ++static void config_registers(struct rkvdec_ctx *ctx, ++ const struct rkvdec_vp9_run *run) ++{ ++ u32 y_len, uv_len, yuv_len, bit_depth, aligned_height, aligned_pitch; ++ const struct v4l2_ctrl_vp9_frame_decode_params *dec_params; ++ struct rkvdec_decoded_buffer *ref_bufs[V4L2_REF_ID_CNT]; ++ struct rkvdec_decoded_buffer *dst, *last, *mv_ref; ++ struct rkvdec_vp9_ctx *vp9_ctx = ctx->priv; ++ u32 val, stream_len, last_frame_info = 0; ++ const struct v4l2_vp9_segmentation *seg; ++ struct rkvdec_dev *rkvdec = ctx->dev; ++ dma_addr_t addr; ++ bool intra_only; ++ unsigned int i; ++ ++ dec_params = run->decode_params; ++ dst = vb2_to_rkvdec_decoded_buf(&run->base.bufs.dst->vb2_buf); ++ for (i = 0; i < ARRAY_SIZE(ref_bufs); i++) ++ ref_bufs[i] = get_ref_buf(ctx, &dst->base.vb, ++ dec_params->refs[i]); ++ ++ if (vp9_ctx->last.valid) ++ last = get_ref_buf(ctx, &dst->base.vb, vp9_ctx->last.timestamp); ++ else ++ last = dst; ++ ++ update_dec_buf_info(dst, dec_params); ++ update_ctx_cur_info(vp9_ctx, dst, dec_params); ++ seg = &dec_params->seg; ++ ++ intra_only = !!(dec_params->flags & ++ (V4L2_VP9_FRAME_FLAG_KEY_FRAME | ++ V4L2_VP9_FRAME_FLAG_INTRA_ONLY)); ++ ++ writel_relaxed(RKVDEC_MODE(RKVDEC_MODE_VP9), ++ rkvdec->regs + RKVDEC_REG_SYSCTRL); ++ ++ bit_depth = dec_params->bit_depth; ++ aligned_height = round_up(ctx->decoded_fmt.fmt.pix_mp.height, 64); ++ ++ aligned_pitch = round_up(ctx->decoded_fmt.fmt.pix_mp.width * ++ bit_depth, ++ 512) / 8; ++ y_len = aligned_height * aligned_pitch; ++ uv_len = y_len / 2; ++ yuv_len = y_len + uv_len; ++ ++ writel_relaxed(RKVDEC_Y_HOR_VIRSTRIDE(aligned_pitch / 16) | ++ RKVDEC_UV_HOR_VIRSTRIDE(aligned_pitch / 16), ++ rkvdec->regs + RKVDEC_REG_PICPAR); ++ writel_relaxed(RKVDEC_Y_VIRSTRIDE(y_len / 16), ++ rkvdec->regs + RKVDEC_REG_Y_VIRSTRIDE); ++ writel_relaxed(RKVDEC_YUV_VIRSTRIDE(yuv_len / 16), ++ rkvdec->regs + RKVDEC_REG_YUV_VIRSTRIDE); ++ ++ stream_len = vb2_get_plane_payload(&run->base.bufs.src->vb2_buf, 0); ++ writel_relaxed(RKVDEC_STRM_LEN(stream_len), ++ rkvdec->regs + RKVDEC_REG_STRM_LEN); ++ ++ /* ++ * Reset count buffer, because decoder only output intra related syntax ++ * counts when decoding intra frame, but update entropy need to update ++ * all the probabilities. ++ */ ++ if (intra_only) ++ memset(vp9_ctx->count_tbl.cpu, 0, vp9_ctx->count_tbl.size); ++ ++ vp9_ctx->cur.segmapid = vp9_ctx->last.segmapid; ++ if (!intra_only && ++ !(dec_params->flags & V4L2_VP9_FRAME_FLAG_ERROR_RESILIENT) && ++ (!(seg->flags & V4L2_VP9_SEGMENTATION_FLAG_ENABLED) || ++ (seg->flags & V4L2_VP9_SEGMENTATION_FLAG_UPDATE_MAP))) ++ vp9_ctx->cur.segmapid++; ++ ++ for (i = 0; i < ARRAY_SIZE(ref_bufs); i++) ++ config_ref_registers(ctx, run, ref_bufs, i); ++ ++ for (i = 0; i < 8; i++) ++ config_seg_registers(ctx, i); ++ ++ writel_relaxed(RKVDEC_VP9_TX_MODE(dec_params->tx_mode) | ++ RKVDEC_VP9_FRAME_REF_MODE(dec_params->reference_mode), ++ rkvdec->regs + RKVDEC_VP9_CPRHEADER_CONFIG); ++ ++ if (!intra_only) { ++ const struct v4l2_vp9_loop_filter *lf; ++ s8 delta; ++ ++ if (vp9_ctx->last.valid) ++ lf = &vp9_ctx->last.lf; ++ else ++ lf = &vp9_ctx->cur.lf; ++ ++ val = 0; ++ for (i = 0; i < ARRAY_SIZE(lf->ref_deltas); i++) { ++ delta = lf->ref_deltas[i]; ++ val |= RKVDEC_REF_DELTAS_LASTFRAME(i, delta); ++ } ++ ++ writel_relaxed(val, ++ rkvdec->regs + RKVDEC_VP9_REF_DELTAS_LASTFRAME); ++ ++ for (i = 0; i < ARRAY_SIZE(lf->mode_deltas); i++) { ++ delta = lf->mode_deltas[i]; ++ last_frame_info |= RKVDEC_MODE_DELTAS_LASTFRAME(i, ++ delta); ++ } ++ } ++ ++ if (vp9_ctx->last.valid && !intra_only && ++ vp9_ctx->last.seg.flags & V4L2_VP9_SEGMENTATION_FLAG_ENABLED) ++ last_frame_info |= RKVDEC_SEG_EN_LASTFRAME; ++ ++ if (vp9_ctx->last.valid && ++ vp9_ctx->last.flags & V4L2_VP9_FRAME_FLAG_SHOW_FRAME) ++ last_frame_info |= RKVDEC_LAST_SHOW_FRAME; ++ ++ if (vp9_ctx->last.valid && ++ vp9_ctx->last.flags & ++ (V4L2_VP9_FRAME_FLAG_KEY_FRAME | V4L2_VP9_FRAME_FLAG_INTRA_ONLY)) ++ last_frame_info |= RKVDEC_LAST_INTRA_ONLY; ++ ++ if (vp9_ctx->last.valid && ++ last->vp9.width == dst->vp9.width && ++ last->vp9.height == dst->vp9.height) ++ last_frame_info |= RKVDEC_LAST_WIDHHEIGHT_EQCUR; ++ ++ writel_relaxed(last_frame_info, ++ rkvdec->regs + RKVDEC_VP9_INFO_LASTFRAME); ++ ++ writel_relaxed(stream_len - dec_params->compressed_header_size - ++ dec_params->uncompressed_header_size, ++ rkvdec->regs + RKVDEC_VP9_LASTTILE_SIZE); ++ ++ for (i = 0; !intra_only && i < ARRAY_SIZE(ref_bufs); i++) { ++ u32 refw = ref_bufs[i]->vp9.width; ++ u32 refh = ref_bufs[i]->vp9.height; ++ u32 hscale, vscale; ++ ++ hscale = (refw << 14) / dst->vp9.width; ++ vscale = (refh << 14) / dst->vp9.height; ++ writel_relaxed(RKVDEC_VP9_REF_HOR_SCALE(hscale) | ++ RKVDEC_VP9_REF_VER_SCALE(vscale), ++ rkvdec->regs + RKVDEC_VP9_REF_SCALE(i)); ++ } ++ ++ addr = vb2_dma_contig_plane_dma_addr(&dst->base.vb.vb2_buf, 0); ++ writel_relaxed(addr, rkvdec->regs + RKVDEC_REG_DECOUT_BASE); ++ addr = vb2_dma_contig_plane_dma_addr(&run->base.bufs.src->vb2_buf, 0); ++ writel_relaxed(addr, rkvdec->regs + RKVDEC_REG_STRM_RLC_BASE); ++ writel_relaxed(vp9_ctx->priv_tbl.dma + ++ offsetof(struct rkvdec_vp9_priv_tbl, probs), ++ rkvdec->regs + RKVDEC_REG_CABACTBL_PROB_BASE); ++ writel_relaxed(vp9_ctx->count_tbl.dma, ++ rkvdec->regs + RKVDEC_REG_VP9COUNT_BASE); ++ ++ writel_relaxed(vp9_ctx->priv_tbl.dma + ++ offsetof(struct rkvdec_vp9_priv_tbl, segmap) + ++ (RKVDEC_VP9_MAX_SEGMAP_SIZE * vp9_ctx->cur.segmapid), ++ rkvdec->regs + RKVDEC_REG_VP9_SEGIDCUR_BASE); ++ writel_relaxed(vp9_ctx->priv_tbl.dma + ++ offsetof(struct rkvdec_vp9_priv_tbl, segmap) + ++ (RKVDEC_VP9_MAX_SEGMAP_SIZE * (!vp9_ctx->cur.segmapid)), ++ rkvdec->regs + RKVDEC_REG_VP9_SEGIDLAST_BASE); ++ ++ if (!intra_only && ++ !(dec_params->flags & V4L2_VP9_FRAME_FLAG_ERROR_RESILIENT) && ++ vp9_ctx->last.valid) ++ mv_ref = last; ++ else ++ mv_ref = dst; ++ ++ writel_relaxed(get_mv_base_addr(mv_ref), ++ rkvdec->regs + RKVDEC_VP9_REF_COLMV_BASE); ++ ++ writel_relaxed(ctx->decoded_fmt.fmt.pix_mp.width | ++ (ctx->decoded_fmt.fmt.pix_mp.height << 16), ++ rkvdec->regs + RKVDEC_REG_PERFORMANCE_CYCLE); ++} ++ ++static int ++validate_dec_params(struct rkvdec_ctx *ctx, ++ const struct v4l2_ctrl_vp9_frame_decode_params *dec_params) ++{ ++ unsigned int aligned_width, aligned_height; ++ ++ /* We only support profile 0. */ ++ if (dec_params->profile != 0) { ++ dev_err(ctx->dev->dev, "unsupported profile %d\n", ++ dec_params->profile); ++ return -EINVAL; ++ } ++ ++ aligned_width = round_up(dec_params->frame_width_minus_1 + 1, 64); ++ aligned_height = round_up(dec_params->frame_height_minus_1 + 1, 64); ++ ++ /* ++ * Userspace should update the capture/decoded format when the ++ * resolution changes. ++ */ ++ if (aligned_width != ctx->decoded_fmt.fmt.pix_mp.width || ++ aligned_height != ctx->decoded_fmt.fmt.pix_mp.height) { ++ dev_err(ctx->dev->dev, ++ "unexpected bitstream resolution %dx%d\n", ++ dec_params->frame_width_minus_1 + 1, ++ dec_params->frame_height_minus_1 +1); ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static int rkvdec_vp9_run_preamble(struct rkvdec_ctx *ctx, ++ struct rkvdec_vp9_run *run) ++{ ++ const struct v4l2_ctrl_vp9_frame_decode_params *dec_params; ++ const struct v4l2_ctrl_vp9_frame_ctx *fctx = NULL; ++ struct rkvdec_vp9_ctx *vp9_ctx = ctx->priv; ++ struct v4l2_ctrl *ctrl; ++ u8 frm_ctx; ++ int ret; ++ ++ rkvdec_run_preamble(ctx, &run->base); ++ ++ ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl, ++ V4L2_CID_MPEG_VIDEO_VP9_FRAME_DECODE_PARAMS); ++ WARN_ON(!ctrl); ++ ++ dec_params = ctrl ? ctrl->p_cur.p : NULL; ++ if (WARN_ON(!dec_params)) ++ return -EINVAL; ++ ++ ret = validate_dec_params(ctx, dec_params); ++ if (ret) ++ return ret; ++ ++ run->decode_params = dec_params; ++ ++ /* No need to load the frame context if we don't need to update it. */ ++ if (!(dec_params->flags & V4L2_VP9_FRAME_FLAG_REFRESH_FRAME_CTX)) ++ return 0; ++ ++ /* ++ * When a refresh context is requested in parallel mode, we should just ++ * update the context with the probs passed in the decode parameters. ++ */ ++ if (dec_params->flags & V4L2_VP9_FRAME_FLAG_PARALLEL_DEC_MODE) { ++ vp9_ctx->frame_context.probs = dec_params->probs; ++ return 0; ++ } ++ ++ frm_ctx = run->decode_params->frame_context_idx; ++ ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl, ++ V4L2_CID_MPEG_VIDEO_VP9_FRAME_CONTEXT(frm_ctx)); ++ if (WARN_ON(!ctrl)) ++ return 0; ++ ++ fctx = ctrl->p_cur.p; ++ vp9_ctx->frame_context = *fctx; ++ ++ /* ++ * For intra-only frames, we must update the context TX and skip probs ++ * with the value passed in the decode params. ++ */ ++ if (dec_params->flags & ++ (V4L2_VP9_FRAME_FLAG_KEY_FRAME | V4L2_VP9_FRAME_FLAG_INTRA_ONLY)) { ++ struct v4l2_vp9_probabilities *probs; ++ ++ probs = &vp9_ctx->frame_context.probs; ++ memcpy(probs->skip, dec_params->probs.skip, ++ sizeof(probs->skip)); ++ memcpy(probs->tx8, dec_params->probs.tx8, ++ sizeof(probs->tx8)); ++ memcpy(probs->tx16, dec_params->probs.tx16, ++ sizeof(probs->tx16)); ++ memcpy(probs->tx32, dec_params->probs.tx32, ++ sizeof(probs->tx32)); ++ } ++ ++ return 0; ++} ++ ++static int rkvdec_vp9_run(struct rkvdec_ctx *ctx) ++{ ++ struct rkvdec_dev *rkvdec = ctx->dev; ++ struct rkvdec_vp9_run run = { }; ++ int ret; ++ ++ ret = rkvdec_vp9_run_preamble(ctx, &run); ++ if (ret) { ++ rkvdec_run_postamble(ctx, &run.base); ++ return ret; ++ } ++ ++ /* Prepare probs. */ ++ init_probs(ctx, &run); ++ ++ /* Configure hardware registers. */ ++ config_registers(ctx, &run); ++ ++ rkvdec_run_postamble(ctx, &run.base); ++ ++ schedule_delayed_work(&rkvdec->watchdog_work, msecs_to_jiffies(2000)); ++ ++ writel(1, rkvdec->regs + RKVDEC_REG_PREF_LUMA_CACHE_COMMAND); ++ writel(1, rkvdec->regs + RKVDEC_REG_PREF_CHR_CACHE_COMMAND); ++ ++ writel(0xe, rkvdec->regs + RKVDEC_REG_STRMD_ERR_EN); ++ /* Start decoding! */ ++ writel(RKVDEC_INTERRUPT_DEC_E | RKVDEC_CONFIG_DEC_CLK_GATE_E | ++ RKVDEC_TIMEOUT_E | RKVDEC_BUF_EMPTY_E, ++ rkvdec->regs + RKVDEC_REG_INTERRUPT); ++ ++ return 0; ++} ++ ++static u8 adapt_prob(u8 p1, u32 ct0, u32 ct1, u16 max_count, u32 update_factor) ++{ ++ u32 ct = ct0 + ct1, p2; ++ u32 lo = 1; ++ u32 hi = 255; ++ ++ if (!ct) ++ return p1; ++ ++ p2 = ((ct0 << 8) + (ct >> 1)) / ct; ++ p2 = clamp(p2, lo, hi); ++ ct = min_t(u32, ct, max_count); ++ ++ if (WARN_ON(max_count >= 257)) ++ return p1; ++ ++ update_factor = rkvdec_fastdiv(update_factor * ct, max_count); ++ ++ return p1 + (((p2 - p1) * update_factor + 128) >> 8); ++} ++ ++#define BAND_6(band) ((band) == 0 ? 3 : 6) ++ ++static void adapt_coeff(u8 coef[6][6][3], ++ const struct rkvdec_vp9_refs_counts ref_cnt[6][6], ++ u32 uf) ++{ ++ s32 l, m, n; ++ ++ for (l = 0; l < 6; l++) { ++ for (m = 0; m < BAND_6(l); m++) { ++ u8 *p = coef[l][m]; ++ const u32 n0 = ref_cnt[l][m].coeff[0]; ++ const u32 n1 = ref_cnt[l][m].coeff[1]; ++ const u32 n2 = ref_cnt[l][m].coeff[2]; ++ const u32 neob = ref_cnt[l][m].eob[1]; ++ const u32 eob_count = ref_cnt[l][m].eob[0]; ++ const u32 branch_ct[3][2] = { ++ { neob, eob_count - neob }, ++ { n0, n1 + n2 }, ++ { n1, n2 } ++ }; ++ ++ for (n = 0; n < 3; n++) ++ p[n] = adapt_prob(p[n], branch_ct[n][0], ++ branch_ct[n][1], 24, uf); ++ } ++ } ++} ++ ++static void ++adapt_coef_probs(struct v4l2_vp9_probabilities *probs, ++ const struct rkvdec_vp9_refs_counts ref_cnt[2][4][2][6][6], ++ unsigned int uf) ++{ ++ unsigned int i, j, k; ++ ++ for (i = 0; i < ARRAY_SIZE(probs->coef); i++) { ++ for (j = 0; j < ARRAY_SIZE(probs->coef[0]); j++) { ++ for (k = 0; k < ARRAY_SIZE(probs->coef[0][0]); ++ k++) { ++ adapt_coeff(probs->coef[i][j][k], ++ ref_cnt[k][i][j], ++ uf); ++ } ++ } ++ } ++} ++ ++static void adapt_intra_frame_probs(struct rkvdec_ctx *ctx) ++{ ++ struct rkvdec_vp9_ctx *vp9_ctx = ctx->priv; ++ struct v4l2_vp9_probabilities *probs = &vp9_ctx->frame_context.probs; ++ const struct rkvdec_vp9_intra_frame_symbol_counts *sym_cnts; ++ ++ sym_cnts = vp9_ctx->count_tbl.cpu; ++ adapt_coef_probs(probs, sym_cnts->ref_cnt, 112); ++} ++ ++static void ++adapt_skip_probs(struct v4l2_vp9_probabilities *probs, ++ const struct rkvdec_vp9_inter_frame_symbol_counts *sym_cnts) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < ARRAY_SIZE(probs->skip); i++) ++ probs->skip[i] = adapt_prob(probs->skip[i], ++ sym_cnts->skip[i][0], ++ sym_cnts->skip[i][1], ++ 20, 128); ++} ++ ++static void ++adapt_is_inter_probs(struct v4l2_vp9_probabilities *probs, ++ const struct rkvdec_vp9_inter_frame_symbol_counts *sym_cnts) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < ARRAY_SIZE(probs->is_inter); i++) ++ probs->is_inter[i] = adapt_prob(probs->is_inter[i], ++ sym_cnts->inter[i][0], ++ sym_cnts->inter[i][1], ++ 20, 128); ++} ++ ++static void ++adapt_comp_mode_probs(struct v4l2_vp9_probabilities *probs, ++ const struct rkvdec_vp9_inter_frame_symbol_counts *sym_cnts) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < ARRAY_SIZE(probs->comp_mode); i++) ++ probs->comp_mode[i] = adapt_prob(probs->comp_mode[i], ++ sym_cnts->comp[i][0], ++ sym_cnts->comp[i][1], ++ 20, 128); ++} ++ ++static void ++adapt_comp_ref_probs(struct v4l2_vp9_probabilities *probs, ++ const struct rkvdec_vp9_inter_frame_symbol_counts *sym_cnts) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < ARRAY_SIZE(probs->comp_ref); i++) ++ probs->comp_ref[i] = adapt_prob(probs->comp_ref[i], ++ sym_cnts->comp_ref[i][0], ++ sym_cnts->comp_ref[i][1], ++ 20, 128); ++} ++ ++static void ++adapt_single_ref_probs(struct v4l2_vp9_probabilities *probs, ++ const struct rkvdec_vp9_inter_frame_symbol_counts *sym_cnts) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < ARRAY_SIZE(probs->single_ref); i++) { ++ u8 *p = probs->single_ref[i]; ++ ++ p[0] = adapt_prob(p[0], sym_cnts->single_ref[i][0][0], ++ sym_cnts->single_ref[i][0][1], 20, 128); ++ p[1] = adapt_prob(p[1], sym_cnts->single_ref[i][1][0], ++ sym_cnts->single_ref[i][1][1], 20, 128); ++ } ++} ++ ++static void ++adapt_partition_probs(struct v4l2_vp9_probabilities *probs, ++ const struct rkvdec_vp9_inter_frame_symbol_counts *sym_cnts) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < ARRAY_SIZE(probs->partition); i++) { ++ const u32 *c = sym_cnts->partition[i]; ++ u8 *p = probs->partition[i]; ++ ++ p[0] = adapt_prob(p[0], c[0], c[1] + c[2] + c[3], 20, 128); ++ p[1] = adapt_prob(p[1], c[1], c[2] + c[3], 20, 128); ++ p[2] = adapt_prob(p[2], c[2], c[3], 20, 128); ++ } ++} ++ ++static void ++adapt_tx_probs(struct v4l2_vp9_probabilities *probs, ++ const struct rkvdec_vp9_inter_frame_symbol_counts *sym_cnts) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < ARRAY_SIZE(probs->tx8); i++) { ++ u8 *p16x16 = probs->tx16[i]; ++ u8 *p32x32 = probs->tx32[i]; ++ const u32 *c16 = sym_cnts->tx16p[i]; ++ const u32 *c32 = sym_cnts->tx32p[i]; ++ const u32 *c8 = sym_cnts->tx8p[i]; ++ u8 *p8x8 = probs->tx8[i]; ++ ++ p8x8[0] = adapt_prob(p8x8[0], c8[0], c8[1], 20, 128); ++ p16x16[0] = adapt_prob(p16x16[0], c16[0], c16[1] + c16[2], ++ 20, 128); ++ p16x16[1] = adapt_prob(p16x16[1], c16[1], c16[2], 20, 128); ++ p32x32[0] = adapt_prob(p32x32[0], c32[0], ++ c32[1] + c32[2] + c32[3], 20, 128); ++ p32x32[1] = adapt_prob(p32x32[1], c32[1], c32[2] + c32[3], ++ 20, 128); ++ p32x32[2] = adapt_prob(p32x32[2], c32[2], c32[3], 20, 128); ++ } ++} ++ ++static void ++adapt_interp_filter_probs(struct v4l2_vp9_probabilities *probs, ++ const struct rkvdec_vp9_inter_frame_symbol_counts *sym_cnts) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < ARRAY_SIZE(probs->interp_filter); i++) { ++ u8 *p = probs->interp_filter[i]; ++ const u32 *c = sym_cnts->filter[i]; ++ ++ p[0] = adapt_prob(p[0], c[0], c[1] + c[2], 20, 128); ++ p[1] = adapt_prob(p[1], c[1], c[2], 20, 128); ++ } ++} ++ ++static void ++adapt_inter_mode_probs(struct v4l2_vp9_probabilities *probs, ++ const struct rkvdec_vp9_inter_frame_symbol_counts *sym_cnts) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < ARRAY_SIZE(probs->inter_mode); i++) { ++ const u32 *c = sym_cnts->mv_mode[i]; ++ u8 *p = probs->inter_mode[i]; ++ ++ p[0] = adapt_prob(p[0], c[2], c[1] + c[0] + c[3], 20, 128); ++ p[1] = adapt_prob(p[1], c[0], c[1] + c[3], 20, 128); ++ p[2] = adapt_prob(p[2], c[1], c[3], 20, 128); ++ } ++} ++ ++static void ++adapt_mv_probs(struct v4l2_vp9_probabilities *probs, ++ const struct rkvdec_vp9_inter_frame_symbol_counts *sym_cnts, ++ bool high_prec_mv) ++{ ++ const u32 *c = sym_cnts->mv_joint; ++ u8 *p = probs->mv.joint; ++ unsigned int i, j; ++ u32 sum; ++ ++ p[0] = adapt_prob(p[0], c[0], c[1] + c[2] + c[3], 20, 128); ++ p[1] = adapt_prob(p[1], c[1], c[2] + c[3], 20, 128); ++ p[2] = adapt_prob(p[2], c[2], c[3], 20, 128); ++ ++ for (i = 0; i < ARRAY_SIZE(probs->mv.sign); i++) { ++ p = probs->mv.sign; ++ ++ p[i] = adapt_prob(p[i], sym_cnts->sign[i][0], ++ sym_cnts->sign[i][1], 20, 128); ++ ++ p = probs->mv.class[i]; ++ c = sym_cnts->classes[i]; ++ sum = c[1] + c[2] + c[3] + c[4] + c[5] + c[6] + c[7] + c[8] + ++ c[9] + c[10]; ++ p[0] = adapt_prob(p[0], c[0], sum, 20, 128); ++ sum -= c[1]; ++ p[1] = adapt_prob(p[1], c[1], sum, 20, 128); ++ sum -= c[2] + c[3]; ++ p[2] = adapt_prob(p[2], c[2] + c[3], sum, 20, 128); ++ p[3] = adapt_prob(p[3], c[2], c[3], 20, 128); ++ sum -= c[4] + c[5]; ++ p[4] = adapt_prob(p[4], c[4] + c[5], sum, 20, 128); ++ p[5] = adapt_prob(p[5], c[4], c[5], 20, 128); ++ sum -= c[6]; ++ p[6] = adapt_prob(p[6], c[6], sum, 20, 128); ++ p[7] = adapt_prob(p[7], c[7] + c[8], c[9] + c[10], 20, 128); ++ p[8] = adapt_prob(p[8], c[7], c[8], 20, 128); ++ p[9] = adapt_prob(p[9], c[9], c[10], 20, 128); ++ ++ p = probs->mv.class0_bit; ++ p[i] = adapt_prob(p[i], ++ sym_cnts->class0[i][0], ++ sym_cnts->class0[i][1], 20, 128); ++ ++ p = probs->mv.bits[i]; ++ for (j = 0; j < 10; j++) ++ p[j] = adapt_prob(p[j], sym_cnts->bits[i][j][0], ++ sym_cnts->bits[i][j][1], 20, 128); ++ ++ for (j = 0; j < 2; j++) { ++ p = probs->mv.class0_fr[i][j]; ++ c = sym_cnts->class0_fp[i][j]; ++ p[0] = adapt_prob(p[0], c[0], c[1] + c[2] + c[3], ++ 20, 128); ++ p[1] = adapt_prob(p[1], c[1], c[2] + c[3], 20, 128); ++ p[2] = adapt_prob(p[2], c[2], c[3], 20, 128); ++ } ++ ++ p = probs->mv.fr[i]; ++ c = sym_cnts->fp[i]; ++ p[0] = adapt_prob(p[0], c[0], c[1] + c[2] + c[3], 20, 128); ++ p[1] = adapt_prob(p[1], c[1], c[2] + c[3], 20, 128); ++ p[2] = adapt_prob(p[2], c[2], c[3], 20, 128); ++ ++ if (!high_prec_mv) ++ continue; ++ ++ p = probs->mv.class0_hp; ++ p[i] = adapt_prob(p[i], sym_cnts->class0_hp[i][0], ++ sym_cnts->class0_hp[i][1], 20, 128); ++ ++ p = probs->mv.hp; ++ p[i] = adapt_prob(p[i], sym_cnts->hp[i][0], ++ sym_cnts->hp[i][1], 20, 128); ++ } ++} ++ ++static void ++adapt_intra_mode_probs(u8 *p, const u32 *c) ++{ ++ u32 sum = 0, s2; ++ unsigned int i; ++ ++ for (i = V4L2_VP9_INTRA_PRED_MODE_V; i <= V4L2_VP9_INTRA_PRED_MODE_TM; ++ i++) ++ sum += c[i]; ++ ++ p[0] = adapt_prob(p[0], c[V4L2_VP9_INTRA_PRED_MODE_DC], sum, 20, 128); ++ sum -= c[V4L2_VP9_INTRA_PRED_MODE_TM]; ++ p[1] = adapt_prob(p[1], c[V4L2_VP9_INTRA_PRED_MODE_TM], sum, 20, 128); ++ sum -= c[V4L2_VP9_INTRA_PRED_MODE_V]; ++ p[2] = adapt_prob(p[2], c[V4L2_VP9_INTRA_PRED_MODE_V], sum, 20, 128); ++ s2 = c[V4L2_VP9_INTRA_PRED_MODE_H] + c[V4L2_VP9_INTRA_PRED_MODE_D135] + ++ c[V4L2_VP9_INTRA_PRED_MODE_D117]; ++ sum -= s2; ++ p[3] = adapt_prob(p[3], s2, sum, 20, 128); ++ s2 -= c[V4L2_VP9_INTRA_PRED_MODE_H]; ++ p[4] = adapt_prob(p[4], c[V4L2_VP9_INTRA_PRED_MODE_H], s2, 20, 128); ++ p[5] = adapt_prob(p[5], c[V4L2_VP9_INTRA_PRED_MODE_D135], ++ c[V4L2_VP9_INTRA_PRED_MODE_D117], 20, 128); ++ sum -= c[V4L2_VP9_INTRA_PRED_MODE_D45]; ++ p[6] = adapt_prob(p[6], c[V4L2_VP9_INTRA_PRED_MODE_D45], ++ sum, 20, 128); ++ sum -= c[V4L2_VP9_INTRA_PRED_MODE_D63]; ++ p[7] = adapt_prob(p[7], c[V4L2_VP9_INTRA_PRED_MODE_D63], sum, ++ 20, 128); ++ p[8] = adapt_prob(p[8], c[V4L2_VP9_INTRA_PRED_MODE_D153], ++ c[V4L2_VP9_INTRA_PRED_MODE_D207], 20, 128); ++} ++ ++static void ++adapt_y_intra_mode_probs(struct v4l2_vp9_probabilities *probs, ++ const struct rkvdec_vp9_inter_frame_symbol_counts *sym_cnts) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < ARRAY_SIZE(probs->y_mode); i++) ++ adapt_intra_mode_probs(probs->y_mode[i], sym_cnts->y_mode[i]); ++} ++ ++static void ++adapt_uv_intra_mode_probs(struct v4l2_vp9_probabilities *probs, ++ const struct rkvdec_vp9_inter_frame_symbol_counts *sym_cnts) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < ARRAY_SIZE(probs->uv_mode); i++) ++ adapt_intra_mode_probs(probs->uv_mode[i], ++ sym_cnts->uv_mode[i]); ++} ++ ++static void ++adapt_inter_frame_probs(struct rkvdec_ctx *ctx) ++{ ++ struct rkvdec_vp9_ctx *vp9_ctx = ctx->priv; ++ struct v4l2_vp9_probabilities *probs = &vp9_ctx->frame_context.probs; ++ const struct rkvdec_vp9_inter_frame_symbol_counts *sym_cnts; ++ ++ sym_cnts = vp9_ctx->count_tbl.cpu; ++ /* coefficients */ ++ if (vp9_ctx->last.valid && ++ !(vp9_ctx->last.flags & V4L2_VP9_FRAME_FLAG_KEY_FRAME)) ++ adapt_coef_probs(probs, sym_cnts->ref_cnt, 112); ++ else ++ adapt_coef_probs(probs, sym_cnts->ref_cnt, 128); ++ ++ /* skip flag */ ++ adapt_skip_probs(probs, sym_cnts); ++ ++ /* intra/inter flag */ ++ adapt_is_inter_probs(probs, sym_cnts); ++ ++ /* comppred flag */ ++ adapt_comp_mode_probs(probs, sym_cnts); ++ ++ /* reference frames */ ++ adapt_comp_ref_probs(probs, sym_cnts); ++ ++ if (vp9_ctx->cur.reference_mode != V4L2_VP9_REF_MODE_COMPOUND) ++ adapt_single_ref_probs(probs, sym_cnts); ++ ++ /* block partitioning */ ++ adapt_partition_probs(probs, sym_cnts); ++ ++ /* tx size */ ++ if (vp9_ctx->cur.tx_mode == V4L2_VP9_TX_MODE_SELECT) ++ adapt_tx_probs(probs, sym_cnts); ++ ++ /* interpolation filter */ ++ if (vp9_ctx->cur.interpolation_filter == V4L2_VP9_INTERP_FILTER_SWITCHABLE) ++ adapt_interp_filter_probs(probs, sym_cnts); ++ ++ /* inter modes */ ++ adapt_inter_mode_probs(probs, sym_cnts); ++ ++ /* mv probs */ ++ adapt_mv_probs(probs, sym_cnts, ++ !!(vp9_ctx->cur.flags & ++ V4L2_VP9_FRAME_FLAG_ALLOW_HIGH_PREC_MV)); ++ ++ /* y intra modes */ ++ adapt_y_intra_mode_probs(probs, sym_cnts); ++ ++ /* uv intra modes */ ++ adapt_uv_intra_mode_probs(probs, sym_cnts); ++} ++ ++static void adapt_probs(struct rkvdec_ctx *ctx) ++{ ++ struct rkvdec_vp9_ctx *vp9_ctx = ctx->priv; ++ bool intra_only; ++ ++ intra_only = !!(vp9_ctx->cur.flags & ++ (V4L2_VP9_FRAME_FLAG_KEY_FRAME | ++ V4L2_VP9_FRAME_FLAG_INTRA_ONLY)); ++ ++ if (intra_only) ++ adapt_intra_frame_probs(ctx); ++ else ++ adapt_inter_frame_probs(ctx); ++} ++ ++static void rkvdec_vp9_done(struct rkvdec_ctx *ctx, ++ struct vb2_v4l2_buffer *src_buf, ++ struct vb2_v4l2_buffer *dst_buf, ++ enum vb2_buffer_state result) ++{ ++ struct rkvdec_vp9_ctx *vp9_ctx = ctx->priv; ++ struct v4l2_ctrl *ctrl; ++ unsigned int fctx_idx; ++ ++ if (result == VB2_BUF_STATE_ERROR) ++ goto out_update_last; ++ ++ if (!(vp9_ctx->cur.flags & V4L2_VP9_FRAME_FLAG_REFRESH_FRAME_CTX)) ++ goto out_update_last; ++ ++ fctx_idx = vp9_ctx->cur.frame_context_idx; ++ ++ if (!(vp9_ctx->cur.flags & ++ (V4L2_VP9_FRAME_FLAG_ERROR_RESILIENT | ++ V4L2_VP9_FRAME_FLAG_PARALLEL_DEC_MODE))) ++ adapt_probs(ctx); ++ ++ ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl, ++ V4L2_CID_MPEG_VIDEO_VP9_FRAME_CONTEXT(fctx_idx)); ++ if (WARN_ON(!ctrl)) ++ goto out_update_last; ++ ++ v4l2_ctrl_s_ctrl_compound(ctrl, V4L2_CTRL_TYPE_VP9_FRAME_CONTEXT, ++ &vp9_ctx->frame_context); ++ ++out_update_last: ++ update_ctx_last_info(vp9_ctx); ++} ++ ++static int rkvdec_vp9_start(struct rkvdec_ctx *ctx) ++{ ++ struct rkvdec_dev *rkvdec = ctx->dev; ++ struct rkvdec_vp9_priv_tbl *priv_tbl; ++ struct rkvdec_vp9_ctx *vp9_ctx; ++ u8 *count_tbl; ++ int ret; ++ ++ vp9_ctx = kzalloc(sizeof(*vp9_ctx), GFP_KERNEL); ++ if (!vp9_ctx) ++ return -ENOMEM; ++ ++ ctx->priv = vp9_ctx; ++ ++ priv_tbl = dma_alloc_coherent(rkvdec->dev, sizeof(*priv_tbl), ++ &vp9_ctx->priv_tbl.dma, GFP_KERNEL); ++ if (!priv_tbl) { ++ ret = -ENOMEM; ++ goto err_free_ctx; ++ } ++ ++ vp9_ctx->priv_tbl.size = sizeof(*priv_tbl); ++ vp9_ctx->priv_tbl.cpu = priv_tbl; ++ memset(priv_tbl, 0, sizeof(*priv_tbl)); ++ ++ count_tbl = dma_alloc_coherent(rkvdec->dev, RKVDEC_VP9_COUNT_SIZE, ++ &vp9_ctx->count_tbl.dma, GFP_KERNEL); ++ if (!count_tbl) { ++ ret = -ENOMEM; ++ goto err_free_priv_tbl; ++ } ++ ++ vp9_ctx->count_tbl.size = RKVDEC_VP9_COUNT_SIZE; ++ vp9_ctx->count_tbl.cpu = count_tbl; ++ memset(count_tbl, 0, sizeof(*count_tbl)); ++ ++ return 0; ++ ++err_free_priv_tbl: ++ dma_free_coherent(rkvdec->dev, vp9_ctx->priv_tbl.size, ++ vp9_ctx->priv_tbl.cpu, vp9_ctx->priv_tbl.dma); ++ ++err_free_ctx: ++ kfree(vp9_ctx); ++ return ret; ++} ++ ++static void rkvdec_vp9_stop(struct rkvdec_ctx *ctx) ++{ ++ struct rkvdec_vp9_ctx *vp9_ctx = ctx->priv; ++ struct rkvdec_dev *rkvdec = ctx->dev; ++ ++ dma_free_coherent(rkvdec->dev, vp9_ctx->count_tbl.size, ++ vp9_ctx->count_tbl.cpu, vp9_ctx->count_tbl.dma); ++ dma_free_coherent(rkvdec->dev, vp9_ctx->priv_tbl.size, ++ vp9_ctx->priv_tbl.cpu, vp9_ctx->priv_tbl.dma); ++ kfree(vp9_ctx); ++} ++ ++static int rkvdec_vp9_adjust_fmt(struct rkvdec_ctx *ctx, ++ struct v4l2_format *f) ++{ ++ struct v4l2_pix_format_mplane *fmt = &f->fmt.pix_mp; ++ ++ fmt->num_planes = 1; ++ if (!fmt->plane_fmt[0].sizeimage) ++ fmt->plane_fmt[0].sizeimage = fmt->width * fmt->height * 2; ++ return 0; ++} ++ ++const struct rkvdec_coded_fmt_ops rkvdec_vp9_fmt_ops = { ++ .adjust_fmt = rkvdec_vp9_adjust_fmt, ++ .start = rkvdec_vp9_start, ++ .stop = rkvdec_vp9_stop, ++ .run = rkvdec_vp9_run, ++ .done = rkvdec_vp9_done, ++}; +diff --git a/drivers/staging/media/rkvdec/rkvdec.c b/drivers/staging/media/rkvdec/rkvdec.c +index 91f8a1bb6176..f0f28f6a68cf 100644 +--- a/drivers/staging/media/rkvdec/rkvdec.c ++++ b/drivers/staging/media/rkvdec/rkvdec.c +@@ -159,6 +159,45 @@ static const u32 rkvdec_h264_decoded_fmts[] = { + V4L2_PIX_FMT_NV20, + }; + ++static const struct rkvdec_ctrl_desc rkvdec_vp9_ctrl_descs[] = { ++ { ++ .per_request = true, ++ .mandatory = true, ++ .cfg.id = V4L2_CID_MPEG_VIDEO_VP9_FRAME_DECODE_PARAMS, ++ }, ++ { ++ .mandatory = true, ++ .cfg.id = V4L2_CID_MPEG_VIDEO_VP9_FRAME_CONTEXT(0), ++ }, ++ { ++ .mandatory = true, ++ .cfg.id = V4L2_CID_MPEG_VIDEO_VP9_FRAME_CONTEXT(1), ++ }, ++ { ++ .mandatory = true, ++ .cfg.id = V4L2_CID_MPEG_VIDEO_VP9_FRAME_CONTEXT(2), ++ }, ++ { ++ .mandatory = true, ++ .cfg.id = V4L2_CID_MPEG_VIDEO_VP9_FRAME_CONTEXT(3), ++ }, ++ { ++ .cfg.id = V4L2_CID_MPEG_VIDEO_VP9_PROFILE, ++ .cfg.min = V4L2_MPEG_VIDEO_VP9_PROFILE_0, ++ .cfg.max = V4L2_MPEG_VIDEO_VP9_PROFILE_0, ++ .cfg.def = V4L2_MPEG_VIDEO_VP9_PROFILE_0, ++ }, ++}; ++ ++static const struct rkvdec_ctrls rkvdec_vp9_ctrls = { ++ .ctrls = rkvdec_vp9_ctrl_descs, ++ .num_ctrls = ARRAY_SIZE(rkvdec_vp9_ctrl_descs), ++}; ++ ++static const u32 rkvdec_vp9_decoded_fmts[] = { ++ V4L2_PIX_FMT_NV12, ++}; ++ + static const struct rkvdec_coded_fmt_desc rkvdec_coded_fmts[] = { + { + .fourcc = V4L2_PIX_FMT_H264_SLICE, +@@ -174,6 +213,21 @@ static const struct rkvdec_coded_fmt_desc rkvdec_coded_fmts[] = { + .ops = &rkvdec_h264_fmt_ops, + .num_decoded_fmts = ARRAY_SIZE(rkvdec_h264_decoded_fmts), + .decoded_fmts = rkvdec_h264_decoded_fmts, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_VP9_FRAME, ++ .frmsize = { ++ .min_width = 64, ++ .max_width = 4096, ++ .step_width = 64, ++ .min_height = 64, ++ .max_height = 2304, ++ .step_height = 64, ++ }, ++ .ctrls = &rkvdec_vp9_ctrls, ++ .ops = &rkvdec_vp9_fmt_ops, ++ .num_decoded_fmts = ARRAY_SIZE(rkvdec_vp9_decoded_fmts), ++ .decoded_fmts = rkvdec_vp9_decoded_fmts, + } + }; + +diff --git a/drivers/staging/media/rkvdec/rkvdec.h b/drivers/staging/media/rkvdec/rkvdec.h +index e95c52e3168a..5f66f07acac5 100644 +--- a/drivers/staging/media/rkvdec/rkvdec.h ++++ b/drivers/staging/media/rkvdec/rkvdec.h +@@ -51,6 +51,10 @@ struct rkvdec_vp9_decoded_buffer_info { + struct rkvdec_decoded_buffer { + /* Must be the first field in this struct. */ + struct v4l2_m2m_buffer base; ++ ++ union { ++ struct rkvdec_vp9_decoded_buffer_info vp9; ++ }; + }; + + static inline struct rkvdec_decoded_buffer * +@@ -119,4 +123,6 @@ void rkvdec_run_preamble(struct rkvdec_ctx *ctx, struct rkvdec_run *run); + void rkvdec_run_postamble(struct rkvdec_ctx *ctx, struct rkvdec_run *run); + + extern const struct rkvdec_coded_fmt_ops rkvdec_h264_fmt_ops; ++extern const struct rkvdec_coded_fmt_ops rkvdec_vp9_fmt_ops; ++ + #endif /* RKVDEC_H_ */ diff --git a/patch/kernel/rk322x-current/01-linux-0013-v4l2-from-list.patch.disabled b/patch/kernel/rk322x-current/01-linux-0013-v4l2-from-list.patch.disabled deleted file mode 100644 index 44e7d191f..000000000 --- a/patch/kernel/rk322x-current/01-linux-0013-v4l2-from-list.patch.disabled +++ /dev/null @@ -1,319 +0,0 @@ -diff --git a/Documentation/media/uapi/v4l/ext-ctrls-codec.rst b/Documentation/media/uapi/v4l/ext-ctrls-codec.rst -index 28313c0f4e7c..d472a54d1c4d 100644 ---- a/Documentation/media/uapi/v4l/ext-ctrls-codec.rst -+++ b/Documentation/media/uapi/v4l/ext-ctrls-codec.rst -@@ -2028,6 +2028,18 @@ enum v4l2_mpeg_video_h264_hierarchical_coding_type - - * - ``V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM`` - - 0x00000004 - - The DPB entry is a long term reference frame -+ * - ``V4L2_H264_DPB_ENTRY_FLAG_FIELD_PICTURE`` -+ - 0x00000008 -+ - The DPB entry is a field picture -+ * - ``V4L2_H264_DPB_ENTRY_FLAG_REF_TOP`` -+ - 0x00000010 -+ - The DPB entry is a top field reference -+ * - ``V4L2_H264_DPB_ENTRY_FLAG_REF_BOTTOM`` -+ - 0x00000020 -+ - The DPB entry is a bottom field reference -+ * - ``V4L2_H264_DPB_ENTRY_FLAG_REF_FRAME`` -+ - 0x00000030 -+ - The DPB entry is a reference frame - - ``V4L2_CID_MPEG_VIDEO_H264_DECODE_MODE (enum)`` - Specifies the decoding mode to use. Currently exposes slice-based and -diff --git a/include/media/h264-ctrls.h b/include/media/h264-ctrls.h -index e877bf1d537c..76020ebd1e6c 100644 ---- a/include/media/h264-ctrls.h -+++ b/include/media/h264-ctrls.h -@@ -185,6 +185,10 @@ struct v4l2_ctrl_h264_slice_params { - #define V4L2_H264_DPB_ENTRY_FLAG_VALID 0x01 - #define V4L2_H264_DPB_ENTRY_FLAG_ACTIVE 0x02 - #define V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM 0x04 -+#define V4L2_H264_DPB_ENTRY_FLAG_FIELD_PICTURE 0x08 -+#define V4L2_H264_DPB_ENTRY_FLAG_REF_TOP 0x10 -+#define V4L2_H264_DPB_ENTRY_FLAG_REF_BOTTOM 0x20 -+#define V4L2_H264_DPB_ENTRY_FLAG_REF_FRAME 0x30 - - struct v4l2_h264_dpb_entry { - __u64 reference_ts; --- -2.17.1 - - -From ef240de60cedea0264ca954a8e8e2fa25db097ae Mon Sep 17 00:00:00 2001 -From: Jonas Karlman -Date: Tue, 29 Oct 2019 01:26:02 +0000 -Subject: [PATCH] RFC: media: hantro: Fix H264 decoding of field encoded - content - -This still need code cleanup and formatting - -Signed-off-by: Jonas Karlman ---- - .../staging/media/hantro/hantro_g1_h264_dec.c | 17 +-- - drivers/staging/media/hantro/hantro_h264.c | 122 ++++++++++++------ - drivers/staging/media/hantro/hantro_hw.h | 2 + - 3 files changed, 85 insertions(+), 56 deletions(-) - -diff --git a/drivers/staging/media/hantro/hantro_g1_h264_dec.c b/drivers/staging/media/hantro/hantro_g1_h264_dec.c -index 424c648ce9fc..89cf5741280e 100644 ---- a/drivers/staging/media/hantro/hantro_g1_h264_dec.c -+++ b/drivers/staging/media/hantro/hantro_g1_h264_dec.c -@@ -132,25 +132,12 @@ static void set_ref(struct hantro_ctx *ctx) - struct v4l2_h264_dpb_entry *dpb = ctx->h264_dec.dpb; - const u8 *b0_reflist, *b1_reflist, *p_reflist; - struct hantro_dev *vpu = ctx->dev; -- u32 dpb_longterm = 0; -- u32 dpb_valid = 0; - int reg_num; - u32 reg; - int i; - -- /* -- * Set up bit maps of valid and long term DPBs. -- * NOTE: The bits are reversed, i.e. MSb is DPB 0. -- */ -- for (i = 0; i < HANTRO_H264_DPB_SIZE; ++i) { -- if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE) -- dpb_valid |= BIT(HANTRO_H264_DPB_SIZE - 1 - i); -- -- if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM) -- dpb_longterm |= BIT(HANTRO_H264_DPB_SIZE - 1 - i); -- } -- vdpu_write_relaxed(vpu, dpb_valid << 16, G1_REG_VALID_REF); -- vdpu_write_relaxed(vpu, dpb_longterm << 16, G1_REG_LT_REF); -+ vdpu_write_relaxed(vpu, ctx->h264_dec.dpb_valid, G1_REG_VALID_REF); -+ vdpu_write_relaxed(vpu, ctx->h264_dec.dpb_longterm, G1_REG_LT_REF); - - /* - * Set up reference frame picture numbers. -diff --git a/drivers/staging/media/hantro/hantro_h264.c b/drivers/staging/media/hantro/hantro_h264.c -index f2d3e81fb6ce..4db779354e89 100644 ---- a/drivers/staging/media/hantro/hantro_h264.c -+++ b/drivers/staging/media/hantro/hantro_h264.c -@@ -225,17 +225,65 @@ static void prepare_table(struct hantro_ctx *ctx) - { - const struct hantro_h264_dec_ctrls *ctrls = &ctx->h264_dec.ctrls; - const struct v4l2_ctrl_h264_decode_params *dec_param = ctrls->decode; -+ const struct v4l2_ctrl_h264_slice_params *slices = ctrls->slices; - struct hantro_h264_dec_priv_tbl *tbl = ctx->h264_dec.priv.cpu; - const struct v4l2_h264_dpb_entry *dpb = ctx->h264_dec.dpb; -+ u32 dpb_longterm = 0; -+ u32 dpb_valid = 0; - int i; - -+ /* -+ * Set up bit maps of valid and long term DPBs. -+ * NOTE: The bits are reversed, i.e. MSb is DPB 0. -+ */ -+ if ((slices[0].flags & V4L2_H264_SLICE_FLAG_FIELD_PIC) || (slices[0].flags & V4L2_H264_SPS_FLAG_MB_ADAPTIVE_FRAME_FIELD)) { -+ for (i = 0; i < HANTRO_H264_DPB_SIZE * 2; ++i) { -+ // check for correct reference use -+ u32 flag = (i & 0x1) ? V4L2_H264_DPB_ENTRY_FLAG_REF_BOTTOM : V4L2_H264_DPB_ENTRY_FLAG_REF_TOP; -+ if (dpb[i / 2].flags & flag) -+ dpb_valid |= BIT(HANTRO_H264_DPB_SIZE * 2 - 1 - i); -+ -+ if (dpb[i / 2].flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM) -+ dpb_longterm |= BIT(HANTRO_H264_DPB_SIZE * 2 - 1 - i); -+ } -+ -+ ctx->h264_dec.dpb_valid = dpb_valid; -+ ctx->h264_dec.dpb_longterm = dpb_longterm; -+ } else { -+ for (i = 0; i < HANTRO_H264_DPB_SIZE; ++i) { -+ if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE) -+ dpb_valid |= BIT(HANTRO_H264_DPB_SIZE - 1 - i); -+ -+ if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM) -+ dpb_longterm |= BIT(HANTRO_H264_DPB_SIZE - 1 - i); -+ } -+ -+ ctx->h264_dec.dpb_valid = dpb_valid << 16; -+ ctx->h264_dec.dpb_longterm = dpb_longterm << 16; -+ } -+ - for (i = 0; i < HANTRO_H264_DPB_SIZE; ++i) { -- tbl->poc[i * 2] = dpb[i].top_field_order_cnt; -- tbl->poc[i * 2 + 1] = dpb[i].bottom_field_order_cnt; -+ if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE) { -+ tbl->poc[i * 2] = dpb[i].top_field_order_cnt; -+ tbl->poc[i * 2 + 1] = dpb[i].bottom_field_order_cnt; -+ } else { -+ tbl->poc[i * 2] = 0; -+ tbl->poc[i * 2 + 1] = 0; -+ } - } - -- tbl->poc[32] = dec_param->top_field_order_cnt; -- tbl->poc[33] = dec_param->bottom_field_order_cnt; -+ if ((slices[0].flags & V4L2_H264_SLICE_FLAG_FIELD_PIC) || !(slices[0].flags & V4L2_H264_SPS_FLAG_MB_ADAPTIVE_FRAME_FIELD)) { -+ if ((slices[0].flags & V4L2_H264_SLICE_FLAG_FIELD_PIC)) -+ tbl->poc[32] = (slices[0].flags & V4L2_H264_SLICE_FLAG_BOTTOM_FIELD) ? -+ dec_param->bottom_field_order_cnt : -+ dec_param->top_field_order_cnt; -+ else -+ tbl->poc[32] = min(dec_param->top_field_order_cnt, dec_param->bottom_field_order_cnt); -+ tbl->poc[33] = 0; -+ } else { -+ tbl->poc[32] = dec_param->top_field_order_cnt; -+ tbl->poc[33] = dec_param->bottom_field_order_cnt; -+ } - - reorder_scaling_list(ctx); - } -@@ -249,21 +297,6 @@ struct hantro_h264_reflist_builder { - u8 num_valid; - }; - --static s32 get_poc(enum v4l2_field field, s32 top_field_order_cnt, -- s32 bottom_field_order_cnt) --{ -- switch (field) { -- case V4L2_FIELD_TOP: -- return top_field_order_cnt; -- case V4L2_FIELD_BOTTOM: -- return bottom_field_order_cnt; -- default: -- break; -- } -- -- return min(top_field_order_cnt, bottom_field_order_cnt); --} -- - static void - init_reflist_builder(struct hantro_ctx *ctx, - struct hantro_h264_reflist_builder *b) -@@ -271,9 +304,7 @@ init_reflist_builder(struct hantro_ctx *ctx, - const struct v4l2_ctrl_h264_slice_params *slice_params; - const struct v4l2_ctrl_h264_decode_params *dec_param; - const struct v4l2_ctrl_h264_sps *sps; -- struct vb2_v4l2_buffer *buf = hantro_get_dst_buf(ctx); - const struct v4l2_h264_dpb_entry *dpb = ctx->h264_dec.dpb; -- struct vb2_queue *cap_q = &ctx->fh.m2m_ctx->cap_q_ctx.q; - int cur_frame_num, max_frame_num; - unsigned int i; - -@@ -285,21 +316,15 @@ init_reflist_builder(struct hantro_ctx *ctx, - - memset(b, 0, sizeof(*b)); - b->dpb = dpb; -- b->curpoc = get_poc(buf->field, dec_param->top_field_order_cnt, -- dec_param->bottom_field_order_cnt); -+ b->curpoc = (slice_params->flags & V4L2_H264_SLICE_FLAG_BOTTOM_FIELD) ? -+ dec_param->bottom_field_order_cnt : -+ dec_param->top_field_order_cnt; - - for (i = 0; i < ARRAY_SIZE(ctx->h264_dec.dpb); i++) { -- int buf_idx; -- -- if (!(dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE)) -+ u32 ref_flag = dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_REF_FRAME; -+ if (!ref_flag) - continue; - -- buf_idx = vb2_find_timestamp(cap_q, dpb[i].reference_ts, 0); -- if (buf_idx < 0) -- continue; -- -- buf = to_vb2_v4l2_buffer(vb2_get_buffer(cap_q, buf_idx)); -- - /* - * Handle frame_num wraparound as described in section - * '8.2.4.1 Decoding process for picture numbers' of the spec. -@@ -311,8 +336,13 @@ init_reflist_builder(struct hantro_ctx *ctx, - else - b->frame_nums[i] = dpb[i].frame_num; - -- b->pocs[i] = get_poc(buf->field, dpb[i].top_field_order_cnt, -- dpb[i].bottom_field_order_cnt); -+ if (ref_flag == V4L2_H264_DPB_ENTRY_FLAG_REF_FRAME) -+ b->pocs[i] = min(dpb[i].bottom_field_order_cnt, dpb[i].top_field_order_cnt); -+ else if (ref_flag == V4L2_H264_DPB_ENTRY_FLAG_REF_BOTTOM) -+ b->pocs[i] = dpb[i].bottom_field_order_cnt; -+ else if (ref_flag == V4L2_H264_DPB_ENTRY_FLAG_REF_TOP) -+ b->pocs[i] = dpb[i].top_field_order_cnt; -+ - b->unordered_reflist[b->num_valid] = i; - b->num_valid++; - } -@@ -466,8 +496,7 @@ build_b_ref_lists(const struct hantro_h264_reflist_builder *builder, - static bool dpb_entry_match(const struct v4l2_h264_dpb_entry *a, - const struct v4l2_h264_dpb_entry *b) - { -- return a->top_field_order_cnt == b->top_field_order_cnt && -- a->bottom_field_order_cnt == b->bottom_field_order_cnt; -+ return a->reference_ts == b->reference_ts; - } - - static void update_dpb(struct hantro_ctx *ctx) -@@ -481,13 +510,13 @@ static void update_dpb(struct hantro_ctx *ctx) - - /* Disable all entries by default. */ - for (i = 0; i < ARRAY_SIZE(ctx->h264_dec.dpb); i++) -- ctx->h264_dec.dpb[i].flags &= ~V4L2_H264_DPB_ENTRY_FLAG_ACTIVE; -+ ctx->h264_dec.dpb[i].flags = 0; - - /* Try to match new DPB entries with existing ones by their POCs. */ - for (i = 0; i < ARRAY_SIZE(dec_param->dpb); i++) { - const struct v4l2_h264_dpb_entry *ndpb = &dec_param->dpb[i]; - -- if (!(ndpb->flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE)) -+ if (!(ndpb->flags & V4L2_H264_DPB_ENTRY_FLAG_VALID)) - continue; - - /* -@@ -498,8 +527,7 @@ static void update_dpb(struct hantro_ctx *ctx) - struct v4l2_h264_dpb_entry *cdpb; - - cdpb = &ctx->h264_dec.dpb[j]; -- if (cdpb->flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE || -- !dpb_entry_match(cdpb, ndpb)) -+ if (!dpb_entry_match(cdpb, ndpb)) - continue; - - *cdpb = *ndpb; -@@ -535,7 +563,11 @@ dma_addr_t hantro_h264_get_ref_buf(struct hantro_ctx *ctx, - unsigned int dpb_idx) - { - struct v4l2_h264_dpb_entry *dpb = ctx->h264_dec.dpb; -+ const struct v4l2_ctrl_h264_decode_params *dec_param = ctx->h264_dec.ctrls.decode; -+ const struct v4l2_ctrl_h264_slice_params *slices = ctx->h264_dec.ctrls.slices; - dma_addr_t dma_addr = 0; -+ s32 cur_poc; -+ u32 flags; - - if (dpb[dpb_idx].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE) - dma_addr = hantro_get_ref(ctx, dpb[dpb_idx].reference_ts); -@@ -553,7 +585,15 @@ dma_addr_t hantro_h264_get_ref_buf(struct hantro_ctx *ctx, - dma_addr = vb2_dma_contig_plane_dma_addr(buf, 0); - } - -- return dma_addr; -+ cur_poc = slices[0].flags & V4L2_H264_SLICE_FLAG_BOTTOM_FIELD ? -+ dec_param->bottom_field_order_cnt : -+ dec_param->top_field_order_cnt; -+ flags = dpb[dpb_idx].flags & V4L2_H264_DPB_ENTRY_FLAG_FIELD_PICTURE ? 0x2 : 0; -+ flags |= abs(dpb[dpb_idx].top_field_order_cnt - cur_poc) < -+ abs(dpb[dpb_idx].bottom_field_order_cnt - cur_poc) ? -+ 0x1 : 0; -+ -+ return dma_addr | flags; - } - - int hantro_h264_dec_prepare_run(struct hantro_ctx *ctx) -diff --git a/drivers/staging/media/hantro/hantro_hw.h b/drivers/staging/media/hantro/hantro_hw.h -index 2398d4c1f207..3dc7b8f27c32 100644 ---- a/drivers/staging/media/hantro/hantro_hw.h -+++ b/drivers/staging/media/hantro/hantro_hw.h -@@ -88,6 +88,8 @@ struct hantro_h264_dec_hw_ctx { - struct v4l2_h264_dpb_entry dpb[HANTRO_H264_DPB_SIZE]; - struct hantro_h264_dec_reflists reflists; - struct hantro_h264_dec_ctrls ctrls; -+ u32 dpb_longterm; -+ u32 dpb_valid; - }; - - /** --- -2.17.1 - diff --git a/patch/kernel/rk322x-current/01-linux-0014-v4l2-work-in-progress.patch.disabled b/patch/kernel/rk322x-current/01-linux-0014-v4l2-work-in-progress.patch.disabled deleted file mode 100644 index c032a8414..000000000 --- a/patch/kernel/rk322x-current/01-linux-0014-v4l2-work-in-progress.patch.disabled +++ /dev/null @@ -1,1525 +0,0 @@ -diff --git a/drivers/staging/media/hantro/rk3399_vpu_hw_mpeg2_dec.c b/drivers/staging/media/hantro/rk3399_vpu_hw_mpeg2_dec.c -index 7e9aad671489..b9b8194b42f2 100644 ---- a/drivers/staging/media/hantro/rk3399_vpu_hw_mpeg2_dec.c -+++ b/drivers/staging/media/hantro/rk3399_vpu_hw_mpeg2_dec.c -@@ -127,7 +127,7 @@ rk3399_vpu_mpeg2_dec_set_buffers(struct hantro_dev *vpu, - current_addr = addr; - - if (picture->picture_structure == PICT_BOTTOM_FIELD) -- addr += ALIGN(ctx->dst_fmt.width, 16); -+ addr += ALIGN(ctx->src_fmt.width, MB_DIM); - vdpu_write_relaxed(vpu, addr, VDPU_REG_DEC_OUT_BASE); - - if (!forward_addr) -@@ -220,8 +220,8 @@ void rk3399_vpu_mpeg2_dec_run(struct hantro_ctx *ctx) - VDPU_REG_DEC_CLK_GATE_E(1); - vdpu_write_relaxed(vpu, reg, VDPU_SWREG(57)); - -- reg = VDPU_REG_PIC_MB_WIDTH(MB_WIDTH(ctx->dst_fmt.width)) | -- VDPU_REG_PIC_MB_HEIGHT_P(MB_HEIGHT(ctx->dst_fmt.height)) | -+ reg = VDPU_REG_PIC_MB_WIDTH(MB_WIDTH(ctx->src_fmt.width)) | -+ VDPU_REG_PIC_MB_HEIGHT_P(MB_HEIGHT(ctx->src_fmt.height)) | - VDPU_REG_ALT_SCAN_E(picture->alternate_scan) | - VDPU_REG_TOPFIELDFIRST_E(picture->top_field_first); - vdpu_write_relaxed(vpu, reg, VDPU_SWREG(120)); --- -2.17.1 - - -From 3b87f8547b97f13afb8db289cc9974760e668b79 Mon Sep 17 00:00:00 2001 -From: Jonas Karlman -Date: Tue, 5 Nov 2019 23:06:34 +0000 -Subject: [PATCH] WIP: media: hantro: g1 mpeg2 src_fmt - -Fixes: ceaac6dc5b7a -Signed-off-by: Jonas Karlman ---- - drivers/staging/media/hantro/hantro_g1_mpeg2_dec.c | 6 +++--- - 1 file changed, 3 insertions(+), 3 deletions(-) - -diff --git a/drivers/staging/media/hantro/hantro_g1_mpeg2_dec.c b/drivers/staging/media/hantro/hantro_g1_mpeg2_dec.c -index 24041849384a..44f7326aba32 100644 ---- a/drivers/staging/media/hantro/hantro_g1_mpeg2_dec.c -+++ b/drivers/staging/media/hantro/hantro_g1_mpeg2_dec.c -@@ -125,7 +125,7 @@ hantro_g1_mpeg2_dec_set_buffers(struct hantro_dev *vpu, struct hantro_ctx *ctx, - current_addr = addr; - - if (picture->picture_structure == PICT_BOTTOM_FIELD) -- addr += ALIGN(ctx->dst_fmt.width, 16); -+ addr += ALIGN(ctx->src_fmt.width, MB_DIM); - vdpu_write_relaxed(vpu, addr, G1_REG_DEC_OUT_BASE); - - if (!forward_addr) -@@ -204,8 +204,8 @@ void hantro_g1_mpeg2_dec_run(struct hantro_ctx *ctx) - G1_REG_DEC_AXI_WR_ID(0); - vdpu_write_relaxed(vpu, reg, G1_SWREG(3)); - -- reg = G1_REG_PIC_MB_WIDTH(MB_WIDTH(ctx->dst_fmt.width)) | -- G1_REG_PIC_MB_HEIGHT_P(MB_HEIGHT(ctx->dst_fmt.height)) | -+ reg = G1_REG_PIC_MB_WIDTH(MB_WIDTH(ctx->src_fmt.width)) | -+ G1_REG_PIC_MB_HEIGHT_P(MB_HEIGHT(ctx->src_fmt.height)) | - G1_REG_ALT_SCAN_E(picture->alternate_scan) | - G1_REG_TOPFIELDFIRST_E(picture->top_field_first); - vdpu_write_relaxed(vpu, reg, G1_SWREG(4)); --- -2.17.1 - - -From 10bf68403975d4fe3b383c7882d6a7d8a8bca64b Mon Sep 17 00:00:00 2001 -From: Jonas Karlman -Date: Tue, 5 Nov 2019 23:09:18 +0000 -Subject: [PATCH] WIP: media: hantro: vp8 src_fmt - -Signed-off-by: Jonas Karlman ---- - drivers/staging/media/hantro/hantro_g1_vp8_dec.c | 4 ++-- - drivers/staging/media/hantro/hantro_vp8.c | 4 ++-- - drivers/staging/media/hantro/rk3399_vpu_hw_vp8_dec.c | 4 ++-- - 3 files changed, 6 insertions(+), 6 deletions(-) - -diff --git a/drivers/staging/media/hantro/hantro_g1_vp8_dec.c b/drivers/staging/media/hantro/hantro_g1_vp8_dec.c -index a5cdf150cd16..e36538117fbf 100644 ---- a/drivers/staging/media/hantro/hantro_g1_vp8_dec.c -+++ b/drivers/staging/media/hantro/hantro_g1_vp8_dec.c -@@ -430,8 +430,8 @@ void hantro_g1_vp8_dec_run(struct hantro_ctx *ctx) - { - const struct v4l2_ctrl_vp8_frame_header *hdr; - struct hantro_dev *vpu = ctx->dev; -- size_t height = ctx->dst_fmt.height; -- size_t width = ctx->dst_fmt.width; -+ size_t height = ctx->src_fmt.height; -+ size_t width = ctx->src_fmt.width; - u32 mb_width, mb_height; - u32 reg; - -diff --git a/drivers/staging/media/hantro/hantro_vp8.c b/drivers/staging/media/hantro/hantro_vp8.c -index 0e02d147b189..e010c9088fde 100644 ---- a/drivers/staging/media/hantro/hantro_vp8.c -+++ b/drivers/staging/media/hantro/hantro_vp8.c -@@ -151,8 +151,8 @@ int hantro_vp8_dec_init(struct hantro_ctx *ctx) - int ret; - - /* segment map table size calculation */ -- mb_width = DIV_ROUND_UP(ctx->dst_fmt.width, 16); -- mb_height = DIV_ROUND_UP(ctx->dst_fmt.height, 16); -+ mb_width = MB_WIDTH(ctx->src_fmt.width); -+ mb_height = MB_HEIGHT(ctx->src_fmt.height); - segment_map_size = round_up(DIV_ROUND_UP(mb_width * mb_height, 4), 64); - - /* -diff --git a/drivers/staging/media/hantro/rk3399_vpu_hw_vp8_dec.c b/drivers/staging/media/hantro/rk3399_vpu_hw_vp8_dec.c -index a4a792f00b11..2f553e740294 100644 ---- a/drivers/staging/media/hantro/rk3399_vpu_hw_vp8_dec.c -+++ b/drivers/staging/media/hantro/rk3399_vpu_hw_vp8_dec.c -@@ -508,8 +508,8 @@ void rk3399_vpu_vp8_dec_run(struct hantro_ctx *ctx) - { - const struct v4l2_ctrl_vp8_frame_header *hdr; - struct hantro_dev *vpu = ctx->dev; -- size_t height = ctx->dst_fmt.height; -- size_t width = ctx->dst_fmt.width; -+ size_t height = ctx->src_fmt.height; -+ size_t width = ctx->src_fmt.width; - u32 mb_width, mb_height; - u32 reg; - --- -2.17.1 - - -From 4f7561c70db7347ade627ee0aacfb45c35022195 Mon Sep 17 00:00:00 2001 -From: Jonas Karlman -Date: Sun, 18 Aug 2019 10:40:31 +0000 -Subject: [PATCH] media: hantro: Refactor G1 H264 code - -Use generated code from my rockchip-vpu-regtool - -Code could possible need some cleanup - -Signed-off-by: Jonas Karlman ---- - .../staging/media/hantro/hantro_g1_h264_dec.c | 653 +++++++++++------- - drivers/staging/media/hantro/hantro_h264.c | 14 + - drivers/staging/media/hantro/hantro_hw.h | 2 + - 3 files changed, 435 insertions(+), 234 deletions(-) - -diff --git a/drivers/staging/media/hantro/hantro_g1_h264_dec.c b/drivers/staging/media/hantro/hantro_g1_h264_dec.c -index 89cf5741280e..20999b005307 100644 ---- a/drivers/staging/media/hantro/hantro_g1_h264_dec.c -+++ b/drivers/staging/media/hantro/hantro_g1_h264_dec.c -@@ -1,6 +1,6 @@ - // SPDX-License-Identifier: GPL-2.0 - /* -- * Rockchip RK3288 VPU codec driver -+ * Hantro VPU codec driver - * - * Copyright (c) 2014 Rockchip Electronics Co., Ltd. - * Hertz Wong -@@ -15,235 +15,430 @@ - - #include - --#include "hantro_g1_regs.h" - #include "hantro_hw.h" - #include "hantro_v4l2.h" - --static void set_params(struct hantro_ctx *ctx) -+#define G1_SWREG(nr) ((nr) * 4) -+ -+#define G1_REG_RLC_VLC_BASE G1_SWREG(12) -+#define G1_REG_DEC_OUT_BASE G1_SWREG(13) -+#define G1_REG_REFER0_BASE G1_SWREG(14) -+#define G1_REG_REFER1_BASE G1_SWREG(15) -+#define G1_REG_REFER2_BASE G1_SWREG(16) -+#define G1_REG_REFER3_BASE G1_SWREG(17) -+#define G1_REG_REFER4_BASE G1_SWREG(18) -+#define G1_REG_REFER5_BASE G1_SWREG(19) -+#define G1_REG_REFER6_BASE G1_SWREG(20) -+#define G1_REG_REFER7_BASE G1_SWREG(21) -+#define G1_REG_REFER8_BASE G1_SWREG(22) -+#define G1_REG_REFER9_BASE G1_SWREG(23) -+#define G1_REG_REFER10_BASE G1_SWREG(24) -+#define G1_REG_REFER11_BASE G1_SWREG(25) -+#define G1_REG_REFER12_BASE G1_SWREG(26) -+#define G1_REG_REFER13_BASE G1_SWREG(27) -+#define G1_REG_REFER14_BASE G1_SWREG(28) -+#define G1_REG_REFER15_BASE G1_SWREG(29) -+#define G1_REG_QTABLE_BASE G1_SWREG(40) -+#define G1_REG_DIR_MV_BASE G1_SWREG(41) -+#define G1_REG_DEC_E(v) ((v) ? BIT(0) : 0) -+ -+#define G1_REG_DEC_AXI_RD_ID(v) (((v) << 24) & GENMASK(31, 24)) -+#define G1_REG_DEC_TIMEOUT_E(v) ((v) ? BIT(23) : 0) -+#define G1_REG_DEC_STRSWAP32_E(v) ((v) ? BIT(22) : 0) -+#define G1_REG_DEC_STRENDIAN_E(v) ((v) ? BIT(21) : 0) -+#define G1_REG_DEC_INSWAP32_E(v) ((v) ? BIT(20) : 0) -+#define G1_REG_DEC_OUTSWAP32_E(v) ((v) ? BIT(19) : 0) -+#define G1_REG_DEC_DATA_DISC_E(v) ((v) ? BIT(18) : 0) -+#define G1_REG_DEC_LATENCY(v) (((v) << 11) & GENMASK(16, 11)) -+#define G1_REG_DEC_CLK_GATE_E(v) ((v) ? BIT(10) : 0) -+#define G1_REG_DEC_IN_ENDIAN(v) ((v) ? BIT(9) : 0) -+#define G1_REG_DEC_OUT_ENDIAN(v) ((v) ? BIT(8) : 0) -+#define G1_REG_DEC_ADV_PRE_DIS(v) ((v) ? BIT(6) : 0) -+#define G1_REG_DEC_SCMD_DIS(v) ((v) ? BIT(5) : 0) -+#define G1_REG_DEC_MAX_BURST(v) (((v) << 0) & GENMASK(4, 0)) -+ -+#define G1_REG_DEC_MODE(v) (((v) << 28) & GENMASK(31, 28)) -+#define G1_REG_RLC_MODE_E(v) ((v) ? BIT(27) : 0) -+#define G1_REG_PIC_INTERLACE_E(v) ((v) ? BIT(23) : 0) -+#define G1_REG_PIC_FIELDMODE_E(v) ((v) ? BIT(22) : 0) -+#define G1_REG_PIC_TOPFIELD_E(v) ((v) ? BIT(19) : 0) -+#define G1_REG_FILTERING_DIS(v) ((v) ? BIT(14) : 0) -+#define G1_REG_PIC_FIXED_QUANT(v) ((v) ? BIT(13) : 0) -+#define G1_REG_WRITE_MVS_E(v) ((v) ? BIT(12) : 0) -+#define G1_REG_SEQ_MBAFF_E(v) ((v) ? BIT(10) : 0) -+#define G1_REG_PICORD_COUNT_E(v) ((v) ? BIT(9) : 0) -+#define G1_REG_DEC_AXI_WR_ID(v) (((v) << 0) & GENMASK(7, 0)) -+ -+#define G1_REG_PIC_MB_WIDTH(v) (((v) << 23) & GENMASK(31, 23)) -+#define G1_REG_PIC_MB_HEIGHT_P(v) (((v) << 11) & GENMASK(18, 11)) -+#define G1_REG_REF_FRAMES(v) (((v) << 0) & GENMASK(4, 0)) -+ -+#define G1_REG_STRM_START_BIT(v) (((v) << 26) & GENMASK(31, 26)) -+#define G1_REG_TYPE1_QUANT_E(v) ((v) ? BIT(24) : 0) -+#define G1_REG_CH_QP_OFFSET(v) (((v) << 19) & GENMASK(23, 19)) -+#define G1_REG_CH_QP_OFFSET2(v) (((v) << 14) & GENMASK(18, 14)) -+#define G1_REG_FIELDPIC_FLAG_E(v) ((v) ? BIT(0) : 0) -+ -+#define G1_REG_START_CODE_E(v) ((v) ? BIT(31) : 0) -+#define G1_REG_INIT_QP(v) (((v) << 25) & GENMASK(30, 25)) -+#define G1_REG_CH_8PIX_ILEAV_E(v) ((v) ? BIT(24) : 0) -+#define G1_REG_STREAM_LEN(v) (((v) << 0) & GENMASK(23, 0)) -+ -+#define G1_REG_CABAC_E(v) ((v) ? BIT(31) : 0) -+#define G1_REG_BLACKWHITE_E(v) ((v) ? BIT(30) : 0) -+#define G1_REG_DIR_8X8_INFER_E(v) ((v) ? BIT(29) : 0) -+#define G1_REG_WEIGHT_PRED_E(v) ((v) ? BIT(28) : 0) -+#define G1_REG_WEIGHT_BIPR_IDC(v) (((v) << 26) & GENMASK(27, 26)) -+#define G1_REG_FRAMENUM_LEN(v) (((v) << 16) & GENMASK(20, 16)) -+#define G1_REG_FRAMENUM(v) (((v) << 0) & GENMASK(15, 0)) -+ -+#define G1_REG_CONST_INTRA_E(v) ((v) ? BIT(31) : 0) -+#define G1_REG_FILT_CTRL_PRES(v) ((v) ? BIT(30) : 0) -+#define G1_REG_RDPIC_CNT_PRES(v) ((v) ? BIT(29) : 0) -+#define G1_REG_8X8TRANS_FLAG_E(v) ((v) ? BIT(28) : 0) -+#define G1_REG_REFPIC_MK_LEN(v) (((v) << 17) & GENMASK(27, 17)) -+#define G1_REG_IDR_PIC_E(v) ((v) ? BIT(16) : 0) -+#define G1_REG_IDR_PIC_ID(v) (((v) << 0) & GENMASK(15, 0)) -+ -+#define G1_REG_PPS_ID(v) (((v) << 24) & GENMASK(31, 24)) -+#define G1_REG_REFIDX1_ACTIVE(v) (((v) << 19) & GENMASK(23, 19)) -+#define G1_REG_REFIDX0_ACTIVE(v) (((v) << 14) & GENMASK(18, 14)) -+#define G1_REG_POC_LENGTH(v) (((v) << 0) & GENMASK(7, 0)) -+ -+#define G1_REG_PINIT_RLIST_F9(v) (((v) << 25) & GENMASK(29, 25)) -+#define G1_REG_PINIT_RLIST_F8(v) (((v) << 20) & GENMASK(24, 20)) -+#define G1_REG_PINIT_RLIST_F7(v) (((v) << 15) & GENMASK(19, 15)) -+#define G1_REG_PINIT_RLIST_F6(v) (((v) << 10) & GENMASK(14, 10)) -+#define G1_REG_PINIT_RLIST_F5(v) (((v) << 5) & GENMASK(9, 5)) -+#define G1_REG_PINIT_RLIST_F4(v) (((v) << 0) & GENMASK(4, 0)) -+ -+#define G1_REG_PINIT_RLIST_F15(v) (((v) << 25) & GENMASK(29, 25)) -+#define G1_REG_PINIT_RLIST_F14(v) (((v) << 20) & GENMASK(24, 20)) -+#define G1_REG_PINIT_RLIST_F13(v) (((v) << 15) & GENMASK(19, 15)) -+#define G1_REG_PINIT_RLIST_F12(v) (((v) << 10) & GENMASK(14, 10)) -+#define G1_REG_PINIT_RLIST_F11(v) (((v) << 5) & GENMASK(9, 5)) -+#define G1_REG_PINIT_RLIST_F10(v) (((v) << 0) & GENMASK(4, 0)) -+ -+#define G1_REG_REFER1_NBR(v) (((v) << 16) & GENMASK(31, 16)) -+#define G1_REG_REFER0_NBR(v) (((v) << 0) & GENMASK(15, 0)) -+ -+#define G1_REG_REFER3_NBR(v) (((v) << 16) & GENMASK(31, 16)) -+#define G1_REG_REFER2_NBR(v) (((v) << 0) & GENMASK(15, 0)) -+ -+#define G1_REG_REFER5_NBR(v) (((v) << 16) & GENMASK(31, 16)) -+#define G1_REG_REFER4_NBR(v) (((v) << 0) & GENMASK(15, 0)) -+ -+#define G1_REG_REFER7_NBR(v) (((v) << 16) & GENMASK(31, 16)) -+#define G1_REG_REFER6_NBR(v) (((v) << 0) & GENMASK(15, 0)) -+ -+#define G1_REG_REFER9_NBR(v) (((v) << 16) & GENMASK(31, 16)) -+#define G1_REG_REFER8_NBR(v) (((v) << 0) & GENMASK(15, 0)) -+ -+#define G1_REG_REFER11_NBR(v) (((v) << 16) & GENMASK(31, 16)) -+#define G1_REG_REFER10_NBR(v) (((v) << 0) & GENMASK(15, 0)) -+ -+#define G1_REG_REFER13_NBR(v) (((v) << 16) & GENMASK(31, 16)) -+#define G1_REG_REFER12_NBR(v) (((v) << 0) & GENMASK(15, 0)) -+ -+#define G1_REG_REFER15_NBR(v) (((v) << 16) & GENMASK(31, 16)) -+#define G1_REG_REFER14_NBR(v) (((v) << 0) & GENMASK(15, 0)) -+ -+#define G1_REG_REFER_LTERM_E(v) (((v) << 0) & GENMASK(31, 0)) -+ -+#define G1_REG_REFER_VALID_E(v) (((v) << 0) & GENMASK(31, 0)) -+ -+#define G1_REG_BINIT_RLIST_B2(v) (((v) << 25) & GENMASK(29, 25)) -+#define G1_REG_BINIT_RLIST_F2(v) (((v) << 20) & GENMASK(24, 20)) -+#define G1_REG_BINIT_RLIST_B1(v) (((v) << 15) & GENMASK(19, 15)) -+#define G1_REG_BINIT_RLIST_F1(v) (((v) << 10) & GENMASK(14, 10)) -+#define G1_REG_BINIT_RLIST_B0(v) (((v) << 5) & GENMASK(9, 5)) -+#define G1_REG_BINIT_RLIST_F0(v) (((v) << 0) & GENMASK(4, 0)) -+ -+#define G1_REG_BINIT_RLIST_B5(v) (((v) << 25) & GENMASK(29, 25)) -+#define G1_REG_BINIT_RLIST_F5(v) (((v) << 20) & GENMASK(24, 20)) -+#define G1_REG_BINIT_RLIST_B4(v) (((v) << 15) & GENMASK(19, 15)) -+#define G1_REG_BINIT_RLIST_F4(v) (((v) << 10) & GENMASK(14, 10)) -+#define G1_REG_BINIT_RLIST_B3(v) (((v) << 5) & GENMASK(9, 5)) -+#define G1_REG_BINIT_RLIST_F3(v) (((v) << 0) & GENMASK(4, 0)) -+ -+#define G1_REG_BINIT_RLIST_B8(v) (((v) << 25) & GENMASK(29, 25)) -+#define G1_REG_BINIT_RLIST_F8(v) (((v) << 20) & GENMASK(24, 20)) -+#define G1_REG_BINIT_RLIST_B7(v) (((v) << 15) & GENMASK(19, 15)) -+#define G1_REG_BINIT_RLIST_F7(v) (((v) << 10) & GENMASK(14, 10)) -+#define G1_REG_BINIT_RLIST_B6(v) (((v) << 5) & GENMASK(9, 5)) -+#define G1_REG_BINIT_RLIST_F6(v) (((v) << 0) & GENMASK(4, 0)) -+ -+#define G1_REG_BINIT_RLIST_B11(v) (((v) << 25) & GENMASK(29, 25)) -+#define G1_REG_BINIT_RLIST_F11(v) (((v) << 20) & GENMASK(24, 20)) -+#define G1_REG_BINIT_RLIST_B10(v) (((v) << 15) & GENMASK(19, 15)) -+#define G1_REG_BINIT_RLIST_F10(v) (((v) << 10) & GENMASK(14, 10)) -+#define G1_REG_BINIT_RLIST_B9(v) (((v) << 5) & GENMASK(9, 5)) -+#define G1_REG_BINIT_RLIST_F9(v) (((v) << 0) & GENMASK(4, 0)) -+ -+#define G1_REG_BINIT_RLIST_B14(v) (((v) << 25) & GENMASK(29, 25)) -+#define G1_REG_BINIT_RLIST_F14(v) (((v) << 20) & GENMASK(24, 20)) -+#define G1_REG_BINIT_RLIST_B13(v) (((v) << 15) & GENMASK(19, 15)) -+#define G1_REG_BINIT_RLIST_F13(v) (((v) << 10) & GENMASK(14, 10)) -+#define G1_REG_BINIT_RLIST_B12(v) (((v) << 5) & GENMASK(9, 5)) -+#define G1_REG_BINIT_RLIST_F12(v) (((v) << 0) & GENMASK(4, 0)) -+ -+#define G1_REG_PINIT_RLIST_F3(v) (((v) << 25) & GENMASK(29, 25)) -+#define G1_REG_PINIT_RLIST_F2(v) (((v) << 20) & GENMASK(24, 20)) -+#define G1_REG_PINIT_RLIST_F1(v) (((v) << 15) & GENMASK(19, 15)) -+#define G1_REG_PINIT_RLIST_F0(v) (((v) << 10) & GENMASK(14, 10)) -+#define G1_REG_BINIT_RLIST_B15(v) (((v) << 5) & GENMASK(9, 5)) -+#define G1_REG_BINIT_RLIST_F15(v) (((v) << 0) & GENMASK(4, 0)) -+ -+#define G1_REG_STARTMB_X(v) (((v) << 23) & GENMASK(31, 23)) -+#define G1_REG_STARTMB_Y(v) (((v) << 15) & GENMASK(22, 15)) -+ -+#define G1_REG_PRED_BC_TAP_0_0(v) (((v) << 22) & GENMASK(31, 22)) -+#define G1_REG_PRED_BC_TAP_0_1(v) (((v) << 12) & GENMASK(21, 12)) -+#define G1_REG_PRED_BC_TAP_0_2(v) (((v) << 2) & GENMASK(11, 2)) -+ -+#define G1_REG_REFBU_E(v) ((v) ? BIT(31) : 0) -+ -+#define G1_REG_APF_THRESHOLD(v) (((v) << 0) & GENMASK(13, 0)) -+ -+void hantro_g1_h264_dec_run(struct hantro_ctx *ctx) - { -- const struct hantro_h264_dec_ctrls *ctrls = &ctx->h264_dec.ctrls; -- const struct v4l2_ctrl_h264_decode_params *dec_param = ctrls->decode; -- const struct v4l2_ctrl_h264_slice_params *slices = ctrls->slices; -- const struct v4l2_ctrl_h264_sps *sps = ctrls->sps; -- const struct v4l2_ctrl_h264_pps *pps = ctrls->pps; -- struct vb2_v4l2_buffer *src_buf = hantro_get_src_buf(ctx); - struct hantro_dev *vpu = ctx->dev; -+ struct vb2_v4l2_buffer *src_buf, *dst_buf; -+ const struct hantro_h264_dec_ctrls *ctrls; -+ const struct v4l2_ctrl_h264_decode_params *decode; -+ const struct v4l2_ctrl_h264_slice_params *slices; -+ const struct v4l2_ctrl_h264_sps *sps; -+ const struct v4l2_ctrl_h264_pps *pps; -+ const u8 *b0_reflist, *b1_reflist, *p_reflist; -+ dma_addr_t addr; -+ size_t offset = 0; - u32 reg; - -- /* Decoder control register 0. */ -- reg = G1_REG_DEC_CTRL0_DEC_AXI_WR_ID(0x0); -- if (sps->flags & V4L2_H264_SPS_FLAG_MB_ADAPTIVE_FRAME_FIELD) -- reg |= G1_REG_DEC_CTRL0_SEQ_MBAFF_E; -- if (sps->profile_idc > 66) { -- reg |= G1_REG_DEC_CTRL0_PICORD_COUNT_E; -- if (dec_param->nal_ref_idc) -- reg |= G1_REG_DEC_CTRL0_WRITE_MVS_E; -- } -+ /* Prepare the H264 decoder context. */ -+ if (hantro_h264_dec_prepare_run(ctx)) -+ return; - -- if (!(sps->flags & V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY) && -- (sps->flags & V4L2_H264_SPS_FLAG_MB_ADAPTIVE_FRAME_FIELD || -- slices[0].flags & V4L2_H264_SLICE_FLAG_FIELD_PIC)) -- reg |= G1_REG_DEC_CTRL0_PIC_INTERLACE_E; -- if (slices[0].flags & V4L2_H264_SLICE_FLAG_FIELD_PIC) -- reg |= G1_REG_DEC_CTRL0_PIC_FIELDMODE_E; -- if (!(slices[0].flags & V4L2_H264_SLICE_FLAG_BOTTOM_FIELD)) -- reg |= G1_REG_DEC_CTRL0_PIC_TOPFIELD_E; -- vdpu_write_relaxed(vpu, reg, G1_REG_DEC_CTRL0); -- -- /* Decoder control register 1. */ -- reg = G1_REG_DEC_CTRL1_PIC_MB_WIDTH(MB_WIDTH(ctx->src_fmt.width)) | -- G1_REG_DEC_CTRL1_PIC_MB_HEIGHT_P(MB_HEIGHT(ctx->src_fmt.height)) | -- G1_REG_DEC_CTRL1_REF_FRAMES(sps->max_num_ref_frames); -- vdpu_write_relaxed(vpu, reg, G1_REG_DEC_CTRL1); -- -- /* Decoder control register 2. */ -- reg = G1_REG_DEC_CTRL2_CH_QP_OFFSET(pps->chroma_qp_index_offset) | -- G1_REG_DEC_CTRL2_CH_QP_OFFSET2(pps->second_chroma_qp_index_offset); -- -- /* always use the matrix sent from userspace */ -- reg |= G1_REG_DEC_CTRL2_TYPE1_QUANT_E; -- -- if (!(sps->flags & V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY)) -- reg |= G1_REG_DEC_CTRL2_FIELDPIC_FLAG_E; -- vdpu_write_relaxed(vpu, reg, G1_REG_DEC_CTRL2); -- -- /* Decoder control register 3. */ -- reg = G1_REG_DEC_CTRL3_START_CODE_E | -- G1_REG_DEC_CTRL3_INIT_QP(pps->pic_init_qp_minus26 + 26) | -- G1_REG_DEC_CTRL3_STREAM_LEN(vb2_get_plane_payload(&src_buf->vb2_buf, 0)); -- vdpu_write_relaxed(vpu, reg, G1_REG_DEC_CTRL3); -- -- /* Decoder control register 4. */ -- reg = G1_REG_DEC_CTRL4_FRAMENUM_LEN(sps->log2_max_frame_num_minus4 + 4) | -- G1_REG_DEC_CTRL4_FRAMENUM(slices[0].frame_num) | -- G1_REG_DEC_CTRL4_WEIGHT_BIPR_IDC(pps->weighted_bipred_idc); -- if (pps->flags & V4L2_H264_PPS_FLAG_ENTROPY_CODING_MODE) -- reg |= G1_REG_DEC_CTRL4_CABAC_E; -- if (sps->flags & V4L2_H264_SPS_FLAG_DIRECT_8X8_INFERENCE) -- reg |= G1_REG_DEC_CTRL4_DIR_8X8_INFER_E; -- if (sps->profile_idc >= 100 && sps->chroma_format_idc == 0) -- reg |= G1_REG_DEC_CTRL4_BLACKWHITE_E; -- if (pps->flags & V4L2_H264_PPS_FLAG_WEIGHTED_PRED) -- reg |= G1_REG_DEC_CTRL4_WEIGHT_PRED_E; -- vdpu_write_relaxed(vpu, reg, G1_REG_DEC_CTRL4); -- -- /* Decoder control register 5. */ -- reg = G1_REG_DEC_CTRL5_REFPIC_MK_LEN(slices[0].dec_ref_pic_marking_bit_size) | -- G1_REG_DEC_CTRL5_IDR_PIC_ID(slices[0].idr_pic_id); -- if (pps->flags & V4L2_H264_PPS_FLAG_CONSTRAINED_INTRA_PRED) -- reg |= G1_REG_DEC_CTRL5_CONST_INTRA_E; -- if (pps->flags & V4L2_H264_PPS_FLAG_DEBLOCKING_FILTER_CONTROL_PRESENT) -- reg |= G1_REG_DEC_CTRL5_FILT_CTRL_PRES; -- if (pps->flags & V4L2_H264_PPS_FLAG_REDUNDANT_PIC_CNT_PRESENT) -- reg |= G1_REG_DEC_CTRL5_RDPIC_CNT_PRES; -- if (pps->flags & V4L2_H264_PPS_FLAG_TRANSFORM_8X8_MODE) -- reg |= G1_REG_DEC_CTRL5_8X8TRANS_FLAG_E; -- if (dec_param->flags & V4L2_H264_DECODE_PARAM_FLAG_IDR_PIC) -- reg |= G1_REG_DEC_CTRL5_IDR_PIC_E; -- vdpu_write_relaxed(vpu, reg, G1_REG_DEC_CTRL5); -- -- /* Decoder control register 6. */ -- reg = G1_REG_DEC_CTRL6_PPS_ID(slices[0].pic_parameter_set_id) | -- G1_REG_DEC_CTRL6_REFIDX0_ACTIVE(pps->num_ref_idx_l0_default_active_minus1 + 1) | -- G1_REG_DEC_CTRL6_REFIDX1_ACTIVE(pps->num_ref_idx_l1_default_active_minus1 + 1) | -- G1_REG_DEC_CTRL6_POC_LENGTH(slices[0].pic_order_cnt_bit_size); -- vdpu_write_relaxed(vpu, reg, G1_REG_DEC_CTRL6); -- -- /* Error concealment register. */ -- vdpu_write_relaxed(vpu, 0, G1_REG_ERR_CONC); -- -- /* Prediction filter tap register. */ -- vdpu_write_relaxed(vpu, -- G1_REG_PRED_FLT_PRED_BC_TAP_0_0(1) | -- G1_REG_PRED_FLT_PRED_BC_TAP_0_1(-5 & 0x3ff) | -- G1_REG_PRED_FLT_PRED_BC_TAP_0_2(20), -- G1_REG_PRED_FLT); -- -- /* Reference picture buffer control register. */ -- vdpu_write_relaxed(vpu, 0, G1_REG_REF_BUF_CTRL); -- -- /* Reference picture buffer control register 2. */ -- vdpu_write_relaxed(vpu, G1_REG_REF_BUF_CTRL2_APF_THRESHOLD(8), -- G1_REG_REF_BUF_CTRL2); --} -+ src_buf = hantro_get_src_buf(ctx); -+ dst_buf = hantro_get_dst_buf(ctx); - --static void set_ref(struct hantro_ctx *ctx) --{ -- struct v4l2_h264_dpb_entry *dpb = ctx->h264_dec.dpb; -- const u8 *b0_reflist, *b1_reflist, *p_reflist; -- struct hantro_dev *vpu = ctx->dev; -- int reg_num; -- u32 reg; -- int i; -- -- vdpu_write_relaxed(vpu, ctx->h264_dec.dpb_valid, G1_REG_VALID_REF); -- vdpu_write_relaxed(vpu, ctx->h264_dec.dpb_longterm, G1_REG_LT_REF); -- -- /* -- * Set up reference frame picture numbers. -- * -- * Each G1_REG_REF_PIC(x) register contains numbers of two -- * subsequential reference pictures. -- */ -- for (i = 0; i < HANTRO_H264_DPB_SIZE; i += 2) { -- reg = 0; -- if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM) -- reg |= G1_REG_REF_PIC_REFER0_NBR(dpb[i].pic_num); -- else -- reg |= G1_REG_REF_PIC_REFER0_NBR(dpb[i].frame_num); -- -- if (dpb[i + 1].flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM) -- reg |= G1_REG_REF_PIC_REFER1_NBR(dpb[i + 1].pic_num); -- else -- reg |= G1_REG_REF_PIC_REFER1_NBR(dpb[i + 1].frame_num); -- -- vdpu_write_relaxed(vpu, reg, G1_REG_REF_PIC(i / 2)); -- } -+ ctrls = &ctx->h264_dec.ctrls; -+ decode = ctrls->decode; -+ slices = ctrls->slices; -+ sps = ctrls->sps; -+ pps = ctrls->pps; - - b0_reflist = ctx->h264_dec.reflists.b0; - b1_reflist = ctx->h264_dec.reflists.b1; - p_reflist = ctx->h264_dec.reflists.p; - -- /* -- * Each G1_REG_BD_REF_PIC(x) register contains three entries -- * of each forward and backward picture list. -- */ -- reg_num = 0; -- for (i = 0; i < 15; i += 3) { -- reg = G1_REG_BD_REF_PIC_BINIT_RLIST_F0(b0_reflist[i]) | -- G1_REG_BD_REF_PIC_BINIT_RLIST_F1(b0_reflist[i + 1]) | -- G1_REG_BD_REF_PIC_BINIT_RLIST_F2(b0_reflist[i + 2]) | -- G1_REG_BD_REF_PIC_BINIT_RLIST_B0(b1_reflist[i]) | -- G1_REG_BD_REF_PIC_BINIT_RLIST_B1(b1_reflist[i + 1]) | -- G1_REG_BD_REF_PIC_BINIT_RLIST_B2(b1_reflist[i + 2]); -- vdpu_write_relaxed(vpu, reg, G1_REG_BD_REF_PIC(reg_num++)); -- } -- -- /* -- * G1_REG_BD_P_REF_PIC register contains last entries (index 15) -- * of forward and backward reference picture lists and first 4 entries -- * of P forward picture list. -- */ -- reg = G1_REG_BD_P_REF_PIC_BINIT_RLIST_F15(b0_reflist[15]) | -- G1_REG_BD_P_REF_PIC_BINIT_RLIST_B15(b1_reflist[15]) | -- G1_REG_BD_P_REF_PIC_PINIT_RLIST_F0(p_reflist[0]) | -- G1_REG_BD_P_REF_PIC_PINIT_RLIST_F1(p_reflist[1]) | -- G1_REG_BD_P_REF_PIC_PINIT_RLIST_F2(p_reflist[2]) | -- G1_REG_BD_P_REF_PIC_PINIT_RLIST_F3(p_reflist[3]); -- vdpu_write_relaxed(vpu, reg, G1_REG_BD_P_REF_PIC); -- -- /* -- * Each G1_REG_FWD_PIC(x) register contains six consecutive -- * entries of P forward picture list, starting from index 4. -- */ -- reg_num = 0; -- for (i = 4; i < HANTRO_H264_DPB_SIZE; i += 6) { -- reg = G1_REG_FWD_PIC_PINIT_RLIST_F0(p_reflist[i]) | -- G1_REG_FWD_PIC_PINIT_RLIST_F1(p_reflist[i + 1]) | -- G1_REG_FWD_PIC_PINIT_RLIST_F2(p_reflist[i + 2]) | -- G1_REG_FWD_PIC_PINIT_RLIST_F3(p_reflist[i + 3]) | -- G1_REG_FWD_PIC_PINIT_RLIST_F4(p_reflist[i + 4]) | -- G1_REG_FWD_PIC_PINIT_RLIST_F5(p_reflist[i + 5]); -- vdpu_write_relaxed(vpu, reg, G1_REG_FWD_PIC(reg_num++)); -- } -+ reg = G1_REG_DEC_AXI_RD_ID(0xff) | -+ G1_REG_DEC_TIMEOUT_E(1) | -+ G1_REG_DEC_STRSWAP32_E(1) | -+ G1_REG_DEC_STRENDIAN_E(1) | -+ G1_REG_DEC_INSWAP32_E(1) | -+ G1_REG_DEC_OUTSWAP32_E(1) | -+ G1_REG_DEC_DATA_DISC_E(0) | -+ G1_REG_DEC_LATENCY(0) | -+ G1_REG_DEC_CLK_GATE_E(1) | -+ G1_REG_DEC_IN_ENDIAN(0) | -+ G1_REG_DEC_OUT_ENDIAN(1) | -+ G1_REG_DEC_ADV_PRE_DIS(0) | -+ G1_REG_DEC_SCMD_DIS(0) | -+ G1_REG_DEC_MAX_BURST(16); -+ vdpu_write_relaxed(vpu, reg, G1_SWREG(2)); -+ -+ reg = G1_REG_DEC_MODE(0) | -+ G1_REG_RLC_MODE_E(0) | -+ G1_REG_PIC_INTERLACE_E(!(sps->flags & V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY) && (sps->flags & V4L2_H264_SPS_FLAG_MB_ADAPTIVE_FRAME_FIELD || slices[0].flags & V4L2_H264_SLICE_FLAG_FIELD_PIC)) | -+ G1_REG_PIC_FIELDMODE_E(slices[0].flags & V4L2_H264_SLICE_FLAG_FIELD_PIC) | -+ G1_REG_PIC_TOPFIELD_E(!(slices[0].flags & V4L2_H264_SLICE_FLAG_BOTTOM_FIELD)) | -+ G1_REG_FILTERING_DIS(0) | -+ G1_REG_PIC_FIXED_QUANT(0) | -+ G1_REG_WRITE_MVS_E(sps->profile_idc > 66 && decode->nal_ref_idc) | -+ G1_REG_SEQ_MBAFF_E(sps->flags & V4L2_H264_SPS_FLAG_MB_ADAPTIVE_FRAME_FIELD) | -+ G1_REG_PICORD_COUNT_E(sps->profile_idc > 66) | -+ G1_REG_DEC_AXI_WR_ID(0); -+ vdpu_write_relaxed(vpu, reg, G1_SWREG(3)); -+ -+ reg = G1_REG_PIC_MB_WIDTH(MB_WIDTH(ctx->src_fmt.width)) | -+ G1_REG_PIC_MB_HEIGHT_P(MB_HEIGHT(ctx->src_fmt.height)) | -+ G1_REG_REF_FRAMES(sps->max_num_ref_frames); -+ vdpu_write_relaxed(vpu, reg, G1_SWREG(4)); -+ -+ reg = G1_REG_STRM_START_BIT(0) | -+ G1_REG_TYPE1_QUANT_E(1) | -+ G1_REG_CH_QP_OFFSET(pps->chroma_qp_index_offset) | -+ G1_REG_CH_QP_OFFSET2(pps->second_chroma_qp_index_offset) | -+ G1_REG_FIELDPIC_FLAG_E(!(sps->flags & V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY)); -+ vdpu_write_relaxed(vpu, reg, G1_SWREG(5)); -+ -+ reg = G1_REG_START_CODE_E(1) | -+ G1_REG_INIT_QP(pps->pic_init_qp_minus26 + 26) | -+ G1_REG_CH_8PIX_ILEAV_E(0) | -+ G1_REG_STREAM_LEN(vb2_get_plane_payload(&src_buf->vb2_buf, 0)); -+ vdpu_write_relaxed(vpu, reg, G1_SWREG(6)); -+ -+ reg = G1_REG_CABAC_E(pps->flags & V4L2_H264_PPS_FLAG_ENTROPY_CODING_MODE) | -+ G1_REG_BLACKWHITE_E(sps->profile_idc >= 100 && sps->chroma_format_idc == 0) | -+ G1_REG_DIR_8X8_INFER_E(sps->flags & V4L2_H264_SPS_FLAG_DIRECT_8X8_INFERENCE) | -+ G1_REG_WEIGHT_PRED_E(pps->flags & V4L2_H264_PPS_FLAG_WEIGHTED_PRED) | -+ G1_REG_WEIGHT_BIPR_IDC(pps->weighted_bipred_idc) | -+ G1_REG_FRAMENUM_LEN(sps->log2_max_frame_num_minus4 + 4) | -+ G1_REG_FRAMENUM(slices[0].frame_num); -+ vdpu_write_relaxed(vpu, reg, G1_SWREG(7)); -+ -+ reg = G1_REG_CONST_INTRA_E(pps->flags & V4L2_H264_PPS_FLAG_CONSTRAINED_INTRA_PRED) | -+ G1_REG_FILT_CTRL_PRES(pps->flags & V4L2_H264_PPS_FLAG_DEBLOCKING_FILTER_CONTROL_PRESENT) | -+ G1_REG_RDPIC_CNT_PRES(pps->flags & V4L2_H264_PPS_FLAG_REDUNDANT_PIC_CNT_PRESENT) | -+ G1_REG_8X8TRANS_FLAG_E(pps->flags & V4L2_H264_PPS_FLAG_TRANSFORM_8X8_MODE) | -+ G1_REG_REFPIC_MK_LEN(slices[0].dec_ref_pic_marking_bit_size) | -+ G1_REG_IDR_PIC_E(decode->flags & V4L2_H264_DECODE_PARAM_FLAG_IDR_PIC) | -+ G1_REG_IDR_PIC_ID(slices[0].idr_pic_id); -+ vdpu_write_relaxed(vpu, reg, G1_SWREG(8)); -+ -+ reg = G1_REG_PPS_ID(slices[0].pic_parameter_set_id) | -+ G1_REG_REFIDX1_ACTIVE(pps->num_ref_idx_l1_default_active_minus1 + 1) | -+ G1_REG_REFIDX0_ACTIVE(pps->num_ref_idx_l0_default_active_minus1 + 1) | -+ G1_REG_POC_LENGTH(slices[0].pic_order_cnt_bit_size); -+ vdpu_write_relaxed(vpu, reg, G1_SWREG(9)); -+ -+ reg = G1_REG_PINIT_RLIST_F9(p_reflist[9]) | -+ G1_REG_PINIT_RLIST_F8(p_reflist[8]) | -+ G1_REG_PINIT_RLIST_F7(p_reflist[7]) | -+ G1_REG_PINIT_RLIST_F6(p_reflist[6]) | -+ G1_REG_PINIT_RLIST_F5(p_reflist[5]) | -+ G1_REG_PINIT_RLIST_F4(p_reflist[4]); -+ vdpu_write_relaxed(vpu, reg, G1_SWREG(10)); -+ -+ reg = G1_REG_PINIT_RLIST_F15(p_reflist[15]) | -+ G1_REG_PINIT_RLIST_F14(p_reflist[14]) | -+ G1_REG_PINIT_RLIST_F13(p_reflist[13]) | -+ G1_REG_PINIT_RLIST_F12(p_reflist[12]) | -+ G1_REG_PINIT_RLIST_F11(p_reflist[11]) | -+ G1_REG_PINIT_RLIST_F10(p_reflist[10]); -+ vdpu_write_relaxed(vpu, reg, G1_SWREG(11)); -+ -+ reg = G1_REG_REFER1_NBR(hantro_h264_get_ref_nbr(ctx, 1)) | -+ G1_REG_REFER0_NBR(hantro_h264_get_ref_nbr(ctx, 0)); -+ vdpu_write_relaxed(vpu, reg, G1_SWREG(30)); -+ -+ reg = G1_REG_REFER3_NBR(hantro_h264_get_ref_nbr(ctx, 3)) | -+ G1_REG_REFER2_NBR(hantro_h264_get_ref_nbr(ctx, 2)); -+ vdpu_write_relaxed(vpu, reg, G1_SWREG(31)); -+ -+ reg = G1_REG_REFER5_NBR(hantro_h264_get_ref_nbr(ctx, 5)) | -+ G1_REG_REFER4_NBR(hantro_h264_get_ref_nbr(ctx, 4)); -+ vdpu_write_relaxed(vpu, reg, G1_SWREG(32)); -+ -+ reg = G1_REG_REFER7_NBR(hantro_h264_get_ref_nbr(ctx, 7)) | -+ G1_REG_REFER6_NBR(hantro_h264_get_ref_nbr(ctx, 6)); -+ vdpu_write_relaxed(vpu, reg, G1_SWREG(33)); -+ -+ reg = G1_REG_REFER9_NBR(hantro_h264_get_ref_nbr(ctx, 9)) | -+ G1_REG_REFER8_NBR(hantro_h264_get_ref_nbr(ctx, 8)); -+ vdpu_write_relaxed(vpu, reg, G1_SWREG(34)); -+ -+ reg = G1_REG_REFER11_NBR(hantro_h264_get_ref_nbr(ctx, 11)) | -+ G1_REG_REFER10_NBR(hantro_h264_get_ref_nbr(ctx, 10)); -+ vdpu_write_relaxed(vpu, reg, G1_SWREG(35)); -+ -+ reg = G1_REG_REFER13_NBR(hantro_h264_get_ref_nbr(ctx, 13)) | -+ G1_REG_REFER12_NBR(hantro_h264_get_ref_nbr(ctx, 12)); -+ vdpu_write_relaxed(vpu, reg, G1_SWREG(36)); -+ -+ reg = G1_REG_REFER15_NBR(hantro_h264_get_ref_nbr(ctx, 15)) | -+ G1_REG_REFER14_NBR(hantro_h264_get_ref_nbr(ctx, 14)); -+ vdpu_write_relaxed(vpu, reg, G1_SWREG(37)); -+ -+ reg = G1_REG_REFER_LTERM_E(ctx->h264_dec.dpb_longterm); -+ vdpu_write_relaxed(vpu, reg, G1_SWREG(38)); -+ -+ reg = G1_REG_REFER_VALID_E(ctx->h264_dec.dpb_valid); -+ vdpu_write_relaxed(vpu, reg, G1_SWREG(39)); -+ -+ reg = G1_REG_BINIT_RLIST_B2(b1_reflist[2]) | -+ G1_REG_BINIT_RLIST_F2(b0_reflist[2]) | -+ G1_REG_BINIT_RLIST_B1(b1_reflist[1]) | -+ G1_REG_BINIT_RLIST_F1(b0_reflist[1]) | -+ G1_REG_BINIT_RLIST_B0(b1_reflist[0]) | -+ G1_REG_BINIT_RLIST_F0(b0_reflist[0]); -+ vdpu_write_relaxed(vpu, reg, G1_SWREG(42)); -+ -+ reg = G1_REG_BINIT_RLIST_B5(b1_reflist[5]) | -+ G1_REG_BINIT_RLIST_F5(b0_reflist[5]) | -+ G1_REG_BINIT_RLIST_B4(b1_reflist[4]) | -+ G1_REG_BINIT_RLIST_F4(b0_reflist[4]) | -+ G1_REG_BINIT_RLIST_B3(b1_reflist[3]) | -+ G1_REG_BINIT_RLIST_F3(b0_reflist[3]); -+ vdpu_write_relaxed(vpu, reg, G1_SWREG(43)); -+ -+ reg = G1_REG_BINIT_RLIST_B8(b1_reflist[8]) | -+ G1_REG_BINIT_RLIST_F8(b0_reflist[8]) | -+ G1_REG_BINIT_RLIST_B7(b1_reflist[7]) | -+ G1_REG_BINIT_RLIST_F7(b0_reflist[7]) | -+ G1_REG_BINIT_RLIST_B6(b1_reflist[6]) | -+ G1_REG_BINIT_RLIST_F6(b0_reflist[6]); -+ vdpu_write_relaxed(vpu, reg, G1_SWREG(44)); -+ -+ reg = G1_REG_BINIT_RLIST_B11(b1_reflist[11]) | -+ G1_REG_BINIT_RLIST_F11(b0_reflist[11]) | -+ G1_REG_BINIT_RLIST_B10(b1_reflist[10]) | -+ G1_REG_BINIT_RLIST_F10(b0_reflist[10]) | -+ G1_REG_BINIT_RLIST_B9(b1_reflist[9]) | -+ G1_REG_BINIT_RLIST_F9(b0_reflist[9]); -+ vdpu_write_relaxed(vpu, reg, G1_SWREG(45)); -+ -+ reg = G1_REG_BINIT_RLIST_B14(b1_reflist[14]) | -+ G1_REG_BINIT_RLIST_F14(b0_reflist[14]) | -+ G1_REG_BINIT_RLIST_B13(b1_reflist[13]) | -+ G1_REG_BINIT_RLIST_F13(b0_reflist[13]) | -+ G1_REG_BINIT_RLIST_B12(b1_reflist[12]) | -+ G1_REG_BINIT_RLIST_F12(b0_reflist[12]); -+ vdpu_write_relaxed(vpu, reg, G1_SWREG(46)); -+ -+ reg = G1_REG_PINIT_RLIST_F3(p_reflist[3]) | -+ G1_REG_PINIT_RLIST_F2(p_reflist[2]) | -+ G1_REG_PINIT_RLIST_F1(p_reflist[1]) | -+ G1_REG_PINIT_RLIST_F0(p_reflist[0]) | -+ G1_REG_BINIT_RLIST_B15(b1_reflist[15]) | -+ G1_REG_BINIT_RLIST_F15(b0_reflist[15]); -+ vdpu_write_relaxed(vpu, reg, G1_SWREG(47)); -+ -+ reg = G1_REG_STARTMB_X(0) | -+ G1_REG_STARTMB_Y(0); -+ vdpu_write_relaxed(vpu, reg, G1_SWREG(48)); -+ -+ reg = G1_REG_PRED_BC_TAP_0_0(1) | -+ G1_REG_PRED_BC_TAP_0_1((u32)-5) | -+ G1_REG_PRED_BC_TAP_0_2(20); -+ vdpu_write_relaxed(vpu, reg, G1_SWREG(49)); -+ -+ reg = G1_REG_REFBU_E(0); -+ vdpu_write_relaxed(vpu, reg, G1_SWREG(51)); -+ -+ reg = G1_REG_APF_THRESHOLD(8); -+ vdpu_write_relaxed(vpu, reg, G1_SWREG(55)); - -- /* Set up addresses of DPB buffers. */ -- for (i = 0; i < HANTRO_H264_DPB_SIZE; i++) { -- dma_addr_t dma_addr = hantro_h264_get_ref_buf(ctx, i); -- -- vdpu_write_relaxed(vpu, dma_addr, G1_REG_ADDR_REF(i)); -- } --} -- --static void set_buffers(struct hantro_ctx *ctx) --{ -- const struct hantro_h264_dec_ctrls *ctrls = &ctx->h264_dec.ctrls; -- struct vb2_v4l2_buffer *src_buf, *dst_buf; -- struct hantro_dev *vpu = ctx->dev; -- dma_addr_t src_dma, dst_dma; -- size_t offset = 0; -- -- src_buf = hantro_get_src_buf(ctx); -- dst_buf = hantro_get_dst_buf(ctx); -+ /* Auxiliary buffer prepared in hantro_g1_h264_dec_prepare_table(). */ -+ vdpu_write_relaxed(vpu, ctx->h264_dec.priv.dma, G1_REG_QTABLE_BASE); - - /* Source (stream) buffer. */ -- src_dma = vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, 0); -- vdpu_write_relaxed(vpu, src_dma, G1_REG_ADDR_STR); -+ addr = vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, 0); -+ vdpu_write_relaxed(vpu, addr, G1_REG_RLC_VLC_BASE); - - /* Destination (decoded frame) buffer. */ -- dst_dma = hantro_get_dec_buf_addr(ctx, &dst_buf->vb2_buf); -+ addr = hantro_get_dec_buf_addr(ctx, &dst_buf->vb2_buf); - /* Adjust dma addr to start at second line for bottom field */ -- if (ctrls->slices[0].flags & V4L2_H264_SLICE_FLAG_BOTTOM_FIELD) -+ if (slices[0].flags & V4L2_H264_SLICE_FLAG_BOTTOM_FIELD) - offset = ALIGN(ctx->src_fmt.width, MB_DIM); -- vdpu_write_relaxed(vpu, dst_dma + offset, G1_REG_ADDR_DST); -+ vdpu_write_relaxed(vpu, addr + offset, G1_REG_DEC_OUT_BASE); - - /* Higher profiles require DMV buffer appended to reference frames. */ -- if (ctrls->sps->profile_idc > 66 && ctrls->decode->nal_ref_idc) { -+ if (sps->profile_idc > 66 && decode->nal_ref_idc) { - unsigned int bytes_per_mb = 384; - - /* DMV buffer for monochrome start directly after Y-plane */ -- if (ctrls->sps->profile_idc >= 100 && -- ctrls->sps->chroma_format_idc == 0) -+ if (sps->profile_idc >= 100 && sps->chroma_format_idc == 0) - bytes_per_mb = 256; - offset = bytes_per_mb * MB_WIDTH(ctx->src_fmt.width) * - MB_HEIGHT(ctx->src_fmt.height); -@@ -252,42 +447,32 @@ static void set_buffers(struct hantro_ctx *ctx) - * DMV buffer is split in two for field encoded frames, - * adjust offset for bottom field - */ -- if (ctrls->slices[0].flags & V4L2_H264_SLICE_FLAG_BOTTOM_FIELD) -+ if (slices[0].flags & V4L2_H264_SLICE_FLAG_BOTTOM_FIELD) - offset += 32 * MB_WIDTH(ctx->src_fmt.width) * - MB_HEIGHT(ctx->src_fmt.height); -- vdpu_write_relaxed(vpu, dst_dma + offset, G1_REG_ADDR_DIR_MV); -+ vdpu_write_relaxed(vpu, addr + offset, G1_REG_DIR_MV_BASE); - } - -- /* Auxiliary buffer prepared in hantro_g1_h264_dec_prepare_table(). */ -- vdpu_write_relaxed(vpu, ctx->h264_dec.priv.dma, G1_REG_ADDR_QTABLE); --} -- --void hantro_g1_h264_dec_run(struct hantro_ctx *ctx) --{ -- struct hantro_dev *vpu = ctx->dev; -- -- /* Prepare the H264 decoder context. */ -- if (hantro_h264_dec_prepare_run(ctx)) -- return; -- -- /* Configure hardware registers. */ -- set_params(ctx); -- set_ref(ctx); -- set_buffers(ctx); -+ vdpu_write_relaxed(vpu, hantro_h264_get_ref_buf(ctx, 0), G1_REG_REFER0_BASE); -+ vdpu_write_relaxed(vpu, hantro_h264_get_ref_buf(ctx, 1), G1_REG_REFER1_BASE); -+ vdpu_write_relaxed(vpu, hantro_h264_get_ref_buf(ctx, 2), G1_REG_REFER2_BASE); -+ vdpu_write_relaxed(vpu, hantro_h264_get_ref_buf(ctx, 3), G1_REG_REFER3_BASE); -+ vdpu_write_relaxed(vpu, hantro_h264_get_ref_buf(ctx, 4), G1_REG_REFER4_BASE); -+ vdpu_write_relaxed(vpu, hantro_h264_get_ref_buf(ctx, 5), G1_REG_REFER5_BASE); -+ vdpu_write_relaxed(vpu, hantro_h264_get_ref_buf(ctx, 6), G1_REG_REFER6_BASE); -+ vdpu_write_relaxed(vpu, hantro_h264_get_ref_buf(ctx, 7), G1_REG_REFER7_BASE); -+ vdpu_write_relaxed(vpu, hantro_h264_get_ref_buf(ctx, 8), G1_REG_REFER8_BASE); -+ vdpu_write_relaxed(vpu, hantro_h264_get_ref_buf(ctx, 9), G1_REG_REFER9_BASE); -+ vdpu_write_relaxed(vpu, hantro_h264_get_ref_buf(ctx, 10), G1_REG_REFER10_BASE); -+ vdpu_write_relaxed(vpu, hantro_h264_get_ref_buf(ctx, 11), G1_REG_REFER11_BASE); -+ vdpu_write_relaxed(vpu, hantro_h264_get_ref_buf(ctx, 12), G1_REG_REFER12_BASE); -+ vdpu_write_relaxed(vpu, hantro_h264_get_ref_buf(ctx, 13), G1_REG_REFER13_BASE); -+ vdpu_write_relaxed(vpu, hantro_h264_get_ref_buf(ctx, 14), G1_REG_REFER14_BASE); -+ vdpu_write_relaxed(vpu, hantro_h264_get_ref_buf(ctx, 15), G1_REG_REFER15_BASE); - - hantro_end_prepare_run(ctx); - - /* Start decoding! */ -- vdpu_write_relaxed(vpu, -- G1_REG_CONFIG_DEC_AXI_RD_ID(0xffu) | -- G1_REG_CONFIG_DEC_TIMEOUT_E | -- G1_REG_CONFIG_DEC_OUT_ENDIAN | -- G1_REG_CONFIG_DEC_STRENDIAN_E | -- G1_REG_CONFIG_DEC_MAX_BURST(16) | -- G1_REG_CONFIG_DEC_OUTSWAP32_E | -- G1_REG_CONFIG_DEC_INSWAP32_E | -- G1_REG_CONFIG_DEC_STRSWAP32_E | -- G1_REG_CONFIG_DEC_CLK_GATE_E, -- G1_REG_CONFIG); -- vdpu_write(vpu, G1_REG_INTERRUPT_DEC_E, G1_REG_INTERRUPT); -+ reg = G1_REG_DEC_E(1); -+ vdpu_write(vpu, reg, G1_SWREG(1)); - } -diff --git a/drivers/staging/media/hantro/hantro_h264.c b/drivers/staging/media/hantro/hantro_h264.c -index 4db779354e89..2edcdda2ad63 100644 ---- a/drivers/staging/media/hantro/hantro_h264.c -+++ b/drivers/staging/media/hantro/hantro_h264.c -@@ -596,6 +596,20 @@ dma_addr_t hantro_h264_get_ref_buf(struct hantro_ctx *ctx, - return dma_addr | flags; - } - -+u16 hantro_h264_get_ref_nbr(struct hantro_ctx *ctx, -+ unsigned int dpb_idx) -+{ -+ const struct v4l2_h264_dpb_entry *dpb = &ctx->h264_dec.dpb[dpb_idx]; -+ -+ if (!(dpb->flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE)) -+ return 0; -+ -+ if (dpb->flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM) -+ return dpb->pic_num; -+ -+ return dpb->frame_num; -+} -+ - int hantro_h264_dec_prepare_run(struct hantro_ctx *ctx) - { - struct hantro_h264_dec_hw_ctx *h264_ctx = &ctx->h264_dec; -diff --git a/drivers/staging/media/hantro/hantro_hw.h b/drivers/staging/media/hantro/hantro_hw.h -index 3dc7b8f27c32..fadd3e1bf0d9 100644 ---- a/drivers/staging/media/hantro/hantro_hw.h -+++ b/drivers/staging/media/hantro/hantro_hw.h -@@ -172,6 +172,8 @@ void hantro_jpeg_enc_exit(struct hantro_ctx *ctx); - - dma_addr_t hantro_h264_get_ref_buf(struct hantro_ctx *ctx, - unsigned int dpb_idx); -+u16 hantro_h264_get_ref_nbr(struct hantro_ctx *ctx, -+ unsigned int dpb_idx); - int hantro_h264_dec_prepare_run(struct hantro_ctx *ctx); - void hantro_g1_h264_dec_run(struct hantro_ctx *ctx); - int hantro_h264_dec_init(struct hantro_ctx *ctx); --- -2.17.1 - - -From 93fc47fb35fdbcc94bf1f1008fccffe16d7465c4 Mon Sep 17 00:00:00 2001 -From: Jonas Karlman -Date: Sun, 18 Aug 2019 10:40:31 +0000 -Subject: [PATCH] media: hantro: Add support for H264 decoding on RK3399 - -Signed-off-by: Jonas Karlman ---- - drivers/staging/media/hantro/Makefile | 1 + - drivers/staging/media/hantro/hantro_hw.h | 1 + - .../media/hantro/rk3399_vpu_hw_h264_dec.c | 493 ++++++++++++++++++ - 3 files changed, 495 insertions(+) - create mode 100644 drivers/staging/media/hantro/rk3399_vpu_hw_h264_dec.c - -diff --git a/drivers/staging/media/hantro/Makefile b/drivers/staging/media/hantro/Makefile -index 496b30c3c396..9bb8a560cb0a 100644 ---- a/drivers/staging/media/hantro/Makefile -+++ b/drivers/staging/media/hantro/Makefile -@@ -9,6 +9,7 @@ hantro-vpu-y += \ - hantro_g1_mpeg2_dec.o \ - hantro_g1_vp8_dec.o \ - rk3399_vpu_hw_jpeg_enc.o \ -+ rk3399_vpu_hw_h264_dec.o \ - rk3399_vpu_hw_mpeg2_dec.o \ - rk3399_vpu_hw_vp8_dec.o \ - hantro_jpeg.o \ -diff --git a/drivers/staging/media/hantro/hantro_hw.h b/drivers/staging/media/hantro/hantro_hw.h -index fadd3e1bf0d9..4a64873bf332 100644 ---- a/drivers/staging/media/hantro/hantro_hw.h -+++ b/drivers/staging/media/hantro/hantro_hw.h -@@ -176,6 +176,7 @@ u16 hantro_h264_get_ref_nbr(struct hantro_ctx *ctx, - unsigned int dpb_idx); - int hantro_h264_dec_prepare_run(struct hantro_ctx *ctx); - void hantro_g1_h264_dec_run(struct hantro_ctx *ctx); -+void rk3399_vpu_h264_dec_run(struct hantro_ctx *ctx); - int hantro_h264_dec_init(struct hantro_ctx *ctx); - void hantro_h264_dec_exit(struct hantro_ctx *ctx); - -diff --git a/drivers/staging/media/hantro/rk3399_vpu_hw_h264_dec.c b/drivers/staging/media/hantro/rk3399_vpu_hw_h264_dec.c -new file mode 100644 -index 000000000000..1f9de7d5a923 ---- /dev/null -+++ b/drivers/staging/media/hantro/rk3399_vpu_hw_h264_dec.c -@@ -0,0 +1,493 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Hantro VPU codec driver -+ * -+ * Copyright (c) 2014 Rockchip Electronics Co., Ltd. -+ * Hertz Wong -+ * Herman Chen -+ * -+ * Copyright (C) 2014 Google, Inc. -+ * Tomasz Figa -+ */ -+ -+#include -+#include -+ -+#include -+ -+#include "hantro_hw.h" -+#include "hantro_v4l2.h" -+ -+#define VDPU_SWREG(nr) ((nr) * 4) -+ -+#define VDPU_REG_DEC_OUT_BASE VDPU_SWREG(63) -+#define VDPU_REG_RLC_VLC_BASE VDPU_SWREG(64) -+#define VDPU_REG_QTABLE_BASE VDPU_SWREG(61) -+#define VDPU_REG_DIR_MV_BASE VDPU_SWREG(62) -+#define VDPU_REG_REFER0_BASE VDPU_SWREG(84) -+#define VDPU_REG_REFER1_BASE VDPU_SWREG(85) -+#define VDPU_REG_REFER2_BASE VDPU_SWREG(86) -+#define VDPU_REG_REFER3_BASE VDPU_SWREG(87) -+#define VDPU_REG_REFER4_BASE VDPU_SWREG(88) -+#define VDPU_REG_REFER5_BASE VDPU_SWREG(89) -+#define VDPU_REG_REFER6_BASE VDPU_SWREG(90) -+#define VDPU_REG_REFER7_BASE VDPU_SWREG(91) -+#define VDPU_REG_REFER8_BASE VDPU_SWREG(92) -+#define VDPU_REG_REFER9_BASE VDPU_SWREG(93) -+#define VDPU_REG_REFER10_BASE VDPU_SWREG(94) -+#define VDPU_REG_REFER11_BASE VDPU_SWREG(95) -+#define VDPU_REG_REFER12_BASE VDPU_SWREG(96) -+#define VDPU_REG_REFER13_BASE VDPU_SWREG(97) -+#define VDPU_REG_REFER14_BASE VDPU_SWREG(98) -+#define VDPU_REG_REFER15_BASE VDPU_SWREG(99) -+#define VDPU_REG_DEC_E(v) ((v) ? BIT(0) : 0) -+ -+#define VDPU_REG_DEC_ADV_PRE_DIS(v) ((v) ? BIT(11) : 0) -+#define VDPU_REG_DEC_SCMD_DIS(v) ((v) ? BIT(10) : 0) -+#define VDPU_REG_FILTERING_DIS(v) ((v) ? BIT(8) : 0) -+#define VDPU_REG_PIC_FIXED_QUANT(v) ((v) ? BIT(7) : 0) -+#define VDPU_REG_DEC_LATENCY(v) (((v) << 1) & GENMASK(6, 1)) -+ -+#define VDPU_REG_INIT_QP(v) (((v) << 25) & GENMASK(30, 25)) -+#define VDPU_REG_STREAM_LEN(v) (((v) << 0) & GENMASK(23, 0)) -+ -+#define VDPU_REG_APF_THRESHOLD(v) (((v) << 17) & GENMASK(30, 17)) -+#define VDPU_REG_STARTMB_X(v) (((v) << 8) & GENMASK(16, 8)) -+#define VDPU_REG_STARTMB_Y(v) (((v) << 0) & GENMASK(7, 0)) -+ -+#define VDPU_REG_DEC_MODE(v) (((v) << 0) & GENMASK(3, 0)) -+ -+#define VDPU_REG_DEC_STRENDIAN_E(v) ((v) ? BIT(5) : 0) -+#define VDPU_REG_DEC_STRSWAP32_E(v) ((v) ? BIT(4) : 0) -+#define VDPU_REG_DEC_OUTSWAP32_E(v) ((v) ? BIT(3) : 0) -+#define VDPU_REG_DEC_INSWAP32_E(v) ((v) ? BIT(2) : 0) -+#define VDPU_REG_DEC_OUT_ENDIAN(v) ((v) ? BIT(1) : 0) -+#define VDPU_REG_DEC_IN_ENDIAN(v) ((v) ? BIT(0) : 0) -+ -+#define VDPU_REG_DEC_DATA_DISC_E(v) ((v) ? BIT(22) : 0) -+#define VDPU_REG_DEC_MAX_BURST(v) (((v) << 16) & GENMASK(20, 16)) -+#define VDPU_REG_DEC_AXI_WR_ID(v) (((v) << 8) & GENMASK(15, 8)) -+#define VDPU_REG_DEC_AXI_RD_ID(v) (((v) << 0) & GENMASK(7, 0)) -+ -+#define VDPU_REG_START_CODE_E(v) ((v) ? BIT(22) : 0) -+#define VDPU_REG_CH_8PIX_ILEAV_E(v) ((v) ? BIT(21) : 0) -+#define VDPU_REG_RLC_MODE_E(v) ((v) ? BIT(20) : 0) -+#define VDPU_REG_PIC_INTERLACE_E(v) ((v) ? BIT(17) : 0) -+#define VDPU_REG_PIC_FIELDMODE_E(v) ((v) ? BIT(16) : 0) -+#define VDPU_REG_PIC_TOPFIELD_E(v) ((v) ? BIT(13) : 0) -+#define VDPU_REG_WRITE_MVS_E(v) ((v) ? BIT(10) : 0) -+#define VDPU_REG_SEQ_MBAFF_E(v) ((v) ? BIT(7) : 0) -+#define VDPU_REG_PICORD_COUNT_E(v) ((v) ? BIT(6) : 0) -+#define VDPU_REG_DEC_TIMEOUT_E(v) ((v) ? BIT(5) : 0) -+#define VDPU_REG_DEC_CLK_GATE_E(v) ((v) ? BIT(4) : 0) -+ -+#define VDPU_REG_PRED_BC_TAP_0_0(v) (((v) << 22) & GENMASK(31, 22)) -+#define VDPU_REG_PRED_BC_TAP_0_1(v) (((v) << 12) & GENMASK(21, 12)) -+#define VDPU_REG_PRED_BC_TAP_0_2(v) (((v) << 2) & GENMASK(11, 2)) -+ -+#define VDPU_REG_REFBU_E(v) ((v) ? BIT(31) : 0) -+ -+#define VDPU_REG_PINIT_RLIST_F9(v) (((v) << 25) & GENMASK(29, 25)) -+#define VDPU_REG_PINIT_RLIST_F8(v) (((v) << 20) & GENMASK(24, 20)) -+#define VDPU_REG_PINIT_RLIST_F7(v) (((v) << 15) & GENMASK(19, 15)) -+#define VDPU_REG_PINIT_RLIST_F6(v) (((v) << 10) & GENMASK(14, 10)) -+#define VDPU_REG_PINIT_RLIST_F5(v) (((v) << 5) & GENMASK(9, 5)) -+#define VDPU_REG_PINIT_RLIST_F4(v) (((v) << 0) & GENMASK(4, 0)) -+ -+#define VDPU_REG_PINIT_RLIST_F15(v) (((v) << 25) & GENMASK(29, 25)) -+#define VDPU_REG_PINIT_RLIST_F14(v) (((v) << 20) & GENMASK(24, 20)) -+#define VDPU_REG_PINIT_RLIST_F13(v) (((v) << 15) & GENMASK(19, 15)) -+#define VDPU_REG_PINIT_RLIST_F12(v) (((v) << 10) & GENMASK(14, 10)) -+#define VDPU_REG_PINIT_RLIST_F11(v) (((v) << 5) & GENMASK(9, 5)) -+#define VDPU_REG_PINIT_RLIST_F10(v) (((v) << 0) & GENMASK(4, 0)) -+ -+#define VDPU_REG_REFER1_NBR(v) (((v) << 16) & GENMASK(31, 16)) -+#define VDPU_REG_REFER0_NBR(v) (((v) << 0) & GENMASK(15, 0)) -+ -+#define VDPU_REG_REFER3_NBR(v) (((v) << 16) & GENMASK(31, 16)) -+#define VDPU_REG_REFER2_NBR(v) (((v) << 0) & GENMASK(15, 0)) -+ -+#define VDPU_REG_REFER5_NBR(v) (((v) << 16) & GENMASK(31, 16)) -+#define VDPU_REG_REFER4_NBR(v) (((v) << 0) & GENMASK(15, 0)) -+ -+#define VDPU_REG_REFER7_NBR(v) (((v) << 16) & GENMASK(31, 16)) -+#define VDPU_REG_REFER6_NBR(v) (((v) << 0) & GENMASK(15, 0)) -+ -+#define VDPU_REG_REFER9_NBR(v) (((v) << 16) & GENMASK(31, 16)) -+#define VDPU_REG_REFER8_NBR(v) (((v) << 0) & GENMASK(15, 0)) -+ -+#define VDPU_REG_REFER11_NBR(v) (((v) << 16) & GENMASK(31, 16)) -+#define VDPU_REG_REFER10_NBR(v) (((v) << 0) & GENMASK(15, 0)) -+ -+#define VDPU_REG_REFER13_NBR(v) (((v) << 16) & GENMASK(31, 16)) -+#define VDPU_REG_REFER12_NBR(v) (((v) << 0) & GENMASK(15, 0)) -+ -+#define VDPU_REG_REFER15_NBR(v) (((v) << 16) & GENMASK(31, 16)) -+#define VDPU_REG_REFER14_NBR(v) (((v) << 0) & GENMASK(15, 0)) -+ -+#define VDPU_REG_BINIT_RLIST_F5(v) (((v) << 25) & GENMASK(29, 25)) -+#define VDPU_REG_BINIT_RLIST_F4(v) (((v) << 20) & GENMASK(24, 20)) -+#define VDPU_REG_BINIT_RLIST_F3(v) (((v) << 15) & GENMASK(19, 15)) -+#define VDPU_REG_BINIT_RLIST_F2(v) (((v) << 10) & GENMASK(14, 10)) -+#define VDPU_REG_BINIT_RLIST_F1(v) (((v) << 5) & GENMASK(9, 5)) -+#define VDPU_REG_BINIT_RLIST_F0(v) (((v) << 0) & GENMASK(4, 0)) -+ -+#define VDPU_REG_BINIT_RLIST_F11(v) (((v) << 25) & GENMASK(29, 25)) -+#define VDPU_REG_BINIT_RLIST_F10(v) (((v) << 20) & GENMASK(24, 20)) -+#define VDPU_REG_BINIT_RLIST_F9(v) (((v) << 15) & GENMASK(19, 15)) -+#define VDPU_REG_BINIT_RLIST_F8(v) (((v) << 10) & GENMASK(14, 10)) -+#define VDPU_REG_BINIT_RLIST_F7(v) (((v) << 5) & GENMASK(9, 5)) -+#define VDPU_REG_BINIT_RLIST_F6(v) (((v) << 0) & GENMASK(4, 0)) -+ -+#define VDPU_REG_BINIT_RLIST_F15(v) (((v) << 15) & GENMASK(19, 15)) -+#define VDPU_REG_BINIT_RLIST_F14(v) (((v) << 10) & GENMASK(14, 10)) -+#define VDPU_REG_BINIT_RLIST_F13(v) (((v) << 5) & GENMASK(9, 5)) -+#define VDPU_REG_BINIT_RLIST_F12(v) (((v) << 0) & GENMASK(4, 0)) -+ -+#define VDPU_REG_BINIT_RLIST_B5(v) (((v) << 25) & GENMASK(29, 25)) -+#define VDPU_REG_BINIT_RLIST_B4(v) (((v) << 20) & GENMASK(24, 20)) -+#define VDPU_REG_BINIT_RLIST_B3(v) (((v) << 15) & GENMASK(19, 15)) -+#define VDPU_REG_BINIT_RLIST_B2(v) (((v) << 10) & GENMASK(14, 10)) -+#define VDPU_REG_BINIT_RLIST_B1(v) (((v) << 5) & GENMASK(9, 5)) -+#define VDPU_REG_BINIT_RLIST_B0(v) (((v) << 0) & GENMASK(4, 0)) -+ -+#define VDPU_REG_BINIT_RLIST_B11(v) (((v) << 25) & GENMASK(29, 25)) -+#define VDPU_REG_BINIT_RLIST_B10(v) (((v) << 20) & GENMASK(24, 20)) -+#define VDPU_REG_BINIT_RLIST_B9(v) (((v) << 15) & GENMASK(19, 15)) -+#define VDPU_REG_BINIT_RLIST_B8(v) (((v) << 10) & GENMASK(14, 10)) -+#define VDPU_REG_BINIT_RLIST_B7(v) (((v) << 5) & GENMASK(9, 5)) -+#define VDPU_REG_BINIT_RLIST_B6(v) (((v) << 0) & GENMASK(4, 0)) -+ -+#define VDPU_REG_BINIT_RLIST_B15(v) (((v) << 15) & GENMASK(19, 15)) -+#define VDPU_REG_BINIT_RLIST_B14(v) (((v) << 10) & GENMASK(14, 10)) -+#define VDPU_REG_BINIT_RLIST_B13(v) (((v) << 5) & GENMASK(9, 5)) -+#define VDPU_REG_BINIT_RLIST_B12(v) (((v) << 0) & GENMASK(4, 0)) -+ -+#define VDPU_REG_PINIT_RLIST_F3(v) (((v) << 15) & GENMASK(19, 15)) -+#define VDPU_REG_PINIT_RLIST_F2(v) (((v) << 10) & GENMASK(14, 10)) -+#define VDPU_REG_PINIT_RLIST_F1(v) (((v) << 5) & GENMASK(9, 5)) -+#define VDPU_REG_PINIT_RLIST_F0(v) (((v) << 0) & GENMASK(4, 0)) -+ -+#define VDPU_REG_REFER_LTERM_E(v) (((v) << 0) & GENMASK(31, 0)) -+ -+#define VDPU_REG_REFER_VALID_E(v) (((v) << 0) & GENMASK(31, 0)) -+ -+#define VDPU_REG_STRM_START_BIT(v) (((v) << 0) & GENMASK(5, 0)) -+ -+#define VDPU_REG_CH_QP_OFFSET2(v) (((v) << 22) & GENMASK(26, 22)) -+#define VDPU_REG_CH_QP_OFFSET(v) (((v) << 17) & GENMASK(21, 17)) -+#define VDPU_REG_PIC_MB_HEIGHT_P(v) (((v) << 9) & GENMASK(16, 9)) -+#define VDPU_REG_PIC_MB_WIDTH(v) (((v) << 0) & GENMASK(8, 0)) -+ -+#define VDPU_REG_WEIGHT_BIPR_IDC(v) (((v) << 16) & GENMASK(17, 16)) -+#define VDPU_REG_REF_FRAMES(v) (((v) << 0) & GENMASK(4, 0)) -+ -+#define VDPU_REG_FILT_CTRL_PRES(v) ((v) ? BIT(31) : 0) -+#define VDPU_REG_RDPIC_CNT_PRES(v) ((v) ? BIT(30) : 0) -+#define VDPU_REG_FRAMENUM_LEN(v) (((v) << 16) & GENMASK(20, 16)) -+#define VDPU_REG_FRAMENUM(v) (((v) << 0) & GENMASK(15, 0)) -+ -+#define VDPU_REG_REFPIC_MK_LEN(v) (((v) << 16) & GENMASK(26, 16)) -+#define VDPU_REG_IDR_PIC_ID(v) (((v) << 0) & GENMASK(15, 0)) -+ -+#define VDPU_REG_PPS_ID(v) (((v) << 24) & GENMASK(31, 24)) -+#define VDPU_REG_REFIDX1_ACTIVE(v) (((v) << 19) & GENMASK(23, 19)) -+#define VDPU_REG_REFIDX0_ACTIVE(v) (((v) << 14) & GENMASK(18, 14)) -+#define VDPU_REG_POC_LENGTH(v) (((v) << 0) & GENMASK(7, 0)) -+ -+#define VDPU_REG_IDR_PIC_E(v) ((v) ? BIT(8) : 0) -+#define VDPU_REG_DIR_8X8_INFER_E(v) ((v) ? BIT(7) : 0) -+#define VDPU_REG_BLACKWHITE_E(v) ((v) ? BIT(6) : 0) -+#define VDPU_REG_CABAC_E(v) ((v) ? BIT(5) : 0) -+#define VDPU_REG_WEIGHT_PRED_E(v) ((v) ? BIT(4) : 0) -+#define VDPU_REG_CONST_INTRA_E(v) ((v) ? BIT(3) : 0) -+#define VDPU_REG_8X8TRANS_FLAG_E(v) ((v) ? BIT(2) : 0) -+#define VDPU_REG_TYPE1_QUANT_E(v) ((v) ? BIT(1) : 0) -+#define VDPU_REG_FIELDPIC_FLAG_E(v) ((v) ? BIT(0) : 0) -+ -+void rk3399_vpu_h264_dec_run(struct hantro_ctx *ctx) -+{ -+ struct hantro_dev *vpu = ctx->dev; -+ struct vb2_v4l2_buffer *src_buf, *dst_buf; -+ const struct hantro_h264_dec_ctrls *ctrls; -+ const struct v4l2_ctrl_h264_decode_params *decode; -+ const struct v4l2_ctrl_h264_slice_params *slices; -+ const struct v4l2_ctrl_h264_sps *sps; -+ const struct v4l2_ctrl_h264_pps *pps; -+ const u8 *b0_reflist, *b1_reflist, *p_reflist; -+ dma_addr_t addr; -+ size_t offset = 0; -+ u32 reg; -+ -+ /* Prepare the H264 decoder context. */ -+ if (hantro_h264_dec_prepare_run(ctx)) -+ return; -+ -+ src_buf = hantro_get_src_buf(ctx); -+ dst_buf = hantro_get_dst_buf(ctx); -+ -+ ctrls = &ctx->h264_dec.ctrls; -+ decode = ctrls->decode; -+ slices = ctrls->slices; -+ sps = ctrls->sps; -+ pps = ctrls->pps; -+ -+ b0_reflist = ctx->h264_dec.reflists.b0; -+ b1_reflist = ctx->h264_dec.reflists.b1; -+ p_reflist = ctx->h264_dec.reflists.p; -+ -+ reg = VDPU_REG_DEC_ADV_PRE_DIS(0) | -+ VDPU_REG_DEC_SCMD_DIS(0) | -+ VDPU_REG_FILTERING_DIS(0) | -+ VDPU_REG_PIC_FIXED_QUANT(0) | -+ VDPU_REG_DEC_LATENCY(0); -+ vdpu_write_relaxed(vpu, reg, VDPU_SWREG(50)); -+ -+ reg = VDPU_REG_INIT_QP(pps->pic_init_qp_minus26 + 26) | -+ VDPU_REG_STREAM_LEN(vb2_get_plane_payload(&src_buf->vb2_buf, 0)); -+ vdpu_write_relaxed(vpu, reg, VDPU_SWREG(51)); -+ -+ reg = VDPU_REG_APF_THRESHOLD(8) | -+ VDPU_REG_STARTMB_X(0) | -+ VDPU_REG_STARTMB_Y(0); -+ vdpu_write_relaxed(vpu, reg, VDPU_SWREG(52)); -+ -+ reg = VDPU_REG_DEC_MODE(0); -+ vdpu_write_relaxed(vpu, reg, VDPU_SWREG(53)); -+ -+ reg = VDPU_REG_DEC_STRENDIAN_E(1) | -+ VDPU_REG_DEC_STRSWAP32_E(1) | -+ VDPU_REG_DEC_OUTSWAP32_E(1) | -+ VDPU_REG_DEC_INSWAP32_E(1) | -+ VDPU_REG_DEC_OUT_ENDIAN(1) | -+ VDPU_REG_DEC_IN_ENDIAN(0); -+ vdpu_write_relaxed(vpu, reg, VDPU_SWREG(54)); -+ -+ reg = VDPU_REG_DEC_DATA_DISC_E(0) | -+ VDPU_REG_DEC_MAX_BURST(16) | -+ VDPU_REG_DEC_AXI_WR_ID(0) | -+ VDPU_REG_DEC_AXI_RD_ID(0xff); -+ vdpu_write_relaxed(vpu, reg, VDPU_SWREG(56)); -+ -+ reg = VDPU_REG_START_CODE_E(1) | -+ VDPU_REG_CH_8PIX_ILEAV_E(0) | -+ VDPU_REG_RLC_MODE_E(0) | -+ VDPU_REG_PIC_INTERLACE_E(!(sps->flags & V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY) && (sps->flags & V4L2_H264_SPS_FLAG_MB_ADAPTIVE_FRAME_FIELD || slices[0].flags & V4L2_H264_SLICE_FLAG_FIELD_PIC)) | -+ VDPU_REG_PIC_FIELDMODE_E(slices[0].flags & V4L2_H264_SLICE_FLAG_FIELD_PIC) | -+ VDPU_REG_PIC_TOPFIELD_E(!(slices[0].flags & V4L2_H264_SLICE_FLAG_BOTTOM_FIELD)) | -+ VDPU_REG_WRITE_MVS_E(sps->profile_idc > 66 && decode->nal_ref_idc) | -+ VDPU_REG_SEQ_MBAFF_E(sps->flags & V4L2_H264_SPS_FLAG_MB_ADAPTIVE_FRAME_FIELD) | -+ VDPU_REG_PICORD_COUNT_E(sps->profile_idc > 66) | -+ VDPU_REG_DEC_TIMEOUT_E(1) | -+ VDPU_REG_DEC_CLK_GATE_E(1); -+ vdpu_write_relaxed(vpu, reg, VDPU_SWREG(57)); -+ -+ reg = VDPU_REG_PRED_BC_TAP_0_0(1) | -+ VDPU_REG_PRED_BC_TAP_0_1((u32)-5) | -+ VDPU_REG_PRED_BC_TAP_0_2(20); -+ vdpu_write_relaxed(vpu, reg, VDPU_SWREG(59)); -+ -+ reg = VDPU_REG_REFBU_E(0); -+ vdpu_write_relaxed(vpu, reg, VDPU_SWREG(65)); -+ -+ reg = VDPU_REG_PINIT_RLIST_F9(p_reflist[9]) | -+ VDPU_REG_PINIT_RLIST_F8(p_reflist[8]) | -+ VDPU_REG_PINIT_RLIST_F7(p_reflist[7]) | -+ VDPU_REG_PINIT_RLIST_F6(p_reflist[6]) | -+ VDPU_REG_PINIT_RLIST_F5(p_reflist[5]) | -+ VDPU_REG_PINIT_RLIST_F4(p_reflist[4]); -+ vdpu_write_relaxed(vpu, reg, VDPU_SWREG(74)); -+ -+ reg = VDPU_REG_PINIT_RLIST_F15(p_reflist[15]) | -+ VDPU_REG_PINIT_RLIST_F14(p_reflist[14]) | -+ VDPU_REG_PINIT_RLIST_F13(p_reflist[13]) | -+ VDPU_REG_PINIT_RLIST_F12(p_reflist[12]) | -+ VDPU_REG_PINIT_RLIST_F11(p_reflist[11]) | -+ VDPU_REG_PINIT_RLIST_F10(p_reflist[10]); -+ vdpu_write_relaxed(vpu, reg, VDPU_SWREG(75)); -+ -+ reg = VDPU_REG_REFER1_NBR(hantro_h264_get_ref_nbr(ctx, 1)) | -+ VDPU_REG_REFER0_NBR(hantro_h264_get_ref_nbr(ctx, 0)); -+ vdpu_write_relaxed(vpu, reg, VDPU_SWREG(76)); -+ -+ reg = VDPU_REG_REFER3_NBR(hantro_h264_get_ref_nbr(ctx, 3)) | -+ VDPU_REG_REFER2_NBR(hantro_h264_get_ref_nbr(ctx, 2)); -+ vdpu_write_relaxed(vpu, reg, VDPU_SWREG(77)); -+ -+ reg = VDPU_REG_REFER5_NBR(hantro_h264_get_ref_nbr(ctx, 5)) | -+ VDPU_REG_REFER4_NBR(hantro_h264_get_ref_nbr(ctx, 4)); -+ vdpu_write_relaxed(vpu, reg, VDPU_SWREG(78)); -+ -+ reg = VDPU_REG_REFER7_NBR(hantro_h264_get_ref_nbr(ctx, 7)) | -+ VDPU_REG_REFER6_NBR(hantro_h264_get_ref_nbr(ctx, 6)); -+ vdpu_write_relaxed(vpu, reg, VDPU_SWREG(79)); -+ -+ reg = VDPU_REG_REFER9_NBR(hantro_h264_get_ref_nbr(ctx, 9)) | -+ VDPU_REG_REFER8_NBR(hantro_h264_get_ref_nbr(ctx, 8)); -+ vdpu_write_relaxed(vpu, reg, VDPU_SWREG(80)); -+ -+ reg = VDPU_REG_REFER11_NBR(hantro_h264_get_ref_nbr(ctx, 11)) | -+ VDPU_REG_REFER10_NBR(hantro_h264_get_ref_nbr(ctx, 10)); -+ vdpu_write_relaxed(vpu, reg, VDPU_SWREG(81)); -+ -+ reg = VDPU_REG_REFER13_NBR(hantro_h264_get_ref_nbr(ctx, 13)) | -+ VDPU_REG_REFER12_NBR(hantro_h264_get_ref_nbr(ctx, 12)); -+ vdpu_write_relaxed(vpu, reg, VDPU_SWREG(82)); -+ -+ reg = VDPU_REG_REFER15_NBR(hantro_h264_get_ref_nbr(ctx, 15)) | -+ VDPU_REG_REFER14_NBR(hantro_h264_get_ref_nbr(ctx, 14)); -+ vdpu_write_relaxed(vpu, reg, VDPU_SWREG(83)); -+ -+ reg = VDPU_REG_BINIT_RLIST_F5(b0_reflist[5]) | -+ VDPU_REG_BINIT_RLIST_F4(b0_reflist[4]) | -+ VDPU_REG_BINIT_RLIST_F3(b0_reflist[3]) | -+ VDPU_REG_BINIT_RLIST_F2(b0_reflist[2]) | -+ VDPU_REG_BINIT_RLIST_F1(b0_reflist[1]) | -+ VDPU_REG_BINIT_RLIST_F0(b0_reflist[0]); -+ vdpu_write_relaxed(vpu, reg, VDPU_SWREG(100)); -+ -+ reg = VDPU_REG_BINIT_RLIST_F11(b0_reflist[11]) | -+ VDPU_REG_BINIT_RLIST_F10(b0_reflist[10]) | -+ VDPU_REG_BINIT_RLIST_F9(b0_reflist[9]) | -+ VDPU_REG_BINIT_RLIST_F8(b0_reflist[8]) | -+ VDPU_REG_BINIT_RLIST_F7(b0_reflist[7]) | -+ VDPU_REG_BINIT_RLIST_F6(b0_reflist[6]); -+ vdpu_write_relaxed(vpu, reg, VDPU_SWREG(101)); -+ -+ reg = VDPU_REG_BINIT_RLIST_F15(b0_reflist[15]) | -+ VDPU_REG_BINIT_RLIST_F14(b0_reflist[14]) | -+ VDPU_REG_BINIT_RLIST_F13(b0_reflist[13]) | -+ VDPU_REG_BINIT_RLIST_F12(b0_reflist[12]); -+ vdpu_write_relaxed(vpu, reg, VDPU_SWREG(102)); -+ -+ reg = VDPU_REG_BINIT_RLIST_B5(b1_reflist[5]) | -+ VDPU_REG_BINIT_RLIST_B4(b1_reflist[4]) | -+ VDPU_REG_BINIT_RLIST_B3(b1_reflist[3]) | -+ VDPU_REG_BINIT_RLIST_B2(b1_reflist[2]) | -+ VDPU_REG_BINIT_RLIST_B1(b1_reflist[1]) | -+ VDPU_REG_BINIT_RLIST_B0(b1_reflist[0]); -+ vdpu_write_relaxed(vpu, reg, VDPU_SWREG(103)); -+ -+ reg = VDPU_REG_BINIT_RLIST_B11(b1_reflist[11]) | -+ VDPU_REG_BINIT_RLIST_B10(b1_reflist[10]) | -+ VDPU_REG_BINIT_RLIST_B9(b1_reflist[9]) | -+ VDPU_REG_BINIT_RLIST_B8(b1_reflist[8]) | -+ VDPU_REG_BINIT_RLIST_B7(b1_reflist[7]) | -+ VDPU_REG_BINIT_RLIST_B6(b1_reflist[6]); -+ vdpu_write_relaxed(vpu, reg, VDPU_SWREG(104)); -+ -+ reg = VDPU_REG_BINIT_RLIST_B15(b1_reflist[15]) | -+ VDPU_REG_BINIT_RLIST_B14(b1_reflist[14]) | -+ VDPU_REG_BINIT_RLIST_B13(b1_reflist[13]) | -+ VDPU_REG_BINIT_RLIST_B12(b1_reflist[12]); -+ vdpu_write_relaxed(vpu, reg, VDPU_SWREG(105)); -+ -+ reg = VDPU_REG_PINIT_RLIST_F3(p_reflist[3]) | -+ VDPU_REG_PINIT_RLIST_F2(p_reflist[2]) | -+ VDPU_REG_PINIT_RLIST_F1(p_reflist[1]) | -+ VDPU_REG_PINIT_RLIST_F0(p_reflist[0]); -+ vdpu_write_relaxed(vpu, reg, VDPU_SWREG(106)); -+ -+ reg = VDPU_REG_REFER_LTERM_E(ctx->h264_dec.dpb_longterm); -+ vdpu_write_relaxed(vpu, reg, VDPU_SWREG(107)); -+ -+ reg = VDPU_REG_REFER_VALID_E(ctx->h264_dec.dpb_valid); -+ vdpu_write_relaxed(vpu, reg, VDPU_SWREG(108)); -+ -+ reg = VDPU_REG_STRM_START_BIT(0); -+ vdpu_write_relaxed(vpu, reg, VDPU_SWREG(109)); -+ -+ reg = VDPU_REG_CH_QP_OFFSET2(pps->second_chroma_qp_index_offset) | -+ VDPU_REG_CH_QP_OFFSET(pps->chroma_qp_index_offset) | -+ VDPU_REG_PIC_MB_HEIGHT_P(MB_HEIGHT(ctx->src_fmt.height)) | -+ VDPU_REG_PIC_MB_WIDTH(MB_WIDTH(ctx->src_fmt.width)); -+ vdpu_write_relaxed(vpu, reg, VDPU_SWREG(110)); -+ -+ reg = VDPU_REG_WEIGHT_BIPR_IDC(pps->weighted_bipred_idc) | -+ VDPU_REG_REF_FRAMES(sps->max_num_ref_frames); -+ vdpu_write_relaxed(vpu, reg, VDPU_SWREG(111)); -+ -+ reg = VDPU_REG_FILT_CTRL_PRES(pps->flags & V4L2_H264_PPS_FLAG_DEBLOCKING_FILTER_CONTROL_PRESENT) | -+ VDPU_REG_RDPIC_CNT_PRES(pps->flags & V4L2_H264_PPS_FLAG_REDUNDANT_PIC_CNT_PRESENT) | -+ VDPU_REG_FRAMENUM_LEN(sps->log2_max_frame_num_minus4 + 4) | -+ VDPU_REG_FRAMENUM(slices[0].frame_num); -+ vdpu_write_relaxed(vpu, reg, VDPU_SWREG(112)); -+ -+ reg = VDPU_REG_REFPIC_MK_LEN(slices[0].dec_ref_pic_marking_bit_size) | -+ VDPU_REG_IDR_PIC_ID(slices[0].idr_pic_id); -+ vdpu_write_relaxed(vpu, reg, VDPU_SWREG(113)); -+ -+ reg = VDPU_REG_PPS_ID(slices[0].pic_parameter_set_id) | -+ VDPU_REG_REFIDX1_ACTIVE(pps->num_ref_idx_l1_default_active_minus1 + 1) | -+ VDPU_REG_REFIDX0_ACTIVE(pps->num_ref_idx_l0_default_active_minus1 + 1) | -+ VDPU_REG_POC_LENGTH(slices[0].pic_order_cnt_bit_size); -+ vdpu_write_relaxed(vpu, reg, VDPU_SWREG(114)); -+ -+ reg = VDPU_REG_IDR_PIC_E(decode->flags & V4L2_H264_DECODE_PARAM_FLAG_IDR_PIC) | -+ VDPU_REG_DIR_8X8_INFER_E(sps->flags & V4L2_H264_SPS_FLAG_DIRECT_8X8_INFERENCE) | -+ VDPU_REG_BLACKWHITE_E(sps->profile_idc >= 100 && sps->chroma_format_idc == 0) | -+ VDPU_REG_CABAC_E(pps->flags & V4L2_H264_PPS_FLAG_ENTROPY_CODING_MODE) | -+ VDPU_REG_WEIGHT_PRED_E(pps->flags & V4L2_H264_PPS_FLAG_WEIGHTED_PRED) | -+ VDPU_REG_CONST_INTRA_E(pps->flags & V4L2_H264_PPS_FLAG_CONSTRAINED_INTRA_PRED) | -+ VDPU_REG_8X8TRANS_FLAG_E(pps->flags & V4L2_H264_PPS_FLAG_TRANSFORM_8X8_MODE) | -+ VDPU_REG_TYPE1_QUANT_E(1) | -+ VDPU_REG_FIELDPIC_FLAG_E(!(sps->flags & V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY)); -+ vdpu_write_relaxed(vpu, reg, VDPU_SWREG(115)); -+ -+ /* Auxiliary buffer prepared in hantro_g1_h264_dec_prepare_table(). */ -+ vdpu_write_relaxed(vpu, ctx->h264_dec.priv.dma, VDPU_REG_QTABLE_BASE); -+ -+ /* Source (stream) buffer. */ -+ addr = vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, 0); -+ vdpu_write_relaxed(vpu, addr, VDPU_REG_RLC_VLC_BASE); -+ -+ /* Destination (decoded frame) buffer. */ -+ addr = hantro_get_dec_buf_addr(ctx, &dst_buf->vb2_buf); -+ /* Adjust dma addr to start at second line for bottom field */ -+ if (slices[0].flags & V4L2_H264_SLICE_FLAG_BOTTOM_FIELD) -+ offset = ALIGN(ctx->src_fmt.width, MB_DIM); -+ vdpu_write_relaxed(vpu, addr + offset, VDPU_REG_DEC_OUT_BASE); -+ -+ /* Higher profiles require DMV buffer appended to reference frames. */ -+ if (sps->profile_idc > 66 && decode->nal_ref_idc) { -+ unsigned int bytes_per_mb = 384; -+ -+ /* DMV buffer for monochrome start directly after Y-plane */ -+ if (sps->profile_idc >= 100 && sps->chroma_format_idc == 0) -+ bytes_per_mb = 256; -+ offset = bytes_per_mb * MB_WIDTH(ctx->src_fmt.width) * -+ MB_HEIGHT(ctx->src_fmt.height); -+ -+ /* -+ * DMV buffer is split in two for field encoded frames, -+ * adjust offset for bottom field -+ */ -+ if (slices[0].flags & V4L2_H264_SLICE_FLAG_BOTTOM_FIELD) -+ offset += 32 * MB_WIDTH(ctx->src_fmt.width) * -+ MB_HEIGHT(ctx->src_fmt.height); -+ vdpu_write_relaxed(vpu, addr + offset, VDPU_REG_DIR_MV_BASE); -+ } -+ -+ vdpu_write_relaxed(vpu, hantro_h264_get_ref_buf(ctx, 0), VDPU_REG_REFER0_BASE); -+ vdpu_write_relaxed(vpu, hantro_h264_get_ref_buf(ctx, 1), VDPU_REG_REFER1_BASE); -+ vdpu_write_relaxed(vpu, hantro_h264_get_ref_buf(ctx, 2), VDPU_REG_REFER2_BASE); -+ vdpu_write_relaxed(vpu, hantro_h264_get_ref_buf(ctx, 3), VDPU_REG_REFER3_BASE); -+ vdpu_write_relaxed(vpu, hantro_h264_get_ref_buf(ctx, 4), VDPU_REG_REFER4_BASE); -+ vdpu_write_relaxed(vpu, hantro_h264_get_ref_buf(ctx, 5), VDPU_REG_REFER5_BASE); -+ vdpu_write_relaxed(vpu, hantro_h264_get_ref_buf(ctx, 6), VDPU_REG_REFER6_BASE); -+ vdpu_write_relaxed(vpu, hantro_h264_get_ref_buf(ctx, 7), VDPU_REG_REFER7_BASE); -+ vdpu_write_relaxed(vpu, hantro_h264_get_ref_buf(ctx, 8), VDPU_REG_REFER8_BASE); -+ vdpu_write_relaxed(vpu, hantro_h264_get_ref_buf(ctx, 9), VDPU_REG_REFER9_BASE); -+ vdpu_write_relaxed(vpu, hantro_h264_get_ref_buf(ctx, 10), VDPU_REG_REFER10_BASE); -+ vdpu_write_relaxed(vpu, hantro_h264_get_ref_buf(ctx, 11), VDPU_REG_REFER11_BASE); -+ vdpu_write_relaxed(vpu, hantro_h264_get_ref_buf(ctx, 12), VDPU_REG_REFER12_BASE); -+ vdpu_write_relaxed(vpu, hantro_h264_get_ref_buf(ctx, 13), VDPU_REG_REFER13_BASE); -+ vdpu_write_relaxed(vpu, hantro_h264_get_ref_buf(ctx, 14), VDPU_REG_REFER14_BASE); -+ vdpu_write_relaxed(vpu, hantro_h264_get_ref_buf(ctx, 15), VDPU_REG_REFER15_BASE); -+ -+ hantro_end_prepare_run(ctx); -+ -+ /* Start decoding! */ -+ reg = vdpu_read(vpu, VDPU_SWREG(57)) | VDPU_REG_DEC_E(1); -+ vdpu_write(vpu, reg, VDPU_SWREG(57)); -+} --- -2.17.1 - - -From c6ad44bc8c4de5b6e468ee4449bfa181ff564f5a Mon Sep 17 00:00:00 2001 -From: Jonas Karlman -Date: Sun, 18 Aug 2019 10:40:31 +0000 -Subject: [PATCH] media: hantro: Enable H264 decoding on RK3399 - -Signed-off-by: Jonas Karlman ---- - drivers/staging/media/hantro/rk3399_vpu_hw.c | 21 +++++++++++++++++++- - 1 file changed, 20 insertions(+), 1 deletion(-) - -diff --git a/drivers/staging/media/hantro/rk3399_vpu_hw.c b/drivers/staging/media/hantro/rk3399_vpu_hw.c -index 9ac1f2cb6a16..3e05cd2c870e 100644 ---- a/drivers/staging/media/hantro/rk3399_vpu_hw.c -+++ b/drivers/staging/media/hantro/rk3399_vpu_hw.c -@@ -60,6 +60,19 @@ static const struct hantro_fmt rk3399_vpu_dec_fmts[] = { - .fourcc = V4L2_PIX_FMT_NV12, - .codec_mode = HANTRO_MODE_NONE, - }, -+ { -+ .fourcc = V4L2_PIX_FMT_H264_SLICE, -+ .codec_mode = HANTRO_MODE_H264_DEC, -+ .max_depth = 2, -+ .frmsize = { -+ .min_width = 48, -+ .max_width = 1920, -+ .step_width = MB_DIM, -+ .min_height = 48, -+ .max_height = 1088, -+ .step_height = MB_DIM, -+ }, -+ }, - { - .fourcc = V4L2_PIX_FMT_MPEG2_SLICE, - .codec_mode = HANTRO_MODE_MPEG2_DEC, -@@ -161,6 +174,12 @@ static const struct hantro_codec_ops rk3399_vpu_codec_ops[] = { - .init = hantro_jpeg_enc_init, - .exit = hantro_jpeg_enc_exit, - }, -+ [HANTRO_MODE_H264_DEC] = { -+ .run = rk3399_vpu_h264_dec_run, -+ .reset = rk3399_vpu_dec_reset, -+ .init = hantro_h264_dec_init, -+ .exit = hantro_h264_dec_exit, -+ }, - [HANTRO_MODE_MPEG2_DEC] = { - .run = rk3399_vpu_mpeg2_dec_run, - .reset = rk3399_vpu_dec_reset, -@@ -196,7 +215,7 @@ const struct hantro_variant rk3399_vpu_variant = { - .dec_fmts = rk3399_vpu_dec_fmts, - .num_dec_fmts = ARRAY_SIZE(rk3399_vpu_dec_fmts), - .codec = HANTRO_JPEG_ENCODER | HANTRO_MPEG2_DECODER | -- HANTRO_VP8_DECODER, -+ HANTRO_VP8_DECODER | HANTRO_H264_DECODER, - .codec_ops = rk3399_vpu_codec_ops, - .irqs = rk3399_irqs, - .num_irqs = ARRAY_SIZE(rk3399_irqs), --- -2.17.1 - - -From 51ec7c26733bd0c96fc9ec7d80b18ee8110d0a7d Mon Sep 17 00:00:00 2001 -From: Jonas Karlman -Date: Sun, 18 Aug 2019 10:40:31 +0000 -Subject: [PATCH] media: hantro: Enable H264 decoding on RK3328 - -RK3328 SoC has the same decoder IP block as RK3399, -lets enable H264 decoding on RK3328. - -Signed-off-by: Jonas Karlman ---- - drivers/staging/media/hantro/rk3399_vpu_hw.c | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/drivers/staging/media/hantro/rk3399_vpu_hw.c b/drivers/staging/media/hantro/rk3399_vpu_hw.c -index 3e05cd2c870e..78f878ca01ff 100644 ---- a/drivers/staging/media/hantro/rk3399_vpu_hw.c -+++ b/drivers/staging/media/hantro/rk3399_vpu_hw.c -@@ -232,7 +232,8 @@ const struct hantro_variant rk3328_vpu_variant = { - .dec_offset = 0x400, - .dec_fmts = rk3399_vpu_dec_fmts, - .num_dec_fmts = ARRAY_SIZE(rk3399_vpu_dec_fmts), -- .codec = HANTRO_MPEG2_DECODER | HANTRO_VP8_DECODER, -+ .codec = HANTRO_MPEG2_DECODER | HANTRO_VP8_DECODER | -+ HANTRO_H264_DECODER, - .codec_ops = rk3399_vpu_codec_ops, - .irqs = rk3328_irqs, - .num_irqs = ARRAY_SIZE(rk3328_irqs), --- -2.17.1 - diff --git a/patch/kernel/rk322x-current/01-linux-0015-fromlist-rga-for-rk322x.patch b/patch/kernel/rk322x-current/01-linux-0015-fromlist-rga-for-rk322x.patch deleted file mode 100644 index be186ba1c..000000000 --- a/patch/kernel/rk322x-current/01-linux-0015-fromlist-rga-for-rk322x.patch +++ /dev/null @@ -1,53 +0,0 @@ -Add a node to define the presence of RGA, a 2D raster -graphic acceleration unit. - -Signed-off-by: Justin Swartz ---- - arch/arm/boot/dts/rk322x.dtsi | 11 +++++++++++ - 1 file changed, 11 insertions(+) - -diff --git a/arch/arm/boot/dts/rk322x.dtsi b/arch/arm/boot/dts/rk322x.dtsi -index 340ed6ccb..29d50bebc 100644 ---- a/arch/arm/boot/dts/rk322x.dtsi -+++ b/arch/arm/boot/dts/rk322x.dtsi -@@ -621,6 +621,17 @@ - status = "disabled"; - }; - -+ rga: rga@20060000 { -+ compatible = "rockchip,rk3228-rga", "rockchip,rk3288-rga"; -+ reg = <0x20060000 0x1000>; -+ interrupts = ; -+ clocks = <&cru ACLK_RGA>, <&cru HCLK_RGA>, <&cru SCLK_RGA>; -+ clock-names = "aclk", "hclk", "sclk"; -+ resets = <&cru SRST_RGA>, <&cru SRST_RGA_A>, <&cru SRST_RGA_H>; -+ reset-names = "core", "axi", "ahb"; -+ status = "disabled"; -+ }; -+ - iep_mmu: iommu@20070800 { - compatible = "rockchip,iommu"; - reg = <0x20070800 0x100>; - -Enable RGA for Mecer Xtreme Mini S6. - -Signed-off-by: Justin Swartz ---- - arch/arm/boot/dts/rk3229-xms6.dts | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/arch/arm/boot/dts/rk3229-xms6.dts b/arch/arm/boot/dts/rk3229-xms6.dts -index 679fc2b00..894f64a4a 100644 ---- a/arch/arm/boot/dts/rk3229-xms6.dts -+++ b/arch/arm/boot/dts/rk3229-xms6.dts -@@ -202,6 +202,10 @@ - status = "okay"; - }; - -+&rga { -+ status = "okay"; -+}; -+ - &sdmmc { - cap-mmc-highspeed; - disable-wp; diff --git a/patch/kernel/rk322x-current/01-linux-0015-hantro-set-of-small-cleanups-and-fixes.patch b/patch/kernel/rk322x-current/01-linux-0015-hantro-set-of-small-cleanups-and-fixes.patch deleted file mode 100644 index f83cb8f8d..000000000 --- a/patch/kernel/rk322x-current/01-linux-0015-hantro-set-of-small-cleanups-and-fixes.patch +++ /dev/null @@ -1,718 +0,0 @@ -diff --git a/drivers/media/v4l2-core/v4l2-mem2mem.c b/drivers/media/v4l2-core/v4l2-mem2mem.c -index cc34c5ab7009..3070672e6b4f 100644 ---- a/drivers/media/v4l2-core/v4l2-mem2mem.c -+++ b/drivers/media/v4l2-core/v4l2-mem2mem.c -@@ -499,12 +499,21 @@ void v4l2_m2m_buf_done_and_job_finish(struct v4l2_m2m_dev *m2m_dev, - - if (WARN_ON(!src_buf || !dst_buf)) - goto unlock; -- v4l2_m2m_buf_done(src_buf, state); - dst_buf->is_held = src_buf->flags & V4L2_BUF_FLAG_M2M_HOLD_CAPTURE_BUF; - if (!dst_buf->is_held) { - v4l2_m2m_dst_buf_remove(m2m_ctx); - v4l2_m2m_buf_done(dst_buf, state); - } -+ /* -+ * If the request API is being used, returning the OUTPUT -+ * (src) buffer will wake-up any process waiting on the -+ * request file descriptor. -+ * -+ * Therefore, return the CAPTURE (dst) buffer first, -+ * to avoid signalling the request file descriptor -+ * before the CAPTURE buffer is done. -+ */ -+ v4l2_m2m_buf_done(src_buf, state); - schedule_next = _v4l2_m2m_job_finish(m2m_dev, m2m_ctx); - unlock: - spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags); --- -2.17.1 - - -From 46fef6ecbc765dedaeef46339474529645f09404 Mon Sep 17 00:00:00 2001 -From: Ezequiel Garcia -Date: Wed, 18 Mar 2020 10:21:02 -0300 -Subject: [PATCH] hantro: Set buffers' zeroth plane payload in .buf_prepare - -Buffers' zeroth plane payload size is calculated at format -negotiation time, and so it can be set in .buf_prepare. - -Keep in mind that, to make this change easier, hantro_buf_prepare -is refactored, using the cedrus driver as reference. This results -in cleaner code as byproduct. - -Signed-off-by: Ezequiel Garcia ---- - drivers/staging/media/hantro/hantro_v4l2.c | 16 +++++++++++----- - 1 file changed, 11 insertions(+), 5 deletions(-) - -diff --git a/drivers/staging/media/hantro/hantro_v4l2.c b/drivers/staging/media/hantro/hantro_v4l2.c -index f4ae2cee0f18..3142ab6697d5 100644 ---- a/drivers/staging/media/hantro/hantro_v4l2.c -+++ b/drivers/staging/media/hantro/hantro_v4l2.c -@@ -608,7 +608,7 @@ hantro_queue_setup(struct vb2_queue *vq, unsigned int *num_buffers, - } - - static int --hantro_buf_plane_check(struct vb2_buffer *vb, const struct hantro_fmt *vpu_fmt, -+hantro_buf_plane_check(struct vb2_buffer *vb, - struct v4l2_pix_format_mplane *pixfmt) - { - unsigned int sz; -@@ -630,12 +630,18 @@ static int hantro_buf_prepare(struct vb2_buffer *vb) - { - struct vb2_queue *vq = vb->vb2_queue; - struct hantro_ctx *ctx = vb2_get_drv_priv(vq); -+ struct v4l2_pix_format_mplane *pix_fmt; -+ int ret; - - if (V4L2_TYPE_IS_OUTPUT(vq->type)) -- return hantro_buf_plane_check(vb, ctx->vpu_src_fmt, -- &ctx->src_fmt); -- -- return hantro_buf_plane_check(vb, ctx->vpu_dst_fmt, &ctx->dst_fmt); -+ pix_fmt = &ctx->src_fmt; -+ else -+ pix_fmt = &ctx->dst_fmt; -+ ret = hantro_buf_plane_check(vb, pix_fmt); -+ if (ret) -+ return ret; -+ vb2_set_plane_payload(vb, 0, pix_fmt->plane_fmt[0].sizeimage); -+ return 0; - } - - static void hantro_buf_queue(struct vb2_buffer *vb) --- -2.17.1 - - -From 49b98070ac9cbd4e731a84f0a3c10e6dd803d37c Mon Sep 17 00:00:00 2001 -From: Ezequiel Garcia -Date: Wed, 18 Mar 2020 10:21:03 -0300 -Subject: [PATCH] hantro: Use v4l2_m2m_buf_done_and_job_finish - -Let the core sort out the nuances of returning buffers -to userspace, by using the v4l2_m2m_buf_done_and_job_finish -helper. - -This change also removes usage of buffer sequence fields, -which shouldn't have any meaning for stateless decoders. - -Signed-off-by: Ezequiel Garcia -Nacked-by: Hans Verkuil ---- - drivers/staging/media/hantro/hantro_drv.c | 27 ++++++++--------------- - 1 file changed, 9 insertions(+), 18 deletions(-) - -diff --git a/drivers/staging/media/hantro/hantro_drv.c b/drivers/staging/media/hantro/hantro_drv.c -index c98835326135..dd503918a017 100644 ---- a/drivers/staging/media/hantro/hantro_drv.c -+++ b/drivers/staging/media/hantro/hantro_drv.c -@@ -94,32 +94,23 @@ static void hantro_job_finish(struct hantro_dev *vpu, - unsigned int bytesused, - enum vb2_buffer_state result) - { -- struct vb2_v4l2_buffer *src, *dst; - int ret; - - pm_runtime_mark_last_busy(vpu->dev); - pm_runtime_put_autosuspend(vpu->dev); - clk_bulk_disable(vpu->variant->num_clocks, vpu->clocks); - -- src = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); -- dst = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); -- -- if (WARN_ON(!src)) -- return; -- if (WARN_ON(!dst)) -- return; -- -- src->sequence = ctx->sequence_out++; -- dst->sequence = ctx->sequence_cap++; -- -- ret = ctx->buf_finish(ctx, &dst->vb2_buf, bytesused); -- if (ret) -- result = VB2_BUF_STATE_ERROR; -+ if (ctx->buf_finish) { -+ struct vb2_v4l2_buffer *dst; - -- v4l2_m2m_buf_done(src, result); -- v4l2_m2m_buf_done(dst, result); -+ dst = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); -+ ret = ctx->buf_finish(ctx, &dst->vb2_buf, bytesused); -+ if (ret) -+ result = VB2_BUF_STATE_ERROR; -+ } - -- v4l2_m2m_job_finish(vpu->m2m_dev, ctx->fh.m2m_ctx); -+ v4l2_m2m_buf_done_and_job_finish(ctx->dev->m2m_dev, ctx->fh.m2m_ctx, -+ result); - } - - void hantro_irq_done(struct hantro_dev *vpu, unsigned int bytesused, --- -2.17.1 - - -From ee3c913094e5776a0b1270b78ecce8a5e9803a42 Mon Sep 17 00:00:00 2001 -From: Ezequiel Garcia -Date: Wed, 18 Mar 2020 10:21:04 -0300 -Subject: [PATCH] hantro: Remove unneeded hantro_dec_buf_finish - -Since now .buf_prepare takes care of setting the -buffer payload size, we can get rid of this, -at least for decoders. - -Signed-off-by: Ezequiel Garcia ---- - drivers/staging/media/hantro/hantro_drv.c | 10 ---------- - 1 file changed, 10 deletions(-) - -diff --git a/drivers/staging/media/hantro/hantro_drv.c b/drivers/staging/media/hantro/hantro_drv.c -index dd503918a017..a732beeb3bb6 100644 ---- a/drivers/staging/media/hantro/hantro_drv.c -+++ b/drivers/staging/media/hantro/hantro_drv.c -@@ -80,15 +80,6 @@ hantro_enc_buf_finish(struct hantro_ctx *ctx, struct vb2_buffer *buf, - return 0; - } - --static int --hantro_dec_buf_finish(struct hantro_ctx *ctx, struct vb2_buffer *buf, -- unsigned int bytesused) --{ -- /* For decoders set bytesused as per the output picture. */ -- buf->planes[0].bytesused = ctx->dst_fmt.plane_fmt[0].sizeimage; -- return 0; --} -- - static void hantro_job_finish(struct hantro_dev *vpu, - struct hantro_ctx *ctx, - unsigned int bytesused, -@@ -412,7 +403,6 @@ static int hantro_open(struct file *filp) - ctx->buf_finish = hantro_enc_buf_finish; - } else if (func->id == MEDIA_ENT_F_PROC_VIDEO_DECODER) { - allowed_codecs = vpu->variant->codec & HANTRO_DECODERS; -- ctx->buf_finish = hantro_dec_buf_finish; - } else { - ret = -ENODEV; - goto err_ctx_free; --- -2.17.1 - - -From 403b36c2db7e39b46f8e0f6a363af6763373933d Mon Sep 17 00:00:00 2001 -From: Ezequiel Garcia -Date: Wed, 18 Mar 2020 10:21:05 -0300 -Subject: [PATCH] hantro: Move H264 motion vector calculation to a helper - -Move the extra bytes calculation that are needed for H264 -motion vector to a helper. This is just a cosmetic cleanup. - -Signed-off-by: Ezequiel Garcia ---- - drivers/staging/media/hantro/hantro.h | 4 --- - drivers/staging/media/hantro/hantro_hw.h | 31 ++++++++++++++++++++++ - drivers/staging/media/hantro/hantro_v4l2.c | 25 ++--------------- - 3 files changed, 33 insertions(+), 27 deletions(-) - -diff --git a/drivers/staging/media/hantro/hantro.h b/drivers/staging/media/hantro/hantro.h -index b0faa43b3f79..1a010d438ac2 100644 ---- a/drivers/staging/media/hantro/hantro.h -+++ b/drivers/staging/media/hantro/hantro.h -@@ -26,10 +26,6 @@ - - #include "hantro_hw.h" - --#define MB_DIM 16 --#define MB_WIDTH(w) DIV_ROUND_UP(w, MB_DIM) --#define MB_HEIGHT(h) DIV_ROUND_UP(h, MB_DIM) -- - struct hantro_ctx; - struct hantro_codec_ops; - -diff --git a/drivers/staging/media/hantro/hantro_hw.h b/drivers/staging/media/hantro/hantro_hw.h -index 4a64873bf332..33c1ce169203 100644 ---- a/drivers/staging/media/hantro/hantro_hw.h -+++ b/drivers/staging/media/hantro/hantro_hw.h -@@ -18,6 +18,10 @@ - - #define DEC_8190_ALIGN_MASK 0x07U - -+#define MB_DIM 16 -+#define MB_WIDTH(w) DIV_ROUND_UP(w, MB_DIM) -+#define MB_HEIGHT(h) DIV_ROUND_UP(h, MB_DIM) -+ - struct hantro_dev; - struct hantro_ctx; - struct hantro_buf; -@@ -180,6 +184,33 @@ void rk3399_vpu_h264_dec_run(struct hantro_ctx *ctx); - int hantro_h264_dec_init(struct hantro_ctx *ctx); - void hantro_h264_dec_exit(struct hantro_ctx *ctx); - -+static inline size_t -+hantro_h264_mv_size(unsigned int width, unsigned int height) -+{ -+ /* -+ * A decoded 8-bit 4:2:0 NV12 frame may need memory for up to -+ * 448 bytes per macroblock with additional 32 bytes on -+ * multi-core variants. -+ * -+ * The H264 decoder needs extra space on the output buffers -+ * to store motion vectors. This is needed for reference -+ * frames and only if the format is non-post-processed NV12. -+ * -+ * Memory layout is as follow: -+ * -+ * +---------------------------+ -+ * | Y-plane 256 bytes x MBs | -+ * +---------------------------+ -+ * | UV-plane 128 bytes x MBs | -+ * +---------------------------+ -+ * | MV buffer 64 bytes x MBs | -+ * +---------------------------+ -+ * | MC sync 32 bytes | -+ * +---------------------------+ -+ */ -+ return 64 * MB_WIDTH(width) * MB_WIDTH(height) + 32; -+} -+ - void hantro_g1_mpeg2_dec_run(struct hantro_ctx *ctx); - void rk3399_vpu_mpeg2_dec_run(struct hantro_ctx *ctx); - void hantro_mpeg2_dec_copy_qtable(u8 *qtable, -diff --git a/drivers/staging/media/hantro/hantro_v4l2.c b/drivers/staging/media/hantro/hantro_v4l2.c -index 3142ab6697d5..458b502ff01b 100644 ---- a/drivers/staging/media/hantro/hantro_v4l2.c -+++ b/drivers/staging/media/hantro/hantro_v4l2.c -@@ -273,32 +273,11 @@ static int vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f, - /* Fill remaining fields */ - v4l2_fill_pixfmt_mp(pix_mp, fmt->fourcc, pix_mp->width, - pix_mp->height); -- /* -- * A decoded 8-bit 4:2:0 NV12 frame may need memory for up to -- * 448 bytes per macroblock with additional 32 bytes on -- * multi-core variants. -- * -- * The H264 decoder needs extra space on the output buffers -- * to store motion vectors. This is needed for reference -- * frames and only if the format is non-post-processed NV12. -- * -- * Memory layout is as follow: -- * -- * +---------------------------+ -- * | Y-plane 256 bytes x MBs | -- * +---------------------------+ -- * | UV-plane 128 bytes x MBs | -- * +---------------------------+ -- * | MV buffer 64 bytes x MBs | -- * +---------------------------+ -- * | MC sync 32 bytes | -- * +---------------------------+ -- */ - if (ctx->vpu_src_fmt->fourcc == V4L2_PIX_FMT_H264_SLICE && - !hantro_needs_postproc(ctx, fmt)) - pix_mp->plane_fmt[0].sizeimage += -- 64 * MB_WIDTH(pix_mp->width) * -- MB_WIDTH(pix_mp->height) + 32; -+ hantro_h264_mv_size(pix_mp->width, -+ pix_mp->height); - } else if (!pix_mp->plane_fmt[0].sizeimage) { - /* - * For coded formats the application can specify --- -2.17.1 - - -From 220559bea572812494ac528eb4bb3af770748641 Mon Sep 17 00:00:00 2001 -From: Ezequiel Garcia -Date: Wed, 18 Mar 2020 10:21:06 -0300 -Subject: [PATCH] hantro: Refactor for V4L2 API spec compliancy - -Refactor how S_FMT and TRY_FMT are handled, and also make sure -internal initial format and format reset are done properly. - -The latter is achieved by making sure the same hantro_{set,try}_fmt -helpers are called on all paths that set the format (which is -part of the driver state). - -This commit removes the following v4l2-compliance warnings: - -test VIDIOC_G_FMT: OK - fail: v4l2-test-formats.cpp(711): Video Capture Multiplanar: TRY_FMT(G_FMT) != G_FMT -test VIDIOC_TRY_FMT: FAIL - fail: v4l2-test-formats.cpp(1116): Video Capture Multiplanar: S_FMT(G_FMT) != G_FMT -test VIDIOC_S_FMT: FAIL - -Reported-by: Nicolas Dufresne -Signed-off-by: Ezequiel Garcia ---- - drivers/staging/media/hantro/hantro.h | 3 +- - drivers/staging/media/hantro/hantro_v4l2.c | 70 ++++++++++++++-------- - 2 files changed, 47 insertions(+), 26 deletions(-) - -diff --git a/drivers/staging/media/hantro/hantro.h b/drivers/staging/media/hantro/hantro.h -index 1a010d438ac2..f0aca46969f9 100644 ---- a/drivers/staging/media/hantro/hantro.h -+++ b/drivers/staging/media/hantro/hantro.h -@@ -417,7 +417,8 @@ hantro_get_dst_buf(struct hantro_ctx *ctx) - } - - static inline bool --hantro_needs_postproc(struct hantro_ctx *ctx, const struct hantro_fmt *fmt) -+hantro_needs_postproc(const struct hantro_ctx *ctx, -+ const struct hantro_fmt *fmt) - { - return fmt->fourcc != V4L2_PIX_FMT_NV12; - } -diff --git a/drivers/staging/media/hantro/hantro_v4l2.c b/drivers/staging/media/hantro/hantro_v4l2.c -index 458b502ff01b..f28a94e2fa93 100644 ---- a/drivers/staging/media/hantro/hantro_v4l2.c -+++ b/drivers/staging/media/hantro/hantro_v4l2.c -@@ -30,6 +30,11 @@ - #include "hantro_hw.h" - #include "hantro_v4l2.h" - -+static int hantro_set_fmt_out(struct hantro_ctx *ctx, -+ struct v4l2_pix_format_mplane *pix_mp); -+static int hantro_set_fmt_cap(struct hantro_ctx *ctx, -+ struct v4l2_pix_format_mplane *pix_mp); -+ - static const struct hantro_fmt * - hantro_get_formats(const struct hantro_ctx *ctx, unsigned int *num_fmts) - { -@@ -227,12 +232,12 @@ static int vidioc_g_fmt_cap_mplane(struct file *file, void *priv, - return 0; - } - --static int vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f, -- bool capture) -+static int hantro_try_fmt(const struct hantro_ctx *ctx, -+ struct v4l2_pix_format_mplane *pix_mp, -+ enum v4l2_buf_type type) - { -- struct hantro_ctx *ctx = fh_to_ctx(priv); -- struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp; - const struct hantro_fmt *fmt, *vpu_fmt; -+ bool capture = !V4L2_TYPE_IS_OUTPUT(type); - bool coded; - - coded = capture == hantro_is_encoder_ctx(ctx); -@@ -246,7 +251,7 @@ static int vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f, - fmt = hantro_find_format(ctx, pix_mp->pixelformat); - if (!fmt) { - fmt = hantro_get_default_fmt(ctx, coded); -- f->fmt.pix_mp.pixelformat = fmt->fourcc; -+ pix_mp->pixelformat = fmt->fourcc; - } - - if (coded) { -@@ -294,13 +299,13 @@ static int vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f, - static int vidioc_try_fmt_cap_mplane(struct file *file, void *priv, - struct v4l2_format *f) - { -- return vidioc_try_fmt(file, priv, f, true); -+ return hantro_try_fmt(fh_to_ctx(priv), &f->fmt.pix_mp, f->type); - } - - static int vidioc_try_fmt_out_mplane(struct file *file, void *priv, - struct v4l2_format *f) - { -- return vidioc_try_fmt(file, priv, f, false); -+ return hantro_try_fmt(fh_to_ctx(priv), &f->fmt.pix_mp, f->type); - } - - static void -@@ -334,11 +339,12 @@ hantro_reset_encoded_fmt(struct hantro_ctx *ctx) - } - - hantro_reset_fmt(fmt, vpu_fmt); -- fmt->num_planes = 1; - fmt->width = vpu_fmt->frmsize.min_width; - fmt->height = vpu_fmt->frmsize.min_height; -- fmt->plane_fmt[0].sizeimage = vpu_fmt->header_size + -- fmt->width * fmt->height * vpu_fmt->max_depth; -+ if (hantro_is_encoder_ctx(ctx)) -+ hantro_set_fmt_cap(ctx, fmt); -+ else -+ hantro_set_fmt_out(ctx, fmt); - } - - static void -@@ -360,9 +366,12 @@ hantro_reset_raw_fmt(struct hantro_ctx *ctx) - } - - hantro_reset_fmt(raw_fmt, raw_vpu_fmt); -- v4l2_fill_pixfmt_mp(raw_fmt, raw_vpu_fmt->fourcc, -- encoded_fmt->width, -- encoded_fmt->height); -+ raw_fmt->width = encoded_fmt->width; -+ raw_fmt->width = encoded_fmt->width; -+ if (hantro_is_encoder_ctx(ctx)) -+ hantro_set_fmt_out(ctx, raw_fmt); -+ else -+ hantro_set_fmt_cap(ctx, raw_fmt); - } - - void hantro_reset_fmts(struct hantro_ctx *ctx) -@@ -388,15 +397,15 @@ hantro_update_requires_request(struct hantro_ctx *ctx, u32 fourcc) - } - } - --static int --vidioc_s_fmt_out_mplane(struct file *file, void *priv, struct v4l2_format *f) -+static int hantro_set_fmt_out(struct hantro_ctx *ctx, -+ struct v4l2_pix_format_mplane *pix_mp) - { -- struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp; -- struct hantro_ctx *ctx = fh_to_ctx(priv); -- struct vb2_queue *vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); -+ struct vb2_queue *vq; - int ret; - -- ret = vidioc_try_fmt_out_mplane(file, priv, f); -+ vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, -+ V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); -+ ret = hantro_try_fmt(ctx, pix_mp, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); - if (ret) - return ret; - -@@ -458,16 +467,15 @@ vidioc_s_fmt_out_mplane(struct file *file, void *priv, struct v4l2_format *f) - return 0; - } - --static int vidioc_s_fmt_cap_mplane(struct file *file, void *priv, -- struct v4l2_format *f) -+static int hantro_set_fmt_cap(struct hantro_ctx *ctx, -+ struct v4l2_pix_format_mplane *pix_mp) - { -- struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp; -- struct hantro_ctx *ctx = fh_to_ctx(priv); - struct vb2_queue *vq; - int ret; - - /* Change not allowed if queue is busy. */ -- vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); -+ vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, -+ V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); - if (vb2_is_busy(vq)) - return -EBUSY; - -@@ -488,7 +496,7 @@ static int vidioc_s_fmt_cap_mplane(struct file *file, void *priv, - return -EBUSY; - } - -- ret = vidioc_try_fmt_cap_mplane(file, priv, f); -+ ret = hantro_try_fmt(ctx, pix_mp, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); - if (ret) - return ret; - -@@ -522,6 +530,18 @@ static int vidioc_s_fmt_cap_mplane(struct file *file, void *priv, - return 0; - } - -+static int -+vidioc_s_fmt_out_mplane(struct file *file, void *priv, struct v4l2_format *f) -+{ -+ return hantro_set_fmt_out(fh_to_ctx(priv), &f->fmt.pix_mp); -+} -+ -+static int -+vidioc_s_fmt_cap_mplane(struct file *file, void *priv, struct v4l2_format *f) -+{ -+ return hantro_set_fmt_cap(fh_to_ctx(priv), &f->fmt.pix_mp); -+} -+ - const struct v4l2_ioctl_ops hantro_ioctl_ops = { - .vidioc_querycap = vidioc_querycap, - .vidioc_enum_framesizes = vidioc_enum_framesizes, --- -2.17.1 - - -From 03a4222379d16c8a5f4a9c74f78c977b6a0e16a0 Mon Sep 17 00:00:00 2001 -From: Ezequiel Garcia -Date: Wed, 18 Mar 2020 10:21:07 -0300 -Subject: [PATCH] dt-bindings: rockchip-vpu: Convert bindings to json-schema - -Convert Rockchip VPU (Hantro IP block) codec driver documentation to -json-schema. - -Cc: Rob Herring -Signed-off-by: Ezequiel Garcia ---- - .../bindings/media/rockchip-vpu.txt | 43 ---------- - .../bindings/media/rockchip-vpu.yaml | 82 +++++++++++++++++++ - MAINTAINERS | 2 +- - 3 files changed, 83 insertions(+), 44 deletions(-) - delete mode 100644 Documentation/devicetree/bindings/media/rockchip-vpu.txt - create mode 100644 Documentation/devicetree/bindings/media/rockchip-vpu.yaml - -diff --git a/Documentation/devicetree/bindings/media/rockchip-vpu.txt b/Documentation/devicetree/bindings/media/rockchip-vpu.txt -deleted file mode 100644 -index 339252d9c515..000000000000 ---- a/Documentation/devicetree/bindings/media/rockchip-vpu.txt -+++ /dev/null -@@ -1,43 +0,0 @@ --device-tree bindings for rockchip VPU codec -- --Rockchip (Video Processing Unit) present in various Rockchip platforms, --such as RK3288, RK3328 and RK3399. -- --Required properties: --- compatible: value should be one of the following -- "rockchip,rk3288-vpu"; -- "rockchip,rk3328-vpu"; -- "rockchip,rk3399-vpu"; --- interrupts: encoding and decoding interrupt specifiers --- interrupt-names: should be -- "vepu", "vdpu" on RK3288 and RK3399, -- "vdpu" on RK3328. --- clocks: phandle to VPU aclk, hclk clocks --- clock-names: should be "aclk" and "hclk" --- power-domains: phandle to power domain node --- iommus: phandle to a iommu node -- --Example: --SoC-specific DT entry: -- vpu: video-codec@ff9a0000 { -- compatible = "rockchip,rk3288-vpu"; -- reg = <0x0 0xff9a0000 0x0 0x800>; -- interrupts = , -- ; -- interrupt-names = "vepu", "vdpu"; -- clocks = <&cru ACLK_VCODEC>, <&cru HCLK_VCODEC>; -- clock-names = "aclk", "hclk"; -- power-domains = <&power RK3288_PD_VIDEO>; -- iommus = <&vpu_mmu>; -- }; -- -- vpu: video-codec@ff350000 { -- compatible = "rockchip,rk3328-vpu"; -- reg = <0x0 0xff350000 0x0 0x800>; -- interrupts = ; -- interrupt-names = "vdpu"; -- clocks = <&cru ACLK_VPU>, <&cru HCLK_VPU>; -- clock-names = "aclk", "hclk"; -- power-domains = <&power RK3328_PD_VPU>; -- iommus = <&vpu_mmu>; -- }; -diff --git a/Documentation/devicetree/bindings/media/rockchip-vpu.yaml b/Documentation/devicetree/bindings/media/rockchip-vpu.yaml -new file mode 100644 -index 000000000000..a0c45e05cf03 ---- /dev/null -+++ b/Documentation/devicetree/bindings/media/rockchip-vpu.yaml -@@ -0,0 +1,82 @@ -+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) -+ -+%YAML 1.2 -+--- -+$id: "http://devicetree.org/schemas/media/rockchip-vpu.yaml#" -+$schema: "http://devicetree.org/meta-schemas/core.yaml#" -+ -+title: Hantro G1 VPU codecs implemented on Rockchip SoCs -+ -+maintainers: -+ - Ezequiel Garcia -+ -+description: -+ Hantro G1 video encode and decode accelerators present on Rockchip SoCs. -+ -+properties: -+ compatible: -+ enum: -+ - rockchip,rk3288-vpu -+ - rockchip,rk3328-vpu -+ - rockchip,rk3399-vpu -+ -+ reg: -+ maxItems: 1 -+ -+ interrupts: -+ maxItems: 2 -+ -+ interrupt-names: -+ items: -+ - const: vepu -+ - const: vdpu -+ -+ clocks: -+ maxItems: 2 -+ -+ clock-names: -+ items: -+ - const: aclk -+ - const: hclk -+ -+ power-domains: -+ maxItems: 1 -+ -+ iommus: -+ maxItems: 1 -+ -+required: -+ - compatible -+ - reg -+ - interrupts -+ - interrupt-names -+ - clocks -+ - clock-names -+ -+examples: -+ - | -+ #include -+ #include -+ -+ vpu: video-codec@ff9a0000 { -+ compatible = "rockchip,rk3288-vpu"; -+ reg = <0x0 0xff9a0000 0x0 0x800>; -+ interrupts = , -+ ; -+ interrupt-names = "vepu", "vdpu"; -+ clocks = <&cru ACLK_VCODEC>, <&cru HCLK_VCODEC>; -+ clock-names = "aclk", "hclk"; -+ power-domains = <&power RK3288_PD_VIDEO>; -+ iommus = <&vpu_mmu>; -+ }; -+ -+ vpu: video-codec@ff350000 { -+ compatible = "rockchip,rk3328-vpu"; -+ reg = <0x0 0xff350000 0x0 0x800>; -+ interrupts = ; -+ interrupt-names = "vdpu"; -+ clocks = <&cru ACLK_VPU>, <&cru HCLK_VPU>; -+ clock-names = "aclk", "hclk"; -+ power-domains = <&power RK3328_PD_VPU>; -+ iommus = <&vpu_mmu>; -+ }; - - - -From 1eba04297572f566a06ab9fe50f901640c77b091 Mon Sep 17 00:00:00 2001 -From: Ezequiel Garcia -Date: Wed, 18 Mar 2020 10:21:08 -0300 -Subject: [PATCH] hantro: Add linux-rockchip mailing list to MAINTAINERS - -The linux-rockchip mailing list is relevant for the -Hantro driver, given this support the VPU present -in Rockchip SoCs. - -Signed-off-by: Ezequiel Garcia -Reviewed-by: Heiko Stuebner ---- - MAINTAINERS | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/MAINTAINERS b/MAINTAINERS -index ca95e804aae0..47876afb9e26 100644 ---- a/MAINTAINERS -+++ b/MAINTAINERS -@@ -14317,6 +14317,7 @@ F: Documentation/devicetree/bindings/media/rockchip-rga.txt - HANTRO VPU CODEC DRIVER - M: Ezequiel Garcia - L: linux-media@vger.kernel.org -+L: linux-rockchip@lists.infradead.org - S: Maintained - F: drivers/staging/media/hantro/ - F: Documentation/devicetree/bindings/media/rockchip-vpu.yaml --- -2.17.1 - diff --git a/patch/kernel/rk322x-current/01-linux-0021-drm-from-5.9.patch b/patch/kernel/rk322x-current/01-linux-0021-drm-from-5.9.patch new file mode 100644 index 000000000..d97f0818a --- /dev/null +++ b/patch/kernel/rk322x-current/01-linux-0021-drm-from-5.9.patch @@ -0,0 +1,3500 @@ +From 761a6a88e4fc8d732b6d4319d0bf6f0206d280de Mon Sep 17 00:00:00 2001 +From: Emil Velikov +Date: Tue, 5 May 2020 16:16:13 +0100 +Subject: [PATCH] drm/rockchip: vop: call vop_cfg_done() under reg_lock +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The function vop_cfg_done() is a simple VOP_REG_SET(). As such it should +be done under a reg_lock. A quick look through the driver shows that all +other instances (apart from driver init) have the lock. Do the same here + +Cc: Sandy Huang +Cc: Heiko Stübner +Signed-off-by: Emil Velikov +Reviewed-by: Sandy Huang +Link: https://patchwork.freedesktop.org/patch/msgid/20200505151613.2932456-1-emil.l.velikov@gmail.com +(cherry picked from commit 5fa63f0773323b1d028f2da5c94b8f3e38619b69) +--- + drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +index 33463b79a37b..1d76455ca933 100644 +--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c ++++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +@@ -645,10 +645,10 @@ static int vop_enable(struct drm_crtc *crtc, struct drm_crtc_state *old_state) + s->enable_afbc = false; + } + +- spin_unlock(&vop->reg_lock); +- + vop_cfg_done(vop); + ++ spin_unlock(&vop->reg_lock); ++ + /* + * At here, vop clock & iommu is enable, R/W vop regs would be safe. + */ + +From 7e1b1997341632ffac3e1ab8fdac8923929403c9 Mon Sep 17 00:00:00 2001 +From: Bernard Zhao +Date: Mon, 27 Apr 2020 01:05:23 -0700 +Subject: [PATCH] drivers: video: hdmi: cleanup coding style in video a bit + +Eliminate the magic numbers, add vendor infoframe size macro +like other hdmi modules. + +Signed-off-by: Bernard Zhao +Cc: Uma Shankar +Cc: Ville Syrjala +Cc: Shashank Sharma +Cc: Laurent Pinchart +Cc: Daniel Vetter +Cc: opensource.kernel@vivo.com +[b.zolnierkie: add "hdmi" to the patch summary] +[b.zolnierkie: fix "vender" -> vendor" typo in the patch description] +Signed-off-by: Bartlomiej Zolnierkiewicz +Link: https://patchwork.freedesktop.org/patch/msgid/20200427080530.3234-1-bernard@vivo.com +(cherry picked from commit d43be2554b58621a21cb5f54b32db2263b3008b6) +--- + drivers/video/hdmi.c | 2 +- + include/linux/hdmi.h | 1 + + 2 files changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/video/hdmi.c b/drivers/video/hdmi.c +index e70792b3e367..b7a1d6fae90d 100644 +--- a/drivers/video/hdmi.c ++++ b/drivers/video/hdmi.c +@@ -495,7 +495,7 @@ int hdmi_vendor_infoframe_init(struct hdmi_vendor_infoframe *frame) + * value + */ + frame->s3d_struct = HDMI_3D_STRUCTURE_INVALID; +- frame->length = 4; ++ frame->length = HDMI_VENDOR_INFOFRAME_SIZE; + + return 0; + } +diff --git a/include/linux/hdmi.h b/include/linux/hdmi.h +index 50c31f1a0a2d..9850d59d6f1c 100644 +--- a/include/linux/hdmi.h ++++ b/include/linux/hdmi.h +@@ -57,6 +57,7 @@ enum hdmi_infoframe_type { + #define HDMI_SPD_INFOFRAME_SIZE 25 + #define HDMI_AUDIO_INFOFRAME_SIZE 10 + #define HDMI_DRM_INFOFRAME_SIZE 26 ++#define HDMI_VENDOR_INFOFRAME_SIZE 4 + + #define HDMI_INFOFRAME_SIZE(type) \ + (HDMI_INFOFRAME_HEADER_SIZE + HDMI_ ## type ## _INFOFRAME_SIZE) + +From 86ce9313bd2561a632b4f3a03bdb894b92b988bb Mon Sep 17 00:00:00 2001 +From: Paul Kocialkowski +Date: Thu, 16 Apr 2020 16:05:26 +0200 +Subject: [PATCH] drm/rockchip: Add per-pixel alpha support for the PX30 VOP + +Compared to its predecessors, the PX30 VOP has a different register layout +for enabling per-pixel alpha. Instead of src_alpha_ctl and dst_alpha_ctl, +there is a single alpha control register. This register takes some fields +from src_alpha_ctl, but with a different layout. + +Add support for the required fields to the PX30 VOP window descriptions, +which makes per-pixel-alpha formats behave correctly. + +Signed-off-by: Paul Kocialkowski +Signed-off-by: Heiko Stuebner +Link: https://patchwork.freedesktop.org/patch/msgid/20200416140526.262533-1-paul.kocialkowski@bootlin.com +(cherry picked from commit 2aae8ed1f390a42ec752e4403ffca877fb3260e1) +--- + drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 4 ++++ + drivers/gpu/drm/rockchip/rockchip_drm_vop.h | 3 +++ + drivers/gpu/drm/rockchip/rockchip_vop_reg.c | 9 +++++++++ + 3 files changed, 16 insertions(+) + +diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +index 1d76455ca933..c80f7d9fd13f 100644 +--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c ++++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +@@ -1007,6 +1007,10 @@ static void vop_plane_atomic_update(struct drm_plane *plane, + SRC_ALPHA_CAL_M0(ALPHA_NO_SATURATION) | + SRC_FACTOR_M0(ALPHA_ONE); + VOP_WIN_SET(vop, win, src_alpha_ctl, val); ++ ++ VOP_WIN_SET(vop, win, alpha_pre_mul, ALPHA_SRC_PRE_MUL); ++ VOP_WIN_SET(vop, win, alpha_mode, ALPHA_PER_PIX); ++ VOP_WIN_SET(vop, win, alpha_en, 1); + } else { + VOP_WIN_SET(vop, win, src_alpha_ctl, SRC_ALPHA_EN(0)); + } +diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h +index d03bdb531ef2..4a2099cb582e 100644 +--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h ++++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h +@@ -167,6 +167,9 @@ struct vop_win_phy { + + struct vop_reg dst_alpha_ctl; + struct vop_reg src_alpha_ctl; ++ struct vop_reg alpha_pre_mul; ++ struct vop_reg alpha_mode; ++ struct vop_reg alpha_en; + struct vop_reg channel; + }; + +diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c +index 2413deded22c..80053d91a301 100644 +--- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c ++++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c +@@ -264,6 +264,9 @@ static const struct vop_win_phy px30_win0_data = { + .uv_mst = VOP_REG(PX30_WIN0_CBR_MST0, 0xffffffff, 0), + .yrgb_vir = VOP_REG(PX30_WIN0_VIR, 0x1fff, 0), + .uv_vir = VOP_REG(PX30_WIN0_VIR, 0x1fff, 16), ++ .alpha_pre_mul = VOP_REG(PX30_WIN0_ALPHA_CTRL, 0x1, 2), ++ .alpha_mode = VOP_REG(PX30_WIN0_ALPHA_CTRL, 0x1, 1), ++ .alpha_en = VOP_REG(PX30_WIN0_ALPHA_CTRL, 0x1, 0), + }; + + static const struct vop_win_phy px30_win1_data = { +@@ -277,6 +280,9 @@ static const struct vop_win_phy px30_win1_data = { + .dsp_st = VOP_REG(PX30_WIN1_DSP_ST, 0xffffffff, 0), + .yrgb_mst = VOP_REG(PX30_WIN1_MST, 0xffffffff, 0), + .yrgb_vir = VOP_REG(PX30_WIN1_VIR, 0x1fff, 0), ++ .alpha_pre_mul = VOP_REG(PX30_WIN1_ALPHA_CTRL, 0x1, 2), ++ .alpha_mode = VOP_REG(PX30_WIN1_ALPHA_CTRL, 0x1, 1), ++ .alpha_en = VOP_REG(PX30_WIN1_ALPHA_CTRL, 0x1, 0), + }; + + static const struct vop_win_phy px30_win2_data = { +@@ -291,6 +297,9 @@ static const struct vop_win_phy px30_win2_data = { + .dsp_st = VOP_REG(PX30_WIN2_DSP_ST0, 0x1fff1fff, 0), + .yrgb_mst = VOP_REG(PX30_WIN2_MST0, 0xffffffff, 0), + .yrgb_vir = VOP_REG(PX30_WIN2_VIR0_1, 0x1fff, 0), ++ .alpha_pre_mul = VOP_REG(PX30_WIN2_ALPHA_CTRL, 0x1, 2), ++ .alpha_mode = VOP_REG(PX30_WIN2_ALPHA_CTRL, 0x1, 1), ++ .alpha_en = VOP_REG(PX30_WIN2_ALPHA_CTRL, 0x1, 0), + }; + + static const struct vop_win_data px30_vop_big_win_data[] = { + +From 022f13fb762722cc81f51f2615131fd4b4cd72e6 Mon Sep 17 00:00:00 2001 +From: Krzysztof Kozlowski +Date: Wed, 27 May 2020 22:05:44 +0200 +Subject: [PATCH] drm/panfrost: Reduce the amount of logs on deferred probe + +There is no point to print deferred probe (and its failures to get +resources) as an error. Also there is no need to print regulator errors +twice. + +In case of multiple probe tries this would pollute the dmesg. + +Signed-off-by: Krzysztof Kozlowski +Reviewed-by: Steven Price +Signed-off-by: Steven Price +Link: https://patchwork.freedesktop.org/patch/msgid/20200527200544.7849-1-krzk@kernel.org +(cherry picked from commit e63adeccc0bbba34a7b988b8898bebbd5bbb6461) +--- + drivers/gpu/drm/panfrost/panfrost_device.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/gpu/drm/panfrost/panfrost_device.c b/drivers/gpu/drm/panfrost/panfrost_device.c +index 8136babd3ba9..b172087eee6a 100644 +--- a/drivers/gpu/drm/panfrost/panfrost_device.c ++++ b/drivers/gpu/drm/panfrost/panfrost_device.c +@@ -101,7 +101,9 @@ static int panfrost_regulator_init(struct panfrost_device *pfdev) + pfdev->comp->num_supplies, + pfdev->regulators); + if (ret < 0) { +- dev_err(pfdev->dev, "failed to get regulators: %d\n", ret); ++ if (ret != -EPROBE_DEFER) ++ dev_err(pfdev->dev, "failed to get regulators: %d\n", ++ ret); + return ret; + } + +@@ -213,10 +215,8 @@ int panfrost_device_init(struct panfrost_device *pfdev) + } + + err = panfrost_regulator_init(pfdev); +- if (err) { +- dev_err(pfdev->dev, "regulator init failed %d\n", err); ++ if (err) + goto err_out0; +- } + + err = panfrost_reset_init(pfdev); + if (err) { + +From 9bda1bca65f6067e191b056e6884ba7a9a0c4c09 Mon Sep 17 00:00:00 2001 +From: Dinghao Liu +Date: Fri, 22 May 2020 21:41:09 +0800 +Subject: [PATCH] drm/panfrost: Fix runtime PM imbalance on error + +The caller expects panfrost_job_hw_submit() to increase +runtime PM usage counter. The refcount decrement on the +error branch of WARN_ON() will break the counter balance +and needs to be removed. + +Signed-off-by: Dinghao Liu +Reviewed-by: Steven Price +Signed-off-by: Steven Price +Link: https://patchwork.freedesktop.org/patch/msgid/20200522134109.27204-1-dinghao.liu@zju.edu.cn +(cherry picked from commit 64092598c4566dc80a71ca57396dc36fdbf3da4b) +--- + drivers/gpu/drm/panfrost/panfrost_job.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/drivers/gpu/drm/panfrost/panfrost_job.c b/drivers/gpu/drm/panfrost/panfrost_job.c +index f9519afca29d..c6242fe34840 100644 +--- a/drivers/gpu/drm/panfrost/panfrost_job.c ++++ b/drivers/gpu/drm/panfrost/panfrost_job.c +@@ -152,7 +152,6 @@ static void panfrost_job_hw_submit(struct panfrost_job *job, int js) + return; + + if (WARN_ON(job_read(pfdev, JS_COMMAND_NEXT(js)))) { +- pm_runtime_put_sync_autosuspend(pfdev->dev); + return; + } + + +From 3c403361c554bd46a9ddb2b0d794785916327a83 Mon Sep 17 00:00:00 2001 +From: Ben Davis +Date: Mon, 1 Jun 2020 17:28:17 +0100 +Subject: [PATCH] drm: drm_fourcc: add NV15, Q410, Q401 YUV formats + +DRM_FORMAT_NV15 is a 2 plane format suitable for linear and 16x16 +block-linear memory layouts (DRM_FORMAT_MOD_SAMSUNG_16_16_TILE). The +format is similar to P010 with 4:2:0 sub-sampling but has no padding +between components. Instead, luminance and chrominance samples are +grouped into 4s so that each group is packed into an integer number +of bytes: + +YYYY = UVUV = 4 * 10 bits = 40 bits = 5 bytes + +The '15' suffix refers to the optimum effective bits per pixel which is +achieved when the total number of luminance samples is a multiple of 8. + +Q410 and Q401 are both 3 plane non-subsampled formats with 16 bits per +component, but only 10 bits are used and 6 are padded. 'Q' is chosen +as the first letter to denote 3 plane YUV444, (and is the next letter +along from P which is usually 2 plane). + +V2: Updated block_w of NV15 to {4, 2, 0} +V3: Updated commit message to include specific modifier name + +NV15: +Tested-by: Jonas Karlman + +Reviewed-by: Brian Starkey +Signed-off-by: Ben Davis +Signed-off-by: Liviu Dudau +Link: https://patchwork.freedesktop.org/patch/msgid/20200601162817.18230-1-ben.davis@arm.com +(cherry picked from commit 94b292b277343190175d39172c903c0c5fb814f1) +--- + drivers/gpu/drm/drm_fourcc.c | 12 ++++++++++++ + include/uapi/drm/drm_fourcc.h | 22 ++++++++++++++++++++++ + 2 files changed, 34 insertions(+) + +diff --git a/drivers/gpu/drm/drm_fourcc.c b/drivers/gpu/drm/drm_fourcc.c +index b234bfaeda06..722c7ebe4e88 100644 +--- a/drivers/gpu/drm/drm_fourcc.c ++++ b/drivers/gpu/drm/drm_fourcc.c +@@ -274,6 +274,18 @@ const struct drm_format_info *__drm_format_info(u32 format) + { .format = DRM_FORMAT_YUV420_10BIT, .depth = 0, + .num_planes = 1, .cpp = { 0, 0, 0 }, .hsub = 2, .vsub = 2, + .is_yuv = true }, ++ { .format = DRM_FORMAT_NV15, .depth = 0, ++ .num_planes = 2, .char_per_block = { 5, 5, 0 }, ++ .block_w = { 4, 2, 0 }, .block_h = { 1, 1, 0 }, .hsub = 2, ++ .vsub = 2, .is_yuv = true }, ++ { .format = DRM_FORMAT_Q410, .depth = 0, ++ .num_planes = 3, .char_per_block = { 2, 2, 2 }, ++ .block_w = { 1, 1, 1 }, .block_h = { 1, 1, 1 }, .hsub = 0, ++ .vsub = 0, .is_yuv = true }, ++ { .format = DRM_FORMAT_Q401, .depth = 0, ++ .num_planes = 3, .char_per_block = { 2, 2, 2 }, ++ .block_w = { 1, 1, 1 }, .block_h = { 1, 1, 1 }, .hsub = 0, ++ .vsub = 0, .is_yuv = true }, + }; + + unsigned int i; +diff --git a/include/uapi/drm/drm_fourcc.h b/include/uapi/drm/drm_fourcc.h +index 490143500a50..8ba2d9153a94 100644 +--- a/include/uapi/drm/drm_fourcc.h ++++ b/include/uapi/drm/drm_fourcc.h +@@ -236,6 +236,12 @@ extern "C" { + #define DRM_FORMAT_NV61 fourcc_code('N', 'V', '6', '1') /* 2x1 subsampled Cb:Cr plane */ + #define DRM_FORMAT_NV24 fourcc_code('N', 'V', '2', '4') /* non-subsampled Cr:Cb plane */ + #define DRM_FORMAT_NV42 fourcc_code('N', 'V', '4', '2') /* non-subsampled Cb:Cr plane */ ++/* ++ * 2 plane YCbCr ++ * index 0 = Y plane, [39:0] Y3:Y2:Y1:Y0 little endian ++ * index 1 = Cr:Cb plane, [39:0] Cr1:Cb1:Cr0:Cb0 little endian ++ */ ++#define DRM_FORMAT_NV15 fourcc_code('N', 'V', '1', '5') /* 2x2 subsampled Cr:Cb plane */ + + /* + * 2 plane YCbCr MSB aligned +@@ -265,6 +271,22 @@ extern "C" { + */ + #define DRM_FORMAT_P016 fourcc_code('P', '0', '1', '6') /* 2x2 subsampled Cr:Cb plane 16 bits per channel */ + ++/* 3 plane non-subsampled (444) YCbCr ++ * 16 bits per component, but only 10 bits are used and 6 bits are padded ++ * index 0: Y plane, [15:0] Y:x [10:6] little endian ++ * index 1: Cb plane, [15:0] Cb:x [10:6] little endian ++ * index 2: Cr plane, [15:0] Cr:x [10:6] little endian ++ */ ++#define DRM_FORMAT_Q410 fourcc_code('Q', '4', '1', '0') ++ ++/* 3 plane non-subsampled (444) YCrCb ++ * 16 bits per component, but only 10 bits are used and 6 bits are padded ++ * index 0: Y plane, [15:0] Y:x [10:6] little endian ++ * index 1: Cr plane, [15:0] Cr:x [10:6] little endian ++ * index 2: Cb plane, [15:0] Cb:x [10:6] little endian ++ */ ++#define DRM_FORMAT_Q401 fourcc_code('Q', '4', '0', '1') ++ + /* + * 3 plane YCbCr + * index 0: Y plane, [7:0] Y + +From 7e57394c63258ac63d5c74cbd2a700916c31d4f6 Mon Sep 17 00:00:00 2001 +From: Ben Davis +Date: Thu, 30 Apr 2020 09:32:20 +0100 +Subject: [PATCH] drm: drm_fourcc: Add uncompressed AFBC modifier + +AFBC has a mode that guarantees use of AFBC with an uncompressed +payloads, we add a new modifier to support this mode. + +V2: updated modifier comment + +Signed-off-by: Ben Davis +Acked-by: Liviu Dudau +Signed-off-by: Liviu Dudau +Link: https://patchwork.freedesktop.org/patch/msgid/20200430083220.17347-1-ben.davis@arm.com +(cherry picked from commit 79ce058032c391b12af928b1e30abf92482a270f) +--- + include/uapi/drm/drm_fourcc.h | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +diff --git a/include/uapi/drm/drm_fourcc.h b/include/uapi/drm/drm_fourcc.h +index 8ba2d9153a94..993c1b342315 100644 +--- a/include/uapi/drm/drm_fourcc.h ++++ b/include/uapi/drm/drm_fourcc.h +@@ -914,6 +914,18 @@ drm_fourcc_canonicalize_nvidia_format_mod(__u64 modifier) + */ + #define AFBC_FORMAT_MOD_BCH (1ULL << 11) + ++/* AFBC uncompressed storage mode ++ * ++ * Indicates that the buffer is using AFBC uncompressed storage mode. ++ * In this mode all superblock payloads in the buffer use the uncompressed ++ * storage mode, which is usually only used for data which cannot be compressed. ++ * The buffer layout is the same as for AFBC buffers without USM set, this only ++ * affects the storage mode of the individual superblocks. Note that even a ++ * buffer without USM set may use uncompressed storage mode for some or all ++ * superblocks, USM just guarantees it for all. ++ */ ++#define AFBC_FORMAT_MOD_USM (1ULL << 12) ++ + /* + * Arm 16x16 Block U-Interleaved modifier + * + +From 32b33df85c3c84ce2a145f2d68305116fbec91fd Mon Sep 17 00:00:00 2001 +From: Laurent Pinchart +Date: Tue, 26 May 2020 04:14:47 +0300 +Subject: [PATCH] drm: edid: Constify connector argument to infoframe functions + +The drm_hdmi_avi_infoframe_from_display_mode(), +drm_hdmi_vendor_infoframe_from_display_mode() and +drm_hdmi_avi_infoframe_quant_range() functions take a drm_connector that +they don't modify. Mark it as const. + +Signed-off-by: Laurent Pinchart +Acked-by: Sam Ravnborg +Signed-off-by: Sam Ravnborg +Link: https://patchwork.freedesktop.org/patch/msgid/20200526011505.31884-10-laurent.pinchart+renesas@ideasonboard.com +(cherry picked from commit 192a3aa0e4e20e1087baa29183c5d64d48716fa9) +--- + drivers/gpu/drm/drm_edid.c | 12 ++++++------ + include/drm/drm_edid.h | 6 +++--- + 2 files changed, 9 insertions(+), 9 deletions(-) + +diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c +index fed653f13c26..b3f659759adb 100644 +--- a/drivers/gpu/drm/drm_edid.c ++++ b/drivers/gpu/drm/drm_edid.c +@@ -5366,7 +5366,7 @@ void drm_set_preferred_mode(struct drm_connector *connector, + } + EXPORT_SYMBOL(drm_set_preferred_mode); + +-static bool is_hdmi2_sink(struct drm_connector *connector) ++static bool is_hdmi2_sink(const struct drm_connector *connector) + { + /* + * FIXME: sil-sii8620 doesn't have a connector around when +@@ -5451,7 +5451,7 @@ drm_hdmi_infoframe_set_hdr_metadata(struct hdmi_drm_infoframe *frame, + } + EXPORT_SYMBOL(drm_hdmi_infoframe_set_hdr_metadata); + +-static u8 drm_mode_hdmi_vic(struct drm_connector *connector, ++static u8 drm_mode_hdmi_vic(const struct drm_connector *connector, + const struct drm_display_mode *mode) + { + bool has_hdmi_infoframe = connector ? +@@ -5467,7 +5467,7 @@ static u8 drm_mode_hdmi_vic(struct drm_connector *connector, + return drm_match_hdmi_mode(mode); + } + +-static u8 drm_mode_cea_vic(struct drm_connector *connector, ++static u8 drm_mode_cea_vic(const struct drm_connector *connector, + const struct drm_display_mode *mode) + { + u8 vic; +@@ -5505,7 +5505,7 @@ static u8 drm_mode_cea_vic(struct drm_connector *connector, + */ + int + drm_hdmi_avi_infoframe_from_display_mode(struct hdmi_avi_infoframe *frame, +- struct drm_connector *connector, ++ const struct drm_connector *connector, + const struct drm_display_mode *mode) + { + enum hdmi_picture_aspect picture_aspect; +@@ -5652,7 +5652,7 @@ EXPORT_SYMBOL(drm_hdmi_avi_infoframe_colorspace); + */ + void + drm_hdmi_avi_infoframe_quant_range(struct hdmi_avi_infoframe *frame, +- struct drm_connector *connector, ++ const struct drm_connector *connector, + const struct drm_display_mode *mode, + enum hdmi_quantization_range rgb_quant_range) + { +@@ -5756,7 +5756,7 @@ s3d_structure_from_display_mode(const struct drm_display_mode *mode) + */ + int + drm_hdmi_vendor_infoframe_from_display_mode(struct hdmi_vendor_infoframe *frame, +- struct drm_connector *connector, ++ const struct drm_connector *connector, + const struct drm_display_mode *mode) + { + /* +diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h +index 34b15e3d070c..43254319ab19 100644 +--- a/include/drm/drm_edid.h ++++ b/include/drm/drm_edid.h +@@ -361,11 +361,11 @@ drm_load_edid_firmware(struct drm_connector *connector) + + int + drm_hdmi_avi_infoframe_from_display_mode(struct hdmi_avi_infoframe *frame, +- struct drm_connector *connector, ++ const struct drm_connector *connector, + const struct drm_display_mode *mode); + int + drm_hdmi_vendor_infoframe_from_display_mode(struct hdmi_vendor_infoframe *frame, +- struct drm_connector *connector, ++ const struct drm_connector *connector, + const struct drm_display_mode *mode); + + void +@@ -378,7 +378,7 @@ drm_hdmi_avi_infoframe_bars(struct hdmi_avi_infoframe *frame, + + void + drm_hdmi_avi_infoframe_quant_range(struct hdmi_avi_infoframe *frame, +- struct drm_connector *connector, ++ const struct drm_connector *connector, + const struct drm_display_mode *mode, + enum hdmi_quantization_range rgb_quant_range); + + +From 23fe85a8775eb3c926be0f3d2bc99b70a6d0bb07 Mon Sep 17 00:00:00 2001 +From: Laurent Pinchart +Date: Tue, 26 May 2020 04:14:48 +0300 +Subject: [PATCH] drm: bridge: Pass drm_display_info to drm_bridge_funcs + .mode_valid() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +When validating a mode, bridges may need to do so in the context of a +display, as specified by drm_display_info. An example is the meson +dw-hdmi bridge that needs to consider the YUV 4:2:0 output format to +perform clock calculations. + +Bridges that need the display info currently retrieve it from the +drm_connector created by the bridge. This gets in the way of moving +connector creation out of bridge drivers. To make this possible, pass +the drm_display_info to drm_bridge_funcs .mode_valid(). + +Changes to the bridge drivers have been performed with the following +coccinelle semantic patch and have been compile-tested. + +@ rule1 @ +identifier funcs; +identifier fn; +@@ + struct drm_bridge_funcs funcs = { + ..., + .mode_valid = fn + }; + +@ depends on rule1 @ +identifier rule1.fn; +identifier bridge; +identifier mode; +@@ + enum drm_mode_status fn( + struct drm_bridge *bridge, ++ const struct drm_display_info *info, + const struct drm_display_mode *mode + ) + { + ... + } + +Signed-off-by: Laurent Pinchart +Reviewed-by: Neil Armstrong +Reviewed-by: Boris Brezillon +Reviewed-by: Guido Günther # for the nwl-dsi part: +Signed-off-by: Sam Ravnborg +Link: https://patchwork.freedesktop.org/patch/msgid/20200526011505.31884-11-laurent.pinchart+renesas@ideasonboard.com +(cherry picked from commit 12c683e12cd8e2dcf7b7143bebceae484d17727a) +--- + drivers/gpu/drm/bridge/analogix/analogix-anx6345.c | 1 + + drivers/gpu/drm/bridge/analogix/analogix-anx78xx.c | 1 + + drivers/gpu/drm/bridge/cdns-dsi.c | 1 + + drivers/gpu/drm/bridge/chrontel-ch7033.c | 1 + + drivers/gpu/drm/bridge/nwl-dsi.c | 1 + + drivers/gpu/drm/bridge/sii9234.c | 1 + + drivers/gpu/drm/bridge/sil-sii8620.c | 1 + + drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 1 + + drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c | 1 + + drivers/gpu/drm/bridge/tc358767.c | 1 + + drivers/gpu/drm/bridge/tc358768.c | 1 + + drivers/gpu/drm/bridge/thc63lvd1024.c | 1 + + drivers/gpu/drm/bridge/ti-tfp410.c | 1 + + drivers/gpu/drm/drm_atomic_helper.c | 3 ++- + drivers/gpu/drm/drm_bridge.c | 4 +++- + drivers/gpu/drm/drm_probe_helper.c | 4 +++- + drivers/gpu/drm/i2c/tda998x_drv.c | 1 + + drivers/gpu/drm/omapdrm/dss/dpi.c | 1 + + drivers/gpu/drm/omapdrm/dss/sdi.c | 1 + + drivers/gpu/drm/omapdrm/dss/venc.c | 1 + + include/drm/drm_bridge.h | 3 +++ + 21 files changed, 28 insertions(+), 3 deletions(-) + +diff --git a/drivers/gpu/drm/bridge/analogix/analogix-anx6345.c b/drivers/gpu/drm/bridge/analogix/analogix-anx6345.c +index 9af39ec958db..f082b4ed4878 100644 +--- a/drivers/gpu/drm/bridge/analogix/analogix-anx6345.c ++++ b/drivers/gpu/drm/bridge/analogix/analogix-anx6345.c +@@ -588,6 +588,7 @@ static int anx6345_bridge_attach(struct drm_bridge *bridge, + + static enum drm_mode_status + anx6345_bridge_mode_valid(struct drm_bridge *bridge, ++ const struct drm_display_info *info, + const struct drm_display_mode *mode) + { + if (mode->flags & DRM_MODE_FLAG_INTERLACE) +diff --git a/drivers/gpu/drm/bridge/analogix/analogix-anx78xx.c b/drivers/gpu/drm/bridge/analogix/analogix-anx78xx.c +index 0d5a5ad0c9ee..81debd02c169 100644 +--- a/drivers/gpu/drm/bridge/analogix/analogix-anx78xx.c ++++ b/drivers/gpu/drm/bridge/analogix/analogix-anx78xx.c +@@ -944,6 +944,7 @@ static int anx78xx_bridge_attach(struct drm_bridge *bridge, + + static enum drm_mode_status + anx78xx_bridge_mode_valid(struct drm_bridge *bridge, ++ const struct drm_display_info *info, + const struct drm_display_mode *mode) + { + if (mode->flags & DRM_MODE_FLAG_INTERLACE) +diff --git a/drivers/gpu/drm/bridge/cdns-dsi.c b/drivers/gpu/drm/bridge/cdns-dsi.c +index 69c3892caee5..76373e31df92 100644 +--- a/drivers/gpu/drm/bridge/cdns-dsi.c ++++ b/drivers/gpu/drm/bridge/cdns-dsi.c +@@ -663,6 +663,7 @@ static int cdns_dsi_bridge_attach(struct drm_bridge *bridge, + + static enum drm_mode_status + cdns_dsi_bridge_mode_valid(struct drm_bridge *bridge, ++ const struct drm_display_info *info, + const struct drm_display_mode *mode) + { + struct cdns_dsi_input *input = bridge_to_cdns_dsi_input(bridge); +diff --git a/drivers/gpu/drm/bridge/chrontel-ch7033.c b/drivers/gpu/drm/bridge/chrontel-ch7033.c +index f8675d82974b..486f405c2e16 100644 +--- a/drivers/gpu/drm/bridge/chrontel-ch7033.c ++++ b/drivers/gpu/drm/bridge/chrontel-ch7033.c +@@ -317,6 +317,7 @@ static void ch7033_bridge_detach(struct drm_bridge *bridge) + } + + static enum drm_mode_status ch7033_bridge_mode_valid(struct drm_bridge *bridge, ++ const struct drm_display_info *info, + const struct drm_display_mode *mode) + { + if (mode->clock > 165000) +diff --git a/drivers/gpu/drm/bridge/nwl-dsi.c b/drivers/gpu/drm/bridge/nwl-dsi.c +index c7bc194bbce3..ce94f797d090 100644 +--- a/drivers/gpu/drm/bridge/nwl-dsi.c ++++ b/drivers/gpu/drm/bridge/nwl-dsi.c +@@ -818,6 +818,7 @@ static bool nwl_dsi_bridge_mode_fixup(struct drm_bridge *bridge, + + static enum drm_mode_status + nwl_dsi_bridge_mode_valid(struct drm_bridge *bridge, ++ const struct drm_display_info *info, + const struct drm_display_mode *mode) + { + struct nwl_dsi *dsi = bridge_to_dsi(bridge); +diff --git a/drivers/gpu/drm/bridge/sii9234.c b/drivers/gpu/drm/bridge/sii9234.c +index b1258f0ed205..15c98a7bd81c 100644 +--- a/drivers/gpu/drm/bridge/sii9234.c ++++ b/drivers/gpu/drm/bridge/sii9234.c +@@ -873,6 +873,7 @@ static inline struct sii9234 *bridge_to_sii9234(struct drm_bridge *bridge) + } + + static enum drm_mode_status sii9234_mode_valid(struct drm_bridge *bridge, ++ const struct drm_display_info *info, + const struct drm_display_mode *mode) + { + if (mode->clock > MHL1_MAX_CLK) +diff --git a/drivers/gpu/drm/bridge/sil-sii8620.c b/drivers/gpu/drm/bridge/sil-sii8620.c +index ca98133411aa..95f3d8cfe9ec 100644 +--- a/drivers/gpu/drm/bridge/sil-sii8620.c ++++ b/drivers/gpu/drm/bridge/sil-sii8620.c +@@ -2244,6 +2244,7 @@ static int sii8620_is_packing_required(struct sii8620 *ctx, + } + + static enum drm_mode_status sii8620_mode_valid(struct drm_bridge *bridge, ++ const struct drm_display_info *info, + const struct drm_display_mode *mode) + { + struct sii8620 *ctx = bridge_to_sii8620(bridge); +diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +index 30681398cfb0..b535354150db 100644 +--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c ++++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +@@ -2767,6 +2767,7 @@ static void dw_hdmi_bridge_detach(struct drm_bridge *bridge) + + static enum drm_mode_status + dw_hdmi_bridge_mode_valid(struct drm_bridge *bridge, ++ const struct drm_display_info *info, + const struct drm_display_mode *mode) + { + struct dw_hdmi *hdmi = bridge->driver_private; +diff --git a/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c b/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c +index 5ef0f154aa7b..c223fb9a04cb 100644 +--- a/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c ++++ b/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c +@@ -924,6 +924,7 @@ static void dw_mipi_dsi_bridge_enable(struct drm_bridge *bridge) + + static enum drm_mode_status + dw_mipi_dsi_bridge_mode_valid(struct drm_bridge *bridge, ++ const struct drm_display_info *info, + const struct drm_display_mode *mode) + { + struct dw_mipi_dsi *dsi = bridge_to_dsi(bridge); +diff --git a/drivers/gpu/drm/bridge/tc358767.c b/drivers/gpu/drm/bridge/tc358767.c +index e4c0ea03ae3a..c2777b226c75 100644 +--- a/drivers/gpu/drm/bridge/tc358767.c ++++ b/drivers/gpu/drm/bridge/tc358767.c +@@ -1306,6 +1306,7 @@ static bool tc_bridge_mode_fixup(struct drm_bridge *bridge, + } + + static enum drm_mode_status tc_mode_valid(struct drm_bridge *bridge, ++ const struct drm_display_info *info, + const struct drm_display_mode *mode) + { + struct tc_data *tc = bridge_to_tc(bridge); +diff --git a/drivers/gpu/drm/bridge/tc358768.c b/drivers/gpu/drm/bridge/tc358768.c +index 6650fe4cfc20..4a463fadf743 100644 +--- a/drivers/gpu/drm/bridge/tc358768.c ++++ b/drivers/gpu/drm/bridge/tc358768.c +@@ -529,6 +529,7 @@ static int tc358768_bridge_attach(struct drm_bridge *bridge, + + static enum drm_mode_status + tc358768_bridge_mode_valid(struct drm_bridge *bridge, ++ const struct drm_display_info *info, + const struct drm_display_mode *mode) + { + struct tc358768_priv *priv = bridge_to_tc358768(bridge); +diff --git a/drivers/gpu/drm/bridge/thc63lvd1024.c b/drivers/gpu/drm/bridge/thc63lvd1024.c +index 97d8129760e9..86b06975bfdd 100644 +--- a/drivers/gpu/drm/bridge/thc63lvd1024.c ++++ b/drivers/gpu/drm/bridge/thc63lvd1024.c +@@ -51,6 +51,7 @@ static int thc63_attach(struct drm_bridge *bridge, + } + + static enum drm_mode_status thc63_mode_valid(struct drm_bridge *bridge, ++ const struct drm_display_info *info, + const struct drm_display_mode *mode) + { + struct thc63_dev *thc63 = to_thc63(bridge); +diff --git a/drivers/gpu/drm/bridge/ti-tfp410.c b/drivers/gpu/drm/bridge/ti-tfp410.c +index e3eb6364c0f7..30230c552aeb 100644 +--- a/drivers/gpu/drm/bridge/ti-tfp410.c ++++ b/drivers/gpu/drm/bridge/ti-tfp410.c +@@ -188,6 +188,7 @@ static void tfp410_disable(struct drm_bridge *bridge) + } + + static enum drm_mode_status tfp410_mode_valid(struct drm_bridge *bridge, ++ const struct drm_display_info *info, + const struct drm_display_mode *mode) + { + if (mode->clock < 25000) +diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c +index b78e142a5620..ab9078eaa912 100644 +--- a/drivers/gpu/drm/drm_atomic_helper.c ++++ b/drivers/gpu/drm/drm_atomic_helper.c +@@ -507,7 +507,8 @@ static enum drm_mode_status mode_valid_path(struct drm_connector *connector, + } + + bridge = drm_bridge_chain_get_first_bridge(encoder); +- ret = drm_bridge_chain_mode_valid(bridge, mode); ++ ret = drm_bridge_chain_mode_valid(bridge, &connector->display_info, ++ mode); + if (ret != MODE_OK) { + DRM_DEBUG_ATOMIC("[BRIDGE] mode_valid() failed\n"); + return ret; +diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c +index afdec8e5fc68..8e31af64e8fe 100644 +--- a/drivers/gpu/drm/drm_bridge.c ++++ b/drivers/gpu/drm/drm_bridge.c +@@ -377,6 +377,7 @@ EXPORT_SYMBOL(drm_bridge_chain_mode_fixup); + * drm_bridge_chain_mode_valid - validate the mode against all bridges in the + * encoder chain. + * @bridge: bridge control structure ++ * @info: display info against which the mode shall be validated + * @mode: desired mode to be validated + * + * Calls &drm_bridge_funcs.mode_valid for all the bridges in the encoder +@@ -390,6 +391,7 @@ EXPORT_SYMBOL(drm_bridge_chain_mode_fixup); + */ + enum drm_mode_status + drm_bridge_chain_mode_valid(struct drm_bridge *bridge, ++ const struct drm_display_info *info, + const struct drm_display_mode *mode) + { + struct drm_encoder *encoder; +@@ -404,7 +406,7 @@ drm_bridge_chain_mode_valid(struct drm_bridge *bridge, + if (!bridge->funcs->mode_valid) + continue; + +- ret = bridge->funcs->mode_valid(bridge, mode); ++ ret = bridge->funcs->mode_valid(bridge, info, mode); + if (ret != MODE_OK) + return ret; + } +diff --git a/drivers/gpu/drm/drm_probe_helper.c b/drivers/gpu/drm/drm_probe_helper.c +index 576b4b7dcd89..f5d141e0400f 100644 +--- a/drivers/gpu/drm/drm_probe_helper.c ++++ b/drivers/gpu/drm/drm_probe_helper.c +@@ -114,7 +114,9 @@ drm_mode_validate_pipeline(struct drm_display_mode *mode, + } + + bridge = drm_bridge_chain_get_first_bridge(encoder); +- ret = drm_bridge_chain_mode_valid(bridge, mode); ++ ret = drm_bridge_chain_mode_valid(bridge, ++ &connector->display_info, ++ mode); + if (ret != MODE_OK) { + /* There is also no point in continuing for crtc check + * here. */ +diff --git a/drivers/gpu/drm/i2c/tda998x_drv.c b/drivers/gpu/drm/i2c/tda998x_drv.c +index 9517f522dcb9..50fd119a5276 100644 +--- a/drivers/gpu/drm/i2c/tda998x_drv.c ++++ b/drivers/gpu/drm/i2c/tda998x_drv.c +@@ -1379,6 +1379,7 @@ static void tda998x_bridge_detach(struct drm_bridge *bridge) + } + + static enum drm_mode_status tda998x_bridge_mode_valid(struct drm_bridge *bridge, ++ const struct drm_display_info *info, + const struct drm_display_mode *mode) + { + /* TDA19988 dotclock can go up to 165MHz */ +diff --git a/drivers/gpu/drm/omapdrm/dss/dpi.c b/drivers/gpu/drm/omapdrm/dss/dpi.c +index 5110acb0c6c1..1d2992daef40 100644 +--- a/drivers/gpu/drm/omapdrm/dss/dpi.c ++++ b/drivers/gpu/drm/omapdrm/dss/dpi.c +@@ -434,6 +434,7 @@ static int dpi_bridge_attach(struct drm_bridge *bridge, + + static enum drm_mode_status + dpi_bridge_mode_valid(struct drm_bridge *bridge, ++ const struct drm_display_info *info, + const struct drm_display_mode *mode) + { + struct dpi_data *dpi = drm_bridge_to_dpi(bridge); +diff --git a/drivers/gpu/drm/omapdrm/dss/sdi.c b/drivers/gpu/drm/omapdrm/dss/sdi.c +index 417a8740ad0a..033fd30074b0 100644 +--- a/drivers/gpu/drm/omapdrm/dss/sdi.c ++++ b/drivers/gpu/drm/omapdrm/dss/sdi.c +@@ -140,6 +140,7 @@ static int sdi_bridge_attach(struct drm_bridge *bridge, + + static enum drm_mode_status + sdi_bridge_mode_valid(struct drm_bridge *bridge, ++ const struct drm_display_info *info, + const struct drm_display_mode *mode) + { + struct sdi_device *sdi = drm_bridge_to_sdi(bridge); +diff --git a/drivers/gpu/drm/omapdrm/dss/venc.c b/drivers/gpu/drm/omapdrm/dss/venc.c +index 01ee6c50b663..e0817934ee16 100644 +--- a/drivers/gpu/drm/omapdrm/dss/venc.c ++++ b/drivers/gpu/drm/omapdrm/dss/venc.c +@@ -548,6 +548,7 @@ static int venc_bridge_attach(struct drm_bridge *bridge, + + static enum drm_mode_status + venc_bridge_mode_valid(struct drm_bridge *bridge, ++ const struct drm_display_info *info, + const struct drm_display_mode *mode) + { + switch (venc_get_videomode(mode)) { +diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h +index ea2aa5ebae34..e3d7f36d8c39 100644 +--- a/include/drm/drm_bridge.h ++++ b/include/drm/drm_bridge.h +@@ -35,6 +35,7 @@ + struct drm_bridge; + struct drm_bridge_timings; + struct drm_connector; ++struct drm_display_info; + struct drm_panel; + struct edid; + struct i2c_adapter; +@@ -112,6 +113,7 @@ struct drm_bridge_funcs { + * drm_mode_status Enum + */ + enum drm_mode_status (*mode_valid)(struct drm_bridge *bridge, ++ const struct drm_display_info *info, + const struct drm_display_mode *mode); + + /** +@@ -836,6 +838,7 @@ bool drm_bridge_chain_mode_fixup(struct drm_bridge *bridge, + struct drm_display_mode *adjusted_mode); + enum drm_mode_status + drm_bridge_chain_mode_valid(struct drm_bridge *bridge, ++ const struct drm_display_info *info, + const struct drm_display_mode *mode); + void drm_bridge_chain_disable(struct drm_bridge *bridge); + void drm_bridge_chain_post_disable(struct drm_bridge *bridge); + +From a9ae85591e16f342fc822ce27a514f2879ac4c06 Mon Sep 17 00:00:00 2001 +From: Laurent Pinchart +Date: Tue, 26 May 2020 04:14:49 +0300 +Subject: [PATCH] drm: bridge: dw-hdmi: Pass private data pointer to + .mode_valid() + +Platform glue drivers for dw_hdmi may need to access device-specific +data from their .mode_valid() implementation. They currently have no +clean way to do so, and one driver hacks around it by accessing the +dev_private data of the drm_device retrieved from the connector. + +Add a priv_data void pointer to the dw_hdmi_plat_data structure, and +pass it to the .mode_valid() function. + +Signed-off-by: Laurent Pinchart +Reviewed-by: Neil Armstrong +Signed-off-by: Sam Ravnborg +Link: https://patchwork.freedesktop.org/patch/msgid/20200526011505.31884-12-laurent.pinchart+renesas@ideasonboard.com +(cherry picked from commit 96591a4b93fb8b335941783dd6e7ded9d6d49f09) +--- + drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 6 ++++-- + drivers/gpu/drm/imx/dw_hdmi-imx.c | 6 ++++-- + drivers/gpu/drm/meson/meson_dw_hdmi.c | 3 ++- + drivers/gpu/drm/rcar-du/rcar_dw_hdmi.c | 3 ++- + drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 3 ++- + drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c | 6 ++++-- + drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h | 3 ++- + include/drm/bridge/dw_hdmi.h | 14 ++++++++++++-- + 8 files changed, 32 insertions(+), 12 deletions(-) + +diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +index b535354150db..2b3f203cf467 100644 +--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c ++++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +@@ -2771,6 +2771,7 @@ dw_hdmi_bridge_mode_valid(struct drm_bridge *bridge, + const struct drm_display_mode *mode) + { + struct dw_hdmi *hdmi = bridge->driver_private; ++ const struct dw_hdmi_plat_data *pdata = hdmi->plat_data; + struct drm_connector *connector = &hdmi->connector; + enum drm_mode_status mode_status = MODE_OK; + +@@ -2778,8 +2779,9 @@ dw_hdmi_bridge_mode_valid(struct drm_bridge *bridge, + if (mode->flags & DRM_MODE_FLAG_DBLCLK) + return MODE_BAD; + +- if (hdmi->plat_data->mode_valid) +- mode_status = hdmi->plat_data->mode_valid(connector, mode); ++ if (pdata->mode_valid) ++ mode_status = pdata->mode_valid(hdmi, pdata->priv_data, ++ connector, mode); + + return mode_status; + } +diff --git a/drivers/gpu/drm/imx/dw_hdmi-imx.c b/drivers/gpu/drm/imx/dw_hdmi-imx.c +index 87869b9997a6..ff4fde0eb5f6 100644 +--- a/drivers/gpu/drm/imx/dw_hdmi-imx.c ++++ b/drivers/gpu/drm/imx/dw_hdmi-imx.c +@@ -145,7 +145,8 @@ static const struct drm_encoder_helper_funcs dw_hdmi_imx_encoder_helper_funcs = + }; + + static enum drm_mode_status +-imx6q_hdmi_mode_valid(struct drm_connector *con, ++imx6q_hdmi_mode_valid(struct dw_hdmi *hdmi, void *data, ++ struct drm_connector *con, + const struct drm_display_mode *mode) + { + if (mode->clock < 13500) +@@ -158,7 +159,8 @@ imx6q_hdmi_mode_valid(struct drm_connector *con, + } + + static enum drm_mode_status +-imx6dl_hdmi_mode_valid(struct drm_connector *con, ++imx6dl_hdmi_mode_valid(struct dw_hdmi *hdmi, void *data, ++ struct drm_connector *con, + const struct drm_display_mode *mode) + { + if (mode->clock < 13500) +diff --git a/drivers/gpu/drm/meson/meson_dw_hdmi.c b/drivers/gpu/drm/meson/meson_dw_hdmi.c +index 24a12c453095..fc594213c0e0 100644 +--- a/drivers/gpu/drm/meson/meson_dw_hdmi.c ++++ b/drivers/gpu/drm/meson/meson_dw_hdmi.c +@@ -630,7 +630,8 @@ static irqreturn_t dw_hdmi_top_thread_irq(int irq, void *dev_id) + } + + static enum drm_mode_status +-dw_hdmi_mode_valid(struct drm_connector *connector, ++dw_hdmi_mode_valid(struct dw_hdmi *hdmi, void *data, ++ struct drm_connector *connector, + const struct drm_display_mode *mode) + { + struct meson_drm *priv = connector->dev->dev_private; +diff --git a/drivers/gpu/drm/rcar-du/rcar_dw_hdmi.c b/drivers/gpu/drm/rcar-du/rcar_dw_hdmi.c +index 452461dc96f2..4d837a4d302d 100644 +--- a/drivers/gpu/drm/rcar-du/rcar_dw_hdmi.c ++++ b/drivers/gpu/drm/rcar-du/rcar_dw_hdmi.c +@@ -38,7 +38,8 @@ static const struct rcar_hdmi_phy_params rcar_hdmi_phy_params[] = { + }; + + static enum drm_mode_status +-rcar_hdmi_mode_valid(struct drm_connector *connector, ++rcar_hdmi_mode_valid(struct dw_hdmi *hdmi, void *data, ++ struct drm_connector *connector, + const struct drm_display_mode *mode) + { + /* +diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +index 121aa8a63a76..d08f86783a28 100644 +--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c ++++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +@@ -220,7 +220,8 @@ static int rockchip_hdmi_parse_dt(struct rockchip_hdmi *hdmi) + } + + static enum drm_mode_status +-dw_hdmi_rockchip_mode_valid(struct drm_connector *connector, ++dw_hdmi_rockchip_mode_valid(struct dw_hdmi *hdmi, void *data, ++ struct drm_connector *connector, + const struct drm_display_mode *mode) + { + const struct dw_hdmi_mpll_config *mpll_cfg = rockchip_mpll_cfg; +diff --git a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c +index 972682bb8000..0a3637442ba6 100644 +--- a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c ++++ b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c +@@ -31,7 +31,8 @@ sun8i_dw_hdmi_encoder_helper_funcs = { + }; + + static enum drm_mode_status +-sun8i_dw_hdmi_mode_valid_a83t(struct drm_connector *connector, ++sun8i_dw_hdmi_mode_valid_a83t(struct dw_hdmi *hdmi, void *data, ++ struct drm_connector *connector, + const struct drm_display_mode *mode) + { + if (mode->clock > 297000) +@@ -41,7 +42,8 @@ sun8i_dw_hdmi_mode_valid_a83t(struct drm_connector *connector, + } + + static enum drm_mode_status +-sun8i_dw_hdmi_mode_valid_h6(struct drm_connector *connector, ++sun8i_dw_hdmi_mode_valid_h6(struct dw_hdmi *hdmi, void *data, ++ struct drm_connector *connector, + const struct drm_display_mode *mode) + { + /* +diff --git a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h +index 8e64945167e9..8587b8d2590e 100644 +--- a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h ++++ b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h +@@ -176,7 +176,8 @@ struct sun8i_hdmi_phy { + }; + + struct sun8i_dw_hdmi_quirks { +- enum drm_mode_status (*mode_valid)(struct drm_connector *connector, ++ enum drm_mode_status (*mode_valid)(struct dw_hdmi *hdmi, void *data, ++ struct drm_connector *connector, + const struct drm_display_mode *mode); + unsigned int set_rate : 1; + unsigned int use_drm_infoframe : 1; +diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h +index 0b34a12c4a1c..66a811f75b91 100644 +--- a/include/drm/bridge/dw_hdmi.h ++++ b/include/drm/bridge/dw_hdmi.h +@@ -124,13 +124,23 @@ struct dw_hdmi_phy_ops { + + struct dw_hdmi_plat_data { + struct regmap *regm; +- enum drm_mode_status (*mode_valid)(struct drm_connector *connector, +- const struct drm_display_mode *mode); ++ + unsigned long input_bus_format; + unsigned long input_bus_encoding; + bool use_drm_infoframe; + bool ycbcr_420_allowed; + ++ /* ++ * Private data passed to all the .mode_valid() and .configure_phy() ++ * callback functions. ++ */ ++ void *priv_data; ++ ++ /* Platform-specific mode validation (optional). */ ++ enum drm_mode_status (*mode_valid)(struct dw_hdmi *hdmi, void *data, ++ struct drm_connector *connector, ++ const struct drm_display_mode *mode); ++ + /* Vendor PHY support */ + const struct dw_hdmi_phy_ops *phy_ops; + const char *phy_name; + +From 5a367989e0577a22f143fd9a0ae8bc3c5e187144 Mon Sep 17 00:00:00 2001 +From: Laurent Pinchart +Date: Tue, 26 May 2020 04:14:50 +0300 +Subject: [PATCH] drm: bridge: dw-hdmi: Pass private data pointer to + .configure_phy() + +The .configure_phy() operation takes a dw_hdmi_plat_data pointer as a +context argument. This differs from .mode_valid() that takes a custom +private context pointer, causing possible confusion. Make the +dw_hdmi_plat_data operations more consistent by passing the private +context pointer to .configure_phy() as well. + +Signed-off-by: Laurent Pinchart +Reviewed-by: Neil Armstrong +Signed-off-by: Sam Ravnborg +Link: https://patchwork.freedesktop.org/patch/msgid/20200526011505.31884-13-laurent.pinchart+renesas@ideasonboard.com +(cherry picked from commit 49da7e5d84e3b520355c0b6148d6dc9e5415a13e) +--- + drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 2 +- + drivers/gpu/drm/rcar-du/rcar_dw_hdmi.c | 3 +-- + include/drm/bridge/dw_hdmi.h | 3 +-- + 3 files changed, 3 insertions(+), 5 deletions(-) + +diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +index 2b3f203cf467..6edb60e6c784 100644 +--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c ++++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +@@ -1514,7 +1514,7 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi) + + /* Write to the PHY as configured by the platform */ + if (pdata->configure_phy) +- ret = pdata->configure_phy(hdmi, pdata, mpixelclock); ++ ret = pdata->configure_phy(hdmi, pdata->priv_data, mpixelclock); + else + ret = phy->configure(hdmi, pdata, mpixelclock); + if (ret) { +diff --git a/drivers/gpu/drm/rcar-du/rcar_dw_hdmi.c b/drivers/gpu/drm/rcar-du/rcar_dw_hdmi.c +index 4d837a4d302d..d0dffe55a7cb 100644 +--- a/drivers/gpu/drm/rcar-du/rcar_dw_hdmi.c ++++ b/drivers/gpu/drm/rcar-du/rcar_dw_hdmi.c +@@ -52,8 +52,7 @@ rcar_hdmi_mode_valid(struct dw_hdmi *hdmi, void *data, + return MODE_OK; + } + +-static int rcar_hdmi_phy_configure(struct dw_hdmi *hdmi, +- const struct dw_hdmi_plat_data *pdata, ++static int rcar_hdmi_phy_configure(struct dw_hdmi *hdmi, void *data, + unsigned long mpixelclock) + { + const struct rcar_hdmi_phy_params *params = rcar_hdmi_phy_params; +diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h +index 66a811f75b91..09348c9cbd11 100644 +--- a/include/drm/bridge/dw_hdmi.h ++++ b/include/drm/bridge/dw_hdmi.h +@@ -151,8 +151,7 @@ struct dw_hdmi_plat_data { + const struct dw_hdmi_mpll_config *mpll_cfg; + const struct dw_hdmi_curr_ctrl *cur_ctr; + const struct dw_hdmi_phy_config *phy_config; +- int (*configure_phy)(struct dw_hdmi *hdmi, +- const struct dw_hdmi_plat_data *pdata, ++ int (*configure_phy)(struct dw_hdmi *hdmi, void *data, + unsigned long mpixelclock); + }; + + +From 93a10000d40b44c93674ca8b596019e0b3908541 Mon Sep 17 00:00:00 2001 +From: Laurent Pinchart +Date: Tue, 26 May 2020 04:14:51 +0300 +Subject: [PATCH] drm: bridge: dw-hdmi: Remove unused field from + dw_hdmi_plat_data + +The input_bus_format field of struct dw_hdmi_plat_data is unused. Remove +it. + +Signed-off-by: Laurent Pinchart +Reviewed-by: Neil Armstrong +Signed-off-by: Sam Ravnborg +Link: https://patchwork.freedesktop.org/patch/msgid/20200526011505.31884-14-laurent.pinchart+renesas@ideasonboard.com +(cherry picked from commit 29fc89719d396e81176974ce37e0cc81e23869d8) +--- + drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 5 +---- + include/drm/bridge/dw_hdmi.h | 1 - + 2 files changed, 1 insertion(+), 5 deletions(-) + +diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +index 6edb60e6c784..adc5a95a06e9 100644 +--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c ++++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +@@ -2137,10 +2137,7 @@ static int dw_hdmi_setup(struct dw_hdmi *hdmi, struct drm_display_mode *mode) + hdmi->hdmi_data.video_mode.mpixelrepetitionoutput = 0; + hdmi->hdmi_data.video_mode.mpixelrepetitioninput = 0; + +- if (hdmi->plat_data->input_bus_format) +- hdmi->hdmi_data.enc_in_bus_format = +- hdmi->plat_data->input_bus_format; +- else if (hdmi->hdmi_data.enc_in_bus_format == MEDIA_BUS_FMT_FIXED) ++ if (hdmi->hdmi_data.enc_in_bus_format == MEDIA_BUS_FMT_FIXED) + hdmi->hdmi_data.enc_in_bus_format = MEDIA_BUS_FMT_RGB888_1X24; + + /* TOFIX: Get input encoding from plat data or fallback to none */ +diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h +index 09348c9cbd11..5dfa9d83e2d3 100644 +--- a/include/drm/bridge/dw_hdmi.h ++++ b/include/drm/bridge/dw_hdmi.h +@@ -125,7 +125,6 @@ struct dw_hdmi_phy_ops { + struct dw_hdmi_plat_data { + struct regmap *regm; + +- unsigned long input_bus_format; + unsigned long input_bus_encoding; + bool use_drm_infoframe; + bool ycbcr_420_allowed; + +From 69d79aec4b09b3dce733fedcef1c5f129220e745 Mon Sep 17 00:00:00 2001 +From: Laurent Pinchart +Date: Tue, 26 May 2020 04:14:52 +0300 +Subject: [PATCH] drm: meson: dw-hdmi: Use dw_hdmi context to replace hack + +The meson-dw-hdmi driver needs to access its own context from the +.mode_valid() operation. It currently gets it from the dev_private field +of the drm_device retrieved from the connector, which is a hack. Use the +private data passed to the .mode_valid() operation instead. + +Signed-off-by: Laurent Pinchart +Reviewed-by: Neil Armstrong +Signed-off-by: Sam Ravnborg +Link: https://patchwork.freedesktop.org/patch/msgid/20200526011505.31884-15-laurent.pinchart+renesas@ideasonboard.com +(cherry picked from commit 9bc78d6dc818701e47c5ebd0879877a512f039f0) +--- + drivers/gpu/drm/meson/meson_dw_hdmi.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/drivers/gpu/drm/meson/meson_dw_hdmi.c b/drivers/gpu/drm/meson/meson_dw_hdmi.c +index fc594213c0e0..607bd9f495b1 100644 +--- a/drivers/gpu/drm/meson/meson_dw_hdmi.c ++++ b/drivers/gpu/drm/meson/meson_dw_hdmi.c +@@ -634,7 +634,8 @@ dw_hdmi_mode_valid(struct dw_hdmi *hdmi, void *data, + struct drm_connector *connector, + const struct drm_display_mode *mode) + { +- struct meson_drm *priv = connector->dev->dev_private; ++ struct meson_dw_hdmi *dw_hdmi = data; ++ struct meson_drm *priv = dw_hdmi->priv; + bool is_hdmi2_sink = connector->display_info.hdmi.scdc.supported; + unsigned int phy_freq; + unsigned int vclk_freq; +@@ -693,7 +694,7 @@ dw_hdmi_mode_valid(struct dw_hdmi *hdmi, void *data, + if (mode->flags & DRM_MODE_FLAG_DBLCLK) + venc_freq /= 2; + +- dev_dbg(connector->dev->dev, "%s: vclk:%d phy=%d venc=%d hdmi=%d\n", ++ dev_dbg(dw_hdmi->dev, "%s: vclk:%d phy=%d venc=%d hdmi=%d\n", + __func__, phy_freq, vclk_freq, venc_freq, hdmi_freq); + + return meson_vclk_vic_supported_freq(priv, phy_freq, vclk_freq); +@@ -1066,6 +1067,7 @@ static int meson_dw_hdmi_bind(struct device *dev, struct device *master, + + /* Bridge / Connector */ + ++ dw_plat_data->priv_data = meson_dw_hdmi; + dw_plat_data->mode_valid = dw_hdmi_mode_valid; + dw_plat_data->phy_ops = &meson_dw_hdmi_phy_ops; + dw_plat_data->phy_name = "meson_dw_hdmi_phy"; + +From 76b17d37e5f17f622d947792abcf4477a27b609e Mon Sep 17 00:00:00 2001 +From: Laurent Pinchart +Date: Tue, 26 May 2020 04:14:53 +0300 +Subject: [PATCH] drm: bridge: dw-hdmi: Pass drm_display_info to .mode_valid() + +Replace the drm_connector pointer passed to the .mode_valid() function +with a const drm_display_info pointer, as that's all the function should +need. Use the display info passed to the bridge .mode_valid() operation +instead of retrieving it from the connector, to prepare for make +connector creation optional. + +Signed-off-by: Laurent Pinchart +Reviewed-by: Neil Armstrong +Signed-off-by: Sam Ravnborg +Link: https://patchwork.freedesktop.org/patch/msgid/20200526011505.31884-16-laurent.pinchart+renesas@ideasonboard.com +(cherry picked from commit af05bba0fbe2c07fe500f697080d78d050be2fbf) +--- + drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 5 ++--- + drivers/gpu/drm/imx/dw_hdmi-imx.c | 4 ++-- + drivers/gpu/drm/meson/meson_dw_hdmi.c | 20 ++++++++++---------- + drivers/gpu/drm/rcar-du/rcar_dw_hdmi.c | 2 +- + drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 2 +- + drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c | 4 ++-- + drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h | 2 +- + include/drm/bridge/dw_hdmi.h | 4 ++-- + 8 files changed, 21 insertions(+), 22 deletions(-) + +diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +index adc5a95a06e9..23650e69604c 100644 +--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c ++++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +@@ -2769,7 +2769,6 @@ dw_hdmi_bridge_mode_valid(struct drm_bridge *bridge, + { + struct dw_hdmi *hdmi = bridge->driver_private; + const struct dw_hdmi_plat_data *pdata = hdmi->plat_data; +- struct drm_connector *connector = &hdmi->connector; + enum drm_mode_status mode_status = MODE_OK; + + /* We don't support double-clocked modes */ +@@ -2777,8 +2776,8 @@ dw_hdmi_bridge_mode_valid(struct drm_bridge *bridge, + return MODE_BAD; + + if (pdata->mode_valid) +- mode_status = pdata->mode_valid(hdmi, pdata->priv_data, +- connector, mode); ++ mode_status = pdata->mode_valid(hdmi, pdata->priv_data, info, ++ mode); + + return mode_status; + } +diff --git a/drivers/gpu/drm/imx/dw_hdmi-imx.c b/drivers/gpu/drm/imx/dw_hdmi-imx.c +index ff4fde0eb5f6..71d84c7a5378 100644 +--- a/drivers/gpu/drm/imx/dw_hdmi-imx.c ++++ b/drivers/gpu/drm/imx/dw_hdmi-imx.c +@@ -146,7 +146,7 @@ static const struct drm_encoder_helper_funcs dw_hdmi_imx_encoder_helper_funcs = + + static enum drm_mode_status + imx6q_hdmi_mode_valid(struct dw_hdmi *hdmi, void *data, +- struct drm_connector *con, ++ const struct drm_display_info *info, + const struct drm_display_mode *mode) + { + if (mode->clock < 13500) +@@ -160,7 +160,7 @@ imx6q_hdmi_mode_valid(struct dw_hdmi *hdmi, void *data, + + static enum drm_mode_status + imx6dl_hdmi_mode_valid(struct dw_hdmi *hdmi, void *data, +- struct drm_connector *con, ++ const struct drm_display_info *info, + const struct drm_display_mode *mode) + { + if (mode->clock < 13500) +diff --git a/drivers/gpu/drm/meson/meson_dw_hdmi.c b/drivers/gpu/drm/meson/meson_dw_hdmi.c +index 607bd9f495b1..50b950f5ca3c 100644 +--- a/drivers/gpu/drm/meson/meson_dw_hdmi.c ++++ b/drivers/gpu/drm/meson/meson_dw_hdmi.c +@@ -631,12 +631,12 @@ static irqreturn_t dw_hdmi_top_thread_irq(int irq, void *dev_id) + + static enum drm_mode_status + dw_hdmi_mode_valid(struct dw_hdmi *hdmi, void *data, +- struct drm_connector *connector, ++ const struct drm_display_info *display_info, + const struct drm_display_mode *mode) + { + struct meson_dw_hdmi *dw_hdmi = data; + struct meson_drm *priv = dw_hdmi->priv; +- bool is_hdmi2_sink = connector->display_info.hdmi.scdc.supported; ++ bool is_hdmi2_sink = display_info->hdmi.scdc.supported; + unsigned int phy_freq; + unsigned int vclk_freq; + unsigned int venc_freq; +@@ -647,10 +647,10 @@ dw_hdmi_mode_valid(struct dw_hdmi *hdmi, void *data, + DRM_DEBUG_DRIVER("Modeline " DRM_MODE_FMT "\n", DRM_MODE_ARG(mode)); + + /* If sink does not support 540MHz, reject the non-420 HDMI2 modes */ +- if (connector->display_info.max_tmds_clock && +- mode->clock > connector->display_info.max_tmds_clock && +- !drm_mode_is_420_only(&connector->display_info, mode) && +- !drm_mode_is_420_also(&connector->display_info, mode)) ++ if (display_info->max_tmds_clock && ++ mode->clock > display_info->max_tmds_clock && ++ !drm_mode_is_420_only(display_info, mode) && ++ !drm_mode_is_420_also(display_info, mode)) + return MODE_BAD; + + /* Check against non-VIC supported modes */ +@@ -667,9 +667,9 @@ dw_hdmi_mode_valid(struct dw_hdmi *hdmi, void *data, + vclk_freq = mode->clock; + + /* For 420, pixel clock is half unlike venc clock */ +- if (drm_mode_is_420_only(&connector->display_info, mode) || ++ if (drm_mode_is_420_only(display_info, mode) || + (!is_hdmi2_sink && +- drm_mode_is_420_also(&connector->display_info, mode))) ++ drm_mode_is_420_also(display_info, mode))) + vclk_freq /= 2; + + /* TMDS clock is pixel_clock * 10 */ +@@ -684,9 +684,9 @@ dw_hdmi_mode_valid(struct dw_hdmi *hdmi, void *data, + + /* VENC double pixels for 1080i, 720p and YUV420 modes */ + if (meson_venc_hdmi_venc_repeat(vic) || +- drm_mode_is_420_only(&connector->display_info, mode) || ++ drm_mode_is_420_only(display_info, mode) || + (!is_hdmi2_sink && +- drm_mode_is_420_also(&connector->display_info, mode))) ++ drm_mode_is_420_also(display_info, mode))) + venc_freq *= 2; + + vclk_freq = max(venc_freq, hdmi_freq); +diff --git a/drivers/gpu/drm/rcar-du/rcar_dw_hdmi.c b/drivers/gpu/drm/rcar-du/rcar_dw_hdmi.c +index d0dffe55a7cb..7b8ec8310699 100644 +--- a/drivers/gpu/drm/rcar-du/rcar_dw_hdmi.c ++++ b/drivers/gpu/drm/rcar-du/rcar_dw_hdmi.c +@@ -39,7 +39,7 @@ static const struct rcar_hdmi_phy_params rcar_hdmi_phy_params[] = { + + static enum drm_mode_status + rcar_hdmi_mode_valid(struct dw_hdmi *hdmi, void *data, +- struct drm_connector *connector, ++ const struct drm_display_info *info, + const struct drm_display_mode *mode) + { + /* +diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +index d08f86783a28..d286751bb333 100644 +--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c ++++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +@@ -221,7 +221,7 @@ static int rockchip_hdmi_parse_dt(struct rockchip_hdmi *hdmi) + + static enum drm_mode_status + dw_hdmi_rockchip_mode_valid(struct dw_hdmi *hdmi, void *data, +- struct drm_connector *connector, ++ const struct drm_display_info *info, + const struct drm_display_mode *mode) + { + const struct dw_hdmi_mpll_config *mpll_cfg = rockchip_mpll_cfg; +diff --git a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c +index 0a3637442ba6..d4c08043dd81 100644 +--- a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c ++++ b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c +@@ -32,7 +32,7 @@ sun8i_dw_hdmi_encoder_helper_funcs = { + + static enum drm_mode_status + sun8i_dw_hdmi_mode_valid_a83t(struct dw_hdmi *hdmi, void *data, +- struct drm_connector *connector, ++ const struct drm_display_info *info, + const struct drm_display_mode *mode) + { + if (mode->clock > 297000) +@@ -43,7 +43,7 @@ sun8i_dw_hdmi_mode_valid_a83t(struct dw_hdmi *hdmi, void *data, + + static enum drm_mode_status + sun8i_dw_hdmi_mode_valid_h6(struct dw_hdmi *hdmi, void *data, +- struct drm_connector *connector, ++ const struct drm_display_info *info, + const struct drm_display_mode *mode) + { + /* +diff --git a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h +index 8587b8d2590e..d983746fa194 100644 +--- a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h ++++ b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h +@@ -177,7 +177,7 @@ struct sun8i_hdmi_phy { + + struct sun8i_dw_hdmi_quirks { + enum drm_mode_status (*mode_valid)(struct dw_hdmi *hdmi, void *data, +- struct drm_connector *connector, ++ const struct drm_display_info *info, + const struct drm_display_mode *mode); + unsigned int set_rate : 1; + unsigned int use_drm_infoframe : 1; +diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h +index 5dfa9d83e2d3..fec293b21c2e 100644 +--- a/include/drm/bridge/dw_hdmi.h ++++ b/include/drm/bridge/dw_hdmi.h +@@ -8,7 +8,7 @@ + + #include + +-struct drm_connector; ++struct drm_display_info; + struct drm_display_mode; + struct drm_encoder; + struct dw_hdmi; +@@ -137,7 +137,7 @@ struct dw_hdmi_plat_data { + + /* Platform-specific mode validation (optional). */ + enum drm_mode_status (*mode_valid)(struct dw_hdmi *hdmi, void *data, +- struct drm_connector *connector, ++ const struct drm_display_info *info, + const struct drm_display_mode *mode); + + /* Vendor PHY support */ + +From 799196d6da0801a31a7129bbdae2aa760714b187 Mon Sep 17 00:00:00 2001 +From: Laurent Pinchart +Date: Tue, 26 May 2020 04:14:54 +0300 +Subject: [PATCH] drm: bridge: dw-hdmi: Constify mode argument to + dw_hdmi_phy_ops .init() + +The PHY .init() must not modify the mode it receives. Make the pointer +const to enfore that. + +Signed-off-by: Laurent Pinchart +Reviewed-by: Neil Armstrong +Signed-off-by: Sam Ravnborg +Link: https://patchwork.freedesktop.org/patch/msgid/20200526011505.31884-17-laurent.pinchart+renesas@ideasonboard.com +(cherry picked from commit 35a395f1134bbbd2984dcca28c04f09fbbb8b0a4) +--- + drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 2 +- + drivers/gpu/drm/meson/meson_dw_hdmi.c | 4 ++-- + drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 2 +- + drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c | 2 +- + include/drm/bridge/dw_hdmi.h | 2 +- + 5 files changed, 6 insertions(+), 6 deletions(-) + +diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +index 23650e69604c..6e6a3d95e68e 100644 +--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c ++++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +@@ -1531,7 +1531,7 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi) + } + + static int dw_hdmi_phy_init(struct dw_hdmi *hdmi, void *data, +- struct drm_display_mode *mode) ++ const struct drm_display_mode *mode) + { + int i, ret; + +diff --git a/drivers/gpu/drm/meson/meson_dw_hdmi.c b/drivers/gpu/drm/meson/meson_dw_hdmi.c +index 50b950f5ca3c..a1217df5fe5a 100644 +--- a/drivers/gpu/drm/meson/meson_dw_hdmi.c ++++ b/drivers/gpu/drm/meson/meson_dw_hdmi.c +@@ -297,7 +297,7 @@ static inline void dw_hdmi_dwc_write_bits(struct meson_dw_hdmi *dw_hdmi, + + /* Setup PHY bandwidth modes */ + static void meson_hdmi_phy_setup_mode(struct meson_dw_hdmi *dw_hdmi, +- struct drm_display_mode *mode) ++ const struct drm_display_mode *mode) + { + struct meson_drm *priv = dw_hdmi->priv; + unsigned int pixel_clock = mode->clock; +@@ -427,7 +427,7 @@ static void dw_hdmi_set_vclk(struct meson_dw_hdmi *dw_hdmi, + } + + static int dw_hdmi_phy_init(struct dw_hdmi *hdmi, void *data, +- struct drm_display_mode *mode) ++ const struct drm_display_mode *mode) + { + struct meson_dw_hdmi *dw_hdmi = (struct meson_dw_hdmi *)data; + struct meson_drm *priv = dw_hdmi->priv; +diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +index d286751bb333..10e210f6455d 100644 +--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c ++++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +@@ -312,7 +312,7 @@ static const struct drm_encoder_helper_funcs dw_hdmi_rockchip_encoder_helper_fun + }; + + static int dw_hdmi_rockchip_genphy_init(struct dw_hdmi *dw_hdmi, void *data, +- struct drm_display_mode *mode) ++ const struct drm_display_mode *mode) + { + struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data; + +diff --git a/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c b/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c +index 43643ad31730..8e078cacf063 100644 +--- a/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c ++++ b/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c +@@ -341,7 +341,7 @@ static int sun8i_hdmi_phy_config_h3(struct dw_hdmi *hdmi, + } + + static int sun8i_hdmi_phy_config(struct dw_hdmi *hdmi, void *data, +- struct drm_display_mode *mode) ++ const struct drm_display_mode *mode) + { + struct sun8i_hdmi_phy *phy = (struct sun8i_hdmi_phy *)data; + u32 val = 0; +diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h +index fec293b21c2e..f930d218cc6b 100644 +--- a/include/drm/bridge/dw_hdmi.h ++++ b/include/drm/bridge/dw_hdmi.h +@@ -114,7 +114,7 @@ struct dw_hdmi_phy_config { + + struct dw_hdmi_phy_ops { + int (*init)(struct dw_hdmi *hdmi, void *data, +- struct drm_display_mode *mode); ++ const struct drm_display_mode *mode); + void (*disable)(struct dw_hdmi *hdmi, void *data); + enum drm_connector_status (*read_hpd)(struct dw_hdmi *hdmi, void *data); + void (*update_hpd)(struct dw_hdmi *hdmi, void *data, + +From 39e51f084a6c1b5a94151803063f5d2ec44c2389 Mon Sep 17 00:00:00 2001 +From: Laurent Pinchart +Date: Tue, 26 May 2020 04:14:55 +0300 +Subject: [PATCH] drm: bridge: dw-hdmi: Constify mode argument to internal + functions + +Several internal functions take a drm_display_mode argument to configure +the HDMI encoder or the HDMI PHY. They must not modify the mode, make +the pointer const to enforce that. + +Signed-off-by: Laurent Pinchart +Reviewed-by: Neil Armstrong +Signed-off-by: Sam Ravnborg +Link: https://patchwork.freedesktop.org/patch/msgid/20200526011505.31884-18-laurent.pinchart+renesas@ideasonboard.com +(cherry picked from commit 9fbfa320b435e6f25499a63f7bb74b4fc5341b30) +--- + drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +index 6e6a3d95e68e..5b5f07a23400 100644 +--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c ++++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +@@ -1628,7 +1628,8 @@ static void hdmi_tx_hdcp_config(struct dw_hdmi *hdmi) + HDMI_A_HDCPCFG1_ENCRYPTIONDISABLE_MASK, HDMI_A_HDCPCFG1); + } + +-static void hdmi_config_AVI(struct dw_hdmi *hdmi, struct drm_display_mode *mode) ++static void hdmi_config_AVI(struct dw_hdmi *hdmi, ++ const struct drm_display_mode *mode) + { + struct hdmi_avi_infoframe frame; + u8 val; +@@ -1756,7 +1757,7 @@ static void hdmi_config_AVI(struct dw_hdmi *hdmi, struct drm_display_mode *mode) + } + + static void hdmi_config_vendor_specific_infoframe(struct dw_hdmi *hdmi, +- struct drm_display_mode *mode) ++ const struct drm_display_mode *mode) + { + struct hdmi_vendor_infoframe frame; + u8 buffer[10]; +@@ -2112,7 +2113,8 @@ static void hdmi_disable_overflow_interrupts(struct dw_hdmi *hdmi) + HDMI_IH_MUTE_FC_STAT2); + } + +-static int dw_hdmi_setup(struct dw_hdmi *hdmi, struct drm_display_mode *mode) ++static int dw_hdmi_setup(struct dw_hdmi *hdmi, ++ const struct drm_display_mode *mode) + { + int ret; + + +From 9dd65c0f564ebe5257c3d5322e40200ac254570b Mon Sep 17 00:00:00 2001 +From: Laurent Pinchart +Date: Tue, 26 May 2020 04:14:56 +0300 +Subject: [PATCH] drm: bridge: dw-hdmi: Pass drm_display_info to + dw_hdmi_support_scdc() + +To prepare for making connector creation optional in the driver, pass +the drm_display_info explicitly to dw_hdmi_support_scdc(). The pointer +is passed to the callers where required, particularly to the +dw_hdmi_phy_ops .init() function. + +Signed-off-by: Laurent Pinchart +Reviewed-by: Neil Armstrong +Signed-off-by: Sam Ravnborg +Link: https://patchwork.freedesktop.org/patch/msgid/20200526011505.31884-19-laurent.pinchart+renesas@ideasonboard.com +(cherry picked from commit 7be390d4c0a125266c558c30a3687d931c3b6101) +--- + drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 32 ++++++++++++--------- + drivers/gpu/drm/meson/meson_dw_hdmi.c | 3 +- + drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 1 + + drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c | 1 + + include/drm/bridge/dw_hdmi.h | 4 ++- + 5 files changed, 26 insertions(+), 15 deletions(-) + +diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +index 5b5f07a23400..a18794cce0d8 100644 +--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c ++++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +@@ -1241,10 +1241,9 @@ void dw_hdmi_phy_i2c_write(struct dw_hdmi *hdmi, unsigned short data, + EXPORT_SYMBOL_GPL(dw_hdmi_phy_i2c_write); + + /* Filter out invalid setups to avoid configuring SCDC and scrambling */ +-static bool dw_hdmi_support_scdc(struct dw_hdmi *hdmi) ++static bool dw_hdmi_support_scdc(struct dw_hdmi *hdmi, ++ const struct drm_display_info *display) + { +- struct drm_display_info *display = &hdmi->connector.display_info; +- + /* Completely disable SCDC support for older controllers */ + if (hdmi->version < 0x200a) + return false; +@@ -1282,12 +1281,13 @@ static bool dw_hdmi_support_scdc(struct dw_hdmi *hdmi) + * helper should called right before enabling the TMDS Clock and Data in + * the PHY configuration callback. + */ +-void dw_hdmi_set_high_tmds_clock_ratio(struct dw_hdmi *hdmi) ++void dw_hdmi_set_high_tmds_clock_ratio(struct dw_hdmi *hdmi, ++ const struct drm_display_info *display) + { + unsigned long mtmdsclock = hdmi->hdmi_data.video_mode.mtmdsclock; + + /* Control for TMDS Bit Period/TMDS Clock-Period Ratio */ +- if (dw_hdmi_support_scdc(hdmi)) { ++ if (dw_hdmi_support_scdc(hdmi, display)) { + if (mtmdsclock > HDMI14_MAX_TMDSCLK) + drm_scdc_set_high_tmds_clock_ratio(hdmi->ddc, 1); + else +@@ -1490,7 +1490,8 @@ static int hdmi_phy_configure_dwc_hdmi_3d_tx(struct dw_hdmi *hdmi, + return 0; + } + +-static int hdmi_phy_configure(struct dw_hdmi *hdmi) ++static int hdmi_phy_configure(struct dw_hdmi *hdmi, ++ const struct drm_display_info *display) + { + const struct dw_hdmi_phy_data *phy = hdmi->phy.data; + const struct dw_hdmi_plat_data *pdata = hdmi->plat_data; +@@ -1500,7 +1501,7 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi) + + dw_hdmi_phy_power_off(hdmi); + +- dw_hdmi_set_high_tmds_clock_ratio(hdmi); ++ dw_hdmi_set_high_tmds_clock_ratio(hdmi, display); + + /* Leave low power consumption mode by asserting SVSRET. */ + if (phy->has_svsret) +@@ -1531,6 +1532,7 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi) + } + + static int dw_hdmi_phy_init(struct dw_hdmi *hdmi, void *data, ++ const struct drm_display_info *display, + const struct drm_display_mode *mode) + { + int i, ret; +@@ -1540,7 +1542,7 @@ static int dw_hdmi_phy_init(struct dw_hdmi *hdmi, void *data, + dw_hdmi_phy_sel_data_en_pol(hdmi, 1); + dw_hdmi_phy_sel_interface_control(hdmi, 0); + +- ret = hdmi_phy_configure(hdmi); ++ ret = hdmi_phy_configure(hdmi, display); + if (ret) + return ret; + } +@@ -1846,10 +1848,11 @@ static void hdmi_config_drm_infoframe(struct dw_hdmi *hdmi) + } + + static void hdmi_av_composer(struct dw_hdmi *hdmi, ++ const struct drm_display_info *display, + const struct drm_display_mode *mode) + { + u8 inv_val, bytes; +- struct drm_hdmi_info *hdmi_info = &hdmi->connector.display_info.hdmi; ++ const struct drm_hdmi_info *hdmi_info = &display->hdmi; + struct hdmi_vmode *vmode = &hdmi->hdmi_data.video_mode; + int hblank, vblank, h_de_hs, v_de_vs, hsync_len, vsync_len; + unsigned int vdisplay, hdisplay; +@@ -1882,7 +1885,7 @@ static void hdmi_av_composer(struct dw_hdmi *hdmi, + + /* Set up HDMI_FC_INVIDCONF */ + inv_val = (hdmi->hdmi_data.hdcp_enable || +- (dw_hdmi_support_scdc(hdmi) && ++ (dw_hdmi_support_scdc(hdmi, display) && + (vmode->mtmdsclock > HDMI14_MAX_TMDSCLK || + hdmi_info->scdc.scrambling.low_rates)) ? + HDMI_FC_INVIDCONF_HDCP_KEEPOUT_ACTIVE : +@@ -1950,7 +1953,7 @@ static void hdmi_av_composer(struct dw_hdmi *hdmi, + } + + /* Scrambling Control */ +- if (dw_hdmi_support_scdc(hdmi)) { ++ if (dw_hdmi_support_scdc(hdmi, display)) { + if (vmode->mtmdsclock > HDMI14_MAX_TMDSCLK || + hdmi_info->scdc.scrambling.low_rates) { + /* +@@ -2116,6 +2119,7 @@ static void hdmi_disable_overflow_interrupts(struct dw_hdmi *hdmi) + static int dw_hdmi_setup(struct dw_hdmi *hdmi, + const struct drm_display_mode *mode) + { ++ struct drm_connector *connector = &hdmi->connector; + int ret; + + hdmi_disable_overflow_interrupts(hdmi); +@@ -2161,10 +2165,12 @@ static int dw_hdmi_setup(struct dw_hdmi *hdmi, + hdmi->hdmi_data.video_mode.mdataenablepolarity = true; + + /* HDMI Initialization Step B.1 */ +- hdmi_av_composer(hdmi, mode); ++ hdmi_av_composer(hdmi, &connector->display_info, mode); + + /* HDMI Initializateion Step B.2 */ +- ret = hdmi->phy.ops->init(hdmi, hdmi->phy.data, &hdmi->previous_mode); ++ ret = hdmi->phy.ops->init(hdmi, hdmi->phy.data, ++ &connector->display_info, ++ &hdmi->previous_mode); + if (ret) + return ret; + hdmi->phy.enabled = true; +diff --git a/drivers/gpu/drm/meson/meson_dw_hdmi.c b/drivers/gpu/drm/meson/meson_dw_hdmi.c +index a1217df5fe5a..29a8ff41595d 100644 +--- a/drivers/gpu/drm/meson/meson_dw_hdmi.c ++++ b/drivers/gpu/drm/meson/meson_dw_hdmi.c +@@ -427,6 +427,7 @@ static void dw_hdmi_set_vclk(struct meson_dw_hdmi *dw_hdmi, + } + + static int dw_hdmi_phy_init(struct dw_hdmi *hdmi, void *data, ++ const struct drm_display_info *display, + const struct drm_display_mode *mode) + { + struct meson_dw_hdmi *dw_hdmi = (struct meson_dw_hdmi *)data; +@@ -496,7 +497,7 @@ static int dw_hdmi_phy_init(struct dw_hdmi *hdmi, void *data, + /* Disable clock, fifo, fifo_wr */ + regmap_update_bits(priv->hhi, HHI_HDMI_PHY_CNTL1, 0xf, 0); + +- dw_hdmi_set_high_tmds_clock_ratio(hdmi); ++ dw_hdmi_set_high_tmds_clock_ratio(hdmi, display); + + msleep(100); + +diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +index 10e210f6455d..23de359a1dec 100644 +--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c ++++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +@@ -312,6 +312,7 @@ static const struct drm_encoder_helper_funcs dw_hdmi_rockchip_encoder_helper_fun + }; + + static int dw_hdmi_rockchip_genphy_init(struct dw_hdmi *dw_hdmi, void *data, ++ const struct drm_display_info *display, + const struct drm_display_mode *mode) + { + struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data; +diff --git a/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c b/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c +index 8e078cacf063..156d00e5165b 100644 +--- a/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c ++++ b/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c +@@ -341,6 +341,7 @@ static int sun8i_hdmi_phy_config_h3(struct dw_hdmi *hdmi, + } + + static int sun8i_hdmi_phy_config(struct dw_hdmi *hdmi, void *data, ++ const struct drm_display_info *display, + const struct drm_display_mode *mode) + { + struct sun8i_hdmi_phy *phy = (struct sun8i_hdmi_phy *)data; +diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h +index f930d218cc6b..ea34ca146b82 100644 +--- a/include/drm/bridge/dw_hdmi.h ++++ b/include/drm/bridge/dw_hdmi.h +@@ -114,6 +114,7 @@ struct dw_hdmi_phy_config { + + struct dw_hdmi_phy_ops { + int (*init)(struct dw_hdmi *hdmi, void *data, ++ const struct drm_display_info *display, + const struct drm_display_mode *mode); + void (*disable)(struct dw_hdmi *hdmi, void *data); + enum drm_connector_status (*read_hpd)(struct dw_hdmi *hdmi, void *data); +@@ -174,7 +175,8 @@ void dw_hdmi_set_channel_status(struct dw_hdmi *hdmi, u8 *channel_status); + void dw_hdmi_set_channel_allocation(struct dw_hdmi *hdmi, unsigned int ca); + void dw_hdmi_audio_enable(struct dw_hdmi *hdmi); + void dw_hdmi_audio_disable(struct dw_hdmi *hdmi); +-void dw_hdmi_set_high_tmds_clock_ratio(struct dw_hdmi *hdmi); ++void dw_hdmi_set_high_tmds_clock_ratio(struct dw_hdmi *hdmi, ++ const struct drm_display_info *display); + + /* PHY configuration */ + void dw_hdmi_phy_i2c_set_addr(struct dw_hdmi *hdmi, u8 address); + +From 57c01c57d5aff20753b3c418abb52b3b317c0166 Mon Sep 17 00:00:00 2001 +From: Laurent Pinchart +Date: Tue, 26 May 2020 04:14:57 +0300 +Subject: [PATCH] drm: bridge: dw-hdmi: Split connector creation to a separate + function + +Isolate all the code related to connector creation to a new +dw_hdmi_connector_create() function, to prepare for making connector +creation optional. + +Signed-off-by: Laurent Pinchart +Reviewed-by: Neil Armstrong +Signed-off-by: Sam Ravnborg +Link: https://patchwork.freedesktop.org/patch/msgid/20200526011505.31884-20-laurent.pinchart+renesas@ideasonboard.com +(cherry picked from commit 3f588fda4b80dbd7dafa08b0e16fd72a42676e3c) +--- + drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 107 +++++++++++++--------- + 1 file changed, 62 insertions(+), 45 deletions(-) + +diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +index a18794cce0d8..35d38b644912 100644 +--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c ++++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +@@ -2317,6 +2317,10 @@ static void dw_hdmi_update_phy_mask(struct dw_hdmi *hdmi) + hdmi->rxsense); + } + ++/* ----------------------------------------------------------------------------- ++ * DRM Connector Operations ++ */ ++ + static enum drm_connector_status + dw_hdmi_connector_detect(struct drm_connector *connector, bool force) + { +@@ -2438,6 +2442,59 @@ static const struct drm_connector_helper_funcs dw_hdmi_connector_helper_funcs = + .atomic_check = dw_hdmi_connector_atomic_check, + }; + ++static int dw_hdmi_connector_create(struct dw_hdmi *hdmi) ++{ ++ struct drm_connector *connector = &hdmi->connector; ++ struct cec_connector_info conn_info; ++ struct cec_notifier *notifier; ++ ++ if (hdmi->version >= 0x200a) ++ connector->ycbcr_420_allowed = ++ hdmi->plat_data->ycbcr_420_allowed; ++ else ++ connector->ycbcr_420_allowed = false; ++ ++ connector->interlace_allowed = 1; ++ connector->polled = DRM_CONNECTOR_POLL_HPD; ++ ++ drm_connector_helper_add(connector, &dw_hdmi_connector_helper_funcs); ++ ++ drm_connector_init_with_ddc(hdmi->bridge.dev, connector, ++ &dw_hdmi_connector_funcs, ++ DRM_MODE_CONNECTOR_HDMIA, ++ hdmi->ddc); ++ ++ /* ++ * drm_connector_attach_max_bpc_property() requires the ++ * connector to have a state. ++ */ ++ drm_atomic_helper_connector_reset(connector); ++ ++ drm_connector_attach_max_bpc_property(connector, 8, 16); ++ ++ if (hdmi->version >= 0x200a && hdmi->plat_data->use_drm_infoframe) ++ drm_object_attach_property(&connector->base, ++ connector->dev->mode_config.hdr_output_metadata_property, 0); ++ ++ drm_connector_attach_encoder(connector, hdmi->bridge.encoder); ++ ++ cec_fill_conn_info_from_drm(&conn_info, connector); ++ ++ notifier = cec_notifier_conn_register(hdmi->dev, NULL, &conn_info); ++ if (!notifier) ++ return -ENOMEM; ++ ++ mutex_lock(&hdmi->cec_notifier_mutex); ++ hdmi->cec_notifier = notifier; ++ mutex_unlock(&hdmi->cec_notifier_mutex); ++ ++ return 0; ++} ++ ++/* ----------------------------------------------------------------------------- ++ * DRM Bridge Operations ++ */ ++ + /* + * Possible output formats : + * - MEDIA_BUS_FMT_UYYVYY16_0_5X48, +@@ -2713,51 +2770,13 @@ static int dw_hdmi_bridge_attach(struct drm_bridge *bridge, + enum drm_bridge_attach_flags flags) + { + struct dw_hdmi *hdmi = bridge->driver_private; +- struct drm_encoder *encoder = bridge->encoder; +- struct drm_connector *connector = &hdmi->connector; +- struct cec_connector_info conn_info; +- struct cec_notifier *notifier; + + if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR) { + DRM_ERROR("Fix bridge driver to make connector optional!"); + return -EINVAL; + } + +- connector->interlace_allowed = 1; +- connector->polled = DRM_CONNECTOR_POLL_HPD; +- +- drm_connector_helper_add(connector, &dw_hdmi_connector_helper_funcs); +- +- drm_connector_init_with_ddc(bridge->dev, connector, +- &dw_hdmi_connector_funcs, +- DRM_MODE_CONNECTOR_HDMIA, +- hdmi->ddc); +- +- /* +- * drm_connector_attach_max_bpc_property() requires the +- * connector to have a state. +- */ +- drm_atomic_helper_connector_reset(connector); +- +- drm_connector_attach_max_bpc_property(connector, 8, 16); +- +- if (hdmi->version >= 0x200a && hdmi->plat_data->use_drm_infoframe) +- drm_object_attach_property(&connector->base, +- connector->dev->mode_config.hdr_output_metadata_property, 0); +- +- drm_connector_attach_encoder(connector, encoder); +- +- cec_fill_conn_info_from_drm(&conn_info, connector); +- +- notifier = cec_notifier_conn_register(hdmi->dev, NULL, &conn_info); +- if (!notifier) +- return -ENOMEM; +- +- mutex_lock(&hdmi->cec_notifier_mutex); +- hdmi->cec_notifier = notifier; +- mutex_unlock(&hdmi->cec_notifier_mutex); +- +- return 0; ++ return dw_hdmi_connector_create(hdmi); + } + + static void dw_hdmi_bridge_detach(struct drm_bridge *bridge) +@@ -2841,6 +2860,10 @@ static const struct drm_bridge_funcs dw_hdmi_bridge_funcs = { + .mode_valid = dw_hdmi_bridge_mode_valid, + }; + ++/* ----------------------------------------------------------------------------- ++ * IRQ Handling ++ */ ++ + static irqreturn_t dw_hdmi_i2c_irq(struct dw_hdmi *hdmi) + { + struct dw_hdmi_i2c *i2c = hdmi->i2c; +@@ -3303,12 +3326,6 @@ __dw_hdmi_probe(struct platform_device *pdev, + hdmi->bridge.of_node = pdev->dev.of_node; + #endif + +- if (hdmi->version >= 0x200a) +- hdmi->connector.ycbcr_420_allowed = +- hdmi->plat_data->ycbcr_420_allowed; +- else +- hdmi->connector.ycbcr_420_allowed = false; +- + memset(&pdevinfo, 0, sizeof(pdevinfo)); + pdevinfo.parent = dev; + pdevinfo.id = PLATFORM_DEVID_AUTO; + +From a3b8c4bc7907f025862b25aca04c9edc999a44e5 Mon Sep 17 00:00:00 2001 +From: Laurent Pinchart +Date: Tue, 26 May 2020 04:14:58 +0300 +Subject: [PATCH] drm: bridge: dw-hdmi: Store current connector in struct + dw_hdmi + +Store the connector that the bridge is currently wired to in the dw_hdmi +structure. This is currently identical to the connector field, but will +differ once the driver supports disabling connector creation. + +Signed-off-by: Laurent Pinchart +Reviewed-by: Neil Armstrong +Signed-off-by: Sam Ravnborg +Link: https://patchwork.freedesktop.org/patch/msgid/20200526011505.31884-21-laurent.pinchart+renesas@ideasonboard.com +(cherry picked from commit ca7b6b7176ffea4d07afbd98ede7a94fb0f68fa1) +--- + drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 18 ++++++++++++++---- + 1 file changed, 14 insertions(+), 4 deletions(-) + +diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +index 35d38b644912..16bffedb4715 100644 +--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c ++++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +@@ -181,6 +181,7 @@ struct dw_hdmi { + + struct mutex mutex; /* for state below and previous_mode */ + enum drm_connector_force force; /* mutex-protected force state */ ++ struct drm_connector *curr_conn;/* current connector (only valid when !disabled) */ + bool disabled; /* DRM has disabled our bridge */ + bool bridge_is_on; /* indicates the bridge is on */ + bool rxsense; /* rxsense state */ +@@ -2823,23 +2824,32 @@ static void dw_hdmi_bridge_mode_set(struct drm_bridge *bridge, + mutex_unlock(&hdmi->mutex); + } + +-static void dw_hdmi_bridge_disable(struct drm_bridge *bridge) ++static void dw_hdmi_bridge_atomic_disable(struct drm_bridge *bridge, ++ struct drm_bridge_state *old_state) + { + struct dw_hdmi *hdmi = bridge->driver_private; + + mutex_lock(&hdmi->mutex); + hdmi->disabled = true; ++ hdmi->curr_conn = NULL; + dw_hdmi_update_power(hdmi); + dw_hdmi_update_phy_mask(hdmi); + mutex_unlock(&hdmi->mutex); + } + +-static void dw_hdmi_bridge_enable(struct drm_bridge *bridge) ++static void dw_hdmi_bridge_atomic_enable(struct drm_bridge *bridge, ++ struct drm_bridge_state *old_state) + { + struct dw_hdmi *hdmi = bridge->driver_private; ++ struct drm_atomic_state *state = old_state->base.state; ++ struct drm_connector *connector; ++ ++ connector = drm_atomic_get_new_connector_for_encoder(state, ++ bridge->encoder); + + mutex_lock(&hdmi->mutex); + hdmi->disabled = false; ++ hdmi->curr_conn = connector; + dw_hdmi_update_power(hdmi); + dw_hdmi_update_phy_mask(hdmi); + mutex_unlock(&hdmi->mutex); +@@ -2854,8 +2864,8 @@ static const struct drm_bridge_funcs dw_hdmi_bridge_funcs = { + .atomic_check = dw_hdmi_bridge_atomic_check, + .atomic_get_output_bus_fmts = dw_hdmi_bridge_atomic_get_output_bus_fmts, + .atomic_get_input_bus_fmts = dw_hdmi_bridge_atomic_get_input_bus_fmts, +- .enable = dw_hdmi_bridge_enable, +- .disable = dw_hdmi_bridge_disable, ++ .atomic_enable = dw_hdmi_bridge_atomic_enable, ++ .atomic_disable = dw_hdmi_bridge_atomic_disable, + .mode_set = dw_hdmi_bridge_mode_set, + .mode_valid = dw_hdmi_bridge_mode_valid, + }; + +From 30b1907401f2475b4b7e8341269a36ef3a45a6bb Mon Sep 17 00:00:00 2001 +From: Laurent Pinchart +Date: Tue, 26 May 2020 04:14:59 +0300 +Subject: [PATCH] drm: bridge: dw-hdmi: Pass drm_connector to internal + functions as needed + +To prepare for making connector creation optional in the driver, pass +the drm_connector explicitly to the internal functions that require it. +The functions that still access the connector from the dw_hdmi structure +are dw_hdmi_connector_create() and __dw_hdmi_probe(). The former access +is expected, as that's where the internal connector is created. The +latter will be addressed separately. + +Signed-off-by: Laurent Pinchart +Reviewed-by: Neil Armstrong +Signed-off-by: Sam Ravnborg +Link: https://patchwork.freedesktop.org/patch/msgid/20200526011505.31884-22-laurent.pinchart+renesas@ideasonboard.com +(cherry picked from commit 81980037fb275d9db1bbb0239682d707e8dd62a0) +--- + drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 31 +++++++++++++---------- + 1 file changed, 18 insertions(+), 13 deletions(-) + +diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +index 16bffedb4715..b69c14b9de62 100644 +--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c ++++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +@@ -1632,18 +1632,17 @@ static void hdmi_tx_hdcp_config(struct dw_hdmi *hdmi) + } + + static void hdmi_config_AVI(struct dw_hdmi *hdmi, ++ const struct drm_connector *connector, + const struct drm_display_mode *mode) + { + struct hdmi_avi_infoframe frame; + u8 val; + + /* Initialise info frame from DRM mode */ +- drm_hdmi_avi_infoframe_from_display_mode(&frame, +- &hdmi->connector, mode); ++ drm_hdmi_avi_infoframe_from_display_mode(&frame, connector, mode); + + if (hdmi_bus_fmt_is_rgb(hdmi->hdmi_data.enc_out_bus_format)) { +- drm_hdmi_avi_infoframe_quant_range(&frame, &hdmi->connector, +- mode, ++ drm_hdmi_avi_infoframe_quant_range(&frame, connector, mode, + hdmi->hdmi_data.rgb_limited_range ? + HDMI_QUANTIZATION_RANGE_LIMITED : + HDMI_QUANTIZATION_RANGE_FULL); +@@ -1760,14 +1759,14 @@ static void hdmi_config_AVI(struct dw_hdmi *hdmi, + } + + static void hdmi_config_vendor_specific_infoframe(struct dw_hdmi *hdmi, ++ const struct drm_connector *connector, + const struct drm_display_mode *mode) + { + struct hdmi_vendor_infoframe frame; + u8 buffer[10]; + ssize_t err; + +- err = drm_hdmi_vendor_infoframe_from_display_mode(&frame, +- &hdmi->connector, ++ err = drm_hdmi_vendor_infoframe_from_display_mode(&frame, connector, + mode); + if (err < 0) + /* +@@ -1813,9 +1812,10 @@ static void hdmi_config_vendor_specific_infoframe(struct dw_hdmi *hdmi, + HDMI_FC_DATAUTO0_VSD_MASK); + } + +-static void hdmi_config_drm_infoframe(struct dw_hdmi *hdmi) ++static void hdmi_config_drm_infoframe(struct dw_hdmi *hdmi, ++ const struct drm_connector *connector) + { +- const struct drm_connector_state *conn_state = hdmi->connector.state; ++ const struct drm_connector_state *conn_state = connector->state; + struct hdmi_drm_infoframe frame; + u8 buffer[30]; + ssize_t err; +@@ -2118,9 +2118,9 @@ static void hdmi_disable_overflow_interrupts(struct dw_hdmi *hdmi) + } + + static int dw_hdmi_setup(struct dw_hdmi *hdmi, ++ const struct drm_connector *connector, + const struct drm_display_mode *mode) + { +- struct drm_connector *connector = &hdmi->connector; + int ret; + + hdmi_disable_overflow_interrupts(hdmi); +@@ -2192,9 +2192,9 @@ static int dw_hdmi_setup(struct dw_hdmi *hdmi, + dev_dbg(hdmi->dev, "%s HDMI mode\n", __func__); + + /* HDMI Initialization Step F - Configure AVI InfoFrame */ +- hdmi_config_AVI(hdmi, mode); +- hdmi_config_vendor_specific_infoframe(hdmi, mode); +- hdmi_config_drm_infoframe(hdmi); ++ hdmi_config_AVI(hdmi, connector, mode); ++ hdmi_config_vendor_specific_infoframe(hdmi, connector, mode); ++ hdmi_config_drm_infoframe(hdmi, connector); + } else { + dev_dbg(hdmi->dev, "%s DVI mode\n", __func__); + } +@@ -2263,7 +2263,12 @@ static void initialize_hdmi_ih_mutes(struct dw_hdmi *hdmi) + static void dw_hdmi_poweron(struct dw_hdmi *hdmi) + { + hdmi->bridge_is_on = true; +- dw_hdmi_setup(hdmi, &hdmi->previous_mode); ++ ++ /* ++ * The curr_conn field is guaranteed to be valid here, as this function ++ * is only be called when !hdmi->disabled. ++ */ ++ dw_hdmi_setup(hdmi, hdmi->curr_conn, &hdmi->previous_mode); + } + + static void dw_hdmi_poweroff(struct dw_hdmi *hdmi) + +From 26ccb66a87e10784ccfc8366494769888f21ebf2 Mon Sep 17 00:00:00 2001 +From: Laurent Pinchart +Date: Tue, 26 May 2020 04:15:00 +0300 +Subject: [PATCH] drm: bridge: dw-hdmi: Make connector creation optional + +Implement the drm_bridge_funcs .detect() and .get_edid() operations, and +call drm_bridge_hpd_notify() notify to report HPD. This provides the +necessary API to support disabling connector creation, do so by +accepting DRM_BRIDGE_ATTACH_NO_CONNECTOR in dw_hdmi_bridge_attach(). + +Signed-off-by: Laurent Pinchart +Reviewed-by: Neil Armstrong +Signed-off-by: Sam Ravnborg +Link: https://patchwork.freedesktop.org/patch/msgid/20200526011505.31884-23-laurent.pinchart+renesas@ideasonboard.com +(cherry picked from commit ec971aaa6775cff555b4f58777ceab1d9a8370e0) +--- + drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 104 +++++++++++++++------- + 1 file changed, 74 insertions(+), 30 deletions(-) + +diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +index b69c14b9de62..6148a022569a 100644 +--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c ++++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +@@ -2323,15 +2323,8 @@ static void dw_hdmi_update_phy_mask(struct dw_hdmi *hdmi) + hdmi->rxsense); + } + +-/* ----------------------------------------------------------------------------- +- * DRM Connector Operations +- */ +- +-static enum drm_connector_status +-dw_hdmi_connector_detect(struct drm_connector *connector, bool force) ++static enum drm_connector_status dw_hdmi_detect(struct dw_hdmi *hdmi) + { +- struct dw_hdmi *hdmi = container_of(connector, struct dw_hdmi, +- connector); + enum drm_connector_status result; + + mutex_lock(&hdmi->mutex); +@@ -2354,31 +2347,57 @@ dw_hdmi_connector_detect(struct drm_connector *connector, bool force) + return result; + } + +-static int dw_hdmi_connector_get_modes(struct drm_connector *connector) ++static struct edid *dw_hdmi_get_edid(struct dw_hdmi *hdmi, ++ struct drm_connector *connector) + { +- struct dw_hdmi *hdmi = container_of(connector, struct dw_hdmi, +- connector); + struct edid *edid; +- int ret = 0; + + if (!hdmi->ddc) +- return 0; ++ return NULL; + + edid = drm_get_edid(connector, hdmi->ddc); +- if (edid) { +- dev_dbg(hdmi->dev, "got edid: width[%d] x height[%d]\n", +- edid->width_cm, edid->height_cm); +- +- hdmi->sink_is_hdmi = drm_detect_hdmi_monitor(edid); +- hdmi->sink_has_audio = drm_detect_monitor_audio(edid); +- drm_connector_update_edid_property(connector, edid); +- cec_notifier_set_phys_addr_from_edid(hdmi->cec_notifier, edid); +- ret = drm_add_edid_modes(connector, edid); +- kfree(edid); +- } else { ++ if (!edid) { + dev_dbg(hdmi->dev, "failed to get edid\n"); ++ return NULL; + } + ++ dev_dbg(hdmi->dev, "got edid: width[%d] x height[%d]\n", ++ edid->width_cm, edid->height_cm); ++ ++ hdmi->sink_is_hdmi = drm_detect_hdmi_monitor(edid); ++ hdmi->sink_has_audio = drm_detect_monitor_audio(edid); ++ ++ return edid; ++} ++ ++/* ----------------------------------------------------------------------------- ++ * DRM Connector Operations ++ */ ++ ++static enum drm_connector_status ++dw_hdmi_connector_detect(struct drm_connector *connector, bool force) ++{ ++ struct dw_hdmi *hdmi = container_of(connector, struct dw_hdmi, ++ connector); ++ return dw_hdmi_detect(hdmi); ++} ++ ++static int dw_hdmi_connector_get_modes(struct drm_connector *connector) ++{ ++ struct dw_hdmi *hdmi = container_of(connector, struct dw_hdmi, ++ connector); ++ struct edid *edid; ++ int ret; ++ ++ edid = dw_hdmi_get_edid(hdmi, connector); ++ if (!edid) ++ return 0; ++ ++ drm_connector_update_edid_property(connector, edid); ++ cec_notifier_set_phys_addr_from_edid(hdmi->cec_notifier, edid); ++ ret = drm_add_edid_modes(connector, edid); ++ kfree(edid); ++ + return ret; + } + +@@ -2777,10 +2796,8 @@ static int dw_hdmi_bridge_attach(struct drm_bridge *bridge, + { + struct dw_hdmi *hdmi = bridge->driver_private; + +- if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR) { +- DRM_ERROR("Fix bridge driver to make connector optional!"); +- return -EINVAL; +- } ++ if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR) ++ return 0; + + return dw_hdmi_connector_create(hdmi); + } +@@ -2860,6 +2877,21 @@ static void dw_hdmi_bridge_atomic_enable(struct drm_bridge *bridge, + mutex_unlock(&hdmi->mutex); + } + ++static enum drm_connector_status dw_hdmi_bridge_detect(struct drm_bridge *bridge) ++{ ++ struct dw_hdmi *hdmi = bridge->driver_private; ++ ++ return dw_hdmi_detect(hdmi); ++} ++ ++static struct edid *dw_hdmi_bridge_get_edid(struct drm_bridge *bridge, ++ struct drm_connector *connector) ++{ ++ struct dw_hdmi *hdmi = bridge->driver_private; ++ ++ return dw_hdmi_get_edid(hdmi, connector); ++} ++ + static const struct drm_bridge_funcs dw_hdmi_bridge_funcs = { + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, +@@ -2873,6 +2905,8 @@ static const struct drm_bridge_funcs dw_hdmi_bridge_funcs = { + .atomic_disable = dw_hdmi_bridge_atomic_disable, + .mode_set = dw_hdmi_bridge_mode_set, + .mode_valid = dw_hdmi_bridge_mode_valid, ++ .detect = dw_hdmi_bridge_detect, ++ .get_edid = dw_hdmi_bridge_get_edid, + }; + + /* ----------------------------------------------------------------------------- +@@ -2988,10 +3022,18 @@ static irqreturn_t dw_hdmi_irq(int irq, void *dev_id) + } + + if (intr_stat & HDMI_IH_PHY_STAT0_HPD) { ++ enum drm_connector_status status = phy_int_pol & HDMI_PHY_HPD ++ ? connector_status_connected ++ : connector_status_disconnected; ++ + dev_dbg(hdmi->dev, "EVENT=%s\n", +- phy_int_pol & HDMI_PHY_HPD ? "plugin" : "plugout"); +- if (hdmi->bridge.dev) ++ status == connector_status_connected ? ++ "plugin" : "plugout"); ++ ++ if (hdmi->bridge.dev) { + drm_helper_hpd_irq_event(hdmi->bridge.dev); ++ drm_bridge_hpd_notify(&hdmi->bridge, status); ++ } + } + + hdmi_writeb(hdmi, intr_stat, HDMI_IH_PHY_STAT0); +@@ -3337,6 +3379,8 @@ __dw_hdmi_probe(struct platform_device *pdev, + + hdmi->bridge.driver_private = hdmi; + hdmi->bridge.funcs = &dw_hdmi_bridge_funcs; ++ hdmi->bridge.ops = DRM_BRIDGE_OP_DETECT | DRM_BRIDGE_OP_EDID ++ | DRM_BRIDGE_OP_HPD; + #ifdef CONFIG_OF + hdmi->bridge.of_node = pdev->dev.of_node; + #endif + +From 5631b3347b2c688d45a5804cc706702553873c3f Mon Sep 17 00:00:00 2001 +From: Stanislav Lisovskiy +Date: Tue, 30 Jun 2020 05:56:58 +0530 +Subject: [PATCH] drm: Add helper to compare edids. + +Many drivers would benefit from using +drm helper to compare edid, rather +than bothering with own implementation. + +v2: Added documentation for this function. + +Signed-off-by: Stanislav Lisovskiy +Signed-off-by: Maarten Lankhorst +Link: https://patchwork.freedesktop.org/patch/msgid/20200630002700.5451-2-kunal1.joshi@intel.com +(cherry picked from commit 536faa450e17f32fddb1a2124e3df71a966122cd) +--- + drivers/gpu/drm/drm_edid.c | 33 +++++++++++++++++++++++++++++++++ + include/drm/drm_edid.h | 9 +++++++++ + 2 files changed, 42 insertions(+) + +diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c +index b3f659759adb..aa0644d8272a 100644 +--- a/drivers/gpu/drm/drm_edid.c ++++ b/drivers/gpu/drm/drm_edid.c +@@ -1615,6 +1615,39 @@ static bool drm_edid_is_zero(const u8 *in_edid, int length) + return true; + } + ++/** ++ * drm_edid_are_equal - compare two edid blobs. ++ * @edid1: pointer to first blob ++ * @edid2: pointer to second blob ++ * This helper can be used during probing to determine if ++ * edid had changed. ++ */ ++bool drm_edid_are_equal(const struct edid *edid1, const struct edid *edid2) ++{ ++ int edid1_len, edid2_len; ++ bool edid1_present = edid1 != NULL; ++ bool edid2_present = edid2 != NULL; ++ ++ if (edid1_present != edid2_present) ++ return false; ++ ++ if (edid1) { ++ ++ edid1_len = EDID_LENGTH * (1 + edid1->extensions); ++ edid2_len = EDID_LENGTH * (1 + edid2->extensions); ++ ++ if (edid1_len != edid2_len) ++ return false; ++ ++ if (memcmp(edid1, edid2, edid1_len)) ++ return false; ++ } ++ ++ return true; ++} ++EXPORT_SYMBOL(drm_edid_are_equal); ++ ++ + /** + * drm_edid_block_valid - Sanity check the EDID block (base or extension) + * @raw_edid: pointer to raw EDID block +diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h +index 43254319ab19..cfa4f5af49af 100644 +--- a/include/drm/drm_edid.h ++++ b/include/drm/drm_edid.h +@@ -359,6 +359,15 @@ drm_load_edid_firmware(struct drm_connector *connector) + } + #endif + ++/** ++ * drm_edid_are_equal - compare two edid blobs. ++ * @edid1: pointer to first blob ++ * @edid2: pointer to second blob ++ * This helper can be used during probing to determine if ++ * edid had changed. ++ */ ++bool drm_edid_are_equal(const struct edid *edid1, const struct edid *edid2); ++ + int + drm_hdmi_avi_infoframe_from_display_mode(struct hdmi_avi_infoframe *frame, + const struct drm_connector *connector, + +From 00fb1055155719f429be43ff1864959cea9a56e2 Mon Sep 17 00:00:00 2001 +From: Stanislav Lisovskiy +Date: Tue, 30 Jun 2020 05:56:59 +0530 +Subject: [PATCH] drm: Introduce epoch counter to drm_connector + +This counter will be used by drm_helper_probe_detect caller to determine +if anything had changed(including edid, connection status and etc). +Hardware specific driver detect hooks are responsible for updating this +counter when some change is detected to notify the drm part, +which can trigger for example hotplug event. + +Also now call drm_connector_update_edid_property +right after we get edid always to make sure there is a +unified way to handle edid change, without having to +change tons of source code as currently +drm_connector_update_edid_property is called only in +certain cases like reprobing and not right after edid is +actually updated. + +v2: Added documentation for the new counter. Rename change_counter to + epoch_counter. + +Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=105540 + +Signed-off-by: Stanislav Lisovskiy +Signed-off-by: Maarten Lankhorst +Link: https://patchwork.freedesktop.org/patch/msgid/20200630002700.5451-3-kunal1.joshi@intel.com +(cherry picked from commit 5186421cbfe250002308d4d759674214b385752f) +--- + drivers/gpu/drm/drm_connector.c | 16 +++++++++++++ + drivers/gpu/drm/drm_edid.c | 8 ++++--- + drivers/gpu/drm/drm_probe_helper.c | 38 ++++++++++++++++++++++++++---- + include/drm/drm_connector.h | 2 ++ + 4 files changed, 56 insertions(+), 8 deletions(-) + +diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c +index d877ddc6dc57..c6d7fc45aeac 100644 +--- a/drivers/gpu/drm/drm_connector.c ++++ b/drivers/gpu/drm/drm_connector.c +@@ -269,6 +269,7 @@ int drm_connector_init(struct drm_device *dev, + INIT_LIST_HEAD(&connector->modes); + mutex_init(&connector->mutex); + connector->edid_blob_ptr = NULL; ++ connector->epoch_counter = 0; + connector->tile_blob_ptr = NULL; + connector->status = connector_status_unknown; + connector->display_info.panel_orientation = +@@ -1954,6 +1955,7 @@ int drm_connector_update_edid_property(struct drm_connector *connector, + struct drm_device *dev = connector->dev; + size_t size = 0; + int ret; ++ const struct edid *old_edid; + + /* ignore requests to set edid when overridden */ + if (connector->override_edid) +@@ -1977,6 +1979,20 @@ int drm_connector_update_edid_property(struct drm_connector *connector, + + drm_update_tile_info(connector, edid); + ++ if (connector->edid_blob_ptr) { ++ old_edid = (const struct edid *)connector->edid_blob_ptr->data; ++ if (old_edid) { ++ if (!drm_edid_are_equal(edid, old_edid)) { ++ DRM_DEBUG_KMS("[CONNECTOR:%d:%s] Edid was changed.\n", ++ connector->base.id, connector->name); ++ ++ connector->epoch_counter += 1; ++ DRM_DEBUG_KMS("Updating change counter to %llu\n", ++ connector->epoch_counter); ++ } ++ } ++ } ++ + drm_object_property_set_value(&connector->base, + dev->mode_config.non_desktop_property, + connector->display_info.non_desktop); +diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c +index aa0644d8272a..ddb9a093ad0d 100644 +--- a/drivers/gpu/drm/drm_edid.c ++++ b/drivers/gpu/drm/drm_edid.c +@@ -1632,7 +1632,6 @@ bool drm_edid_are_equal(const struct edid *edid1, const struct edid *edid2) + return false; + + if (edid1) { +- + edid1_len = EDID_LENGTH * (1 + edid1->extensions); + edid2_len = EDID_LENGTH * (1 + edid2->extensions); + +@@ -1647,7 +1646,6 @@ bool drm_edid_are_equal(const struct edid *edid1, const struct edid *edid2) + } + EXPORT_SYMBOL(drm_edid_are_equal); + +- + /** + * drm_edid_block_valid - Sanity check the EDID block (base or extension) + * @raw_edid: pointer to raw EDID block +@@ -2050,13 +2048,17 @@ EXPORT_SYMBOL(drm_probe_ddc); + struct edid *drm_get_edid(struct drm_connector *connector, + struct i2c_adapter *adapter) + { ++ struct edid *edid; ++ + if (connector->force == DRM_FORCE_OFF) + return NULL; + + if (connector->force == DRM_FORCE_UNSPECIFIED && !drm_probe_ddc(adapter)) + return NULL; + +- return drm_do_get_edid(connector, drm_do_probe_ddc_edid, adapter); ++ edid = drm_do_get_edid(connector, drm_do_probe_ddc_edid, adapter); ++ drm_connector_update_edid_property(connector, edid); ++ return edid; + } + EXPORT_SYMBOL(drm_get_edid); + +diff --git a/drivers/gpu/drm/drm_probe_helper.c b/drivers/gpu/drm/drm_probe_helper.c +index f5d141e0400f..6d3a1dbfcba5 100644 +--- a/drivers/gpu/drm/drm_probe_helper.c ++++ b/drivers/gpu/drm/drm_probe_helper.c +@@ -290,6 +290,9 @@ drm_helper_probe_detect_ctx(struct drm_connector *connector, bool force) + if (WARN_ON(ret < 0)) + ret = connector_status_unknown; + ++ if (ret != connector->status) ++ connector->epoch_counter += 1; ++ + drm_modeset_drop_locks(&ctx); + drm_modeset_acquire_fini(&ctx); + +@@ -323,11 +326,16 @@ drm_helper_probe_detect(struct drm_connector *connector, + return ret; + + if (funcs->detect_ctx) +- return funcs->detect_ctx(connector, ctx, force); ++ ret = funcs->detect_ctx(connector, ctx, force); + else if (connector->funcs->detect) +- return connector->funcs->detect(connector, force); ++ ret = connector->funcs->detect(connector, force); + else +- return connector_status_connected; ++ ret = connector_status_connected; ++ ++ if (ret != connector->status) ++ connector->epoch_counter += 1; ++ ++ return ret; + } + EXPORT_SYMBOL(drm_helper_probe_detect); + +@@ -780,6 +788,7 @@ bool drm_helper_hpd_irq_event(struct drm_device *dev) + struct drm_connector_list_iter conn_iter; + enum drm_connector_status old_status; + bool changed = false; ++ u64 old_epoch_counter; + + if (!dev->mode_config.poll_enabled) + return false; +@@ -793,20 +802,39 @@ bool drm_helper_hpd_irq_event(struct drm_device *dev) + + old_status = connector->status; + ++ old_epoch_counter = connector->epoch_counter; ++ ++ DRM_DEBUG_KMS("[CONNECTOR:%d:%s] Old epoch counter %llu\n", connector->base.id, ++ connector->name, ++ old_epoch_counter); ++ + connector->status = drm_helper_probe_detect(connector, NULL, false); + DRM_DEBUG_KMS("[CONNECTOR:%d:%s] status updated from %s to %s\n", + connector->base.id, + connector->name, + drm_get_connector_status_name(old_status), + drm_get_connector_status_name(connector->status)); +- if (old_status != connector->status) ++ ++ DRM_DEBUG_KMS("[CONNECTOR:%d:%s] New epoch counter %llu\n", ++ connector->base.id, ++ connector->name, ++ connector->epoch_counter); ++ ++ /* ++ * Check if epoch counter had changed, meaning that we need ++ * to send a uevent. ++ */ ++ if (old_epoch_counter != connector->epoch_counter) + changed = true; ++ + } + drm_connector_list_iter_end(&conn_iter); + mutex_unlock(&dev->mode_config.mutex); + +- if (changed) ++ if (changed) { + drm_kms_helper_hotplug_event(dev); ++ DRM_DEBUG_KMS("Sent hotplug event\n"); ++ } + + return changed; + } +diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h +index fd543d1db9b2..6a451b86c454 100644 +--- a/include/drm/drm_connector.h ++++ b/include/drm/drm_connector.h +@@ -1329,6 +1329,8 @@ struct drm_connector { + enum drm_connector_force force; + /** @override_edid: has the EDID been overwritten through debugfs for testing? */ + bool override_edid; ++ /** @epoch_counter: used to detect any other changes in connector, besides status */ ++ u64 epoch_counter; + + /** + * @possible_encoders: Bit mask of encoders that can drive this + +From 0402c6b6ec3351cdf475a0a7b4196cea5e213bd0 Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Fri, 3 Jul 2020 10:07:23 +0200 +Subject: [PATCH] drm/fourcc: Add modifier definitions for describing Amlogic + Video Framebuffer Compression + +Amlogic uses a proprietary lossless image compression protocol and format +for their hardware video codec accelerators, either video decoders or +video input encoders. + +It considerably reduces memory bandwidth while writing and reading +frames in memory. + +The underlying storage is considered to be 3 components, 8bit or 10-bit +per component, YCbCr 420, single plane : +- DRM_FORMAT_YUV420_8BIT +- DRM_FORMAT_YUV420_10BIT + +This modifier will be notably added to DMA-BUF frames imported from the V4L2 +Amlogic VDEC decoder. + +This introduces the basic layout composed of: +- a body content organized in 64x32 superblocks with 4096 bytes per + superblock in default mode. +- a 32 bytes per 128x64 header block + +This layout is tranferrable between Amlogic SoCs supporting this modifier. + +The Memory Saving option exist changing the layout superblock size to save memory when +using 8bit components pixels size. + +Finally is also adds the Scatter Memory layout, meaning the header contains IOMMU +references to the compressed frames content to optimize memory access +and layout. + +In this mode, only the header memory address is needed, thus the content +memory organization is tied to the current producer execution and cannot +be saved/dumped neither transferrable between Amlogic SoCs supporting this +modifier. + +Signed-off-by: Neil Armstrong +Tested-by: Kevin Hilman +Reviewed-by: Kevin Hilman +Acked-by: Daniel Vetter +Link: https://patchwork.freedesktop.org/patch/msgid/20200703080728.25207-2-narmstrong@baylibre.com +(cherry picked from commit d6528ec883096e7ccdb08257bcc45670bc878519) +--- + include/uapi/drm/drm_fourcc.h | 81 +++++++++++++++++++++++++++++++++++ + 1 file changed, 81 insertions(+) + +diff --git a/include/uapi/drm/drm_fourcc.h b/include/uapi/drm/drm_fourcc.h +index 993c1b342315..cbf92fdf2712 100644 +--- a/include/uapi/drm/drm_fourcc.h ++++ b/include/uapi/drm/drm_fourcc.h +@@ -331,6 +331,7 @@ extern "C" { + #define DRM_FORMAT_MOD_VENDOR_BROADCOM 0x07 + #define DRM_FORMAT_MOD_VENDOR_ARM 0x08 + #define DRM_FORMAT_MOD_VENDOR_ALLWINNER 0x09 ++#define DRM_FORMAT_MOD_VENDOR_AMLOGIC 0x0a + + /* add more to the end as needed */ + +@@ -950,6 +951,86 @@ drm_fourcc_canonicalize_nvidia_format_mod(__u64 modifier) + */ + #define DRM_FORMAT_MOD_ALLWINNER_TILED fourcc_mod_code(ALLWINNER, 1) + ++/* ++ * Amlogic Video Framebuffer Compression modifiers ++ * ++ * Amlogic uses a proprietary lossless image compression protocol and format ++ * for their hardware video codec accelerators, either video decoders or ++ * video input encoders. ++ * ++ * It considerably reduces memory bandwidth while writing and reading ++ * frames in memory. ++ * ++ * The underlying storage is considered to be 3 components, 8bit or 10-bit ++ * per component YCbCr 420, single plane : ++ * - DRM_FORMAT_YUV420_8BIT ++ * - DRM_FORMAT_YUV420_10BIT ++ * ++ * The first 8 bits of the mode defines the layout, then the following 8 bits ++ * defines the options changing the layout. ++ * ++ * Not all combinations are valid, and different SoCs may support different ++ * combinations of layout and options. ++ */ ++#define __fourcc_mod_amlogic_layout_mask 0xf ++#define __fourcc_mod_amlogic_options_shift 8 ++#define __fourcc_mod_amlogic_options_mask 0xf ++ ++#define DRM_FORMAT_MOD_AMLOGIC_FBC(__layout, __options) \ ++ fourcc_mod_code(AMLOGIC, \ ++ ((__layout) & __fourcc_mod_amlogic_layout_mask) | \ ++ ((__options) & __fourcc_mod_amlogic_options_mask \ ++ << __fourcc_mod_amlogic_options_shift)) ++ ++/* Amlogic FBC Layouts */ ++ ++/* ++ * Amlogic FBC Basic Layout ++ * ++ * The basic layout is composed of: ++ * - a body content organized in 64x32 superblocks with 4096 bytes per ++ * superblock in default mode. ++ * - a 32 bytes per 128x64 header block ++ * ++ * This layout is transferrable between Amlogic SoCs supporting this modifier. ++ */ ++#define AMLOGIC_FBC_LAYOUT_BASIC (1ULL) ++ ++/* ++ * Amlogic FBC Scatter Memory layout ++ * ++ * Indicates the header contains IOMMU references to the compressed ++ * frames content to optimize memory access and layout. ++ * ++ * In this mode, only the header memory address is needed, thus the ++ * content memory organization is tied to the current producer ++ * execution and cannot be saved/dumped neither transferrable between ++ * Amlogic SoCs supporting this modifier. ++ * ++ * Due to the nature of the layout, these buffers are not expected to ++ * be accessible by the user-space clients, but only accessible by the ++ * hardware producers and consumers. ++ * ++ * The user-space clients should expect a failure while trying to mmap ++ * the DMA-BUF handle returned by the producer. ++ */ ++#define AMLOGIC_FBC_LAYOUT_SCATTER (2ULL) ++ ++/* Amlogic FBC Layout Options Bit Mask */ ++ ++/* ++ * Amlogic FBC Memory Saving mode ++ * ++ * Indicates the storage is packed when pixel size is multiple of word ++ * boudaries, i.e. 8bit should be stored in this mode to save allocation ++ * memory. ++ * ++ * This mode reduces body layout to 3072 bytes per 64x32 superblock with ++ * the basic layout and 3200 bytes per 64x32 superblock combined with ++ * the scatter layout. ++ */ ++#define AMLOGIC_FBC_OPTION_MEM_SAVING (1ULL << 0) ++ + #if defined(__cplusplus) + } + #endif + +From bca1f53e15b80ac4fa24a073f96e8f99d994ca8a Mon Sep 17 00:00:00 2001 +From: Brian Starkey +Date: Fri, 26 Jun 2020 17:48:00 +0100 +Subject: [PATCH] drm: drm_fourcc: Add generic alias for 16_16_TILE modifier + +In cases such as DRM_FORMAT_MOD_SAMSUNG_16_16_TILE, the modifier +describes a generic pixel re-ordering which can be applicable to +multiple vendors. + +Define an alias: DRM_FORMAT_MOD_GENERIC_16_16_TILE, which can be +used to describe this layout in a vendor-neutral way, and add a +comment about the expected usage of such "generic" modifiers. + +Changes in v2: + - Move note about future cases to comment (Daniel) + +Signed-off-by: Brian Starkey +Reviewed-by: Daniel Vetter +Signed-off-by: Liviu Dudau +Link: https://patchwork.freedesktop.org/patch/msgid/20200626164800.11595-1-brian.starkey@arm.com +(cherry picked from commit 9ac2b63791ef63935c71e2a7f5444a1118c4d084) +--- + include/uapi/drm/drm_fourcc.h | 25 +++++++++++++++++++++++++ + 1 file changed, 25 insertions(+) + +diff --git a/include/uapi/drm/drm_fourcc.h b/include/uapi/drm/drm_fourcc.h +index cbf92fdf2712..4bee7de5f306 100644 +--- a/include/uapi/drm/drm_fourcc.h ++++ b/include/uapi/drm/drm_fourcc.h +@@ -346,8 +346,33 @@ extern "C" { + * When adding a new token please document the layout with a code comment, + * similar to the fourcc codes above. drm_fourcc.h is considered the + * authoritative source for all of these. ++ * ++ * Generic modifier names: ++ * ++ * DRM_FORMAT_MOD_GENERIC_* definitions are used to provide vendor-neutral names ++ * for layouts which are common across multiple vendors. To preserve ++ * compatibility, in cases where a vendor-specific definition already exists and ++ * a generic name for it is desired, the common name is a purely symbolic alias ++ * and must use the same numerical value as the original definition. ++ * ++ * Note that generic names should only be used for modifiers which describe ++ * generic layouts (such as pixel re-ordering), which may have ++ * independently-developed support across multiple vendors. ++ * ++ * In future cases where a generic layout is identified before merging with a ++ * vendor-specific modifier, a new 'GENERIC' vendor or modifier using vendor ++ * 'NONE' could be considered. This should only be for obvious, exceptional ++ * cases to avoid polluting the 'GENERIC' namespace with modifiers which only ++ * apply to a single vendor. ++ * ++ * Generic names should not be used for cases where multiple hardware vendors ++ * have implementations of the same standardised compression scheme (such as ++ * AFBC). In those cases, all implementations should use the same format ++ * modifier(s), reflecting the vendor of the standard. + */ + ++#define DRM_FORMAT_MOD_GENERIC_16_16_TILE DRM_FORMAT_MOD_SAMSUNG_16_16_TILE ++ + /* + * Invalid Modifier + * + +From 01f7cea4ef8c373df777713ceef5599a3efa88cb Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= +Date: Wed, 27 May 2020 16:03:08 +0300 +Subject: [PATCH] drm/edid: Allow looking for ext blocks starting from a + specified index +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Apparently EDIDs with multiple DispID ext blocks is a thing, so prepare +for iterating through multiple ext blocks of the same type by +passing the starting ext block index to drm_find_edid_extension(). Well +also have drm_find_edid_extension() update the index to point to the +next ext block on success. Thus we should be able to call +drm_find_edid_extension() in loop. + +Signed-off-by: Ville Syrjälä +Link: https://patchwork.freedesktop.org/patch/msgid/20200527130310.27099-1-ville.syrjala@linux.intel.com +Reviewed-by: José Roberto de Souza +(cherry picked from commit 8873cfa384055d0348c03161420b1e9b6c1dc5d0) +--- + drivers/gpu/drm/drm_edid.c | 30 +++++++++++++++++++++--------- + 1 file changed, 21 insertions(+), 9 deletions(-) + +diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c +index ddb9a093ad0d..06cb75b9fc44 100644 +--- a/drivers/gpu/drm/drm_edid.c ++++ b/drivers/gpu/drm/drm_edid.c +@@ -3226,7 +3226,8 @@ add_detailed_modes(struct drm_connector *connector, struct edid *edid, + /* + * Search EDID for CEA extension block. + */ +-static u8 *drm_find_edid_extension(const struct edid *edid, int ext_id) ++static u8 *drm_find_edid_extension(const struct edid *edid, ++ int ext_id, int *ext_index) + { + u8 *edid_ext = NULL; + int i; +@@ -3236,23 +3237,26 @@ static u8 *drm_find_edid_extension(const struct edid *edid, int ext_id) + return NULL; + + /* Find CEA extension */ +- for (i = 0; i < edid->extensions; i++) { ++ for (i = *ext_index; i < edid->extensions; i++) { + edid_ext = (u8 *)edid + EDID_LENGTH * (i + 1); + if (edid_ext[0] == ext_id) + break; + } + +- if (i == edid->extensions) ++ if (i >= edid->extensions) + return NULL; + ++ *ext_index = i + 1; ++ + return edid_ext; + } + + + static u8 *drm_find_displayid_extension(const struct edid *edid, +- int *length, int *idx) ++ int *length, int *idx, ++ int *ext_index) + { +- u8 *displayid = drm_find_edid_extension(edid, DISPLAYID_EXT); ++ u8 *displayid = drm_find_edid_extension(edid, DISPLAYID_EXT, ext_index); + struct displayid_hdr *base; + int ret; + +@@ -3279,14 +3283,18 @@ static u8 *drm_find_cea_extension(const struct edid *edid) + struct displayid_block *block; + u8 *cea; + u8 *displayid; ++ int ext_index; + + /* Look for a top level CEA extension block */ +- cea = drm_find_edid_extension(edid, CEA_EXT); ++ ext_index = 0; ++ cea = drm_find_edid_extension(edid, CEA_EXT, &ext_index); + if (cea) + return cea; + + /* CEA blocks can also be found embedded in a DisplayID block */ +- displayid = drm_find_displayid_extension(edid, &length, &idx); ++ ext_index = 0; ++ displayid = drm_find_displayid_extension(edid, &length, &idx, ++ &ext_index); + if (!displayid) + return NULL; + +@@ -5236,8 +5244,10 @@ static int add_displayid_detailed_modes(struct drm_connector *connector, + int length, idx; + struct displayid_block *block; + int num_modes = 0; ++ int ext_index = 0; + +- displayid = drm_find_displayid_extension(edid, &length, &idx); ++ displayid = drm_find_displayid_extension(edid, &length, &idx, ++ &ext_index); + if (!displayid) + return 0; + +@@ -5911,11 +5921,13 @@ void drm_update_tile_info(struct drm_connector *connector, + const struct edid *edid) + { + const void *displayid = NULL; ++ int ext_index = 0; + int length, idx; + int ret; + + connector->has_tile = false; +- displayid = drm_find_displayid_extension(edid, &length, &idx); ++ displayid = drm_find_displayid_extension(edid, &length, &idx, ++ &ext_index); + if (!displayid) { + /* drop reference to any tile group we had */ + goto out_drop_ref; + +From 181edc12e551c8194591969ee528ed6041e4ada4 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= +Date: Wed, 27 May 2020 16:03:09 +0300 +Subject: [PATCH] drm/edid: Iterate through all DispID ext blocks +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Apparently there are EDIDs in the wild with multiple DispID extension +blocks. Iterate through them all. + +In one particular case the tile information is specicied in the +second DispID ext block, and since the current parser only looks +at the first DispID ext block we don't notice that we're dealing +with a tiled display. + +While at it change a few functions to return void since we have +no use for the errno. + +References: https://gitlab.freedesktop.org/drm/intel/-/issues/27 +Signed-off-by: Ville Syrjälä +Link: https://patchwork.freedesktop.org/patch/msgid/20200527130310.27099-2-ville.syrjala@linux.intel.com +Reviewed-by: José Roberto de Souza +(cherry picked from commit 7f261afdcfae363192e3eef52dd34855cc149c15) +--- + drivers/gpu/drm/drm_edid.c | 84 +++++++++++++++++--------------------- + 1 file changed, 38 insertions(+), 46 deletions(-) + +diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c +index 06cb75b9fc44..fcd739af570f 100644 +--- a/drivers/gpu/drm/drm_edid.c ++++ b/drivers/gpu/drm/drm_edid.c +@@ -3286,6 +3286,7 @@ static u8 *drm_find_cea_extension(const struct edid *edid) + int ext_index; + + /* Look for a top level CEA extension block */ ++ /* FIXME: make callers iterate through multiple CEA ext blocks? */ + ext_index = 0; + cea = drm_find_edid_extension(edid, CEA_EXT, &ext_index); + if (cea) +@@ -3293,20 +3294,20 @@ static u8 *drm_find_cea_extension(const struct edid *edid) + + /* CEA blocks can also be found embedded in a DisplayID block */ + ext_index = 0; +- displayid = drm_find_displayid_extension(edid, &length, &idx, +- &ext_index); +- if (!displayid) +- return NULL; ++ for (;;) { ++ displayid = drm_find_displayid_extension(edid, &length, &idx, ++ &ext_index); ++ if (!displayid) ++ return NULL; + +- idx += sizeof(struct displayid_hdr); +- for_each_displayid_db(displayid, block, idx, length) { +- if (block->tag == DATA_BLOCK_CTA) { +- cea = (u8 *)block; +- break; ++ idx += sizeof(struct displayid_hdr); ++ for_each_displayid_db(displayid, block, idx, length) { ++ if (block->tag == DATA_BLOCK_CTA) ++ return (u8 *)block; + } + } + +- return cea; ++ return NULL; + } + + static __always_inline const struct drm_display_mode *cea_mode_for_vic(u8 vic) +@@ -5246,19 +5247,22 @@ static int add_displayid_detailed_modes(struct drm_connector *connector, + int num_modes = 0; + int ext_index = 0; + +- displayid = drm_find_displayid_extension(edid, &length, &idx, +- &ext_index); +- if (!displayid) +- return 0; +- +- idx += sizeof(struct displayid_hdr); +- for_each_displayid_db(displayid, block, idx, length) { +- switch (block->tag) { +- case DATA_BLOCK_TYPE_1_DETAILED_TIMING: +- num_modes += add_displayid_detailed_1_modes(connector, block); ++ for (;;) { ++ displayid = drm_find_displayid_extension(edid, &length, &idx, ++ &ext_index); ++ if (!displayid) + break; ++ ++ idx += sizeof(struct displayid_hdr); ++ for_each_displayid_db(displayid, block, idx, length) { ++ switch (block->tag) { ++ case DATA_BLOCK_TYPE_1_DETAILED_TIMING: ++ num_modes += add_displayid_detailed_1_modes(connector, block); ++ break; ++ } + } + } ++ + return num_modes; + } + +@@ -5838,8 +5842,8 @@ drm_hdmi_vendor_infoframe_from_display_mode(struct hdmi_vendor_infoframe *frame, + } + EXPORT_SYMBOL(drm_hdmi_vendor_infoframe_from_display_mode); + +-static int drm_parse_tiled_block(struct drm_connector *connector, +- const struct displayid_block *block) ++static void drm_parse_tiled_block(struct drm_connector *connector, ++ const struct displayid_block *block) + { + const struct displayid_tiled_block *tile = (struct displayid_tiled_block *)block; + u16 w, h; +@@ -5877,7 +5881,7 @@ static int drm_parse_tiled_block(struct drm_connector *connector, + tg = drm_mode_create_tile_group(connector->dev, tile->topology_id); + } + if (!tg) +- return -ENOMEM; ++ return; + + if (connector->tile_group != tg) { + /* if we haven't got a pointer, +@@ -5889,14 +5893,12 @@ static int drm_parse_tiled_block(struct drm_connector *connector, + } else + /* if same tile group, then release the ref we just took. */ + drm_mode_put_tile_group(connector->dev, tg); +- return 0; + } + +-static int drm_displayid_parse_tiled(struct drm_connector *connector, +- const u8 *displayid, int length, int idx) ++static void drm_displayid_parse_tiled(struct drm_connector *connector, ++ const u8 *displayid, int length, int idx) + { + const struct displayid_block *block; +- int ret; + + idx += sizeof(struct displayid_hdr); + for_each_displayid_db(displayid, block, idx, length) { +@@ -5905,16 +5907,13 @@ static int drm_displayid_parse_tiled(struct drm_connector *connector, + + switch (block->tag) { + case DATA_BLOCK_TILED_DISPLAY: +- ret = drm_parse_tiled_block(connector, block); +- if (ret) +- return ret; ++ drm_parse_tiled_block(connector, block); + break; + default: + DRM_DEBUG_KMS("found DisplayID tag 0x%x, unhandled\n", block->tag); + break; + } + } +- return 0; + } + + void drm_update_tile_info(struct drm_connector *connector, +@@ -5923,26 +5922,19 @@ void drm_update_tile_info(struct drm_connector *connector, + const void *displayid = NULL; + int ext_index = 0; + int length, idx; +- int ret; + + connector->has_tile = false; +- displayid = drm_find_displayid_extension(edid, &length, &idx, +- &ext_index); +- if (!displayid) { +- /* drop reference to any tile group we had */ +- goto out_drop_ref; ++ for (;;) { ++ displayid = drm_find_displayid_extension(edid, &length, &idx, ++ &ext_index); ++ if (!displayid) ++ break; ++ ++ drm_displayid_parse_tiled(connector, displayid, length, idx); + } + +- ret = drm_displayid_parse_tiled(connector, displayid, length, idx); +- if (ret < 0) +- goto out_drop_ref; +- if (!connector->has_tile) +- goto out_drop_ref; +- return; +-out_drop_ref: +- if (connector->tile_group) { ++ if (!connector->has_tile && connector->tile_group) { + drm_mode_put_tile_group(connector->dev, connector->tile_group); + connector->tile_group = NULL; + } +- return; + } + +From c4a01f31ea528f8a1057b720eed47d502b19a3fb Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= +Date: Wed, 27 May 2020 16:03:10 +0300 +Subject: [PATCH] drm/edid: Clean up some curly braces +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Drop some pointless curly braces, and add some across the +else when the if has them too. + +Signed-off-by: Ville Syrjälä +Link: https://patchwork.freedesktop.org/patch/msgid/20200527130310.27099-3-ville.syrjala@linux.intel.com +Reviewed-by: José Roberto de Souza +(cherry picked from commit 392f9fcb159bf95ec3c7de340a880f4778167275) +--- + drivers/gpu/drm/drm_edid.c | 9 ++++----- + 1 file changed, 4 insertions(+), 5 deletions(-) + +diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c +index fcd739af570f..c28e7678014d 100644 +--- a/drivers/gpu/drm/drm_edid.c ++++ b/drivers/gpu/drm/drm_edid.c +@@ -5877,22 +5877,21 @@ static void drm_parse_tiled_block(struct drm_connector *connector, + DRM_DEBUG_KMS("vend %c%c%c\n", tile->topology_id[0], tile->topology_id[1], tile->topology_id[2]); + + tg = drm_mode_get_tile_group(connector->dev, tile->topology_id); +- if (!tg) { ++ if (!tg) + tg = drm_mode_create_tile_group(connector->dev, tile->topology_id); +- } + if (!tg) + return; + + if (connector->tile_group != tg) { + /* if we haven't got a pointer, + take the reference, drop ref to old tile group */ +- if (connector->tile_group) { ++ if (connector->tile_group) + drm_mode_put_tile_group(connector->dev, connector->tile_group); +- } + connector->tile_group = tg; +- } else ++ } else { + /* if same tile group, then release the ref we just took. */ + drm_mode_put_tile_group(connector->dev, tg); ++ } + } + + static void drm_displayid_parse_tiled(struct drm_connector *connector, + +From 7a5d301a5077083f45d826c49248882eacec778d Mon Sep 17 00:00:00 2001 +From: Liu Ying +Date: Thu, 9 Jul 2020 10:02:35 +0800 +Subject: [PATCH] drm/bridge: dw-hdmi: Don't cleanup i2c adapter and ddc ptr in + __dw_hdmi_probe() bailout path + +It's unnecessary to cleanup the i2c adapter and the ddc pointer in +the bailout path of __dw_hdmi_probe(), since the adapter is not +added and the ddc pointer is not set. + +Fixes: a23d6265f033 ("drm: bridge: dw-hdmi: Extract PHY interrupt setup to a function") +Cc: Andrzej Hajda +Cc: Neil Armstrong +Cc: Laurent Pinchart +Cc: Jonas Karlman +Cc: Jernej Skrabec +Cc: David Airlie +Cc: Daniel Vetter +Cc: Boris Brezillon +Cc: Jerome Brunet +Cc: Cheng-Yi Chiang +Cc: Dariusz Marcinkiewicz +Cc: Archit Taneja +Cc: Jose Abreu +Cc: dri-devel@lists.freedesktop.org +Cc: NXP Linux Team +Signed-off-by: Liu Ying +Reviewed-by: Laurent Pinchart +Signed-off-by: Sam Ravnborg +Link: https://patchwork.freedesktop.org/patch/msgid/1594260156-8316-1-git-send-email-victor.liu@nxp.com +(cherry picked from commit 2ae53e79f2dec41949d7b089c0b6d7edce292d10) +--- + drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 5 ----- + 1 file changed, 5 deletions(-) + +diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +index 6148a022569a..137b6ebfed19 100644 +--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c ++++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +@@ -3441,11 +3441,6 @@ __dw_hdmi_probe(struct platform_device *pdev, + return hdmi; + + err_iahb: +- if (hdmi->i2c) { +- i2c_del_adapter(&hdmi->i2c->adap); +- hdmi->ddc = NULL; +- } +- + clk_disable_unprepare(hdmi->iahb_clk); + if (hdmi->cec_clk) + clk_disable_unprepare(hdmi->cec_clk); + +From fe98962cfe32f385bed8c1fea444aeb887b472e6 Mon Sep 17 00:00:00 2001 +From: Liu Ying +Date: Thu, 9 Jul 2020 10:02:36 +0800 +Subject: [PATCH] drm/bridge: dw-hdmi: Always add the bridge in the global + bridge list + +It doesn't hurt to add the bridge in the global bridge list also for +platform specific dw-hdmi drivers which are based on the component +framework. This can be achieved by moving the drm_bridge_add() function +call from dw_hdmi_probe() to __dw_hdmi_probe(). A counterpart movement +for drm_bridge_remove() is also needed then. Moreover, since drm_bridge_add() +initializes &bridge->hpd_mutex, this may help those platform specific +dw-hdmi drivers(based on the component framework) avoid accessing the +uninitialized mutex in drm_bridge_hpd_notify() which is called in +dw_hdmi_irq(). Putting drm_bridge_add() in __dw_hdmi_probe() just before +it returns successfully should bring no logic change for platforms based +on the DRM bridge API, which is a good choice from safety point of view. +Also, __dw_hdmi_probe() is renamed to dw_hdmi_probe() since dw_hdmi_probe() +does nothing else but calling __dw_hdmi_probe(). Similar renaming applies +to the __dw_hdmi_remove()/dw_hdmi_remove() pair. + +Fixes: ec971aaa6775 ("drm: bridge: dw-hdmi: Make connector creation optional") +Cc: Andrzej Hajda +Cc: Neil Armstrong +Cc: Laurent Pinchart +Cc: Jonas Karlman +Cc: Jernej Skrabec +Cc: David Airlie +Cc: Daniel Vetter +Cc: Boris Brezillon +Cc: Jerome Brunet +Cc: Cheng-Yi Chiang +Cc: Dariusz Marcinkiewicz +Cc: Archit Taneja +Cc: Jose Abreu +Cc: Sam Ravnborg +Cc: dri-devel@lists.freedesktop.org +Cc: NXP Linux Team +Signed-off-by: Liu Ying +Signed-off-by: Sam Ravnborg +Link: https://patchwork.freedesktop.org/patch/msgid/1594260156-8316-2-git-send-email-victor.liu@nxp.com +(cherry picked from commit 0bf4f5b5d3972df7014df302b95b58b8de1a1e94) +--- + drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 44 +++++++---------------- + 1 file changed, 13 insertions(+), 31 deletions(-) + +diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +index 137b6ebfed19..748df1cacd2b 100644 +--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c ++++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +@@ -3179,9 +3179,11 @@ static void dw_hdmi_init_hw(struct dw_hdmi *hdmi) + hdmi->phy.ops->setup_hpd(hdmi, hdmi->phy.data); + } + +-static struct dw_hdmi * +-__dw_hdmi_probe(struct platform_device *pdev, +- const struct dw_hdmi_plat_data *plat_data) ++/* ----------------------------------------------------------------------------- ++ * Probe/remove API, used from platforms based on the DRM bridge API. ++ */ ++struct dw_hdmi *dw_hdmi_probe(struct platform_device *pdev, ++ const struct dw_hdmi_plat_data *plat_data) + { + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; +@@ -3438,6 +3440,8 @@ __dw_hdmi_probe(struct platform_device *pdev, + hdmi->cec = platform_device_register_full(&pdevinfo); + } + ++ drm_bridge_add(&hdmi->bridge); ++ + return hdmi; + + err_iahb: +@@ -3451,9 +3455,12 @@ __dw_hdmi_probe(struct platform_device *pdev, + + return ERR_PTR(ret); + } ++EXPORT_SYMBOL_GPL(dw_hdmi_probe); + +-static void __dw_hdmi_remove(struct dw_hdmi *hdmi) ++void dw_hdmi_remove(struct dw_hdmi *hdmi) + { ++ drm_bridge_remove(&hdmi->bridge); ++ + if (hdmi->audio && !IS_ERR(hdmi->audio)) + platform_device_unregister(hdmi->audio); + if (!IS_ERR(hdmi->cec)) +@@ -3472,31 +3479,6 @@ static void __dw_hdmi_remove(struct dw_hdmi *hdmi) + else + i2c_put_adapter(hdmi->ddc); + } +- +-/* ----------------------------------------------------------------------------- +- * Probe/remove API, used from platforms based on the DRM bridge API. +- */ +-struct dw_hdmi *dw_hdmi_probe(struct platform_device *pdev, +- const struct dw_hdmi_plat_data *plat_data) +-{ +- struct dw_hdmi *hdmi; +- +- hdmi = __dw_hdmi_probe(pdev, plat_data); +- if (IS_ERR(hdmi)) +- return hdmi; +- +- drm_bridge_add(&hdmi->bridge); +- +- return hdmi; +-} +-EXPORT_SYMBOL_GPL(dw_hdmi_probe); +- +-void dw_hdmi_remove(struct dw_hdmi *hdmi) +-{ +- drm_bridge_remove(&hdmi->bridge); +- +- __dw_hdmi_remove(hdmi); +-} + EXPORT_SYMBOL_GPL(dw_hdmi_remove); + + /* ----------------------------------------------------------------------------- +@@ -3509,7 +3491,7 @@ struct dw_hdmi *dw_hdmi_bind(struct platform_device *pdev, + struct dw_hdmi *hdmi; + int ret; + +- hdmi = __dw_hdmi_probe(pdev, plat_data); ++ hdmi = dw_hdmi_probe(pdev, plat_data); + if (IS_ERR(hdmi)) + return hdmi; + +@@ -3526,7 +3508,7 @@ EXPORT_SYMBOL_GPL(dw_hdmi_bind); + + void dw_hdmi_unbind(struct dw_hdmi *hdmi) + { +- __dw_hdmi_remove(hdmi); ++ dw_hdmi_remove(hdmi); + } + EXPORT_SYMBOL_GPL(dw_hdmi_unbind); + + +From d046fd09e47e5ea681fa9a0ba441eb493a8b5b14 Mon Sep 17 00:00:00 2001 +From: Andrey Lebedev +Date: Fri, 19 Jun 2020 10:58:59 +0300 +Subject: [PATCH] drm/lima: Expose job_hang_limit module parameter + +Some pp or gp jobs can be successfully repeated even after they time outs. +Introduce lima module parameter to specify number of times a job can hang +before being dropped. + +Signed-off-by: Andrey Lebedev +Signed-off-by: Qiang Yu +Link: https://patchwork.freedesktop.org/patch/msgid/20200619075900.3030696-1-andrey.lebedev@gmail.com +(cherry picked from commit de48984486d942d4f23e2b29374639f21042bdaa) +--- + drivers/gpu/drm/lima/lima_drv.c | 4 ++++ + drivers/gpu/drm/lima/lima_drv.h | 1 + + drivers/gpu/drm/lima/lima_sched.c | 5 +++-- + 3 files changed, 8 insertions(+), 2 deletions(-) + +diff --git a/drivers/gpu/drm/lima/lima_drv.c b/drivers/gpu/drm/lima/lima_drv.c +index a831565af813..ab460121fd52 100644 +--- a/drivers/gpu/drm/lima/lima_drv.c ++++ b/drivers/gpu/drm/lima/lima_drv.c +@@ -19,6 +19,7 @@ + int lima_sched_timeout_ms; + uint lima_heap_init_nr_pages = 8; + uint lima_max_error_tasks; ++uint lima_job_hang_limit; + + MODULE_PARM_DESC(sched_timeout_ms, "task run timeout in ms"); + module_param_named(sched_timeout_ms, lima_sched_timeout_ms, int, 0444); +@@ -29,6 +30,9 @@ module_param_named(heap_init_nr_pages, lima_heap_init_nr_pages, uint, 0444); + MODULE_PARM_DESC(max_error_tasks, "max number of error tasks to save"); + module_param_named(max_error_tasks, lima_max_error_tasks, uint, 0644); + ++MODULE_PARM_DESC(job_hang_limit, "number of times to allow a job to hang before dropping it (default 0)"); ++module_param_named(job_hang_limit, lima_job_hang_limit, uint, 0444); ++ + static int lima_ioctl_get_param(struct drm_device *dev, void *data, struct drm_file *file) + { + struct drm_lima_get_param *args = data; +diff --git a/drivers/gpu/drm/lima/lima_drv.h b/drivers/gpu/drm/lima/lima_drv.h +index fdbd4077c768..c738d288547b 100644 +--- a/drivers/gpu/drm/lima/lima_drv.h ++++ b/drivers/gpu/drm/lima/lima_drv.h +@@ -11,6 +11,7 @@ + extern int lima_sched_timeout_ms; + extern uint lima_heap_init_nr_pages; + extern uint lima_max_error_tasks; ++extern uint lima_job_hang_limit; + + struct lima_vm; + struct lima_bo; +diff --git a/drivers/gpu/drm/lima/lima_sched.c b/drivers/gpu/drm/lima/lima_sched.c +index e6cefda00279..1602985dfa04 100644 +--- a/drivers/gpu/drm/lima/lima_sched.c ++++ b/drivers/gpu/drm/lima/lima_sched.c +@@ -503,8 +503,9 @@ int lima_sched_pipe_init(struct lima_sched_pipe *pipe, const char *name) + + INIT_WORK(&pipe->recover_work, lima_sched_recover_work); + +- return drm_sched_init(&pipe->base, &lima_sched_ops, 1, 0, +- msecs_to_jiffies(timeout), name); ++ return drm_sched_init(&pipe->base, &lima_sched_ops, 1, ++ lima_job_hang_limit, msecs_to_jiffies(timeout), ++ name); + } + + void lima_sched_pipe_fini(struct lima_sched_pipe *pipe) diff --git a/patch/kernel/rk322x-current/01-linux-0022-drm-from-next.patch b/patch/kernel/rk322x-current/01-linux-0022-drm-from-next.patch new file mode 100644 index 000000000..4cf8cdbe7 --- /dev/null +++ b/patch/kernel/rk322x-current/01-linux-0022-drm-from-next.patch @@ -0,0 +1,1276 @@ +From 055013808487a12514bd6a10d5f1be4267d3cf4a Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Thu, 23 Jul 2020 11:05:50 +0200 +Subject: [PATCH] drm/fourcc: fix Amlogic Video Framebuffer Compression macro + +Fix the Amlogic Video Framebuffer Compression modifier macro to +correctly add the layout options, a pair of parenthesis was missing. + +Fixes: d6528ec88309 ("drm/fourcc: Add modifier definitions for describing Amlogic Video Framebuffer Compression") +Signed-off-by: Neil Armstrong +Acked-by: Sam Ravnborg +Link: https://patchwork.freedesktop.org/patch/msgid/20200723090551.27529-1-narmstrong@baylibre.com +(cherry picked from commit da3a9e9a6aa96ef589c153078f66e0646bf06b55) +--- + include/uapi/drm/drm_fourcc.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/include/uapi/drm/drm_fourcc.h b/include/uapi/drm/drm_fourcc.h +index 4bee7de5f306..82f327801267 100644 +--- a/include/uapi/drm/drm_fourcc.h ++++ b/include/uapi/drm/drm_fourcc.h +@@ -1004,7 +1004,7 @@ drm_fourcc_canonicalize_nvidia_format_mod(__u64 modifier) + #define DRM_FORMAT_MOD_AMLOGIC_FBC(__layout, __options) \ + fourcc_mod_code(AMLOGIC, \ + ((__layout) & __fourcc_mod_amlogic_layout_mask) | \ +- ((__options) & __fourcc_mod_amlogic_options_mask \ ++ (((__options) & __fourcc_mod_amlogic_options_mask) \ + << __fourcc_mod_amlogic_options_shift)) + + /* Amlogic FBC Layouts */ + +From 9df4c74d07ec7d3141b2a243b49de48f3e36932b Mon Sep 17 00:00:00 2001 +From: Tomeu Vizoso +Date: Thu, 11 Jun 2020 10:58:43 +0200 +Subject: [PATCH] drm/panfrost: Make sure GPU is powered on when reading + GPU_LATEST_FLUSH_ID + +Bifrost devices do support the flush reduction feature, so on first job +submit we were trying to read the register while still powered off. + +If the GPU is powered off, the feature doesn't bring any benefit, so +don't try to read. + +Tested-by: Heiko Stuebner +Reviewed-by: Steven Price +Signed-off-by: Tomeu Vizoso +Signed-off-by: Rob Herring +Link: https://patchwork.freedesktop.org/patch/msgid/20200611085900.49740-1-tomeu.vizoso@collabora.com +(cherry picked from commit 3a74265c54f883c847ed8554129baefb3e04f135) +--- + drivers/gpu/drm/panfrost/panfrost_gpu.c | 14 ++++++++++++-- + 1 file changed, 12 insertions(+), 2 deletions(-) + +diff --git a/drivers/gpu/drm/panfrost/panfrost_gpu.c b/drivers/gpu/drm/panfrost/panfrost_gpu.c +index f2c1ddc41a9b..e0f190e43813 100644 +--- a/drivers/gpu/drm/panfrost/panfrost_gpu.c ++++ b/drivers/gpu/drm/panfrost/panfrost_gpu.c +@@ -10,6 +10,7 @@ + #include + #include + #include ++#include + + #include "panfrost_device.h" + #include "panfrost_features.h" +@@ -368,7 +369,16 @@ void panfrost_gpu_fini(struct panfrost_device *pfdev) + + u32 panfrost_gpu_get_latest_flush_id(struct panfrost_device *pfdev) + { +- if (panfrost_has_hw_feature(pfdev, HW_FEATURE_FLUSH_REDUCTION)) +- return gpu_read(pfdev, GPU_LATEST_FLUSH_ID); ++ u32 flush_id; ++ ++ if (panfrost_has_hw_feature(pfdev, HW_FEATURE_FLUSH_REDUCTION)) { ++ /* Flush reduction only makes sense when the GPU is kept powered on between jobs */ ++ if (pm_runtime_get_if_in_use(pfdev->dev)) { ++ flush_id = gpu_read(pfdev, GPU_LATEST_FLUSH_ID); ++ pm_runtime_put(pfdev->dev); ++ return flush_id; ++ } ++ } ++ + return 0; + } + +From 956be03f3fc751937bbb07a4e4201a2a73aa87f1 Mon Sep 17 00:00:00 2001 +From: Tomeu Vizoso +Date: Thu, 11 Jun 2020 10:58:44 +0200 +Subject: [PATCH] drm/panfrost: Add compatible string for bifrost + +Mesa now supports some Bifrost devices, so enable it. + +Tested-by: Heiko Stuebner +Reviewed-by: Steven Price +Reviewed-by: Heiko Stuebner +Signed-off-by: Tomeu Vizoso +Signed-off-by: Rob Herring +Link: https://patchwork.freedesktop.org/patch/msgid/20200611085900.49740-2-tomeu.vizoso@collabora.com +(cherry picked from commit 72ef7fe96fd20d3d0e538e165b393819f99870ad) +--- + drivers/gpu/drm/panfrost/panfrost_drv.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/gpu/drm/panfrost/panfrost_drv.c b/drivers/gpu/drm/panfrost/panfrost_drv.c +index 882fecc33fdb..8ff8e140f91e 100644 +--- a/drivers/gpu/drm/panfrost/panfrost_drv.c ++++ b/drivers/gpu/drm/panfrost/panfrost_drv.c +@@ -677,6 +677,7 @@ static const struct of_device_id dt_match[] = { + { .compatible = "arm,mali-t830", .data = &default_data, }, + { .compatible = "arm,mali-t860", .data = &default_data, }, + { .compatible = "arm,mali-t880", .data = &default_data, }, ++ { .compatible = "arm,mali-bifrost", .data = &default_data, }, + {} + }; + MODULE_DEVICE_TABLE(of, dt_match); + +From 1404f107a58a28fb71227550469c4785fa58081c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Cl=C3=A9ment=20P=C3=A9ron?= +Date: Fri, 10 Jul 2020 11:53:56 +0200 +Subject: [PATCH] drm/panfrost: avoid static declaration +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This declaration can be avoided so change it. + +Reviewed-by: Steven Price +Reviewed-by: Alyssa Rosenzweig +Signed-off-by: Clément Péron +Signed-off-by: Rob Herring +Link: https://patchwork.freedesktop.org/patch/msgid/20200710095409.407087-2-peron.clem@gmail.com +(cherry picked from commit 862cc626210e34501b4d7a7795c41a67785987e5) +--- + drivers/gpu/drm/panfrost/panfrost_devfreq.c | 38 ++++++++++----------- + 1 file changed, 18 insertions(+), 20 deletions(-) + +diff --git a/drivers/gpu/drm/panfrost/panfrost_devfreq.c b/drivers/gpu/drm/panfrost/panfrost_devfreq.c +index 413987038fbf..1b560b903ea6 100644 +--- a/drivers/gpu/drm/panfrost/panfrost_devfreq.c ++++ b/drivers/gpu/drm/panfrost/panfrost_devfreq.c +@@ -14,7 +14,24 @@ + #include "panfrost_gpu.h" + #include "panfrost_regs.h" + +-static void panfrost_devfreq_update_utilization(struct panfrost_device *pfdev); ++static void panfrost_devfreq_update_utilization(struct panfrost_device *pfdev) ++{ ++ ktime_t now; ++ ktime_t last; ++ ++ if (!pfdev->devfreq.devfreq) ++ return; ++ ++ now = ktime_get(); ++ last = pfdev->devfreq.time_last_update; ++ ++ if (atomic_read(&pfdev->devfreq.busy_count) > 0) ++ pfdev->devfreq.busy_time += ktime_sub(now, last); ++ else ++ pfdev->devfreq.idle_time += ktime_sub(now, last); ++ ++ pfdev->devfreq.time_last_update = now; ++} + + static int panfrost_devfreq_target(struct device *dev, unsigned long *freq, + u32 flags) +@@ -139,25 +156,6 @@ void panfrost_devfreq_suspend(struct panfrost_device *pfdev) + devfreq_suspend_device(pfdev->devfreq.devfreq); + } + +-static void panfrost_devfreq_update_utilization(struct panfrost_device *pfdev) +-{ +- ktime_t now; +- ktime_t last; +- +- if (!pfdev->devfreq.devfreq) +- return; +- +- now = ktime_get(); +- last = pfdev->devfreq.time_last_update; +- +- if (atomic_read(&pfdev->devfreq.busy_count) > 0) +- pfdev->devfreq.busy_time += ktime_sub(now, last); +- else +- pfdev->devfreq.idle_time += ktime_sub(now, last); +- +- pfdev->devfreq.time_last_update = now; +-} +- + void panfrost_devfreq_record_busy(struct panfrost_device *pfdev) + { + panfrost_devfreq_update_utilization(pfdev); + +From 42e45c3c4195d8e7ebe5bf970c7da55fc9c0d157 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Cl=C3=A9ment=20P=C3=A9ron?= +Date: Fri, 10 Jul 2020 11:53:57 +0200 +Subject: [PATCH] drm/panfrost: clean headers in devfreq +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Don't include not required headers and sort them. + +Reviewed-by: Steven Price +Reviewed-by: Alyssa Rosenzweig +Signed-off-by: Clément Péron +Signed-off-by: Rob Herring +Link: https://patchwork.freedesktop.org/patch/msgid/20200710095409.407087-3-peron.clem@gmail.com +(cherry picked from commit 9713e942a539c55b5e0bc64ba83b736bda1087fe) +--- + drivers/gpu/drm/panfrost/panfrost_devfreq.c | 8 ++------ + 1 file changed, 2 insertions(+), 6 deletions(-) + +diff --git a/drivers/gpu/drm/panfrost/panfrost_devfreq.c b/drivers/gpu/drm/panfrost/panfrost_devfreq.c +index 1b560b903ea6..df7b71da9a84 100644 +--- a/drivers/gpu/drm/panfrost/panfrost_devfreq.c ++++ b/drivers/gpu/drm/panfrost/panfrost_devfreq.c +@@ -1,18 +1,14 @@ + // SPDX-License-Identifier: GPL-2.0 + /* Copyright 2019 Collabora ltd. */ ++ ++#include + #include + #include + #include + #include +-#include +-#include + + #include "panfrost_device.h" + #include "panfrost_devfreq.h" +-#include "panfrost_features.h" +-#include "panfrost_issues.h" +-#include "panfrost_gpu.h" +-#include "panfrost_regs.h" + + static void panfrost_devfreq_update_utilization(struct panfrost_device *pfdev) + { + +From 99fda3d26b30e5f30d45fc6197da6335a2806e73 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Cl=C3=A9ment=20P=C3=A9ron?= +Date: Fri, 10 Jul 2020 11:53:58 +0200 +Subject: [PATCH] drm/panfrost: don't use pfdevfreq.busy_count to know if hw is + idle +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This use devfreq variable that will be lock with spinlock in future +patches. We should either introduce a function to access this one +but as devfreq is optional let's just remove it. + +Reviewed-by: Steven Price +Reviewed-by: Alyssa Rosenzweig +Signed-off-by: Clément Péron +Signed-off-by: Rob Herring +Link: https://patchwork.freedesktop.org/patch/msgid/20200710095409.407087-4-peron.clem@gmail.com +(cherry picked from commit eb9dd67249b55fd1fa3d7359be387ea2079247a6) +--- + drivers/gpu/drm/panfrost/panfrost_job.c | 4 ---- + 1 file changed, 4 deletions(-) + +diff --git a/drivers/gpu/drm/panfrost/panfrost_job.c b/drivers/gpu/drm/panfrost/panfrost_job.c +index c6242fe34840..aec05be1ba7a 100644 +--- a/drivers/gpu/drm/panfrost/panfrost_job.c ++++ b/drivers/gpu/drm/panfrost/panfrost_job.c +@@ -581,10 +581,6 @@ int panfrost_job_is_idle(struct panfrost_device *pfdev) + struct panfrost_job_slot *js = pfdev->js; + int i; + +- /* Check whether the hardware is idle */ +- if (atomic_read(&pfdev->devfreq.busy_count)) +- return false; +- + for (i = 0; i < NUM_JOB_SLOTS; i++) { + /* If there are any jobs in the HW queue, we're not idle */ + if (atomic_read(&js->queue[i].sched.hw_rq_count)) + +From ca3fb7080e5fbaf5894bed7e119e8f4e49545449 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Cl=C3=A9ment=20P=C3=A9ron?= +Date: Fri, 10 Jul 2020 11:53:59 +0200 +Subject: [PATCH] drm/panfrost: introduce panfrost_devfreq struct +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Introduce a proper panfrost_devfreq to deal with devfreq variables. + +Reviewed-by: Steven Price +Reviewed-by: Alyssa Rosenzweig +Signed-off-by: Clément Péron +Signed-off-by: Rob Herring +Link: https://patchwork.freedesktop.org/patch/msgid/20200710095409.407087-5-peron.clem@gmail.com +(cherry picked from commit 9bfacfc82f903b066b0b63460d5b7943705048a4) +--- + drivers/gpu/drm/panfrost/panfrost_devfreq.c | 76 ++++++++++++--------- + drivers/gpu/drm/panfrost/panfrost_devfreq.h | 20 +++++- + drivers/gpu/drm/panfrost/panfrost_device.h | 11 +-- + drivers/gpu/drm/panfrost/panfrost_job.c | 6 +- + 4 files changed, 66 insertions(+), 47 deletions(-) + +diff --git a/drivers/gpu/drm/panfrost/panfrost_devfreq.c b/drivers/gpu/drm/panfrost/panfrost_devfreq.c +index df7b71da9a84..962550363391 100644 +--- a/drivers/gpu/drm/panfrost/panfrost_devfreq.c ++++ b/drivers/gpu/drm/panfrost/panfrost_devfreq.c +@@ -10,23 +10,23 @@ + #include "panfrost_device.h" + #include "panfrost_devfreq.h" + +-static void panfrost_devfreq_update_utilization(struct panfrost_device *pfdev) ++static void panfrost_devfreq_update_utilization(struct panfrost_devfreq *pfdevfreq) + { + ktime_t now; + ktime_t last; + +- if (!pfdev->devfreq.devfreq) ++ if (!pfdevfreq->devfreq) + return; + + now = ktime_get(); +- last = pfdev->devfreq.time_last_update; ++ last = pfdevfreq->time_last_update; + +- if (atomic_read(&pfdev->devfreq.busy_count) > 0) +- pfdev->devfreq.busy_time += ktime_sub(now, last); ++ if (atomic_read(&pfdevfreq->busy_count) > 0) ++ pfdevfreq->busy_time += ktime_sub(now, last); + else +- pfdev->devfreq.idle_time += ktime_sub(now, last); ++ pfdevfreq->idle_time += ktime_sub(now, last); + +- pfdev->devfreq.time_last_update = now; ++ pfdevfreq->time_last_update = now; + } + + static int panfrost_devfreq_target(struct device *dev, unsigned long *freq, +@@ -47,30 +47,31 @@ static int panfrost_devfreq_target(struct device *dev, unsigned long *freq, + return 0; + } + +-static void panfrost_devfreq_reset(struct panfrost_device *pfdev) ++static void panfrost_devfreq_reset(struct panfrost_devfreq *pfdevfreq) + { +- pfdev->devfreq.busy_time = 0; +- pfdev->devfreq.idle_time = 0; +- pfdev->devfreq.time_last_update = ktime_get(); ++ pfdevfreq->busy_time = 0; ++ pfdevfreq->idle_time = 0; ++ pfdevfreq->time_last_update = ktime_get(); + } + + static int panfrost_devfreq_get_dev_status(struct device *dev, + struct devfreq_dev_status *status) + { + struct panfrost_device *pfdev = dev_get_drvdata(dev); ++ struct panfrost_devfreq *pfdevfreq = &pfdev->pfdevfreq; + +- panfrost_devfreq_update_utilization(pfdev); ++ panfrost_devfreq_update_utilization(pfdevfreq); + + status->current_frequency = clk_get_rate(pfdev->clock); +- status->total_time = ktime_to_ns(ktime_add(pfdev->devfreq.busy_time, +- pfdev->devfreq.idle_time)); ++ status->total_time = ktime_to_ns(ktime_add(pfdevfreq->busy_time, ++ pfdevfreq->idle_time)); + +- status->busy_time = ktime_to_ns(pfdev->devfreq.busy_time); ++ status->busy_time = ktime_to_ns(pfdevfreq->busy_time); + +- panfrost_devfreq_reset(pfdev); ++ panfrost_devfreq_reset(pfdevfreq); + +- dev_dbg(pfdev->dev, "busy %lu total %lu %lu %% freq %lu MHz\n", status->busy_time, +- status->total_time, ++ dev_dbg(pfdev->dev, "busy %lu total %lu %lu %% freq %lu MHz\n", ++ status->busy_time, status->total_time, + status->busy_time / (status->total_time / 100), + status->current_frequency / 1000 / 1000); + +@@ -91,6 +92,7 @@ int panfrost_devfreq_init(struct panfrost_device *pfdev) + struct device *dev = &pfdev->pdev->dev; + struct devfreq *devfreq; + struct thermal_cooling_device *cooling; ++ struct panfrost_devfreq *pfdevfreq = &pfdev->pfdevfreq; + + ret = dev_pm_opp_of_add_table(dev); + if (ret == -ENODEV) /* Optional, continue without devfreq */ +@@ -98,7 +100,7 @@ int panfrost_devfreq_init(struct panfrost_device *pfdev) + else if (ret) + return ret; + +- panfrost_devfreq_reset(pfdev); ++ panfrost_devfreq_reset(pfdevfreq); + + cur_freq = clk_get_rate(pfdev->clock); + +@@ -116,53 +118,59 @@ int panfrost_devfreq_init(struct panfrost_device *pfdev) + dev_pm_opp_of_remove_table(dev); + return PTR_ERR(devfreq); + } +- pfdev->devfreq.devfreq = devfreq; ++ pfdevfreq->devfreq = devfreq; + + cooling = of_devfreq_cooling_register(dev->of_node, devfreq); + if (IS_ERR(cooling)) + DRM_DEV_INFO(dev, "Failed to register cooling device\n"); + else +- pfdev->devfreq.cooling = cooling; ++ pfdevfreq->cooling = cooling; + + return 0; + } + + void panfrost_devfreq_fini(struct panfrost_device *pfdev) + { +- if (pfdev->devfreq.cooling) +- devfreq_cooling_unregister(pfdev->devfreq.cooling); ++ struct panfrost_devfreq *pfdevfreq = &pfdev->pfdevfreq; ++ ++ if (pfdevfreq->cooling) ++ devfreq_cooling_unregister(pfdevfreq->cooling); + dev_pm_opp_of_remove_table(&pfdev->pdev->dev); + } + + void panfrost_devfreq_resume(struct panfrost_device *pfdev) + { +- if (!pfdev->devfreq.devfreq) ++ struct panfrost_devfreq *pfdevfreq = &pfdev->pfdevfreq; ++ ++ if (!pfdevfreq->devfreq) + return; + +- panfrost_devfreq_reset(pfdev); ++ panfrost_devfreq_reset(pfdevfreq); + +- devfreq_resume_device(pfdev->devfreq.devfreq); ++ devfreq_resume_device(pfdevfreq->devfreq); + } + + void panfrost_devfreq_suspend(struct panfrost_device *pfdev) + { +- if (!pfdev->devfreq.devfreq) ++ struct panfrost_devfreq *pfdevfreq = &pfdev->pfdevfreq; ++ ++ if (!pfdevfreq->devfreq) + return; + +- devfreq_suspend_device(pfdev->devfreq.devfreq); ++ devfreq_suspend_device(pfdevfreq->devfreq); + } + +-void panfrost_devfreq_record_busy(struct panfrost_device *pfdev) ++void panfrost_devfreq_record_busy(struct panfrost_devfreq *pfdevfreq) + { +- panfrost_devfreq_update_utilization(pfdev); +- atomic_inc(&pfdev->devfreq.busy_count); ++ panfrost_devfreq_update_utilization(pfdevfreq); ++ atomic_inc(&pfdevfreq->busy_count); + } + +-void panfrost_devfreq_record_idle(struct panfrost_device *pfdev) ++void panfrost_devfreq_record_idle(struct panfrost_devfreq *pfdevfreq) + { + int count; + +- panfrost_devfreq_update_utilization(pfdev); +- count = atomic_dec_if_positive(&pfdev->devfreq.busy_count); ++ panfrost_devfreq_update_utilization(pfdevfreq); ++ count = atomic_dec_if_positive(&pfdevfreq->busy_count); + WARN_ON(count < 0); + } +diff --git a/drivers/gpu/drm/panfrost/panfrost_devfreq.h b/drivers/gpu/drm/panfrost/panfrost_devfreq.h +index 0611beffc8d0..0697f8d5aa34 100644 +--- a/drivers/gpu/drm/panfrost/panfrost_devfreq.h ++++ b/drivers/gpu/drm/panfrost/panfrost_devfreq.h +@@ -4,13 +4,29 @@ + #ifndef __PANFROST_DEVFREQ_H__ + #define __PANFROST_DEVFREQ_H__ + ++#include ++ ++struct devfreq; ++struct thermal_cooling_device; ++ ++struct panfrost_device; ++ ++struct panfrost_devfreq { ++ struct devfreq *devfreq; ++ struct thermal_cooling_device *cooling; ++ ktime_t busy_time; ++ ktime_t idle_time; ++ ktime_t time_last_update; ++ atomic_t busy_count; ++}; ++ + int panfrost_devfreq_init(struct panfrost_device *pfdev); + void panfrost_devfreq_fini(struct panfrost_device *pfdev); + + void panfrost_devfreq_resume(struct panfrost_device *pfdev); + void panfrost_devfreq_suspend(struct panfrost_device *pfdev); + +-void panfrost_devfreq_record_busy(struct panfrost_device *pfdev); +-void panfrost_devfreq_record_idle(struct panfrost_device *pfdev); ++void panfrost_devfreq_record_busy(struct panfrost_devfreq *devfreq); ++void panfrost_devfreq_record_idle(struct panfrost_devfreq *devfreq); + + #endif /* __PANFROST_DEVFREQ_H__ */ +diff --git a/drivers/gpu/drm/panfrost/panfrost_device.h b/drivers/gpu/drm/panfrost/panfrost_device.h +index c30c719a8059..2efa59c9d1c5 100644 +--- a/drivers/gpu/drm/panfrost/panfrost_device.h ++++ b/drivers/gpu/drm/panfrost/panfrost_device.h +@@ -13,6 +13,8 @@ + #include + #include + ++#include "panfrost_devfreq.h" ++ + struct panfrost_device; + struct panfrost_mmu; + struct panfrost_job_slot; +@@ -107,14 +109,7 @@ struct panfrost_device { + struct list_head shrinker_list; + struct shrinker shrinker; + +- struct { +- struct devfreq *devfreq; +- struct thermal_cooling_device *cooling; +- ktime_t busy_time; +- ktime_t idle_time; +- ktime_t time_last_update; +- atomic_t busy_count; +- } devfreq; ++ struct panfrost_devfreq pfdevfreq; + }; + + struct panfrost_mmu { +diff --git a/drivers/gpu/drm/panfrost/panfrost_job.c b/drivers/gpu/drm/panfrost/panfrost_job.c +index aec05be1ba7a..2f297d962e64 100644 +--- a/drivers/gpu/drm/panfrost/panfrost_job.c ++++ b/drivers/gpu/drm/panfrost/panfrost_job.c +@@ -145,7 +145,7 @@ static void panfrost_job_hw_submit(struct panfrost_job *job, int js) + u64 jc_head = job->jc; + int ret; + +- panfrost_devfreq_record_busy(pfdev); ++ panfrost_devfreq_record_busy(&pfdev->pfdevfreq); + + ret = pm_runtime_get_sync(pfdev->dev); + if (ret < 0) +@@ -410,7 +410,7 @@ static void panfrost_job_timedout(struct drm_sched_job *sched_job) + for (i = 0; i < NUM_JOB_SLOTS; i++) { + if (pfdev->jobs[i]) { + pm_runtime_put_noidle(pfdev->dev); +- panfrost_devfreq_record_idle(pfdev); ++ panfrost_devfreq_record_idle(&pfdev->pfdevfreq); + pfdev->jobs[i] = NULL; + } + } +@@ -478,7 +478,7 @@ static irqreturn_t panfrost_job_irq_handler(int irq, void *data) + pfdev->jobs[j] = NULL; + + panfrost_mmu_as_put(pfdev, &job->file_priv->mmu); +- panfrost_devfreq_record_idle(pfdev); ++ panfrost_devfreq_record_idle(&pfdev->pfdevfreq); + + dma_fence_signal_locked(job->done_fence); + pm_runtime_put_autosuspend(pfdev->dev); + +From 950ed8f4f8c6ab02e5f1c7b107e5af9a896c90dc Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Cl=C3=A9ment=20P=C3=A9ron?= +Date: Fri, 10 Jul 2020 11:54:00 +0200 +Subject: [PATCH] drm/panfrost: use spinlock instead of atomic +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Convert busy_count to a simple int protected by spinlock. + +Reviewed-by: Steven Price +Reviewed-by: Alyssa Rosenzweig +Signed-off-by: Clément Péron +Signed-off-by: Rob Herring +Link: https://patchwork.freedesktop.org/patch/msgid/20200710095409.407087-6-peron.clem@gmail.com +(cherry picked from commit ed85df3f60740bb4be23fbc2db283d59b361a834) +--- + drivers/gpu/drm/panfrost/panfrost_devfreq.c | 43 +++++++++++++++------ + drivers/gpu/drm/panfrost/panfrost_devfreq.h | 9 ++++- + 2 files changed, 40 insertions(+), 12 deletions(-) + +diff --git a/drivers/gpu/drm/panfrost/panfrost_devfreq.c b/drivers/gpu/drm/panfrost/panfrost_devfreq.c +index 962550363391..78753cfb59fb 100644 +--- a/drivers/gpu/drm/panfrost/panfrost_devfreq.c ++++ b/drivers/gpu/drm/panfrost/panfrost_devfreq.c +@@ -12,16 +12,12 @@ + + static void panfrost_devfreq_update_utilization(struct panfrost_devfreq *pfdevfreq) + { +- ktime_t now; +- ktime_t last; +- +- if (!pfdevfreq->devfreq) +- return; ++ ktime_t now, last; + + now = ktime_get(); + last = pfdevfreq->time_last_update; + +- if (atomic_read(&pfdevfreq->busy_count) > 0) ++ if (pfdevfreq->busy_count > 0) + pfdevfreq->busy_time += ktime_sub(now, last); + else + pfdevfreq->idle_time += ktime_sub(now, last); +@@ -59,10 +55,14 @@ static int panfrost_devfreq_get_dev_status(struct device *dev, + { + struct panfrost_device *pfdev = dev_get_drvdata(dev); + struct panfrost_devfreq *pfdevfreq = &pfdev->pfdevfreq; ++ unsigned long irqflags; ++ ++ status->current_frequency = clk_get_rate(pfdev->clock); ++ ++ spin_lock_irqsave(&pfdevfreq->lock, irqflags); + + panfrost_devfreq_update_utilization(pfdevfreq); + +- status->current_frequency = clk_get_rate(pfdev->clock); + status->total_time = ktime_to_ns(ktime_add(pfdevfreq->busy_time, + pfdevfreq->idle_time)); + +@@ -70,6 +70,8 @@ static int panfrost_devfreq_get_dev_status(struct device *dev, + + panfrost_devfreq_reset(pfdevfreq); + ++ spin_unlock_irqrestore(&pfdevfreq->lock, irqflags); ++ + dev_dbg(pfdev->dev, "busy %lu total %lu %lu %% freq %lu MHz\n", + status->busy_time, status->total_time, + status->busy_time / (status->total_time / 100), +@@ -100,6 +102,8 @@ int panfrost_devfreq_init(struct panfrost_device *pfdev) + else if (ret) + return ret; + ++ spin_lock_init(&pfdevfreq->lock); ++ + panfrost_devfreq_reset(pfdevfreq); + + cur_freq = clk_get_rate(pfdev->clock); +@@ -162,15 +166,32 @@ void panfrost_devfreq_suspend(struct panfrost_device *pfdev) + + void panfrost_devfreq_record_busy(struct panfrost_devfreq *pfdevfreq) + { ++ unsigned long irqflags; ++ ++ if (!pfdevfreq->devfreq) ++ return; ++ ++ spin_lock_irqsave(&pfdevfreq->lock, irqflags); ++ + panfrost_devfreq_update_utilization(pfdevfreq); +- atomic_inc(&pfdevfreq->busy_count); ++ ++ pfdevfreq->busy_count++; ++ ++ spin_unlock_irqrestore(&pfdevfreq->lock, irqflags); + } + + void panfrost_devfreq_record_idle(struct panfrost_devfreq *pfdevfreq) + { +- int count; ++ unsigned long irqflags; ++ ++ if (!pfdevfreq->devfreq) ++ return; ++ ++ spin_lock_irqsave(&pfdevfreq->lock, irqflags); + + panfrost_devfreq_update_utilization(pfdevfreq); +- count = atomic_dec_if_positive(&pfdevfreq->busy_count); +- WARN_ON(count < 0); ++ ++ WARN_ON(--pfdevfreq->busy_count < 0); ++ ++ spin_unlock_irqrestore(&pfdevfreq->lock, irqflags); + } +diff --git a/drivers/gpu/drm/panfrost/panfrost_devfreq.h b/drivers/gpu/drm/panfrost/panfrost_devfreq.h +index 0697f8d5aa34..3392df1020be 100644 +--- a/drivers/gpu/drm/panfrost/panfrost_devfreq.h ++++ b/drivers/gpu/drm/panfrost/panfrost_devfreq.h +@@ -4,6 +4,7 @@ + #ifndef __PANFROST_DEVFREQ_H__ + #define __PANFROST_DEVFREQ_H__ + ++#include + #include + + struct devfreq; +@@ -14,10 +15,16 @@ struct panfrost_device; + struct panfrost_devfreq { + struct devfreq *devfreq; + struct thermal_cooling_device *cooling; ++ + ktime_t busy_time; + ktime_t idle_time; + ktime_t time_last_update; +- atomic_t busy_count; ++ int busy_count; ++ /* ++ * Protect busy_time, idle_time, time_last_update and busy_count ++ * because these can be updated concurrently between multiple jobs. ++ */ ++ spinlock_t lock; + }; + + int panfrost_devfreq_init(struct panfrost_device *pfdev); + +From ac548872c7b7887d34b549efa3b8334b2cc862ed Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Cl=C3=A9ment=20P=C3=A9ron?= +Date: Fri, 10 Jul 2020 11:54:01 +0200 +Subject: [PATCH] drm/panfrost: properly handle error in probe +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Introduce a boolean to know if opp table has been added. + +With this, we can call panfrost_devfreq_fini() in case of error +and release what has been initialised. + +Reviewed-by: Steven Price +Reviewed-by: Alyssa Rosenzweig +Signed-off-by: Clément Péron +Signed-off-by: Rob Herring +Link: https://patchwork.freedesktop.org/patch/msgid/20200710095409.407087-7-peron.clem@gmail.com +(cherry picked from commit 81f2fbe62cb54b6cf3d91078c4d49451ba7b9877) +--- + drivers/gpu/drm/panfrost/panfrost_devfreq.c | 25 ++++++++++++++++----- + drivers/gpu/drm/panfrost/panfrost_devfreq.h | 1 + + 2 files changed, 20 insertions(+), 6 deletions(-) + +diff --git a/drivers/gpu/drm/panfrost/panfrost_devfreq.c b/drivers/gpu/drm/panfrost/panfrost_devfreq.c +index 78753cfb59fb..d9007f44b772 100644 +--- a/drivers/gpu/drm/panfrost/panfrost_devfreq.c ++++ b/drivers/gpu/drm/panfrost/panfrost_devfreq.c +@@ -101,6 +101,7 @@ int panfrost_devfreq_init(struct panfrost_device *pfdev) + return 0; + else if (ret) + return ret; ++ pfdevfreq->opp_of_table_added = true; + + spin_lock_init(&pfdevfreq->lock); + +@@ -109,8 +110,10 @@ int panfrost_devfreq_init(struct panfrost_device *pfdev) + cur_freq = clk_get_rate(pfdev->clock); + + opp = devfreq_recommended_opp(dev, &cur_freq, 0); +- if (IS_ERR(opp)) +- return PTR_ERR(opp); ++ if (IS_ERR(opp)) { ++ ret = PTR_ERR(opp); ++ goto err_fini; ++ } + + panfrost_devfreq_profile.initial_freq = cur_freq; + dev_pm_opp_put(opp); +@@ -119,8 +122,8 @@ int panfrost_devfreq_init(struct panfrost_device *pfdev) + DEVFREQ_GOV_SIMPLE_ONDEMAND, NULL); + if (IS_ERR(devfreq)) { + DRM_DEV_ERROR(dev, "Couldn't initialize GPU devfreq\n"); +- dev_pm_opp_of_remove_table(dev); +- return PTR_ERR(devfreq); ++ ret = PTR_ERR(devfreq); ++ goto err_fini; + } + pfdevfreq->devfreq = devfreq; + +@@ -131,15 +134,25 @@ int panfrost_devfreq_init(struct panfrost_device *pfdev) + pfdevfreq->cooling = cooling; + + return 0; ++ ++err_fini: ++ panfrost_devfreq_fini(pfdev); ++ return ret; + } + + void panfrost_devfreq_fini(struct panfrost_device *pfdev) + { + struct panfrost_devfreq *pfdevfreq = &pfdev->pfdevfreq; + +- if (pfdevfreq->cooling) ++ if (pfdevfreq->cooling) { + devfreq_cooling_unregister(pfdevfreq->cooling); +- dev_pm_opp_of_remove_table(&pfdev->pdev->dev); ++ pfdevfreq->cooling = NULL; ++ } ++ ++ if (pfdevfreq->opp_of_table_added) { ++ dev_pm_opp_of_remove_table(&pfdev->pdev->dev); ++ pfdevfreq->opp_of_table_added = false; ++ } + } + + void panfrost_devfreq_resume(struct panfrost_device *pfdev) +diff --git a/drivers/gpu/drm/panfrost/panfrost_devfreq.h b/drivers/gpu/drm/panfrost/panfrost_devfreq.h +index 3392df1020be..210269944687 100644 +--- a/drivers/gpu/drm/panfrost/panfrost_devfreq.h ++++ b/drivers/gpu/drm/panfrost/panfrost_devfreq.h +@@ -15,6 +15,7 @@ struct panfrost_device; + struct panfrost_devfreq { + struct devfreq *devfreq; + struct thermal_cooling_device *cooling; ++ bool opp_of_table_added; + + ktime_t busy_time; + ktime_t idle_time; + +From 96a752deaead8b45cd188cde09cb873fd8dfd4b6 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Cl=C3=A9ment=20P=C3=A9ron?= +Date: Fri, 10 Jul 2020 11:54:02 +0200 +Subject: [PATCH] drm/panfrost: rename error labels in device_init +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Rename goto labels in device_init it will be easier to maintain. + +Reviewed-by: Alyssa Rosenzweig +Reviewed-by: Steven Price +Signed-off-by: Clément Péron +Signed-off-by: Rob Herring +Link: https://patchwork.freedesktop.org/patch/msgid/20200710095409.407087-8-peron.clem@gmail.com +(cherry picked from commit d3c335da0200be9287cdf5755d19f62ce1670a8d) +--- + drivers/gpu/drm/panfrost/panfrost_device.c | 30 +++++++++++----------- + 1 file changed, 15 insertions(+), 15 deletions(-) + +diff --git a/drivers/gpu/drm/panfrost/panfrost_device.c b/drivers/gpu/drm/panfrost/panfrost_device.c +index b172087eee6a..9f89984f652a 100644 +--- a/drivers/gpu/drm/panfrost/panfrost_device.c ++++ b/drivers/gpu/drm/panfrost/panfrost_device.c +@@ -216,56 +216,56 @@ int panfrost_device_init(struct panfrost_device *pfdev) + + err = panfrost_regulator_init(pfdev); + if (err) +- goto err_out0; ++ goto out_clk; + + err = panfrost_reset_init(pfdev); + if (err) { + dev_err(pfdev->dev, "reset init failed %d\n", err); +- goto err_out1; ++ goto out_regulator; + } + + err = panfrost_pm_domain_init(pfdev); + if (err) +- goto err_out2; ++ goto out_reset; + + res = platform_get_resource(pfdev->pdev, IORESOURCE_MEM, 0); + pfdev->iomem = devm_ioremap_resource(pfdev->dev, res); + if (IS_ERR(pfdev->iomem)) { + dev_err(pfdev->dev, "failed to ioremap iomem\n"); + err = PTR_ERR(pfdev->iomem); +- goto err_out3; ++ goto out_pm_domain; + } + + err = panfrost_gpu_init(pfdev); + if (err) +- goto err_out3; ++ goto out_pm_domain; + + err = panfrost_mmu_init(pfdev); + if (err) +- goto err_out4; ++ goto out_gpu; + + err = panfrost_job_init(pfdev); + if (err) +- goto err_out5; ++ goto out_mmu; + + err = panfrost_perfcnt_init(pfdev); + if (err) +- goto err_out6; ++ goto out_job; + + return 0; +-err_out6: ++out_job: + panfrost_job_fini(pfdev); +-err_out5: ++out_mmu: + panfrost_mmu_fini(pfdev); +-err_out4: ++out_gpu: + panfrost_gpu_fini(pfdev); +-err_out3: ++out_pm_domain: + panfrost_pm_domain_fini(pfdev); +-err_out2: ++out_reset: + panfrost_reset_fini(pfdev); +-err_out1: ++out_regulator: + panfrost_regulator_fini(pfdev); +-err_out0: ++out_clk: + panfrost_clk_fini(pfdev); + return err; + } + +From 9c803e01258f241d49e1162ca6db5b29a98ba57d Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Cl=C3=A9ment=20P=C3=A9ron?= +Date: Fri, 10 Jul 2020 11:54:03 +0200 +Subject: [PATCH] drm/panfrost: move devfreq_init()/fini() in device +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Later we will introduce devfreq probing regulator if they +are present. As regulator should be probe only one time we +need to get this logic in the device_init(). + +panfrost_device is already taking care of devfreq_resume() +and devfreq_suspend(), so it's not totally illogic to move +the devfreq_init() and devfreq_fini() here. + +Reviewed-by: Alyssa Rosenzweig +Reviewed-by: Steven Price +Signed-off-by: Clément Péron +Signed-off-by: Rob Herring +Link: https://patchwork.freedesktop.org/patch/msgid/20200710095409.407087-9-peron.clem@gmail.com +(cherry picked from commit 25e247bbf85af3ad721dfeb2e2caf405f43b7e66) +--- + drivers/gpu/drm/panfrost/panfrost_device.c | 12 +++++++++++- + drivers/gpu/drm/panfrost/panfrost_drv.c | 15 ++------------- + 2 files changed, 13 insertions(+), 14 deletions(-) + +diff --git a/drivers/gpu/drm/panfrost/panfrost_device.c b/drivers/gpu/drm/panfrost/panfrost_device.c +index 9f89984f652a..36b5c8fea3eb 100644 +--- a/drivers/gpu/drm/panfrost/panfrost_device.c ++++ b/drivers/gpu/drm/panfrost/panfrost_device.c +@@ -214,9 +214,16 @@ int panfrost_device_init(struct panfrost_device *pfdev) + return err; + } + ++ err = panfrost_devfreq_init(pfdev); ++ if (err) { ++ if (err != -EPROBE_DEFER) ++ dev_err(pfdev->dev, "devfreq init failed %d\n", err); ++ goto out_clk; ++ } ++ + err = panfrost_regulator_init(pfdev); + if (err) +- goto out_clk; ++ goto out_devfreq; + + err = panfrost_reset_init(pfdev); + if (err) { +@@ -265,6 +272,8 @@ int panfrost_device_init(struct panfrost_device *pfdev) + panfrost_reset_fini(pfdev); + out_regulator: + panfrost_regulator_fini(pfdev); ++out_devfreq: ++ panfrost_devfreq_fini(pfdev); + out_clk: + panfrost_clk_fini(pfdev); + return err; +@@ -278,6 +287,7 @@ void panfrost_device_fini(struct panfrost_device *pfdev) + panfrost_gpu_fini(pfdev); + panfrost_pm_domain_fini(pfdev); + panfrost_reset_fini(pfdev); ++ panfrost_devfreq_fini(pfdev); + panfrost_regulator_fini(pfdev); + panfrost_clk_fini(pfdev); + } +diff --git a/drivers/gpu/drm/panfrost/panfrost_drv.c b/drivers/gpu/drm/panfrost/panfrost_drv.c +index 8ff8e140f91e..ed8bcdd6b211 100644 +--- a/drivers/gpu/drm/panfrost/panfrost_drv.c ++++ b/drivers/gpu/drm/panfrost/panfrost_drv.c +@@ -14,7 +14,6 @@ + #include + + #include "panfrost_device.h" +-#include "panfrost_devfreq.h" + #include "panfrost_gem.h" + #include "panfrost_mmu.h" + #include "panfrost_job.h" +@@ -606,13 +605,6 @@ static int panfrost_probe(struct platform_device *pdev) + goto err_out0; + } + +- err = panfrost_devfreq_init(pfdev); +- if (err) { +- if (err != -EPROBE_DEFER) +- dev_err(&pdev->dev, "Fatal error during devfreq init\n"); +- goto err_out1; +- } +- + pm_runtime_set_active(pfdev->dev); + pm_runtime_mark_last_busy(pfdev->dev); + pm_runtime_enable(pfdev->dev); +@@ -625,16 +617,14 @@ static int panfrost_probe(struct platform_device *pdev) + */ + err = drm_dev_register(ddev, 0); + if (err < 0) +- goto err_out2; ++ goto err_out1; + + panfrost_gem_shrinker_init(ddev); + + return 0; + +-err_out2: +- pm_runtime_disable(pfdev->dev); +- panfrost_devfreq_fini(pfdev); + err_out1: ++ pm_runtime_disable(pfdev->dev); + panfrost_device_fini(pfdev); + err_out0: + drm_dev_put(ddev); +@@ -650,7 +640,6 @@ static int panfrost_remove(struct platform_device *pdev) + panfrost_gem_shrinker_cleanup(ddev); + + pm_runtime_get_sync(pfdev->dev); +- panfrost_devfreq_fini(pfdev); + panfrost_device_fini(pfdev); + pm_runtime_put_sync_suspend(pfdev->dev); + pm_runtime_disable(pfdev->dev); + +From d858649520907e147d85147efb8cfdb280ee5852 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Cl=C3=A9ment=20P=C3=A9ron?= +Date: Fri, 10 Jul 2020 11:54:04 +0200 +Subject: [PATCH] drm/panfrost: dynamically alloc regulators +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +We will later introduce regulators managed by OPP. + +Only alloc regulators when it's needed. This also help use +to release the regulators only when they are allocated. + +Reviewed-by: Steven Price +Reviewed-by: Alyssa Rosenzweig +Signed-off-by: Clément Péron +Signed-off-by: Rob Herring +Link: https://patchwork.freedesktop.org/patch/msgid/20200710095409.407087-10-peron.clem@gmail.com +(cherry picked from commit 512f21227fd3d2dbe7aad57a995b9732229c9b56) +--- + drivers/gpu/drm/panfrost/panfrost_device.c | 14 +++++++++----- + drivers/gpu/drm/panfrost/panfrost_device.h | 3 +-- + 2 files changed, 10 insertions(+), 7 deletions(-) + +diff --git a/drivers/gpu/drm/panfrost/panfrost_device.c b/drivers/gpu/drm/panfrost/panfrost_device.c +index 36b5c8fea3eb..f1474b961def 100644 +--- a/drivers/gpu/drm/panfrost/panfrost_device.c ++++ b/drivers/gpu/drm/panfrost/panfrost_device.c +@@ -90,9 +90,11 @@ static int panfrost_regulator_init(struct panfrost_device *pfdev) + { + int ret, i; + +- if (WARN(pfdev->comp->num_supplies > ARRAY_SIZE(pfdev->regulators), +- "Too many supplies in compatible structure.\n")) +- return -EINVAL; ++ pfdev->regulators = devm_kcalloc(pfdev->dev, pfdev->comp->num_supplies, ++ sizeof(*pfdev->regulators), ++ GFP_KERNEL); ++ if (!pfdev->regulators) ++ return -ENOMEM; + + for (i = 0; i < pfdev->comp->num_supplies; i++) + pfdev->regulators[i].supply = pfdev->comp->supply_names[i]; +@@ -119,8 +121,10 @@ static int panfrost_regulator_init(struct panfrost_device *pfdev) + + static void panfrost_regulator_fini(struct panfrost_device *pfdev) + { +- regulator_bulk_disable(pfdev->comp->num_supplies, +- pfdev->regulators); ++ if (!pfdev->regulators) ++ return; ++ ++ regulator_bulk_disable(pfdev->comp->num_supplies, pfdev->regulators); + } + + static void panfrost_pm_domain_fini(struct panfrost_device *pfdev) +diff --git a/drivers/gpu/drm/panfrost/panfrost_device.h b/drivers/gpu/drm/panfrost/panfrost_device.h +index 2efa59c9d1c5..953f7536a773 100644 +--- a/drivers/gpu/drm/panfrost/panfrost_device.h ++++ b/drivers/gpu/drm/panfrost/panfrost_device.h +@@ -22,7 +22,6 @@ struct panfrost_job; + struct panfrost_perfcnt; + + #define NUM_JOB_SLOTS 3 +-#define MAX_REGULATORS 2 + #define MAX_PM_DOMAINS 3 + + struct panfrost_features { +@@ -81,7 +80,7 @@ struct panfrost_device { + void __iomem *iomem; + struct clk *clock; + struct clk *bus_clock; +- struct regulator_bulk_data regulators[MAX_REGULATORS]; ++ struct regulator_bulk_data *regulators; + struct reset_control *rstc; + /* pm_domains for devices with more than one. */ + struct device *pm_domain_devs[MAX_PM_DOMAINS]; + +From 1ee7aed7c3c6736b33828d488a6d29bd8f0e0e84 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Cl=C3=A9ment=20P=C3=A9ron?= +Date: Fri, 10 Jul 2020 11:54:05 +0200 +Subject: [PATCH] drm/panfrost: add regulators to devfreq +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Some OPP tables specify voltage for each frequency. Devfreq can +handle these regulators but they should be get only 1 time to avoid +issue and know who is in charge. + +If OPP table is probe don't init regulator. + +Reviewed-by: Steven Price +Reviewed-by: Alyssa Rosenzweig +Signed-off-by: Clément Péron +Signed-off-by: Rob Herring +Link: https://patchwork.freedesktop.org/patch/msgid/20200710095409.407087-11-peron.clem@gmail.com +(cherry picked from commit fd587ff01d59554144e2fd20f4113638a45c7c4e) +--- + drivers/gpu/drm/panfrost/panfrost_devfreq.c | 29 ++++++++++++++++++--- + drivers/gpu/drm/panfrost/panfrost_devfreq.h | 2 ++ + drivers/gpu/drm/panfrost/panfrost_device.c | 9 ++++--- + 3 files changed, 33 insertions(+), 7 deletions(-) + +diff --git a/drivers/gpu/drm/panfrost/panfrost_devfreq.c b/drivers/gpu/drm/panfrost/panfrost_devfreq.c +index d9007f44b772..8ab025d0035f 100644 +--- a/drivers/gpu/drm/panfrost/panfrost_devfreq.c ++++ b/drivers/gpu/drm/panfrost/panfrost_devfreq.c +@@ -93,14 +93,30 @@ int panfrost_devfreq_init(struct panfrost_device *pfdev) + unsigned long cur_freq; + struct device *dev = &pfdev->pdev->dev; + struct devfreq *devfreq; ++ struct opp_table *opp_table; + struct thermal_cooling_device *cooling; + struct panfrost_devfreq *pfdevfreq = &pfdev->pfdevfreq; + ++ opp_table = dev_pm_opp_set_regulators(dev, pfdev->comp->supply_names, ++ pfdev->comp->num_supplies); ++ if (IS_ERR(opp_table)) { ++ ret = PTR_ERR(opp_table); ++ /* Continue if the optional regulator is missing */ ++ if (ret != -ENODEV) { ++ DRM_DEV_ERROR(dev, "Couldn't set OPP regulators\n"); ++ goto err_fini; ++ } ++ } else { ++ pfdevfreq->regulators_opp_table = opp_table; ++ } ++ + ret = dev_pm_opp_of_add_table(dev); +- if (ret == -ENODEV) /* Optional, continue without devfreq */ +- return 0; +- else if (ret) +- return ret; ++ if (ret) { ++ /* Optional, continue without devfreq */ ++ if (ret == -ENODEV) ++ ret = 0; ++ goto err_fini; ++ } + pfdevfreq->opp_of_table_added = true; + + spin_lock_init(&pfdevfreq->lock); +@@ -153,6 +169,11 @@ void panfrost_devfreq_fini(struct panfrost_device *pfdev) + dev_pm_opp_of_remove_table(&pfdev->pdev->dev); + pfdevfreq->opp_of_table_added = false; + } ++ ++ if (pfdevfreq->regulators_opp_table) { ++ dev_pm_opp_put_regulators(pfdevfreq->regulators_opp_table); ++ pfdevfreq->regulators_opp_table = NULL; ++ } + } + + void panfrost_devfreq_resume(struct panfrost_device *pfdev) +diff --git a/drivers/gpu/drm/panfrost/panfrost_devfreq.h b/drivers/gpu/drm/panfrost/panfrost_devfreq.h +index 210269944687..db6ea48e21f9 100644 +--- a/drivers/gpu/drm/panfrost/panfrost_devfreq.h ++++ b/drivers/gpu/drm/panfrost/panfrost_devfreq.h +@@ -8,12 +8,14 @@ + #include + + struct devfreq; ++struct opp_table; + struct thermal_cooling_device; + + struct panfrost_device; + + struct panfrost_devfreq { + struct devfreq *devfreq; ++ struct opp_table *regulators_opp_table; + struct thermal_cooling_device *cooling; + bool opp_of_table_added; + +diff --git a/drivers/gpu/drm/panfrost/panfrost_device.c b/drivers/gpu/drm/panfrost/panfrost_device.c +index f1474b961def..e6896733838a 100644 +--- a/drivers/gpu/drm/panfrost/panfrost_device.c ++++ b/drivers/gpu/drm/panfrost/panfrost_device.c +@@ -225,9 +225,12 @@ int panfrost_device_init(struct panfrost_device *pfdev) + goto out_clk; + } + +- err = panfrost_regulator_init(pfdev); +- if (err) +- goto out_devfreq; ++ /* OPP will handle regulators */ ++ if (!pfdev->pfdevfreq.opp_of_table_added) { ++ err = panfrost_regulator_init(pfdev); ++ if (err) ++ goto out_devfreq; ++ } + + err = panfrost_reset_init(pfdev); + if (err) { + +From 94b3398f3b4d5e963f284bd39515bfdf84530c6c Mon Sep 17 00:00:00 2001 +From: Navid Emamdoost +Date: Sun, 14 Jun 2020 01:36:19 -0500 +Subject: [PATCH] drm/panfrost: perfcnt: fix ref count leak in + panfrost_perfcnt_enable_locked + +in panfrost_perfcnt_enable_locked, pm_runtime_get_sync is called which +increments the counter even in case of failure, leading to incorrect +ref count. In case of failure, decrement the ref count before returning. + +Acked-by: Alyssa Rosenzweig +Signed-off-by: Navid Emamdoost +Signed-off-by: Rob Herring +Link: https://patchwork.freedesktop.org/patch/msgid/20200614063619.44944-1-navid.emamdoost@gmail.com +(cherry picked from commit 9df0e0c1889677175037445d5ad1654d54176369) +--- + drivers/gpu/drm/panfrost/panfrost_perfcnt.c | 10 +++++++--- + 1 file changed, 7 insertions(+), 3 deletions(-) + +diff --git a/drivers/gpu/drm/panfrost/panfrost_perfcnt.c b/drivers/gpu/drm/panfrost/panfrost_perfcnt.c +index 6913578d5aa7..6169644d4469 100644 +--- a/drivers/gpu/drm/panfrost/panfrost_perfcnt.c ++++ b/drivers/gpu/drm/panfrost/panfrost_perfcnt.c +@@ -83,11 +83,13 @@ static int panfrost_perfcnt_enable_locked(struct panfrost_device *pfdev, + + ret = pm_runtime_get_sync(pfdev->dev); + if (ret < 0) +- return ret; ++ goto err_put_pm; + + bo = drm_gem_shmem_create(pfdev->ddev, perfcnt->bosize); +- if (IS_ERR(bo)) +- return PTR_ERR(bo); ++ if (IS_ERR(bo)) { ++ ret = PTR_ERR(bo); ++ goto err_put_pm; ++ } + + /* Map the perfcnt buf in the address space attached to file_priv. */ + ret = panfrost_gem_open(&bo->base, file_priv); +@@ -168,6 +170,8 @@ static int panfrost_perfcnt_enable_locked(struct panfrost_device *pfdev, + panfrost_gem_close(&bo->base, file_priv); + err_put_bo: + drm_gem_object_put_unlocked(&bo->base); ++err_put_pm: ++ pm_runtime_put(pfdev->dev); + return ret; + } + diff --git a/patch/kernel/rk322x-current/01-linux-1000-clk-rockchip-rk3228-fixup.patch b/patch/kernel/rk322x-current/01-linux-1000-clk-rockchip-rk3228-fixup.patch deleted file mode 100644 index 21826f856..000000000 --- a/patch/kernel/rk322x-current/01-linux-1000-clk-rockchip-rk3228-fixup.patch +++ /dev/null @@ -1,98 +0,0 @@ -diff --git a/drivers/clk/rockchip/clk-rk3228.c b/drivers/clk/rockchip/clk-rk3228.c -index 0127d702720c..6ef71ec239ae 100644 ---- a/drivers/clk/rockchip/clk-rk3228.c -+++ b/drivers/clk/rockchip/clk-rk3228.c -@@ -353,7 +353,7 @@ static struct rockchip_clk_branch rk3228_clk_branches[] __initdata = { - RK2928_CLKGATE_CON(10), 12, GFLAGS), - - COMPOSITE(SCLK_WIFI, "sclk_wifi", mux_pll_src_cpll_gpll_usb480m_p, 0, -- RK2928_CLKSEL_CON(23), 5, 2, MFLAGS, 0, 6, DFLAGS, -+ RK2928_CLKSEL_CON(23), 5, 2, MFLAGS, 0, 5, DFLAGS, - RK2928_CLKGATE_CON(2), 15, GFLAGS), - - COMPOSITE(SCLK_SDMMC, "sclk_sdmmc", mux_mmc_src_p, 0, --- -2.17.1 - - -From 3acbbe5eb438e8b1061a803881579030d3c2b424 Mon Sep 17 00:00:00 2001 -From: Chen Lei -Date: Tue, 25 Dec 2018 18:29:04 +0800 -Subject: [PATCH] clk: rockchip: rk322x: fix wrong mmc phase shift for rk3228 - -mmc sample shift should be 1 for rk3228, or it will fail -if we enable mmc tuning for rk3228. - -Change-Id: I301c2a7d33de8d519d7c288aef03a82531016373 -Signed-off-by: Chen Lei ---- - drivers/clk/rockchip/clk-rk3228.c | 6 +++--- - 1 file changed, 3 insertions(+), 3 deletions(-) - -diff --git a/drivers/clk/rockchip/clk-rk3228.c b/drivers/clk/rockchip/clk-rk3228.c -index 6ef71ec239ae..27adfca1a095 100644 ---- a/drivers/clk/rockchip/clk-rk3228.c -+++ b/drivers/clk/rockchip/clk-rk3228.c -@@ -610,13 +610,13 @@ static struct rockchip_clk_branch rk3228_clk_branches[] __initdata = { - - /* PD_MMC */ - MMC(SCLK_SDMMC_DRV, "sdmmc_drv", "sclk_sdmmc", RK3228_SDMMC_CON0, 1), -- MMC(SCLK_SDMMC_SAMPLE, "sdmmc_sample", "sclk_sdmmc", RK3228_SDMMC_CON1, 0), -+ MMC(SCLK_SDMMC_SAMPLE, "sdmmc_sample", "sclk_sdmmc", RK3228_SDMMC_CON1, 1), - - MMC(SCLK_SDIO_DRV, "sdio_drv", "sclk_sdio", RK3228_SDIO_CON0, 1), -- MMC(SCLK_SDIO_SAMPLE, "sdio_sample", "sclk_sdio", RK3228_SDIO_CON1, 0), -+ MMC(SCLK_SDIO_SAMPLE, "sdio_sample", "sclk_sdio", RK3228_SDIO_CON1, 1), - - MMC(SCLK_EMMC_DRV, "emmc_drv", "sclk_emmc", RK3228_EMMC_CON0, 1), -- MMC(SCLK_EMMC_SAMPLE, "emmc_sample", "sclk_emmc", RK3228_EMMC_CON1, 0), -+ MMC(SCLK_EMMC_SAMPLE, "emmc_sample", "sclk_emmc", RK3228_EMMC_CON1, 1), - }; - - static const char *const rk3228_critical_clocks[] __initconst = { --- -2.17.1 - - -From a692001c1249473bdfe975ef53d2bdb8a4df736d Mon Sep 17 00:00:00 2001 -From: Finley Xiao -Date: Mon, 5 Feb 2018 10:04:15 +0800 -Subject: [PATCH] clk: rockchip: rk3228: Fix armclk parent - -Change-Id: I09830d96b37cca600f1782b9013b25e043467f97 -Signed-off-by: Finley Xiao ---- - drivers/clk/rockchip/clk-rk3228.c | 8 +++++++- - 1 file changed, 7 insertions(+), 1 deletion(-) - -diff --git a/drivers/clk/rockchip/clk-rk3228.c b/drivers/clk/rockchip/clk-rk3228.c -index 58292f80ad66..fba513de94eb 100644 ---- a/drivers/clk/rockchip/clk-rk3228.c -+++ b/drivers/clk/rockchip/clk-rk3228.c -@@ -170,7 +170,7 @@ static struct rockchip_pll_clock rk3228_pll_clks[] __initdata = { - [cpll] = PLL(pll_rk3036, PLL_CPLL, "cpll", mux_pll_p, 0, RK2928_PLL_CON(6), - RK2928_MODE_CON, 8, 8, 0, NULL), - [gpll] = PLL(pll_rk3036, PLL_GPLL, "gpll", mux_pll_p, 0, RK2928_PLL_CON(9), -- RK2928_MODE_CON, 12, 9, ROCKCHIP_PLL_SYNC_RATE, rk3228_pll_rates), -+ RK2928_MODE_CON, 12, 9, 0, rk3228_pll_rates), - }; - - #define MFLAGS CLK_MUX_HIWORD_MASK --- -2.17.1 - - -From f57d5061e7357a8f7a181517530658a223ba415b Mon Sep 17 00:00:00 2001 -From: Finley Xiao -Date: Thu, 22 Jun 2017 19:53:46 +0800 -Subject: [PATCH] clk: rockchip: rk3228: fix gpu gate-register - -Fix a typo making the aclk_gpu and aclk_gpu_noc access a wrong register to -handle its gate. - -Change-Id: Ie0bac8014363af7c0409b8a56eacf2e858818843 -Signed-off-by: Finley Xiao ---- - drivers/clk/rockchip/clk-rk3228.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - diff --git a/patch/kernel/rk322x-current/01-linux-1000-export-mm_trace_rss_stat.patch b/patch/kernel/rk322x-current/01-linux-1000-export-mm_trace_rss_stat.patch new file mode 100644 index 000000000..03be01030 --- /dev/null +++ b/patch/kernel/rk322x-current/01-linux-1000-export-mm_trace_rss_stat.patch @@ -0,0 +1,12 @@ +diff --git a/mm/memory.c b/mm/memory.c +index 606da18..8429abc 100644 +--- a/mm/memory.c ++++ b/mm/memory.c +@@ -158,6 +158,7 @@ + { + trace_rss_stat(mm, member, count); + } ++EXPORT_SYMBOL(mm_trace_rss_stat); + + #if defined(SPLIT_RSS_COUNTING) + diff --git a/patch/kernel/rk322x-current/01-linux-1001-clk-rockchip-rk3228-more-fixes.patch b/patch/kernel/rk322x-current/01-linux-1001-clk-rockchip-rk3228-more-fixes.patch deleted file mode 100644 index 024940cd3..000000000 --- a/patch/kernel/rk322x-current/01-linux-1001-clk-rockchip-rk3228-more-fixes.patch +++ /dev/null @@ -1,219 +0,0 @@ -diff --git a/drivers/clk/rockchip/clk-rk3228.c b/drivers/clk/rockchip/clk-rk3228.c -index 448b202bf4f3..828d0003a18e 100644 ---- a/drivers/clk/rockchip/clk-rk3228.c -+++ b/drivers/clk/rockchip/clk-rk3228.c -@@ -510,12 +510,12 @@ static struct rockchip_clk_branch rk3228_clk_branches[] __initdata = { - - /* PD_VOP */ - GATE(ACLK_RGA, "aclk_rga", "aclk_rga_pre", 0, RK2928_CLKGATE_CON(13), 0, GFLAGS), -- GATE(0, "aclk_rga_noc", "aclk_rga_pre", 0, RK2928_CLKGATE_CON(13), 11, GFLAGS), -+ GATE(0, "aclk_rga_noc", "aclk_rga_pre", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(13), 11, GFLAGS), - GATE(ACLK_IEP, "aclk_iep", "aclk_iep_pre", 0, RK2928_CLKGATE_CON(13), 2, GFLAGS), -- GATE(0, "aclk_iep_noc", "aclk_iep_pre", 0, RK2928_CLKGATE_CON(13), 9, GFLAGS), -+ GATE(0, "aclk_iep_noc", "aclk_iep_pre", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(13), 9, GFLAGS), - - GATE(ACLK_VOP, "aclk_vop", "aclk_vop_pre", 0, RK2928_CLKGATE_CON(13), 5, GFLAGS), -- GATE(0, "aclk_vop_noc", "aclk_vop_pre", 0, RK2928_CLKGATE_CON(13), 12, GFLAGS), -+ GATE(0, "aclk_vop_noc", "aclk_vop_pre", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(13), 12, GFLAGS), - - GATE(ACLK_HDCP, "aclk_hdcp", "aclk_hdcp_pre", 0, RK2928_CLKGATE_CON(14), 10, GFLAGS), - GATE(0, "aclk_hdcp_noc", "aclk_hdcp_pre", 0, RK2928_CLKGATE_CON(13), 10, GFLAGS), -@@ -523,13 +523,13 @@ static struct rockchip_clk_branch rk3228_clk_branches[] __initdata = { - GATE(HCLK_RGA, "hclk_rga", "hclk_vio_pre", 0, RK2928_CLKGATE_CON(13), 1, GFLAGS), - GATE(HCLK_IEP, "hclk_iep", "hclk_vio_pre", 0, RK2928_CLKGATE_CON(13), 3, GFLAGS), - GATE(HCLK_VOP, "hclk_vop", "hclk_vio_pre", 0, RK2928_CLKGATE_CON(13), 6, GFLAGS), -- GATE(0, "hclk_vio_ahb_arbi", "hclk_vio_pre", 0, RK2928_CLKGATE_CON(13), 7, GFLAGS), -- GATE(0, "hclk_vio_noc", "hclk_vio_pre", 0, RK2928_CLKGATE_CON(13), 8, GFLAGS), -- GATE(0, "hclk_vop_noc", "hclk_vio_pre", 0, RK2928_CLKGATE_CON(13), 13, GFLAGS), -- GATE(HCLK_VIO_H2P, "hclk_vio_h2p", "hclk_vio_pre", 0, RK2928_CLKGATE_CON(14), 7, GFLAGS), -+ GATE(0, "hclk_vio_ahb_arbi", "hclk_vio_pre", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(13), 7, GFLAGS), -+ GATE(0, "hclk_vio_noc", "hclk_vio_pre", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(13), 8, GFLAGS), -+ GATE(0, "hclk_vop_noc", "hclk_vio_pre", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(13), 13, GFLAGS), -+ GATE(HCLK_VIO_H2P, "hclk_vio_h2p", "hclk_vio_pre", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(14), 7, GFLAGS), - GATE(HCLK_HDCP_MMU, "hclk_hdcp_mmu", "hclk_vio_pre", 0, RK2928_CLKGATE_CON(14), 12, GFLAGS), - GATE(PCLK_HDMI_CTRL, "pclk_hdmi_ctrl", "hclk_vio_pre", 0, RK2928_CLKGATE_CON(14), 6, GFLAGS), -- GATE(PCLK_VIO_H2P, "pclk_vio_h2p", "hclk_vio_pre", 0, RK2928_CLKGATE_CON(14), 8, GFLAGS), -+ GATE(PCLK_VIO_H2P, "pclk_vio_h2p", "hclk_vio_pre", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(14), 8, GFLAGS), - GATE(PCLK_HDCP, "pclk_hdcp", "hclk_vio_pre", 0, RK2928_CLKGATE_CON(14), 11, GFLAGS), - - /* PD_PERI */ -@@ -541,13 +541,13 @@ static struct rockchip_clk_branch rk3228_clk_branches[] __initdata = { - GATE(HCLK_EMMC, "hclk_emmc", "hclk_peri", 0, RK2928_CLKGATE_CON(11), 2, GFLAGS), - GATE(HCLK_NANDC, "hclk_nandc", "hclk_peri", 0, RK2928_CLKGATE_CON(11), 3, GFLAGS), - GATE(HCLK_HOST0, "hclk_host0", "hclk_peri", 0, RK2928_CLKGATE_CON(11), 6, GFLAGS), -- GATE(0, "hclk_host0_arb", "hclk_peri", 0, RK2928_CLKGATE_CON(11), 7, GFLAGS), -+ GATE(0, "hclk_host0_arb", "hclk_peri", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(11), 7, GFLAGS), - GATE(HCLK_HOST1, "hclk_host1", "hclk_peri", 0, RK2928_CLKGATE_CON(11), 8, GFLAGS), -- GATE(0, "hclk_host1_arb", "hclk_peri", 0, RK2928_CLKGATE_CON(11), 9, GFLAGS), -+ GATE(0, "hclk_host1_arb", "hclk_peri", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(11), 9, GFLAGS), - GATE(HCLK_HOST2, "hclk_host2", "hclk_peri", 0, RK2928_CLKGATE_CON(11), 10, GFLAGS), - GATE(HCLK_OTG, "hclk_otg", "hclk_peri", 0, RK2928_CLKGATE_CON(11), 12, GFLAGS), -- GATE(0, "hclk_otg_pmu", "hclk_peri", 0, RK2928_CLKGATE_CON(11), 13, GFLAGS), -- GATE(0, "hclk_host2_arb", "hclk_peri", 0, RK2928_CLKGATE_CON(11), 14, GFLAGS), -+ GATE(0, "hclk_otg_pmu", "hclk_peri", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(11), 13, GFLAGS), -+ GATE(0, "hclk_host2_arb", "hclk_peri", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(11), 14, GFLAGS), - GATE(0, "hclk_peri_noc", "hclk_peri", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(12), 1, GFLAGS), - - GATE(PCLK_GMAC, "pclk_gmac", "pclk_peri", 0, RK2928_CLKGATE_CON(11), 5, GFLAGS), -@@ -555,15 +555,15 @@ static struct rockchip_clk_branch rk3228_clk_branches[] __initdata = { - - /* PD_GPU */ - GATE(ACLK_GPU, "aclk_gpu", "aclk_gpu_pre", 0, RK2928_CLKGATE_CON(7), 14, GFLAGS), -- GATE(0, "aclk_gpu_noc", "aclk_gpu_pre", 0, RK2928_CLKGATE_CON(7), 15, GFLAGS), -+ GATE(0, "aclk_gpu_noc", "aclk_gpu_pre", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(7), 15, GFLAGS), - - /* PD_BUS */ -- GATE(0, "sclk_initmem_mbist", "aclk_cpu", 0, RK2928_CLKGATE_CON(8), 1, GFLAGS), -- GATE(0, "aclk_initmem", "aclk_cpu", 0, RK2928_CLKGATE_CON(8), 0, GFLAGS), -+ GATE(0, "sclk_initmem_mbist", "aclk_cpu", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(8), 1, GFLAGS), -+ GATE(0, "aclk_initmem", "aclk_cpu", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(8), 0, GFLAGS), - GATE(ACLK_DMAC, "aclk_dmac_bus", "aclk_cpu", 0, RK2928_CLKGATE_CON(8), 2, GFLAGS), - GATE(0, "aclk_bus_noc", "aclk_cpu", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(10), 1, GFLAGS), - -- GATE(0, "hclk_rom", "hclk_cpu", 0, RK2928_CLKGATE_CON(8), 3, GFLAGS), -+ GATE(0, "hclk_rom", "hclk_cpu", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(8), 3, GFLAGS), - GATE(HCLK_I2S0_8CH, "hclk_i2s0_8ch", "hclk_cpu", 0, RK2928_CLKGATE_CON(8), 7, GFLAGS), - GATE(HCLK_I2S1_8CH, "hclk_i2s1_8ch", "hclk_cpu", 0, RK2928_CLKGATE_CON(8), 8, GFLAGS), - GATE(HCLK_I2S2_2CH, "hclk_i2s2_2ch", "hclk_cpu", 0, RK2928_CLKGATE_CON(8), 9, GFLAGS), -@@ -572,9 +572,9 @@ static struct rockchip_clk_branch rk3228_clk_branches[] __initdata = { - GATE(HCLK_M_CRYPTO, "hclk_crypto_mst", "hclk_cpu", 0, RK2928_CLKGATE_CON(8), 11, GFLAGS), - GATE(HCLK_S_CRYPTO, "hclk_crypto_slv", "hclk_cpu", 0, RK2928_CLKGATE_CON(8), 12, GFLAGS), - -- GATE(0, "pclk_ddrupctl", "pclk_ddr_pre", 0, RK2928_CLKGATE_CON(8), 4, GFLAGS), -- GATE(0, "pclk_ddrmon", "pclk_ddr_pre", 0, RK2928_CLKGATE_CON(8), 6, GFLAGS), -- GATE(0, "pclk_msch_noc", "pclk_ddr_pre", 0, RK2928_CLKGATE_CON(10), 2, GFLAGS), -+ GATE(0, "pclk_ddrupctl", "pclk_ddr_pre", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(8), 4, GFLAGS), -+ GATE(0, "pclk_ddrmon", "pclk_ddr_pre", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(8), 6, GFLAGS), -+ GATE(0, "pclk_msch_noc", "pclk_ddr_pre", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(10), 2, GFLAGS), - - GATE(PCLK_EFUSE_1024, "pclk_efuse_1024", "pclk_cpu", 0, RK2928_CLKGATE_CON(8), 13, GFLAGS), - GATE(PCLK_EFUSE_256, "pclk_efuse_256", "pclk_cpu", 0, RK2928_CLKGATE_CON(8), 14, GFLAGS), -@@ -583,7 +583,7 @@ static struct rockchip_clk_branch rk3228_clk_branches[] __initdata = { - GATE(PCLK_I2C2, "pclk_i2c2", "pclk_cpu", 0, RK2928_CLKGATE_CON(9), 1, GFLAGS), - GATE(PCLK_I2C3, "pclk_i2c3", "pclk_cpu", 0, RK2928_CLKGATE_CON(9), 2, GFLAGS), - GATE(PCLK_TIMER, "pclk_timer0", "pclk_cpu", 0, RK2928_CLKGATE_CON(9), 4, GFLAGS), -- GATE(0, "pclk_stimer", "pclk_cpu", 0, RK2928_CLKGATE_CON(9), 5, GFLAGS), -+ GATE(0, "pclk_stimer", "pclk_cpu", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(9), 5, GFLAGS), - GATE(PCLK_SPI0, "pclk_spi0", "pclk_cpu", 0, RK2928_CLKGATE_CON(9), 6, GFLAGS), - GATE(PCLK_PWM, "pclk_rk_pwm", "pclk_cpu", 0, RK2928_CLKGATE_CON(9), 7, GFLAGS), - GATE(PCLK_GPIO0, "pclk_gpio0", "pclk_cpu", 0, RK2928_CLKGATE_CON(9), 8, GFLAGS), -@@ -597,22 +597,22 @@ static struct rockchip_clk_branch rk3228_clk_branches[] __initdata = { - GATE(PCLK_GRF, "pclk_grf", "pclk_cpu", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(10), 0, GFLAGS), - GATE(0, "pclk_cru", "pclk_cpu", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(10), 1, GFLAGS), - GATE(0, "pclk_sgrf", "pclk_cpu", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(10), 2, GFLAGS), -- GATE(0, "pclk_sim", "pclk_cpu", 0, RK2928_CLKGATE_CON(10), 3, GFLAGS), -+ GATE(0, "pclk_sim", "pclk_cpu", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(10), 3, GFLAGS), - -- GATE(0, "pclk_ddrphy", "pclk_phy_pre", 0, RK2928_CLKGATE_CON(10), 3, GFLAGS), -- GATE(0, "pclk_acodecphy", "pclk_phy_pre", 0, RK2928_CLKGATE_CON(10), 5, GFLAGS), -+ GATE(0, "pclk_ddrphy", "pclk_phy_pre", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(10), 3, GFLAGS), -+ GATE(PCLK_ACODECPHY, "pclk_acodecphy", "pclk_phy_pre", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(10), 5, GFLAGS), - GATE(PCLK_HDMI_PHY, "pclk_hdmiphy", "pclk_phy_pre", 0, RK2928_CLKGATE_CON(10), 7, GFLAGS), -- GATE(0, "pclk_vdacphy", "pclk_phy_pre", 0, RK2928_CLKGATE_CON(10), 8, GFLAGS), -- GATE(0, "pclk_phy_noc", "pclk_phy_pre", 0, RK2928_CLKGATE_CON(10), 9, GFLAGS), -+ GATE(0, "pclk_vdacphy", "pclk_phy_pre", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(10), 8, GFLAGS), -+ GATE(0, "pclk_phy_noc", "pclk_phy_pre", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(10), 9, GFLAGS), - - GATE(ACLK_VPU, "aclk_vpu", "aclk_vpu_pre", 0, RK2928_CLKGATE_CON(15), 0, GFLAGS), -- GATE(0, "aclk_vpu_noc", "aclk_vpu_pre", 0, RK2928_CLKGATE_CON(15), 4, GFLAGS), -+ GATE(0, "aclk_vpu_noc", "aclk_vpu_pre", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(15), 4, GFLAGS), - GATE(ACLK_RKVDEC, "aclk_rkvdec", "aclk_rkvdec_pre", 0, RK2928_CLKGATE_CON(15), 2, GFLAGS), -- GATE(0, "aclk_rkvdec_noc", "aclk_rkvdec_pre", 0, RK2928_CLKGATE_CON(15), 6, GFLAGS), -+ GATE(0, "aclk_rkvdec_noc", "aclk_rkvdec_pre", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(15), 6, GFLAGS), - GATE(HCLK_VPU, "hclk_vpu", "hclk_vpu_pre", 0, RK2928_CLKGATE_CON(15), 1, GFLAGS), -- GATE(0, "hclk_vpu_noc", "hclk_vpu_pre", 0, RK2928_CLKGATE_CON(15), 5, GFLAGS), -+ GATE(0, "hclk_vpu_noc", "hclk_vpu_pre", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(15), 5, GFLAGS), - GATE(HCLK_RKVDEC, "hclk_rkvdec", "hclk_rkvdec_pre", 0, RK2928_CLKGATE_CON(15), 3, GFLAGS), -- GATE(0, "hclk_rkvdec_noc", "hclk_rkvdec_pre", 0, RK2928_CLKGATE_CON(15), 7, GFLAGS), -+ GATE(0, "hclk_rkvdec_noc", "hclk_rkvdec_pre", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(15), 7, GFLAGS), - - /* PD_MMC */ - MMC(SCLK_SDMMC_DRV, "sdmmc_drv", "sclk_sdmmc", RK3228_SDMMC_CON0, 1), -@@ -656,25 +656,34 @@ static const char *const rk3228_critical_clocks[] __initconst = { - "pclk_phy_noc", - "aclk_vpu_noc", - "aclk_rkvdec_noc", -+ "aclk_rkvdec", - "hclk_vpu_noc", - "hclk_rkvdec_noc", -+ "hclk_rkvdec", - }; - -+static void __iomem *rk3228_cru_base; -+ -+static void rk3228_clk_shutdown(void) -+{ -+ writel_relaxed(0x11010000, rk3228_cru_base + RK3228_MODE_CON); -+} -+ - static void __init rk3228_clk_init(struct device_node *np) - { - struct rockchip_clk_provider *ctx; -- void __iomem *reg_base; - -- reg_base = of_iomap(np, 0); -- if (!reg_base) { -+ rk3228_cru_base = of_iomap(np, 0); -+ -+ if (!rk3228_cru_base) { - pr_err("%s: could not map cru region\n", __func__); - return; - } - -- ctx = rockchip_clk_init(np, reg_base, CLK_NR_CLKS); -+ ctx = rockchip_clk_init(np, rk3228_cru_base, CLK_NR_CLKS); - if (IS_ERR(ctx)) { - pr_err("%s: rockchip clk init failed\n", __func__); -- iounmap(reg_base); -+ iounmap(rk3228_cru_base); - return; - } - -@@ -691,10 +700,10 @@ static void __init rk3228_clk_init(struct device_node *np) - &rk3228_cpuclk_data, rk3228_cpuclk_rates, - ARRAY_SIZE(rk3228_cpuclk_rates)); - -- rockchip_register_softrst(np, 9, reg_base + RK2928_SOFTRST_CON(0), -+ rockchip_register_softrst(np, 9, rk3228_cru_base + RK2928_SOFTRST_CON(0), - ROCKCHIP_SOFTRST_HIWORD_MASK); - -- rockchip_register_restart_notifier(ctx, RK3228_GLB_SRST_FST, NULL); -+ rockchip_register_restart_notifier(ctx, RK3228_GLB_SRST_FST, rk3228_clk_shutdown); - - rockchip_clk_of_add_provider(np, ctx); - } -diff --git a/drivers/clk/rockchip/clk.h b/drivers/clk/rockchip/clk.h -index 2271a84124b0..f2f80f224f30 100644 ---- a/drivers/clk/rockchip/clk.h -+++ b/drivers/clk/rockchip/clk.h -@@ -134,6 +134,7 @@ struct clk; - #define RK3308_EMMC_CON0 0x490 - #define RK3308_EMMC_CON1 0x494 - -+#define RK3228_MODE_CON 0x40 - #define RK3328_PLL_CON(x) RK2928_PLL_CON(x) - #define RK3328_CLKSEL_CON(x) ((x) * 0x4 + 0x100) - #define RK3328_CLKGATE_CON(x) ((x) * 0x4 + 0x200) -diff --git a/include/dt-bindings/clock/rk3228-cru.h b/include/dt-bindings/clock/rk3228-cru.h -index de550ea56eeb..16e1feae5ce4 100644 ---- a/include/dt-bindings/clock/rk3228-cru.h -+++ b/include/dt-bindings/clock/rk3228-cru.h -@@ -65,6 +65,7 @@ - #define SCLK_OTGPHY0 142 - #define SCLK_OTGPHY1 143 - #define SCLK_HDMI_PHY 144 -+#define SCLK_DDRC 145 - - /* dclk gates */ - #define DCLK_VOP 190 -@@ -115,6 +116,7 @@ - #define PCLK_HDMI_CTRL 364 - #define PCLK_HDMI_PHY 365 - #define PCLK_GMAC 367 -+#define PCLK_ACODECPHY 368 - - /* hclk gates */ - #define HCLK_I2S0_8CH 442 --- -2.17.1 - diff --git a/patch/kernel/rk322x-current/01-linux-1002-arm-dts-rk322x-dts.patch b/patch/kernel/rk322x-current/01-linux-1002-arm-dts-rk322x-dts.patch deleted file mode 100644 index 45cb9be72..000000000 --- a/patch/kernel/rk322x-current/01-linux-1002-arm-dts-rk322x-dts.patch +++ /dev/null @@ -1,1586 +0,0 @@ -diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile -index e8dd99201..02d9d3ae7 100644 ---- a/arch/arm/boot/dts/Makefile -+++ b/arch/arm/boot/dts/Makefile -@@ -952,6 +952,12 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += \ - rk3188-px3-evb.dtb \ - rk3188-radxarock.dtb \ - rk3228-evb.dtb \ -+ rk3228a-box.dtb \ -+ rk3228a-box-h96mini.dtb \ -+ rk3228a-box-nand.dtb \ -+ rk3229-box.dtb \ -+ rk3229-box-a95xr1.dtb \ -+ rk3229-box-nand.dtb \ - rk3229-evb.dtb \ - rk3229-xms6.dtb \ - rk3288-evb-act8846.dtb \ -diff --git a/arch/arm/boot/dts/rk3228a-box-h96mini.dts b/arch/arm/boot/dts/rk3228a-box-h96mini.dts -new file mode 100644 -index 000000000..c624500d1 ---- /dev/null -+++ b/arch/arm/boot/dts/rk3228a-box-h96mini.dts -@@ -0,0 +1,106 @@ -+// SPDX-License-Identifier: (GPL-2.0+ OR MIT) -+ -+/dts-v1/; -+#include -+#include -+#include "rk3228a-box.dtsi" -+ -+/ { -+ compatible = "eledvb,h96mini", "rockchip,rk3228a-box", "rockchip,rk3229"; -+ model = "Rockchip RK3228A Box H96 mini"; -+ -+ leds { -+ compatible = "gpio-leds"; -+ -+ led_green { -+ gpios = <&gpio3 RK_PC5 GPIO_ACTIVE_HIGH>; -+ default-state = "on"; -+ }; -+ -+ led_red { -+ gpios = <&gpio0 RK_PB0 GPIO_ACTIVE_HIGH>; -+ default-state = "off"; -+ }; -+ }; -+ -+}; -+ -+&emmc { -+ mmc-hs200-1_8v; -+ status = "okay"; -+}; -+ -+&gmac { -+ tx_delay = <0x26>; -+ rx_delay = <0x11>; -+}; -+ -+&ir_receiver { -+ status = "okay"; -+}; -+ -+&pinctrl { -+ wifi { -+ wifi_host_wake_l: wifi-host-wake-l { -+ rockchip,pins = <0 RK_PD4 RK_FUNC_GPIO &pcfg_pull_none>; -+ }; -+ }; -+ -+ bt { -+ bt_host_wake_l: bt-host-wake-l { -+ rockchip,pins = <3 RK_PD2 RK_FUNC_GPIO &pcfg_pull_none>; -+ }; -+ -+ bt_reg_on_h: bt-reg-on-h { -+ rockchip,pins = <2 RK_PD5 RK_FUNC_GPIO &pcfg_pull_none>; -+ }; -+ -+ bt_wake_l: bt-wake-l { -+ rockchip,pins = <3 RK_PD3 RK_FUNC_GPIO &pcfg_pull_none>; -+ }; -+ }; -+}; -+ -+&power_key { -+ status = "okay"; -+}; -+ -+&sdio { -+ #address-cells = <1>; -+ #size-cells = <0>; -+ status = "okay"; -+ -+ brcmf: wifi@1 { -+ compatible = "brcm,bcm4329-fmac"; -+ reg = <1>; -+ interrupt-parent = <&gpio0>; -+ interrupts = ; -+ interrupt-names = "host-wake"; -+ brcm,drive-strength = <5>; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&wifi_host_wake_l>; -+ }; -+}; -+ -+&sdmmc { -+ disable-wp; -+ status = "okay"; -+}; -+ -+&uart1 { -+ status = "okay"; -+ -+ bluetooth { -+ compatible = "brcm,bcm4330-bt"; -+ host-wakeup-gpios = <&gpio3 RK_PD2 GPIO_ACTIVE_HIGH>; -+ device-wakeup-gpios = <&gpio3 RK_PD3 GPIO_ACTIVE_HIGH>; -+ shutdown-gpios = <&gpio2 RK_PD5 GPIO_ACTIVE_HIGH>; -+ max-speed = <4000000>; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&bt_reg_on_h &bt_host_wake_l &bt_wake_l>; -+ }; -+}; -+ -+&usb_otg { -+ dr_mode = "host"; -+}; -diff --git a/arch/arm/boot/dts/rk3228a-box-nand.dts b/arch/arm/boot/dts/rk3228a-box-nand.dts -new file mode 100644 -index 000000000..f3e5ab894 ---- /dev/null -+++ b/arch/arm/boot/dts/rk3228a-box-nand.dts -@@ -0,0 +1,57 @@ -+// SPDX-License-Identifier: (GPL-2.0+ OR MIT) -+ -+/dts-v1/; -+#include "rk3228a-box.dtsi" -+ -+/ { -+ model = "Rockchip RK3228A Box"; -+ -+ leds { -+ compatible = "gpio-leds"; -+ -+ led_blue { -+ gpios = <&gpio3 RK_PC5 GPIO_ACTIVE_HIGH>; -+ default-state = "on"; -+ }; -+ -+ led_red { -+ gpios = <&gpio1 RK_PA7 GPIO_ACTIVE_HIGH>; -+ default-state = "off"; -+ }; -+ }; -+ -+}; -+ -+&ir_receiver { -+ status = "okay"; -+}; -+ -+&nfc { -+ #address-cells = <1>; -+ #size-cells = <0>; -+ status = "okay"; -+ -+ nand@0 { -+ reg = <0>; -+ nand-ecc-mode = "hw"; -+ nand-ecc-strength = <60>; -+ nand-ecc-step-size = <1024>; -+ nand-bus-width = <8>; -+ }; -+}; -+ -+&sdio { -+ status = "okay"; -+}; -+ -+&sdmmc { -+ status = "okay"; -+}; -+ -+&uart1 { -+ status = "okay"; -+}; -+ -+&usb_otg { -+ dr_mode = "host"; -+}; -diff --git a/arch/arm/boot/dts/rk3228a-box.dts b/arch/arm/boot/dts/rk3228a-box.dts -new file mode 100644 -index 000000000..e68ef44b9 ---- /dev/null -+++ b/arch/arm/boot/dts/rk3228a-box.dts -@@ -0,0 +1,47 @@ -+// SPDX-License-Identifier: (GPL-2.0+ OR MIT) -+ -+/dts-v1/; -+#include "rk3228a-box.dtsi" -+ -+/ { -+ model = "Rockchip RK3228A Box"; -+ -+ leds { -+ compatible = "gpio-leds"; -+ -+ led_blue { -+ gpios = <&gpio3 RK_PC5 GPIO_ACTIVE_HIGH>; -+ default-state = "on"; -+ }; -+ -+ led_red { -+ gpios = <&gpio1 RK_PA7 GPIO_ACTIVE_HIGH>; -+ default-state = "off"; -+ }; -+ }; -+ -+}; -+ -+&emmc { -+ status = "okay"; -+}; -+ -+&ir_receiver { -+ status = "okay"; -+}; -+ -+&sdio { -+ status = "okay"; -+}; -+ -+&sdmmc { -+ status = "okay"; -+}; -+ -+&uart1 { -+ status = "okay"; -+}; -+ -+&usb_otg { -+ dr_mode = "host"; -+}; -diff --git a/arch/arm/boot/dts/rk3228a-box.dtsi b/arch/arm/boot/dts/rk3228a-box.dtsi -new file mode 100644 -index 000000000..dbd5c5dc4 ---- /dev/null -+++ b/arch/arm/boot/dts/rk3228a-box.dtsi -@@ -0,0 +1,12 @@ -+// SPDX-License-Identifier: (GPL-2.0+ OR MIT) -+ -+/dts-v1/; -+ -+#include "rk322x-box.dtsi" -+ -+/ { -+ -+ model = "Rockchip RK3228A Box"; -+ compatible = "rockchip,rk3228a-box", "rockchip,rk3229"; -+ -+}; -diff --git a/arch/arm/boot/dts/rk3229-box-a95xr1.dts b/arch/arm/boot/dts/rk3229-box-a95xr1.dts -new file mode 100644 -index 000000000..b3695fb0b ---- /dev/null -+++ b/arch/arm/boot/dts/rk3229-box-a95xr1.dts -@@ -0,0 +1,57 @@ -+// SPDX-License-Identifier: (GPL-2.0+ OR MIT) -+ -+/dts-v1/; -+#include -+#include -+#include "rk3229-box.dtsi" -+ -+/ { -+ model = "Rockchip RK3229 Box A95X-R1"; -+ -+ leds { -+ compatible = "gpio-leds"; -+ -+ led_blue { -+ gpios = <&gpio3 RK_PC5 GPIO_ACTIVE_HIGH>; -+ default-state = "on"; -+ }; -+ -+ led_red { -+ gpios = <&gpio1 RK_PA7 GPIO_ACTIVE_HIGH>; -+ default-state = "off"; -+ linux,default-trigger = "rc-feedback"; -+ }; -+ }; -+ -+}; -+ -+&emmc { -+ mmc-hs200-1_8v; -+ status = "okay"; -+}; -+ -+&gmac { -+ tx_delay = <0x26>; -+ rx_delay = <0x11>; -+}; -+ -+&ir_receiver { -+ status = "okay"; -+}; -+ -+&power_key { -+ status = "okay"; -+}; -+ -+&sdio { -+ status = "okay"; -+}; -+ -+&sdmmc { -+ disable-wp; -+ status = "okay"; -+}; -+ -+&usb_otg { -+ dr_mode = "host"; -+}; -diff --git a/arch/arm/boot/dts/rk3229-box-nand.dts b/arch/arm/boot/dts/rk3229-box-nand.dts -new file mode 100644 -index 000000000..5eca0f335 ---- /dev/null -+++ b/arch/arm/boot/dts/rk3229-box-nand.dts -@@ -0,0 +1,60 @@ -+// SPDX-License-Identifier: (GPL-2.0+ OR MIT) -+ -+/dts-v1/; -+#include "rk3229-box.dtsi" -+ -+/ { -+ model = "Rockchip RK3229 Box"; -+ -+ leds { -+ compatible = "gpio-leds"; -+ -+ led_green { -+ gpios = <&gpio3 RK_PC5 GPIO_ACTIVE_HIGH>; -+ default-state = "on"; -+ }; -+ -+ led_red { -+ gpios = <&gpio0 RK_PB0 GPIO_ACTIVE_HIGH>; -+ default-state = "off"; -+ }; -+ }; -+}; -+ -+&ir_receiver { -+ status = "okay"; -+}; -+ -+&nfc { -+ #address-cells = <1>; -+ #size-cells = <0>; -+ status = "okay"; -+ -+ nand@0 { -+ reg = <0>; -+ nand-ecc-mode = "hw"; -+ nand-ecc-strength = <60>; -+ nand-ecc-step-size = <1024>; -+ nand-bus-width = <8>; -+ }; -+}; -+ -+&power_key { -+ status = "okay"; -+}; -+ -+&sdio { -+ status = "okay"; -+}; -+ -+&sdmmc { -+ status = "okay"; -+}; -+ -+&uart1 { -+ status = "okay"; -+}; -+ -+&usb_otg { -+ dr_mode = "host"; -+}; -diff --git a/arch/arm/boot/dts/rk3229-box.dts b/arch/arm/boot/dts/rk3229-box.dts -new file mode 100644 -index 000000000..b63e61cda ---- /dev/null -+++ b/arch/arm/boot/dts/rk3229-box.dts -@@ -0,0 +1,50 @@ -+// SPDX-License-Identifier: (GPL-2.0+ OR MIT) -+ -+/dts-v1/; -+#include "rk3229-box.dtsi" -+ -+/ { -+ model = "Rockchip RK3229 Box"; -+ -+ leds { -+ compatible = "gpio-leds"; -+ -+ led_green { -+ gpios = <&gpio3 RK_PC5 GPIO_ACTIVE_HIGH>; -+ default-state = "on"; -+ }; -+ -+ led_red { -+ gpios = <&gpio0 RK_PB0 GPIO_ACTIVE_HIGH>; -+ default-state = "off"; -+ }; -+ }; -+}; -+ -+&emmc { -+ status = "okay"; -+}; -+ -+&ir_receiver { -+ status = "okay"; -+}; -+ -+&power_key { -+ status = "okay"; -+}; -+ -+&sdio { -+ status = "okay"; -+}; -+ -+&sdmmc { -+ status = "okay"; -+}; -+ -+&uart1 { -+ status = "okay"; -+}; -+ -+&usb_otg { -+ dr_mode = "host"; -+}; -diff --git a/arch/arm/boot/dts/rk3229-box.dtsi b/arch/arm/boot/dts/rk3229-box.dtsi -new file mode 100644 -index 000000000..79e2524e0 ---- /dev/null -+++ b/arch/arm/boot/dts/rk3229-box.dtsi -@@ -0,0 +1,21 @@ -+// SPDX-License-Identifier: (GPL-2.0+ OR MIT) -+ -+/dts-v1/; -+ -+#include "rk322x-box.dtsi" -+#include "rk3229-cpu-opp.dtsi" -+ -+/ { -+ -+ model = "Rockchip RK3229 Box"; -+ compatible = "rockchip,rk3229-box", "rockchip,rk3229"; -+ -+}; -+ -+&cpu0_opp_table { -+ -+ opp-1464000000 { -+ status = "disabled"; -+ }; -+ -+}; -diff --git a/arch/arm/boot/dts/rk3229-cpu-opp.dtsi b/arch/arm/boot/dts/rk3229-cpu-opp.dtsi -new file mode 100644 -index 000000000..c1c7613ba ---- /dev/null -+++ b/arch/arm/boot/dts/rk3229-cpu-opp.dtsi -@@ -0,0 +1,50 @@ -+// SPDX-License-Identifier: (GPL-2.0+ OR MIT) -+/* -+ * Copyright (c) 2017 Fuzhou Rockchip Electronics Co., Ltd -+ */ -+ -+/ { -+ compatible = "rockchip,rk3229"; -+ -+ /delete-node/ opp-table0; -+ -+ cpu0_opp_table: opp_table0 { -+ compatible = "operating-points-v2"; -+ opp-shared; -+ -+ opp-408000000 { -+ opp-hz = /bits/ 64 <408000000>; -+ opp-microvolt = <950000 950000 1400000>; -+ clock-latency-ns = <40000>; -+ opp-suspend; -+ }; -+ opp-600000000 { -+ opp-hz = /bits/ 64 <600000000>; -+ opp-microvolt = <975000 975000 1400000>; -+ }; -+ opp-816000000 { -+ opp-hz = /bits/ 64 <816000000>; -+ opp-microvolt = <1000000 1000000 1400000>; -+ }; -+ opp-1008000000 { -+ opp-hz = /bits/ 64 <1008000000>; -+ opp-microvolt = <1175000 1175000 1400000>; -+ }; -+ opp-1200000000 { -+ opp-hz = /bits/ 64 <1200000000>; -+ opp-microvolt = <1275000 1275000 1400000>; -+ }; -+ opp-1296000000 { -+ opp-hz = /bits/ 64 <1296000000>; -+ opp-microvolt = <1325000 1325000 1400000>; -+ }; -+ opp-1392000000 { -+ opp-hz = /bits/ 64 <1392000000>; -+ opp-microvolt = <1350000 1350000 1400000>; -+ }; -+ opp-1464000000 { -+ opp-hz = /bits/ 64 <1464000000>; -+ opp-microvolt = <1400000 1400000 1400000>; -+ }; -+ }; -+}; -diff --git a/arch/arm/boot/dts/rk322x-box.dtsi b/arch/arm/boot/dts/rk322x-box.dtsi -new file mode 100644 -index 000000000..44fb2f4ea ---- /dev/null -+++ b/arch/arm/boot/dts/rk322x-box.dtsi -@@ -0,0 +1,250 @@ -+// SPDX-License-Identifier: (GPL-2.0+ OR MIT) -+ -+/dts-v1/; -+ -+#include -+#include -+#include -+#include -+#include "rk322x-dcdc.dtsi" -+ -+/ { -+ model = "Rockchip RK322x Box"; -+ compatible = "rockchip,rk3229"; -+ -+ chosen { -+ bootargs = "earlyprintk=uart8250,mmio32,0x11030000"; -+ }; -+ -+ gpio_keys { -+ compatible = "gpio-keys"; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ autorepeat; -+ -+ pinctrl-names = "default"; -+ pinctrl-0 = <&pwr_key>; -+ -+ power_key: power-key { -+ label = "GPIO Key Power"; -+ gpios = <&gpio3 RK_PD1 GPIO_ACTIVE_LOW>; -+ linux,code = ; -+ debounce-interval = <100>; -+ wakeup-source; -+ status = "disabled"; -+ }; -+ }; -+ -+ ir_receiver: ir-receiver { -+ compatible = "gpio-ir-receiver"; -+ gpios = <&gpio1 RK_PB3 GPIO_ACTIVE_LOW>; -+ pinctrl-0 = <&ir_int>; -+ pinctrl-names = "default"; -+ status = "disabled"; -+ }; -+ -+ memory@60000000 { -+ device_type = "memory"; -+ reg = <0x60000000 0x40000000>; -+ }; -+ -+ reserved-memory { -+ #address-cells = <1>; -+ #size-cells = <1>; -+ ranges; -+ -+ trust_reserved: trust@68400000 { -+ reg = <0x68400000 0xe00000>; -+ no-map; -+ }; -+ }; -+ -+ sdio_pwrseq: sdio-pwrseq { -+ compatible = "mmc-pwrseq-simple"; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&wifi_enable_h>; -+ reset-gpios = <&gpio2 RK_PD2 GPIO_ACTIVE_LOW>; -+ }; -+ -+ timer { -+ arm,cpu-registers-not-fw-configured; -+ }; -+}; -+ -+&cpu_alert1 { -+ temperature = <105000>; -+}; -+ -+&cpu_crit { -+ temperature = <115000>; -+}; -+ -+&cpu_thermal { -+ cooling-maps { -+ /delete-node/ map0; -+ }; -+}; -+ -+&emmc { -+ cap-mmc-highspeed; -+ keep-power-in-suspend; -+ non-removable; -+}; -+ -+&gmac { -+ assigned-clocks = <&cru SCLK_MAC_SRC>; -+ assigned-clock-rates = <50000000>; -+ clock_in_out = "output"; -+ phy-handle = <&phy>; -+ phy-mode = "rmii"; -+ status = "okay"; -+ -+ mdio { -+ compatible = "snps,dwmac-mdio"; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ -+ phy: phy@0 { -+ compatible = "ethernet-phy-id1234.d400", -+ "ethernet-phy-ieee802.3-c22"; -+ reg = <0>; -+ clocks = <&cru SCLK_MAC_PHY>; -+ phy-is-integrated; -+ resets = <&cru SRST_MACPHY>; -+ }; -+ }; -+}; -+ -+&hdmi { -+ status = "okay"; -+}; -+ -+&hdmi_sound { -+ status = "okay"; -+}; -+ -+&hdmi_phy { -+ status = "okay"; -+}; -+ -+&i2s0 { -+ status = "okay"; -+}; -+ -+&pinctrl { -+ -+ ir { -+ ir_int: ir-int { -+ rockchip,pins = <1 RK_PB3 RK_FUNC_GPIO &pcfg_pull_none>; -+ }; -+ }; -+ -+ keys { -+ pwr_key: pwr-key { -+ rockchip,pins = <3 RK_PC7 RK_FUNC_GPIO &pcfg_pull_up>; -+ }; -+ }; -+ -+ sdio-pwrseq { -+ wifi_enable_h: wifi-enable-h { -+ rockchip,pins = <2 RK_PD2 RK_FUNC_GPIO &pcfg_pull_none>; -+ }; -+ }; -+ -+}; -+ -+&rga { -+ status = "okay"; -+}; -+ -+&sdio { -+ mmc-pwrseq = <&sdio_pwrseq>; -+ cap-sd-highspeed; -+ cap-sdio-irq; -+ keep-power-in-suspend; -+ non-removable; -+ no-sd; -+}; -+ -+&sdmmc { -+ cap-sd-highspeed; -+ keep-power-in-suspend; -+ no-sdio; -+}; -+ -+&spdif { -+ status = "okay"; -+}; -+ -+&spdif_out { -+ status = "okay"; -+}; -+ -+&spdif_sound { -+ status = "okay"; -+}; -+ -+&tsadc { -+ rockchip,hw-tshut-mode = <0>; -+ rockchip,hw-tshut-polarity = <1>; -+ status = "okay"; -+}; -+ -+&u2phy0 { -+ status = "okay"; -+}; -+ -+&u2phy1 { -+ status = "okay"; -+}; -+ -+&uart1 { -+ pinctrl-names = "default"; -+ pinctrl-0 = <&uart11_xfer &uart11_rts &uart11_cts>; -+}; -+ -+&uart2 { -+ status = "okay"; -+}; -+ -+&usb_host0_ehci { -+ status = "okay"; -+}; -+ -+&usb_host0_ohci { -+ status = "okay"; -+}; -+ -+&usb_host1_ehci { -+ status = "okay"; -+}; -+ -+&usb_host1_ohci { -+ status = "okay"; -+}; -+ -+&usb_host2_ehci { -+ status = "okay"; -+}; -+ -+&usb_host2_ohci { -+ status = "okay"; -+}; -+ -+&usb_otg { -+ status = "okay"; -+}; -+ -+&vop { -+ assigned-clocks = <&cru DCLK_VOP>; -+ assigned-clock-parents = <&cru SCLK_HDMI_PHY>; -+ status = "okay"; -+}; -+ -+&vop_mmu { -+ status = "okay"; -+}; -+ -+&wdt { -+ status = "okay"; -+}; -diff --git a/arch/arm/boot/dts/rk322x-dcdc.dtsi b/arch/arm/boot/dts/rk322x-dcdc.dtsi -new file mode 100644 -index 000000000..6076cb1d0 ---- /dev/null -+++ b/arch/arm/boot/dts/rk322x-dcdc.dtsi -@@ -0,0 +1,164 @@ -+// SPDX-License-Identifier: (GPL-2.0+ OR MIT) -+ -+/dts-v1/; -+ -+#include -+#include -+#include "rk322x.dtsi" -+ -+/ { -+ -+ vcc_host: vcc-host-regulator { -+ compatible = "regulator-fixed"; -+ enable-active-high; -+ gpio = <&gpio3 RK_PC4 GPIO_ACTIVE_HIGH>; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&host_vbus_drv>; -+ regulator-name = "vcc_host"; -+ regulator-always-on; -+ regulator-boot-on; -+ vin-supply = <&vcc_sys>; -+ }; -+ -+ vccio_1v8: vccio-1v8-regulator { -+ compatible = "regulator-fixed"; -+ regulator-name = "vccio_1v8"; -+ regulator-min-microvolt = <1800000>; -+ regulator-max-microvolt = <1800000>; -+ regulator-always-on; -+ vin-supply = <&vcc_sys>; -+ }; -+ -+ vccio_3v3: vccio-3v3-regulator { -+ compatible = "regulator-fixed"; -+ regulator-name = "vccio_3v3"; -+ regulator-min-microvolt = <3300000>; -+ regulator-max-microvolt = <3300000>; -+ regulator-always-on; -+ vin-supply = <&vcc_sys>; -+ }; -+ -+ -+ vcc_otg: vcc-otg-regulator { -+ compatible = "regulator-fixed"; -+ enable-active-high; -+ gpio = <&gpio3 RK_PC6 GPIO_ACTIVE_HIGH>; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&otg_vbus_drv>; -+ regulator-name = "vcc_otg_vbus"; -+ regulator-min-microvolt = <5000000>; -+ regulator-max-microvolt = <5000000>; -+ regulator-always-on; -+ regulator-boot-on; -+ vin-supply = <&vcc_sys>; -+ }; -+ -+ vcc_phy: vcc-phy-regulator { -+ compatible = "regulator-fixed"; -+ enable-active-high; -+ regulator-name = "vcc_phy"; -+ regulator-min-microvolt = <1800000>; -+ regulator-max-microvolt = <1800000>; -+ regulator-always-on; -+ regulator-boot-on; -+ vin-supply = <&vccio_1v8>; -+ }; -+ -+ vcc_sys: vcc-sys-regulator { -+ compatible = "regulator-fixed"; -+ regulator-name = "vcc_sys"; -+ regulator-always-on; -+ regulator-boot-on; -+ regulator-min-microvolt = <5000000>; -+ regulator-max-microvolt = <5000000>; -+ }; -+ -+ vdd_arm: vdd-arm-regulator { -+ compatible = "pwm-regulator"; -+ pwms = <&pwm1 0 5000 1>; -+ pwm-supply = <&vcc_sys>; -+ regulator-name = "vdd_arm"; -+ regulator-min-microvolt = <950000>; -+ regulator-max-microvolt = <1400000>; -+ regulator-ramp-delay = <12500>; -+ regulator-settling-time-up-us = <250>; -+ regulator-always-on; -+ regulator-boot-on; -+ }; -+ -+ vdd_log: vdd-log-regulator { -+ compatible = "pwm-regulator"; -+ pwms = <&pwm2 0 5000 1>; -+ pwm-supply = <&vcc_sys>; -+ regulator-name = "vdd_log"; -+ regulator-min-microvolt = <1000000>; -+ regulator-max-microvolt = <1300000>; -+ regulator-ramp-delay = <12500>; -+ regulator-settling-time-up-us = <250>; -+ regulator-always-on; -+ regulator-boot-on; -+ }; -+ -+}; -+ -+ -+&cpu0 { -+ cpu-supply = <&vdd_arm>; -+}; -+ -+&cpu1 { -+ cpu-supply = <&vdd_arm>; -+}; -+ -+&cpu2 { -+ cpu-supply = <&vdd_arm>; -+}; -+ -+&cpu3 { -+ cpu-supply = <&vdd_arm>; -+}; -+ -+&io_domains { -+ vccio1-supply = <&vccio_3v3>; -+ vccio2-supply = <&vccio_1v8>; -+ vccio4-supply = <&vccio_3v3>; -+ status = "okay"; -+}; -+ -+&gmac { -+ phy-supply = <&vcc_phy>; -+}; -+ -+&gpu { -+ mali-supply = <&vdd_log>; -+}; -+ -+&pwm1 { -+ pinctrl-0 = <&pwm1_pin_pull_down>; -+ status = "okay"; -+}; -+ -+&pwm2 { -+ pinctrl-0 = <&pwm2_pin_pull_up>; -+ status = "okay"; -+}; -+ -+&u2phy0 { -+ u2phy0_host: host-port { -+ phy-supply = <&vcc_host>; -+ }; -+ -+ u2phy0_otg: otg-port { -+ phy-supply = <&vcc_otg>; -+ }; -+}; -+ -+&u2phy1 { -+ u2phy1_host: host-port { -+ phy-supply = <&vcc_host>; -+ }; -+ -+ u2phy1_otg: otg-port { -+ phy-supply = <&vcc_otg>; -+ }; -+}; -diff --git a/arch/arm/boot/dts/rk322x.dtsi b/arch/arm/boot/dts/rk322x.dtsi -index 5485a9918..c3ca67301 100644 ---- a/arch/arm/boot/dts/rk322x.dtsi -+++ b/arch/arm/boot/dts/rk322x.dtsi -@@ -5,6 +5,8 @@ - #include - #include - #include -+#include -+#include - #include - - / { -@@ -14,6 +16,7 @@ / { - interrupt-parent = <&gic>; - - aliases { -+ ethernet0 = &gmac; - serial0 = &uart0; - serial1 = &uart1; - serial2 = &uart2; -@@ -73,25 +76,25 @@ cpu0_opp_table: opp_table0 { - - opp-408000000 { - opp-hz = /bits/ 64 <408000000>; -- opp-microvolt = <950000>; -+ opp-microvolt = <950000 950000 1275000>; - clock-latency-ns = <40000>; - opp-suspend; - }; - opp-600000000 { - opp-hz = /bits/ 64 <600000000>; -- opp-microvolt = <975000>; -+ opp-microvolt = <975000 975000 1275000>; - }; - opp-816000000 { - opp-hz = /bits/ 64 <816000000>; -- opp-microvolt = <1000000>; -+ opp-microvolt = <1000000 1000000 1275000>; - }; - opp-1008000000 { - opp-hz = /bits/ 64 <1008000000>; -- opp-microvolt = <1175000>; -+ opp-microvolt = <1175000 1175000 1275000>; - }; - opp-1200000000 { - opp-hz = /bits/ 64 <1200000000>; -- opp-microvolt = <1275000>; -+ opp-microvolt = <1275000 1275000 1275000>; - }; - }; - -@@ -121,11 +124,52 @@ arm-pmu { - interrupt-affinity = <&cpu0>, <&cpu1>, <&cpu2>, <&cpu3>; - }; - -+ display_subsystem: display-subsystem { -+ compatible = "rockchip,display-subsystem"; -+ ports = <&vop_out>; -+ }; -+ -+ hdmi_sound: hdmi-sound { -+ compatible = "simple-audio-card"; -+ simple-audio-card,name = "HDMI"; -+ simple-audio-card,format = "i2s"; -+ simple-audio-card,mclk-fs = <128>; -+ status = "disabled"; -+ -+ simple-audio-card,cpu { -+ sound-dai = <&i2s0>; -+ }; -+ -+ simple-audio-card,codec { -+ sound-dai = <&hdmi>; -+ }; -+ }; -+ - psci { - compatible = "arm,psci-1.0", "arm,psci-0.2"; - method = "smc"; - }; - -+ spdif_out: spdif-out { -+ compatible = "linux,spdif-dit"; -+ #sound-dai-cells = <0>; -+ status = "disabled"; -+ }; -+ -+ spdif_sound: spdif-sound { -+ compatible = "simple-audio-card"; -+ simple-audio-card,name = "SPDIF"; -+ status = "disabled"; -+ -+ simple-audio-card,cpu { -+ sound-dai = <&spdif>; -+ }; -+ -+ simple-audio-card,codec { -+ sound-dai = <&spdif_out>; -+ }; -+ }; -+ - timer { - compatible = "arm,armv7-timer"; - arm,cpu-registers-not-fw-configured; -@@ -143,15 +187,13 @@ xin24m: oscillator { - #clock-cells = <0>; - }; - -- display_subsystem: display-subsystem { -- compatible = "rockchip,display-subsystem"; -- ports = <&vop_out>; -- }; -- - i2s1: i2s1@100b0000 { - compatible = "rockchip,rk3228-i2s", "rockchip,rk3066-i2s"; - reg = <0x100b0000 0x4000>; - interrupts = ; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ #sound-dai-cells = <0>; - clock-names = "i2s_clk", "i2s_hclk"; - clocks = <&cru SCLK_I2S1>, <&cru HCLK_I2S1_8CH>; - dmas = <&pdma 14>, <&pdma 15>; -@@ -165,6 +207,9 @@ i2s0: i2s0@100c0000 { - compatible = "rockchip,rk3228-i2s", "rockchip,rk3066-i2s"; - reg = <0x100c0000 0x4000>; - interrupts = ; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ #sound-dai-cells = <0>; - clock-names = "i2s_clk", "i2s_hclk"; - clocks = <&cru SCLK_I2S0>, <&cru HCLK_I2S0_8CH>; - dmas = <&pdma 11>, <&pdma 12>; -@@ -182,6 +227,7 @@ spdif: spdif@100d0000 { - dma-names = "tx"; - pinctrl-names = "default"; - pinctrl-0 = <&spdif_tx>; -+ #sound-dai-cells = <0>; - status = "disabled"; - }; - -@@ -189,6 +235,9 @@ i2s2: i2s2@100e0000 { - compatible = "rockchip,rk3228-i2s", "rockchip,rk3066-i2s"; - reg = <0x100e0000 0x4000>; - interrupts = ; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ #sound-dai-cells = <0>; - clock-names = "i2s_clk", "i2s_hclk"; - clocks = <&cru SCLK_I2S2>, <&cru HCLK_I2S2_2CH>; - dmas = <&pdma 0>, <&pdma 1>; -@@ -207,6 +256,43 @@ io_domains: io-domains { - status = "disabled"; - }; - -+ power: power-controller { -+ compatible = "rockchip,rk3228-power-controller"; -+ #power-domain-cells = <1>; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ -+ pd_gpu@RK3228_PD_GPU { -+ reg = ; -+ clocks = <&cru ACLK_GPU>; -+ pm_qos = <&qos_gpu>; -+ }; -+ -+ pd_vpu@RK3228_PD_VPU { -+ reg = ; -+ clocks = <&cru ACLK_VPU>, <&cru HCLK_VPU>; -+ pm_qos = <&qos_vpu>; -+ }; -+ -+ pd_rkvdec@RK3228_PD_RKVDEC { -+ reg = ; -+ clocks = <&cru ACLK_RKVDEC>, -+ <&cru HCLK_RKVDEC>, -+ <&cru SCLK_VDEC_CABAC>, -+ <&cru SCLK_VDEC_CORE>; -+ pm_qos = <&qos_rkvdec_r>, <&qos_rkvdec_w>; -+ }; -+ }; -+ -+ reboot_mode: reboot-mode { -+ compatible = "syscon-reboot-mode"; -+ offset = <0x5c8>; -+ mode-normal = ; -+ mode-recovery = ; -+ mode-bootloader = ; -+ mode-loader = ; -+ }; -+ - u2phy0: usb2-phy@760 { - compatible = "rockchip,rk3228-usb2phy"; - reg = <0x0760 0x0c>; -@@ -257,6 +343,7 @@ u2phy1_host: host-port { - status = "disabled"; - }; - }; -+ - }; - - uart0: serial@11010000 { -@@ -295,7 +382,7 @@ uart2: serial@11030000 { - clocks = <&cru SCLK_UART2>, <&cru PCLK_UART2>; - clock-names = "baudclk", "apb_pclk"; - pinctrl-names = "default"; -- pinctrl-0 = <&uart2_xfer>; -+ pinctrl-0 = <&uart21_xfer>; - reg-shift = <2>; - reg-io-width = <4>; - status = "disabled"; -@@ -454,13 +541,13 @@ cru: clock-controller@110e0000 { - <&cru PLL_CPLL>, <&cru ACLK_PERI>, - <&cru HCLK_PERI>, <&cru PCLK_PERI>, - <&cru ACLK_CPU>, <&cru HCLK_CPU>, -- <&cru PCLK_CPU>; -+ <&cru PCLK_CPU>, <&cru ACLK_VOP>; - assigned-clock-rates = -- <594000000>, <816000000>, -+ <1200000000>, <816000000>, - <500000000>, <150000000>, - <150000000>, <75000000>, - <150000000>, <150000000>, -- <75000000>; -+ <75000000>, <400000000>; - }; - - thermal-zones { -@@ -505,6 +592,12 @@ map1 { - <&cpu2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&cpu3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; - }; -+ -+ map2 { -+ trip = <&cpu_alert1>; -+ cooling-device = -+ <&gpu THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; -+ }; - }; - }; - }; -@@ -523,8 +616,9 @@ tsadc: tsadc@11150000 { - pinctrl-0 = <&otp_gpio>; - pinctrl-1 = <&otp_out>; - pinctrl-2 = <&otp_gpio>; -+ rockchip,grf = <&grf>; -+ rockchip,hw-tshut-temp = <120000>; - #thermal-sensor-cells = <0>; -- rockchip,hw-tshut-temp = <95000>; - status = "disabled"; - }; - -@@ -554,10 +648,33 @@ gpu: gpu@20000000 { - "ppmmu0", - "pp1", - "ppmmu1"; -+ assigned-clocks = <&cru ACLK_GPU>; -+ assigned-clock-rates = <300000000>; - clocks = <&cru ACLK_GPU>, <&cru ACLK_GPU>; - clock-names = "bus", "core"; -+ operating-points-v2 = <&gpu_opp_table>; -+ #cooling-cells = <2>; /* min followed by max */ -+ power-domains = <&power RK3228_PD_GPU>; - resets = <&cru SRST_GPU_A>; -- status = "disabled"; -+ }; -+ -+ gpu_opp_table: opp-table2 { -+ compatible = "operating-points-v2"; -+ -+ opp-200000000 { -+ opp-hz = /bits/ 64 <200000000>; -+ opp-microvolt = <1050000>; -+ }; -+ -+ opp-300000000 { -+ opp-hz = /bits/ 64 <300000000>; -+ opp-microvolt = <1050000>; -+ }; -+ -+ opp-500000000 { -+ opp-hz = /bits/ 64 <500000000>; -+ opp-microvolt = <1150000>; -+ }; - }; - - vpu_mmu: iommu@20020800 { -@@ -567,8 +684,8 @@ vpu_mmu: iommu@20020800 { - interrupt-names = "vpu_mmu"; - clocks = <&cru ACLK_VPU>, <&cru HCLK_VPU>; - clock-names = "aclk", "iface"; -- iommu-cells = <0>; -- status = "disabled"; -+ power-domains = <&power RK3228_PD_VPU>; -+ #iommu-cells = <0>; - }; - - vdec_mmu: iommu@20030480 { -@@ -578,8 +695,8 @@ vdec_mmu: iommu@20030480 { - interrupt-names = "vdec_mmu"; - clocks = <&cru ACLK_RKVDEC>, <&cru HCLK_RKVDEC>; - clock-names = "aclk", "iface"; -- iommu-cells = <0>; -- status = "disabled"; -+ power-domains = <&power RK3228_PD_RKVDEC>; -+ #iommu-cells = <0>; - }; - - vop: vop@20050000 { -@@ -622,7 +739,7 @@ iep_mmu: iommu@20070800 { - interrupt-names = "iep_mmu"; - clocks = <&cru ACLK_IEP>, <&cru HCLK_IEP>; - clock-names = "aclk", "iface"; -- iommu-cells = <0>; -+ #iommu-cells = <0>; - status = "disabled"; - }; - -@@ -642,6 +759,7 @@ hdmi: hdmi@200a0000 { - phys = <&hdmi_phy>; - phy-names = "hdmi"; - rockchip,grf = <&grf>; -+ #sound-dai-cells = <0>; - status = "disabled"; - - ports { -@@ -663,9 +781,13 @@ sdmmc: mmc@30000000 { - clocks = <&cru HCLK_SDMMC>, <&cru SCLK_SDMMC>, - <&cru SCLK_SDMMC_DRV>, <&cru SCLK_SDMMC_SAMPLE>; - clock-names = "biu", "ciu", "ciu-drive", "ciu-sample"; -+ bus-width = <4>; - fifo-depth = <0x100>; -+ max-frequency = <150000000>; - pinctrl-names = "default"; -- pinctrl-0 = <&sdmmc_clk &sdmmc_cmd &sdmmc_bus4>; -+ pinctrl-0 = <&sdmmc_clk &sdmmc_cmd &sdmmc_bus4 &sdmmc_pwr>; -+ resets = <&cru SRST_SDMMC>; -+ reset-names = "reset"; - status = "disabled"; - }; - -@@ -675,10 +797,14 @@ sdio: mmc@30010000 { - interrupts = ; - clocks = <&cru HCLK_SDIO>, <&cru SCLK_SDIO>, - <&cru SCLK_SDIO_DRV>, <&cru SCLK_SDIO_SAMPLE>; -+ bus-width = <4>; - clock-names = "biu", "ciu", "ciu-drive", "ciu-sample"; - fifo-depth = <0x100>; -+ max-frequency = <150000000>; - pinctrl-names = "default"; - pinctrl-0 = <&sdio_clk &sdio_cmd &sdio_bus4>; -+ resets = <&cru SRST_SDIO>; -+ reset-names = "reset"; - status = "disabled"; - }; - -@@ -686,8 +812,7 @@ emmc: mmc@30020000 { - compatible = "rockchip,rk3228-dw-mshc", "rockchip,rk3288-dw-mshc"; - reg = <0x30020000 0x4000>; - interrupts = ; -- clock-frequency = <37500000>; -- max-frequency = <37500000>; -+ max-frequency = <150000000>; - clocks = <&cru HCLK_EMMC>, <&cru SCLK_EMMC>, - <&cru SCLK_EMMC_DRV>, <&cru SCLK_EMMC_SAMPLE>; - clock-names = "biu", "ciu", "ciu-drive", "ciu-sample"; -@@ -701,6 +826,22 @@ emmc: mmc@30020000 { - status = "disabled"; - }; - -+ nfc: nand-controller@ff4b0000 { -+ compatible = "rockchip,rk3228_nfc"; -+ reg = <0x30030000 0x4000>; -+ interrupts = ; -+ clocks = <&cru SCLK_NANDC>, <&cru HCLK_NANDC>; -+ clock-names = "nfc", "ahb"; -+ assigned-clocks = <&cru SCLK_NANDC>; -+ assigned-clock-rates = <150000000>; -+ -+ pinctrl-names = "default"; -+ pinctrl-0 = <&flash_cs0 &flash_rdy &flash_ale &flash_cle -+ &flash_wrn &flash_rdn &flash_bus8>; -+ status = "disabled"; -+ -+ }; -+ - usb_otg: usb@30040000 { - compatible = "rockchip,rk3228-usb", "rockchip,rk3066-usb", - "snps,dwc2"; -@@ -796,6 +937,26 @@ gmac: ethernet@30200000 { - status = "disabled"; - }; - -+ qos_vpu: qos@31040000 { -+ compatible = "syscon"; -+ reg = <0x31040000 0x20>; -+ }; -+ -+ qos_gpu: qos@31050000 { -+ compatible = "syscon"; -+ reg = <0x31050000 0x20>; -+ }; -+ -+ qos_rkvdec_r: qos@31070000 { -+ compatible = "syscon"; -+ reg = <0x31070000 0x20>; -+ }; -+ -+ qos_rkvdec_w: qos@31070080 { -+ compatible = "syscon"; -+ reg = <0x31070080 0x20>; -+ }; -+ - gic: interrupt-controller@32010000 { - compatible = "arm,gic-400"; - interrupt-controller; -@@ -884,6 +1045,11 @@ pcfg_pull_none_drv_12ma: pcfg-pull-none-drv-12ma { - drive-strength = <12>; - }; - -+ pcfg_pull_up_12ma: pcfg-pull-up-12ma { -+ bias-pull-up; -+ drive-strength = <12>; -+ }; -+ - sdmmc { - sdmmc_clk: sdmmc-clk { - rockchip,pins = <1 RK_PC0 1 &pcfg_pull_none_drv_12ma>; -@@ -899,6 +1065,10 @@ sdmmc_bus4: sdmmc-bus4 { - <1 RK_PC4 1 &pcfg_pull_none_drv_12ma>, - <1 RK_PC5 1 &pcfg_pull_none_drv_12ma>; - }; -+ -+ sdmmc_pwr: sdmmc-pwr { -+ rockchip,pins = <1 RK_PB6 RK_FUNC_GPIO &pcfg_pull_none>; -+ }; - }; - - sdio { -@@ -939,6 +1109,55 @@ emmc_bus8: emmc-bus8 { - }; - }; - -+ flash { -+ -+ flash_cs0: flash-cs0 { -+ rockchip,pins = -+ <2 RK_PA6 1 &pcfg_pull_none>; -+ }; -+ -+ flash_cs1: flash-cs1 { -+ rockchip,pins = -+ <0 RK_PC7 1 &pcfg_pull_none>; -+ }; -+ -+ flash_rdy: flash-rdy { -+ rockchip,pins = -+ <2 RK_PA4 1 &pcfg_pull_none>; -+ }; -+ -+ flash_ale: flash-ale { -+ rockchip,pins = -+ <2 RK_PA0 1 &pcfg_pull_none>; -+ }; -+ -+ flash_cle: flash-cle { -+ rockchip,pins = -+ <2 RK_PA1 1 &pcfg_pull_none>; -+ }; -+ -+ flash_wrn: flash-wrn { -+ rockchip,pins = -+ <2 RK_PA2 1 &pcfg_pull_none>; -+ }; -+ -+ flash_rdn: flash-rdn { -+ rockchip,pins = -+ <2 RK_PA3 1 &pcfg_pull_none>; -+ }; -+ -+ flash_bus8: flash-bus8 { -+ rockchip,pins = <1 RK_PD0 1 &pcfg_pull_none>, -+ <1 RK_PD1 1 &pcfg_pull_none>, -+ <1 RK_PD2 1 &pcfg_pull_none>, -+ <1 RK_PD3 1 &pcfg_pull_none>, -+ <1 RK_PD4 1 &pcfg_pull_none>, -+ <1 RK_PD5 1 &pcfg_pull_none>, -+ <1 RK_PD6 1 &pcfg_pull_none>, -+ <1 RK_PD7 1 &pcfg_pull_none>; -+ }; -+ }; -+ - gmac { - rgmii_pins: rgmii-pins { - rockchip,pins = <2 RK_PB6 1 &pcfg_pull_none>, -@@ -1080,12 +1299,20 @@ pwm1 { - pwm1_pin: pwm1-pin { - rockchip,pins = <0 RK_PD6 2 &pcfg_pull_none>; - }; -+ -+ pwm1_pin_pull_down: pwm1-pin-pull-down { -+ rockchip,pins = <0 RK_PD6 RK_FUNC_2 &pcfg_pull_down>; -+ }; - }; - - pwm2 { - pwm2_pin: pwm2-pin { - rockchip,pins = <1 RK_PB4 2 &pcfg_pull_none>; - }; -+ -+ pwm2_pin_pull_up: pwm2-pin-pull-up { -+ rockchip,pins = <1 RK_PB4 RK_FUNC_2 &pcfg_pull_up>; -+ }; - }; - - pwm3 { -@@ -1140,16 +1367,31 @@ uart1_rts: uart1-rts { - }; - }; - -+ uart1-1 { -+ uart11_xfer: uart11-xfer { -+ rockchip,pins = <3 RK_PB6 RK_FUNC_1 &pcfg_pull_up>, -+ <3 RK_PB5 RK_FUNC_1 &pcfg_pull_none>; -+ }; -+ -+ uart11_cts: uart11-cts { -+ rockchip,pins = <3 RK_PA7 RK_FUNC_1 &pcfg_pull_none>; -+ }; -+ -+ uart11_rts: uart11-rts { -+ rockchip,pins = <3 RK_PA6 RK_FUNC_1 &pcfg_pull_none>; -+ }; -+ -+ uart11_rts_gpio: uart11-rts-gpio { -+ rockchip,pins = <3 RK_PA6 RK_FUNC_GPIO &pcfg_pull_none>; -+ }; -+ }; -+ - uart2 { - uart2_xfer: uart2-xfer { - rockchip,pins = <1 RK_PC2 2 &pcfg_pull_up>, - <1 RK_PC3 2 &pcfg_pull_none>; - }; - -- uart21_xfer: uart21-xfer { -- rockchip,pins = <1 RK_PB2 2 &pcfg_pull_up>, -- <1 RK_PB1 2 &pcfg_pull_none>; -- }; - - uart2_cts: uart2-cts { - rockchip,pins = <0 RK_PD1 1 &pcfg_pull_none>; -@@ -1159,5 +1401,23 @@ uart2_rts: uart2-rts { - rockchip,pins = <0 RK_PD0 1 &pcfg_pull_none>; - }; - }; -+ -+ uart2-1 { -+ uart21_xfer: uart21-xfer { -+ rockchip,pins = <1 RK_PB2 RK_FUNC_2 &pcfg_pull_up>, -+ <1 RK_PB1 RK_FUNC_2 &pcfg_pull_none>; -+ }; -+ }; -+ -+ usb { -+ host_vbus_drv: host-vbus-drv { -+ rockchip,pins = <3 RK_PC4 RK_FUNC_GPIO &pcfg_pull_none>; -+ }; -+ -+ otg_vbus_drv: otg-vbus-drv { -+ rockchip,pins = <3 RK_PC6 RK_FUNC_GPIO &pcfg_pull_none>; -+ }; -+ }; -+ - }; - }; -diff --git a/arch/arm/boot/dts/rk322x.dtsi.rej b/arch/arm/boot/dts/rk322x.dtsi.rej -new file mode 100644 -index 000000000..cc36be3e9 ---- /dev/null -+++ b/arch/arm/boot/dts/rk322x.dtsi.rej -@@ -0,0 +1,45 @@ -+--- arch/arm/boot/dts/rk322x.dtsi -++++ arch/arm/boot/dts/rk322x.dtsi -+@@ -187,17 +231,13 @@ -+ #clock-cells = <0>; -+ }; -+ -+- display_subsystem: display-subsystem { -+- compatible = "rockchip,display-subsystem"; -+- ports = <&vop_out>; -+- }; -+- -+ i2s1: i2s1@100b0000 { -+ compatible = "rockchip,rk3228-i2s", "rockchip,rk3066-i2s"; -+ reg = <0x100b0000 0x4000>; -+ interrupts = ; -+ #address-cells = <1>; -+ #size-cells = <0>; -++ #sound-dai-cells = <0>; -+ clock-names = "i2s_clk", "i2s_hclk"; -+ clocks = <&cru SCLK_I2S1>, <&cru HCLK_I2S1_8CH>; -+ dmas = <&pdma 14>, <&pdma 15>; -+@@ -213,6 +253,7 @@ -+ interrupts = ; -+ #address-cells = <1>; -+ #size-cells = <0>; -++ #sound-dai-cells = <0>; -+ clock-names = "i2s_clk", "i2s_hclk"; -+ clocks = <&cru SCLK_I2S0>, <&cru HCLK_I2S0_8CH>; -+ dmas = <&pdma 11>, <&pdma 12>; -+@@ -825,14 +944,13 @@ -+ compatible = "rockchip,rk3228-dw-mshc", "rockchip,rk3288-dw-mshc"; -+ reg = <0x30020000 0x4000>; -+ interrupts = ; -+- clock-frequency = <37500000>; -+- max-frequency = <37500000>; -+ clocks = <&cru HCLK_EMMC>, <&cru SCLK_EMMC>, -+ <&cru SCLK_EMMC_DRV>, <&cru SCLK_EMMC_SAMPLE>; -+ clock-names = "biu", "ciu", "ciu-drive", "ciu-sample"; -+ bus-width = <8>; -+ default-sample-phase = <158>; -+ fifo-depth = <0x100>; -++ max-frequency = <150000000>; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&emmc_clk &emmc_cmd &emmc_bus8>; -+ resets = <&cru SRST_EMMC>; diff --git a/patch/kernel/rk322x-current/01-linux-1003-rk322x-hantro.patch b/patch/kernel/rk322x-current/01-linux-1003-rk322x-hantro.patch deleted file mode 100644 index e63bce853..000000000 --- a/patch/kernel/rk322x-current/01-linux-1003-rk322x-hantro.patch +++ /dev/null @@ -1,98 +0,0 @@ -diff --git a/Documentation/devicetree/bindings/media/rockchip-vpu.yaml b/Documentation/devicetree/bindings/media/rockchip-vpu.yaml -index a0c45e05cf03..a20cfaa8973e 100644 ---- a/Documentation/devicetree/bindings/media/rockchip-vpu.yaml -+++ b/Documentation/devicetree/bindings/media/rockchip-vpu.yaml -@@ -16,6 +16,7 @@ description: - properties: - compatible: - enum: -+ - rockchip,rk322x-vpu - - rockchip,rk3288-vpu - - rockchip,rk3328-vpu - - rockchip,rk3399-vpu -diff --git a/arch/arm/boot/dts/rk322x.dtsi b/arch/arm/boot/dts/rk322x.dtsi -index f7a50b903a7d..2ed8aa7ae520 100644 ---- a/arch/arm/boot/dts/rk322x.dtsi -+++ b/arch/arm/boot/dts/rk322x.dtsi -@@ -676,6 +676,18 @@ - }; - }; - -+ vpu: video-codec@20020000 { -+ compatible = "rockchip,rk322x-vpu"; -+ reg = <0x20020000 0x800>; -+ interrupts = , -+ ; -+ interrupt-names = "vepu", "vdpu"; -+ clocks = <&cru ACLK_VPU>, <&cru HCLK_VPU>; -+ clock-names = "aclk", "hclk"; -+ iommus = <&vpu_mmu>; -+ power-domains = <&power RK3228_PD_VPU>; -+ }; -+ - vpu_mmu: iommu@20020800 { - compatible = "rockchip,iommu"; - reg = <0x20020800 0x100>; -diff --git a/drivers/staging/media/hantro/Kconfig b/drivers/staging/media/hantro/Kconfig -index de77fe6554e7..9f99d1c9f453 100644 ---- a/drivers/staging/media/hantro/Kconfig -+++ b/drivers/staging/media/hantro/Kconfig -@@ -20,4 +20,4 @@ config VIDEO_HANTRO_ROCKCHIP - depends on ARCH_ROCKCHIP || COMPILE_TEST - default y - help -- Enable support for RK3288, RK3328, and RK3399 SoCs. -+ Enable support for RK322x, RK3288, RK3328, and RK3399 SoCs. -diff --git a/drivers/staging/media/hantro/hantro_drv.c b/drivers/staging/media/hantro/hantro_drv.c -index a732beeb3bb6..fae9555a349b 100644 ---- a/drivers/staging/media/hantro/hantro_drv.c -+++ b/drivers/staging/media/hantro/hantro_drv.c -@@ -469,6 +469,7 @@ static const struct of_device_id of_hantro_match[] = { - { .compatible = "rockchip,rk3399-vpu", .data = &rk3399_vpu_variant, }, - { .compatible = "rockchip,rk3328-vpu", .data = &rk3328_vpu_variant, }, - { .compatible = "rockchip,rk3288-vpu", .data = &rk3288_vpu_variant, }, -+ { .compatible = "rockchip,rk322x-vpu", .data = &rk322x_vpu_variant, }, - #endif - { /* sentinel */ } - }; -diff --git a/drivers/staging/media/hantro/hantro_hw.h b/drivers/staging/media/hantro/hantro_hw.h -index 33c1ce169203..e64369e01a21 100644 ---- a/drivers/staging/media/hantro/hantro_hw.h -+++ b/drivers/staging/media/hantro/hantro_hw.h -@@ -157,6 +157,7 @@ enum hantro_enc_fmt { - extern const struct hantro_variant rk3399_vpu_variant; - extern const struct hantro_variant rk3328_vpu_variant; - extern const struct hantro_variant rk3288_vpu_variant; -+extern const struct hantro_variant rk322x_vpu_variant; - extern const struct hantro_variant imx8mq_vpu_variant; - - extern const struct hantro_postproc_regs hantro_g1_postproc_regs; - -diff --git a/drivers/staging/media/hantro/rk3399_vpu_hw.c b/drivers/staging/media/hantro/rk3399_vpu_hw.c -index 78f878ca01ff..0a6c021c2332 100644 ---- a/drivers/staging/media/hantro/rk3399_vpu_hw.c -+++ b/drivers/staging/media/hantro/rk3399_vpu_hw.c -@@ -241,3 +241,20 @@ const struct hantro_variant rk3328_vpu_variant = { - .clk_names = rk3399_clk_names, - .num_clocks = ARRAY_SIZE(rk3399_clk_names), - }; -+ -+const struct hantro_variant rk322x_vpu_variant = { -+ .enc_offset = 0x0, -+ .enc_fmts = rk3399_vpu_enc_fmts, -+ .num_enc_fmts = ARRAY_SIZE(rk3399_vpu_enc_fmts), -+ .dec_offset = 0x400, -+ .dec_fmts = rk3399_vpu_dec_fmts, -+ .num_dec_fmts = ARRAY_SIZE(rk3399_vpu_dec_fmts), -+ .codec = HANTRO_MPEG2_DECODER | HANTRO_VP8_DECODER | -+ HANTRO_H264_DECODER, -+ .codec_ops = rk3399_vpu_codec_ops, -+ .irqs = rk3399_irqs, -+ .num_irqs = ARRAY_SIZE(rk3399_irqs), -+ .init = rk3399_vpu_hw_init, -+ .clk_names = rk3399_clk_names, -+ .num_clocks = ARRAY_SIZE(rk3399_clk_names) -+}; --- -2.17.1 - diff --git a/patch/kernel/rk322x-current/01-linux-1004-rockchip-rk322x-enhancements-and-fixes.patch b/patch/kernel/rk322x-current/01-linux-1004-rockchip-rk322x-enhancements-and-fixes.patch deleted file mode 100644 index aa5a48973..000000000 --- a/patch/kernel/rk322x-current/01-linux-1004-rockchip-rk322x-enhancements-and-fixes.patch +++ /dev/null @@ -1,383 +0,0 @@ -diff --git a/drivers/soc/rockchip/pm_domains.c b/drivers/soc/rockchip/pm_domains.c -index 54eb6cfc5d5b..c6b33f7c43df 100644 ---- a/drivers/soc/rockchip/pm_domains.c -+++ b/drivers/soc/rockchip/pm_domains.c -@@ -71,6 +71,7 @@ struct rockchip_pm_domain { - struct regmap **qos_regmap; - u32 *qos_save_regs[MAX_QOS_REGS_NUM]; - int num_clks; -+ bool is_ignore_pwr; - struct clk_bulk_data *clks; - }; - -@@ -330,6 +331,9 @@ static int rockchip_pd_power_on(struct generic_pm_domain *domain) - { - struct rockchip_pm_domain *pd = to_rockchip_pd(domain); - -+ if (pd->is_ignore_pwr) -+ return 0; -+ - return rockchip_pd_power(pd, true); - } - -@@ -337,6 +341,9 @@ static int rockchip_pd_power_off(struct generic_pm_domain *domain) - { - struct rockchip_pm_domain *pd = to_rockchip_pd(domain); - -+ if (pd->is_ignore_pwr) -+ return 0; -+ - return rockchip_pd_power(pd, false); - } - -@@ -416,6 +423,9 @@ static int rockchip_pm_add_one_domain(struct rockchip_pmu *pmu, - pd->info = pd_info; - pd->pmu = pmu; - -+ if (!pd_info->pwr_mask) -+ pd->is_ignore_pwr = true; -+ - pd->num_clks = of_clk_get_parent_count(node); - if (pd->num_clks > 0) { - pd->clks = devm_kcalloc(pmu->dev, pd->num_clks, -@@ -566,6 +576,7 @@ static int rockchip_pm_add_subdomain(struct rockchip_pmu *pmu, - { - struct device_node *np; - struct generic_pm_domain *child_domain, *parent_domain; -+ struct rockchip_pm_domain *child_pd, *parent_pd; - int error; - - for_each_child_of_node(parent, np) { -@@ -606,6 +617,18 @@ static int rockchip_pm_add_subdomain(struct rockchip_pmu *pmu, - parent_domain->name, child_domain->name); - } - -+ /* -+ * If child_pd doesn't do idle request or power on/off, -+ * parent_pd may fail to do power on/off, so if parent_pd -+ * need to power on/off, child_pd can't ignore to do idle -+ * request and power on/off. -+ */ -+ child_pd = to_rockchip_pd(child_domain); -+ parent_pd = to_rockchip_pd(parent_domain); -+ if (!parent_pd->is_ignore_pwr) -+ child_pd->is_ignore_pwr = false; -+ -+ - rockchip_pm_add_subdomain(pmu, np); - } - --- -2.17.1 - -From c94b1272290bafced10d79b7da1525466e8c843b Mon Sep 17 00:00:00 2001 -From: "Huang, Tao" -Date: Thu, 28 Jul 2016 10:59:22 +0800 -Subject: [PATCH] power: reset: reboot-mode: fix normal mode setup - -If cmd is empty in get_reboot_mode_magic, we should return normal magic. - -Change-Id: I10931adc49e33f72ae73d9471159f82cc02ff0c0 -Signed-off-by: Huang, Tao ---- - drivers/power/reset/reboot-mode.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/drivers/power/reset/reboot-mode.c b/drivers/power/reset/reboot-mode.c -index b4076b10b893..47f9a162807d 100644 ---- a/drivers/power/reset/reboot-mode.c -+++ b/drivers/power/reset/reboot-mode.c -@@ -26,7 +26,7 @@ static unsigned int get_reboot_mode_magic(struct reboot_mode_driver *reboot, - int magic = 0; - struct mode_info *info; - -- if (!cmd) -+ if (!cmd || !cmd[0]) - cmd = normal; - - list_for_each_entry(info, &reboot->head, list) { --- -2.17.1 - - -From be9674f270c97399f9f6b1facb11e93eced6ec34 Mon Sep 17 00:00:00 2001 -From: Andy Yan -Date: Thu, 8 Dec 2016 16:58:07 +0800 -Subject: [PATCH] power: reset: reboot-mode: treat unrecognized reboot mode as - normal mode - -Some bootloader will check the reboot mode to take different action, so -we treat unrecognized reboot mode as normal mode to prevent the system -run into abnormal case. - -Change-Id: I88063a5b41e4e645443229fa490b2b55db5ccf27 -Signed-off-by: Andy Yan ---- - drivers/power/reset/reboot-mode.c | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/drivers/power/reset/reboot-mode.c b/drivers/power/reset/reboot-mode.c -index 47f9a162807d..99bf938404e3 100644 ---- a/drivers/power/reset/reboot-mode.c -+++ b/drivers/power/reset/reboot-mode.c -@@ -47,6 +47,8 @@ static int reboot_mode_notify(struct notifier_block *this, - - reboot = container_of(this, struct reboot_mode_driver, reboot_notifier); - magic = get_reboot_mode_magic(reboot, cmd); -+ if (!magic) -+ magic = get_reboot_mode_magic(reboot, NULL); - if (magic) - reboot->write(reboot, magic); - --- -2.17.1 - -From 7c097120eb21a9bd15ab63c0ac60ffd5cba902b2 Mon Sep 17 00:00:00 2001 -From: Alex Bee -Date: Fri, 24 Apr 2020 13:01:07 +0200 -Subject: [PATCH] sound: soc: rockchip: use rouned rate for i2s - ---- - sound/soc/rockchip/rockchip_i2s.c | 9 +++++++-- - 1 file changed, 7 insertions(+), 2 deletions(-) - -diff --git a/sound/soc/rockchip/rockchip_i2s.c b/sound/soc/rockchip/rockchip_i2s.c -index 61c984f10d8e..efca853eba6b 100644 ---- a/sound/soc/rockchip/rockchip_i2s.c -+++ b/sound/soc/rockchip/rockchip_i2s.c -@@ -279,10 +279,13 @@ static int rockchip_i2s_hw_params(struct snd_pcm_substream *substream, - if (i2s->is_master_mode) { - mclk_rate = clk_get_rate(i2s->mclk); - bclk_rate = 2 * 32 * params_rate(params); -- if (bclk_rate && mclk_rate % bclk_rate) -+ if (!bclk_rate) { -+ dev_err(i2s->dev, "invalid bclk_rate: %d\n", -+ bclk_rate); - return -EINVAL; -+ } - -- div_bclk = mclk_rate / bclk_rate; -+ div_bclk = DIV_ROUND_CLOSEST(mclk_rate, bclk_rate); - div_lrck = bclk_rate / params_rate(params); - regmap_update_bits(i2s->regmap, I2S_CKR, - I2S_CKR_MDIV_MASK, -@@ -312,6 +315,8 @@ static int rockchip_i2s_hw_params(struct snd_pcm_substream *substream, - val |= I2S_TXCR_VDW(32); - break; - default: -+ dev_err(i2s->dev, "invalid format: %d\n", -+ params_format(params)); - return -EINVAL; - } - --- -2.17.1 - - -From 4102c5b07d8610c729d577612c1df52737fb9a0f Mon Sep 17 00:00:00 2001 -From: Alex Bee -Date: Fri, 24 Apr 2020 09:08:44 +0200 -Subject: [PATCH] phy: rockchip: hdmi: readout hdmi phy flag for RK3228 HDMI - phys - -Some RK3228 HDMI phys only get a stable pll on frequencies higher 337,5 MHz. -This is defined in a flag in efuse of those devices. ---- - arch/arm/boot/dts/rk322x.dtsi | 7 ++++ - drivers/phy/rockchip/phy-rockchip-inno-hdmi.c | 38 ++++++++++++++++++- - 2 files changed, 43 insertions(+), 2 deletions(-) - -diff --git a/arch/arm/boot/dts/rk322x.dtsi b/arch/arm/boot/dts/rk322x.dtsi -index 2ed8aa7ae520..8c50dcb0e9f1 100644 ---- a/arch/arm/boot/dts/rk322x.dtsi -+++ b/arch/arm/boot/dts/rk322x.dtsi -@@ -402,6 +402,11 @@ - cpu_leakage: cpu_leakage@17 { - reg = <0x17 0x1>; - }; -+ -+ hdmi_phy_flag: hdmi-phy-flag@1d { -+ reg = <0x1d 0x1>; -+ bits = <1 1>; -+ }; - }; - - i2c0: i2c@11050000 { -@@ -628,6 +633,8 @@ - clock-names = "sysclk", "refoclk", "refpclk"; - #clock-cells = <0>; - clock-output-names = "hdmiphy_phy"; -+ nvmem-cells = <&hdmi_phy_flag>; -+ nvmem-cell-names = "hdmi-phy-flag"; - #phy-cells = <0>; - status = "disabled"; - }; -diff --git a/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c b/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c -index bb8bdf5e3301..0c7a97352714 100644 ---- a/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c -+++ b/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c -@@ -237,6 +237,9 @@ struct inno_hdmi_phy { - struct clk *refoclk; - struct clk *refpclk; - -+ /* phy_flag flag */ -+ bool phy_flag; -+ - /* platform data */ - const struct inno_hdmi_phy_drv_data *plat_data; - int chip_version; -@@ -347,6 +350,7 @@ static const struct pre_pll_config pre_pll_cfg_table[] = { - static const struct post_pll_config post_pll_cfg_table[] = { - {33750000, 1, 40, 8, 1}, - {33750000, 1, 80, 8, 2}, -+ {33750000, 1, 10, 2, 4}, - {74250000, 1, 40, 8, 1}, - {74250000, 18, 80, 8, 2}, - {148500000, 2, 40, 4, 3}, -@@ -497,8 +501,11 @@ static int inno_hdmi_phy_power_on(struct phy *phy) - return -EINVAL; - - for (; cfg->tmdsclock != 0; cfg++) -- if (tmdsclock <= cfg->tmdsclock && -- cfg->version & inno->chip_version) -+ if (((!inno->phy_flag || tmdsclock > 33750000) -+ && tmdsclock <= cfg->tmdsclock -+ && cfg->version & inno->chip_version) || -+ (inno->phy_flag && tmdsclock <= 33750000 -+ && cfg->version & 4)) - break; - - for (; phy_cfg->tmdsclock != 0; phy_cfg++) -@@ -909,6 +916,10 @@ static int inno_hdmi_phy_clk_register(struct inno_hdmi_phy *inno) - - static int inno_hdmi_phy_rk3228_init(struct inno_hdmi_phy *inno) - { -+ struct nvmem_cell *cell; -+ unsigned char *efuse_buf; -+ size_t len; -+ - /* - * Use phy internal register control - * rxsense/poweron/pllpd/pdataen signal. -@@ -923,7 +934,28 @@ static int inno_hdmi_phy_rk3228_init(struct inno_hdmi_phy *inno) - inno_update_bits(inno, 0xaa, RK3228_POST_PLL_CTRL_MANUAL, - RK3228_POST_PLL_CTRL_MANUAL); - -+ - inno->chip_version = 1; -+ inno->phy_flag = false; -+ -+ cell = nvmem_cell_get(inno->dev, "hdmi-phy-flag"); -+ if (IS_ERR(cell)) { -+ if (PTR_ERR(cell) == -EPROBE_DEFER) -+ return -EPROBE_DEFER; -+ -+ return 0; -+ } -+ -+ efuse_buf = nvmem_cell_read(cell, &len); -+ nvmem_cell_put(cell); -+ -+ if (IS_ERR(efuse_buf)) -+ return 0; -+ if (len == 1) -+ inno->phy_flag = (efuse_buf[0] & BIT(1)) ? true : false; -+ kfree(efuse_buf); -+ -+ dev_info(inno->dev, "phy_flag is: %d\n", inno->phy_flag); - - return 0; - } -@@ -1023,6 +1055,8 @@ static int inno_hdmi_phy_rk3328_init(struct inno_hdmi_phy *inno) - - /* try to read the chip-version */ - inno->chip_version = 1; -+ inno->phy_flag = false; -+ - cell = nvmem_cell_get(inno->dev, "cpu-version"); - if (IS_ERR(cell)) { - if (PTR_ERR(cell) == -EPROBE_DEFER) --- -2.17.1 - - -From fe30b024a7a7d6261dff0b87c2aec270ad530c39 Mon Sep 17 00:00:00 2001 -From: Alex Bee -Date: Fri, 24 Apr 2020 14:23:38 +0200 -Subject: [PATCH] drm: rockchip: Use 2nd RK3228 plane as an overlay - -As per datasheet the second plane of RK3228 vop is an overlay window. For -the missing implementation of hardware cursor it is missued as such (as -already pointed in comment for RK3288). Furthermore the overlay window -does not support YUV modes with the current implementation - so it -supports only RGB modes for now. ---- - drivers/gpu/drm/rockchip/rockchip_vop_reg.c | 44 +++++++++++++++++++-- - 1 file changed, 41 insertions(+), 3 deletions(-) - -diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c -index 73d24c6bbf05..d4ac6e161ef2 100644 ---- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c -+++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c -@@ -614,6 +614,44 @@ static const struct vop_common rk3288_common = { - .dsp_background = VOP_REG(RK3288_DSP_BG, 0xffffffff, 0), - }; - -+static const struct vop_win_phy rk3228_win0_data = { -+ .scl = &rk3288_win_full_scl, -+ .data_formats = formats_win_full, -+ .nformats = ARRAY_SIZE(formats_win_full), -+ .enable = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 0), -+ .format = VOP_REG(RK3288_WIN0_CTRL0, 0x7, 1), -+ .rb_swap = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 12), -+ .act_info = VOP_REG(RK3288_WIN0_ACT_INFO, 0x1fff1fff, 0), -+ .dsp_info = VOP_REG(RK3288_WIN0_DSP_INFO, 0x0fff0fff, 0), -+ .dsp_st = VOP_REG(RK3288_WIN0_DSP_ST, 0x1fff1fff, 0), -+ .yrgb_mst = VOP_REG(RK3288_WIN0_YRGB_MST, 0xffffffff, 0), -+ .uv_mst = VOP_REG(RK3288_WIN0_CBR_MST, 0xffffffff, 0), -+ .yrgb_vir = VOP_REG(RK3288_WIN0_VIR, 0x3fff, 0), -+ .uv_vir = VOP_REG(RK3288_WIN0_VIR, 0x3fff, 16), -+ .src_alpha_ctl = VOP_REG(RK3288_WIN0_SRC_ALPHA_CTRL, 0xff, 0), -+ .dst_alpha_ctl = VOP_REG(RK3288_WIN0_DST_ALPHA_CTRL, 0xff, 0), -+ .channel = VOP_REG(RK3288_WIN0_CTRL2, 0xff, 0), -+}; -+ -+static const struct vop_win_phy rk3228_win1_data = { -+ .scl = &rk3288_win_full_scl, -+ .data_formats = formats_win_lite, -+ .nformats = ARRAY_SIZE(formats_win_lite), -+ .enable = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 0), -+ .format = VOP_REG(RK3288_WIN0_CTRL0, 0x7, 1), -+ .rb_swap = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 12), -+ .act_info = VOP_REG(RK3288_WIN0_ACT_INFO, 0x1fff1fff, 0), -+ .dsp_info = VOP_REG(RK3288_WIN0_DSP_INFO, 0x0fff0fff, 0), -+ .dsp_st = VOP_REG(RK3288_WIN0_DSP_ST, 0x1fff1fff, 0), -+ .yrgb_mst = VOP_REG(RK3288_WIN0_YRGB_MST, 0xffffffff, 0), -+ .uv_mst = VOP_REG(RK3288_WIN0_CBR_MST, 0xffffffff, 0), -+ .yrgb_vir = VOP_REG(RK3288_WIN0_VIR, 0x3fff, 0), -+ .uv_vir = VOP_REG(RK3288_WIN0_VIR, 0x3fff, 16), -+ .src_alpha_ctl = VOP_REG(RK3288_WIN0_SRC_ALPHA_CTRL, 0xff, 0), -+ .dst_alpha_ctl = VOP_REG(RK3288_WIN0_DST_ALPHA_CTRL, 0xff, 0), -+ .channel = VOP_REG(RK3288_WIN0_CTRL2, 0xff, 0), -+}; -+ - /* - * Note: rk3288 has a dedicated 'cursor' window, however, that window requires - * special support to get alpha blending working. For now, just use overlay -@@ -864,10 +902,10 @@ static const struct vop_data rk3399_vop_lit = { - }; - - static const struct vop_win_data rk3228_vop_win_data[] = { -- { .base = 0x00, .phy = &rk3288_win01_data, -+ { .base = 0x00, .phy = &rk3228_win0_data, - .type = DRM_PLANE_TYPE_PRIMARY }, -- { .base = 0x40, .phy = &rk3288_win01_data, -- .type = DRM_PLANE_TYPE_CURSOR }, -+ { .base = 0x40, .phy = &rk3228_win1_data, -+ .type = DRM_PLANE_TYPE_OVERLAY }, - }; - - static const struct vop_data rk3228_vop = { --- -2.17.1 - diff --git a/patch/kernel/rk322x-current/01-linux-2000-rockchip-drm-wip.patch b/patch/kernel/rk322x-current/01-linux-2000-rockchip-drm-wip.patch new file mode 100644 index 000000000..454c77a33 --- /dev/null +++ b/patch/kernel/rk322x-current/01-linux-2000-rockchip-drm-wip.patch @@ -0,0 +1,5333 @@ +From 4fe70563eb6f08f737ecc7091b8c4806e18a2479 Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Wed, 8 Jan 2020 21:07:47 +0000 +Subject: [PATCH] phy/rockchip: inno-hdmi: use correct vco_div_5 macro on + rk3328 + +inno_hdmi_phy_rk3328_clk_set_rate() is using the RK3228 macro +when configuring vco_div_5 on RK3328. + +Fix this by using correct vco_div_5 macro for RK3328. + +Fixes: 53706a116863 ("phy: add Rockchip Innosilicon hdmi phy") +Signed-off-by: Jonas Karlman +--- + drivers/phy/rockchip/phy-rockchip-inno-hdmi.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c b/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c +index 9ca20c947283..b0ac1d3ee390 100644 +--- a/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c ++++ b/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c +@@ -790,8 +790,8 @@ static int inno_hdmi_phy_rk3328_clk_set_rate(struct clk_hw *hw, + RK3328_PRE_PLL_POWER_DOWN); + + /* Configure pre-pll */ +- inno_update_bits(inno, 0xa0, RK3228_PCLK_VCO_DIV_5_MASK, +- RK3228_PCLK_VCO_DIV_5(cfg->vco_div_5_en)); ++ inno_update_bits(inno, 0xa0, RK3328_PCLK_VCO_DIV_5_MASK, ++ RK3328_PCLK_VCO_DIV_5(cfg->vco_div_5_en)); + inno_write(inno, 0xa1, RK3328_PRE_PLL_PRE_DIV(cfg->prediv)); + + val = RK3328_SPREAD_SPECTRUM_MOD_DISABLE; + +From 619967c6bc6f6c81a3dabf8b2d4c0f5f3b3afc78 Mon Sep 17 00:00:00 2001 +From: Zheng Yang +Date: Wed, 8 Jan 2020 21:07:48 +0000 +Subject: [PATCH] phy/rockchip: inno-hdmi: round fractal pixclock in rk3328 + recalc_rate + +inno_hdmi_phy_rk3328_clk_recalc_rate() is returning a rate not found +in the pre pll config table when the fractal divider is used. +This can prevent proper power_on because a tmdsclock for the new rate +is not found in the pre pll config table. + +Fix this by saving and returning a rounded pixel rate that exist +in the pre pll config table. + +Fixes: 53706a116863 ("phy: add Rockchip Innosilicon hdmi phy") +Signed-off-by: Zheng Yang +Signed-off-by: Jonas Karlman +--- + drivers/phy/rockchip/phy-rockchip-inno-hdmi.c | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +diff --git a/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c b/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c +index b0ac1d3ee390..093d2334e8cd 100644 +--- a/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c ++++ b/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c +@@ -745,10 +745,12 @@ unsigned long inno_hdmi_phy_rk3328_clk_recalc_rate(struct clk_hw *hw, + do_div(vco, (nd * (no_a == 1 ? no_b : no_a) * no_d * 2)); + } + +- inno->pixclock = vco; +- dev_dbg(inno->dev, "%s rate %lu\n", __func__, inno->pixclock); ++ inno->pixclock = DIV_ROUND_CLOSEST((unsigned long)vco, 1000) * 1000; + +- return vco; ++ dev_dbg(inno->dev, "%s rate %lu vco %llu\n", ++ __func__, inno->pixclock, vco); ++ ++ return inno->pixclock; + } + + static long inno_hdmi_phy_rk3328_clk_round_rate(struct clk_hw *hw, + +From 8fe477a61c44d9df65a1f3a7bd9a0d7b4be7760b Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Wed, 8 Jan 2020 21:07:48 +0000 +Subject: [PATCH] phy/rockchip: inno-hdmi: remove unused no_c from rk3328 + recalc_rate + +no_c is not used in any calculation, lets remove it. + +Signed-off-by: Jonas Karlman +--- + drivers/phy/rockchip/phy-rockchip-inno-hdmi.c | 5 +---- + 1 file changed, 1 insertion(+), 4 deletions(-) + +diff --git a/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c b/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c +index 093d2334e8cd..06db69c8373e 100644 +--- a/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c ++++ b/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c +@@ -714,7 +714,7 @@ unsigned long inno_hdmi_phy_rk3328_clk_recalc_rate(struct clk_hw *hw, + { + struct inno_hdmi_phy *inno = to_inno_hdmi_phy(hw); + unsigned long frac; +- u8 nd, no_a, no_b, no_c, no_d; ++ u8 nd, no_a, no_b, no_d; + u64 vco; + u16 nf; + +@@ -737,9 +737,6 @@ unsigned long inno_hdmi_phy_rk3328_clk_recalc_rate(struct clk_hw *hw, + no_b = inno_read(inno, 0xa5) & RK3328_PRE_PLL_PCLK_DIV_B_MASK; + no_b >>= RK3328_PRE_PLL_PCLK_DIV_B_SHIFT; + no_b += 2; +- no_c = inno_read(inno, 0xa6) & RK3328_PRE_PLL_PCLK_DIV_C_MASK; +- no_c >>= RK3328_PRE_PLL_PCLK_DIV_C_SHIFT; +- no_c = 1 << no_c; + no_d = inno_read(inno, 0xa6) & RK3328_PRE_PLL_PCLK_DIV_D_MASK; + + do_div(vco, (nd * (no_a == 1 ? no_b : no_a) * no_d * 2)); + +From 428d1129cfacf119ed86954e6b21c938510ef2b2 Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Wed, 8 Jan 2020 21:07:48 +0000 +Subject: [PATCH] phy/rockchip: inno-hdmi: do not power on rk3328 post pll on + reg write + +inno_write is used to configure 0xaa reg, that also hold the +POST_PLL_POWER_DOWN bit. +When POST_PLL_REFCLK_SEL_TMDS is configured the power down bit is not +taken into consideration. + +Fix this by keeping the power down bit until configuration is complete. +Also reorder the reg write order for consistency. + +Fixes: 53706a116863 ("phy: add Rockchip Innosilicon hdmi phy") +Signed-off-by: Jonas Karlman +--- + drivers/phy/rockchip/phy-rockchip-inno-hdmi.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c b/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c +index 06db69c8373e..3a59a6da0440 100644 +--- a/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c ++++ b/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c +@@ -1020,9 +1020,10 @@ inno_hdmi_phy_rk3328_power_on(struct inno_hdmi_phy *inno, + + inno_write(inno, 0xac, RK3328_POST_PLL_FB_DIV_7_0(cfg->fbdiv)); + if (cfg->postdiv == 1) { +- inno_write(inno, 0xaa, RK3328_POST_PLL_REFCLK_SEL_TMDS); + inno_write(inno, 0xab, RK3328_POST_PLL_FB_DIV_8(cfg->fbdiv) | + RK3328_POST_PLL_PRE_DIV(cfg->prediv)); ++ inno_write(inno, 0xaa, RK3328_POST_PLL_REFCLK_SEL_TMDS | ++ RK3328_POST_PLL_POWER_DOWN); + } else { + v = (cfg->postdiv / 2) - 1; + v &= RK3328_POST_PLL_POST_DIV_MASK; +@@ -1030,7 +1031,8 @@ inno_hdmi_phy_rk3328_power_on(struct inno_hdmi_phy *inno, + inno_write(inno, 0xab, RK3328_POST_PLL_FB_DIV_8(cfg->fbdiv) | + RK3328_POST_PLL_PRE_DIV(cfg->prediv)); + inno_write(inno, 0xaa, RK3328_POST_PLL_POST_DIV_ENABLE | +- RK3328_POST_PLL_REFCLK_SEL_TMDS); ++ RK3328_POST_PLL_REFCLK_SEL_TMDS | ++ RK3328_POST_PLL_POWER_DOWN); + } + + for (v = 0; v < 14; v++) + +From 335bf9964e953ca56351df1c35ed4249740f548d Mon Sep 17 00:00:00 2001 +From: Huicong Xu +Date: Wed, 8 Jan 2020 21:07:49 +0000 +Subject: [PATCH] phy/rockchip: inno-hdmi: force set_rate on power_on + +Regular 8-bit and Deep Color video formats mainly differ in TMDS rate and +not in pixel clock rate. +When the hdmiphy clock is configured with the same pixel clock rate using +clk_set_rate() the clock framework do not signal the hdmi phy driver +to set_rate when switching between 8-bit and Deep Color. +This result in pre/post pll not being re-configured when switching between +regular 8-bit and Deep Color video formats. + +Fix this by calling set_rate in power_on to force pre pll re-configuration. + +Signed-off-by: Huicong Xu +Signed-off-by: Jonas Karlman +--- + drivers/phy/rockchip/phy-rockchip-inno-hdmi.c | 13 +++++++++++++ + 1 file changed, 13 insertions(+) + +diff --git a/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c b/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c +index 3a59a6da0440..3719309ad0d0 100644 +--- a/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c ++++ b/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c +@@ -245,6 +245,7 @@ struct inno_hdmi_phy { + struct clk_hw hw; + struct clk *phyclk; + unsigned long pixclock; ++ unsigned long tmdsclock; + }; + + struct pre_pll_config { +@@ -485,6 +486,8 @@ static int inno_hdmi_phy_power_on(struct phy *phy) + + dev_dbg(inno->dev, "Inno HDMI PHY Power On\n"); + ++ inno->plat_data->clk_ops->set_rate(&inno->hw, inno->pixclock, 24000000); ++ + ret = clk_prepare_enable(inno->phyclk); + if (ret) + return ret; +@@ -509,6 +512,8 @@ static int inno_hdmi_phy_power_off(struct phy *phy) + + clk_disable_unprepare(inno->phyclk); + ++ inno->tmdsclock = 0; ++ + dev_dbg(inno->dev, "Inno HDMI PHY Power Off\n"); + + return 0; +@@ -628,6 +633,9 @@ static int inno_hdmi_phy_rk3228_clk_set_rate(struct clk_hw *hw, + dev_dbg(inno->dev, "%s rate %lu tmdsclk %lu\n", + __func__, rate, tmdsclock); + ++ if (inno->pixclock == rate && inno->tmdsclock == tmdsclock) ++ return 0; ++ + cfg = inno_hdmi_phy_get_pre_pll_cfg(inno, rate); + if (IS_ERR(cfg)) + return PTR_ERR(cfg); +@@ -670,6 +678,7 @@ static int inno_hdmi_phy_rk3228_clk_set_rate(struct clk_hw *hw, + } + + inno->pixclock = rate; ++ inno->tmdsclock = tmdsclock; + + return 0; + } +@@ -781,6 +790,9 @@ static int inno_hdmi_phy_rk3328_clk_set_rate(struct clk_hw *hw, + dev_dbg(inno->dev, "%s rate %lu tmdsclk %lu\n", + __func__, rate, tmdsclock); + ++ if (inno->pixclock == rate && inno->tmdsclock == tmdsclock) ++ return 0; ++ + cfg = inno_hdmi_phy_get_pre_pll_cfg(inno, rate); + if (IS_ERR(cfg)) + return PTR_ERR(cfg); +@@ -820,6 +832,7 @@ static int inno_hdmi_phy_rk3328_clk_set_rate(struct clk_hw *hw, + } + + inno->pixclock = rate; ++ inno->tmdsclock = tmdsclock; + + return 0; + } + +From b4a0c66750a98eea4b1ab65026cd46a4364512cb Mon Sep 17 00:00:00 2001 +From: Algea Cao +Date: Wed, 8 Jan 2020 21:07:53 +0000 +Subject: [PATCH] phy/rockchip: inno-hdmi: Support more pre-pll configuration + +Adding the following freq cfg in 8-bit and 10-bit color depth: + +{ + 40000000, 65000000, 71000000, 83500000, 85750000, + 88750000, 108000000, 119000000, 162000000 +} + +New freq has been validated by quantumdata 980. + +For some freq which can't be got by only using integer freq div, +frac freq div is needed, Such as 88.75Mhz 10-bit. But The actual +freq is different from the target freq, We must try to narrow +the gap between them. RK322X only support integer freq div. + +The VCO of pre-PLL must be more than 2Ghz, otherwise PLL may be +unlocked. + +Signed-off-by: Algea Cao +Signed-off-by: Jonas Karlman +Acked-by: Heiko Stuebner +--- + drivers/phy/rockchip/phy-rockchip-inno-hdmi.c | 74 ++++++++++++------- + 1 file changed, 49 insertions(+), 25 deletions(-) + +diff --git a/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c b/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c +index 3719309ad0d0..bb8bdf5e3301 100644 +--- a/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c ++++ b/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c +@@ -291,32 +291,56 @@ struct inno_hdmi_phy_drv_data { + const struct phy_config *phy_cfg_table; + }; + ++/* ++ * If only using integer freq div can't get frequency we want, frac ++ * freq div is needed. For example, pclk 88.75 Mhz and tmdsclk ++ * 110.9375 Mhz must use frac div 0xF00000. The actual frequency is different ++ * from the target frequency. Such as the tmds clock 110.9375 Mhz, ++ * the actual tmds clock we get is 110.93719 Mhz. It is important ++ * to note that RK322X platforms do not support frac div. ++ */ + static const struct pre_pll_config pre_pll_cfg_table[] = { +- { 27000000, 27000000, 1, 90, 3, 2, 2, 10, 3, 3, 4, 0, 0}, +- { 27000000, 33750000, 1, 90, 1, 3, 3, 10, 3, 3, 4, 0, 0}, +- { 40000000, 40000000, 1, 80, 2, 2, 2, 12, 2, 2, 2, 0, 0}, +- { 59341000, 59341000, 1, 98, 3, 1, 2, 1, 3, 3, 4, 0, 0xE6AE6B}, +- { 59400000, 59400000, 1, 99, 3, 1, 1, 1, 3, 3, 4, 0, 0}, +- { 59341000, 74176250, 1, 98, 0, 3, 3, 1, 3, 3, 4, 0, 0xE6AE6B}, +- { 59400000, 74250000, 1, 99, 1, 2, 2, 1, 3, 3, 4, 0, 0}, +- { 74176000, 74176000, 1, 98, 1, 2, 2, 1, 2, 3, 4, 0, 0xE6AE6B}, +- { 74250000, 74250000, 1, 99, 1, 2, 2, 1, 2, 3, 4, 0, 0}, +- { 74176000, 92720000, 4, 494, 1, 2, 2, 1, 3, 3, 4, 0, 0x816817}, +- { 74250000, 92812500, 4, 495, 1, 2, 2, 1, 3, 3, 4, 0, 0}, +- {148352000, 148352000, 1, 98, 1, 1, 1, 1, 2, 2, 2, 0, 0xE6AE6B}, +- {148500000, 148500000, 1, 99, 1, 1, 1, 1, 2, 2, 2, 0, 0}, +- {148352000, 185440000, 4, 494, 0, 2, 2, 1, 3, 2, 2, 0, 0x816817}, +- {148500000, 185625000, 4, 495, 0, 2, 2, 1, 3, 2, 2, 0, 0}, +- {296703000, 296703000, 1, 98, 0, 1, 1, 1, 0, 2, 2, 0, 0xE6AE6B}, +- {297000000, 297000000, 1, 99, 0, 1, 1, 1, 0, 2, 2, 0, 0}, +- {296703000, 370878750, 4, 494, 1, 2, 0, 1, 3, 1, 1, 0, 0x816817}, +- {297000000, 371250000, 4, 495, 1, 2, 0, 1, 3, 1, 1, 0, 0}, +- {593407000, 296703500, 1, 98, 0, 1, 1, 1, 0, 2, 1, 0, 0xE6AE6B}, +- {594000000, 297000000, 1, 99, 0, 1, 1, 1, 0, 2, 1, 0, 0}, +- {593407000, 370879375, 4, 494, 1, 2, 0, 1, 3, 1, 1, 1, 0x816817}, +- {594000000, 371250000, 4, 495, 1, 2, 0, 1, 3, 1, 1, 1, 0}, +- {593407000, 593407000, 1, 98, 0, 2, 0, 1, 0, 1, 1, 0, 0xE6AE6B}, +- {594000000, 594000000, 1, 99, 0, 2, 0, 1, 0, 1, 1, 0, 0}, ++ { 27000000, 27000000, 1, 90, 3, 2, 2, 10, 3, 3, 4, 0, 0}, ++ { 27000000, 33750000, 1, 90, 1, 3, 3, 10, 3, 3, 4, 0, 0}, ++ { 40000000, 40000000, 1, 80, 2, 2, 2, 12, 2, 2, 2, 0, 0}, ++ { 40000000, 50000000, 1, 100, 2, 2, 2, 1, 0, 0, 15, 0, 0}, ++ { 59341000, 59341000, 1, 98, 3, 1, 2, 1, 3, 3, 4, 0, 0xE6AE6B}, ++ { 59400000, 59400000, 1, 99, 3, 1, 1, 1, 3, 3, 4, 0, 0}, ++ { 59341000, 74176250, 1, 98, 0, 3, 3, 1, 3, 3, 4, 0, 0xE6AE6B}, ++ { 59400000, 74250000, 1, 99, 1, 2, 2, 1, 3, 3, 4, 0, 0}, ++ { 65000000, 65000000, 1, 130, 2, 2, 2, 1, 0, 0, 12, 0, 0}, ++ { 65000000, 81250000, 3, 325, 0, 3, 3, 1, 0, 0, 10, 0, 0}, ++ { 71000000, 71000000, 3, 284, 0, 3, 3, 1, 0, 0, 8, 0, 0}, ++ { 71000000, 88750000, 3, 355, 0, 3, 3, 1, 0, 0, 10, 0, 0}, ++ { 74176000, 74176000, 1, 98, 1, 2, 2, 1, 2, 3, 4, 0, 0xE6AE6B}, ++ { 74250000, 74250000, 1, 99, 1, 2, 2, 1, 2, 3, 4, 0, 0}, ++ { 74176000, 92720000, 4, 494, 1, 2, 2, 1, 3, 3, 4, 0, 0x816817}, ++ { 74250000, 92812500, 4, 495, 1, 2, 2, 1, 3, 3, 4, 0, 0}, ++ { 83500000, 83500000, 2, 167, 2, 1, 1, 1, 0, 0, 6, 0, 0}, ++ { 83500000, 104375000, 1, 104, 2, 1, 1, 1, 1, 0, 5, 0, 0x600000}, ++ { 85750000, 85750000, 3, 343, 0, 3, 3, 1, 0, 0, 8, 0, 0}, ++ { 88750000, 88750000, 3, 355, 0, 3, 3, 1, 0, 0, 8, 0, 0}, ++ { 88750000, 110937500, 1, 110, 2, 1, 1, 1, 1, 0, 5, 0, 0xF00000}, ++ {108000000, 108000000, 1, 90, 3, 0, 0, 1, 0, 0, 5, 0, 0}, ++ {108000000, 135000000, 1, 90, 0, 2, 2, 1, 0, 0, 5, 0, 0}, ++ {119000000, 119000000, 1, 119, 2, 1, 1, 1, 0, 0, 6, 0, 0}, ++ {119000000, 148750000, 1, 99, 0, 2, 2, 1, 0, 0, 5, 0, 0x2AAAAA}, ++ {148352000, 148352000, 1, 98, 1, 1, 1, 1, 2, 2, 2, 0, 0xE6AE6B}, ++ {148500000, 148500000, 1, 99, 1, 1, 1, 1, 2, 2, 2, 0, 0}, ++ {148352000, 185440000, 4, 494, 0, 2, 2, 1, 3, 2, 2, 0, 0x816817}, ++ {148500000, 185625000, 4, 495, 0, 2, 2, 1, 3, 2, 2, 0, 0}, ++ {162000000, 162000000, 1, 108, 0, 2, 2, 1, 0, 0, 4, 0, 0}, ++ {162000000, 202500000, 1, 135, 0, 2, 2, 1, 0, 0, 5, 0, 0}, ++ {296703000, 296703000, 1, 98, 0, 1, 1, 1, 0, 2, 2, 0, 0xE6AE6B}, ++ {297000000, 297000000, 1, 99, 0, 1, 1, 1, 0, 2, 2, 0, 0}, ++ {296703000, 370878750, 4, 494, 1, 2, 0, 1, 3, 1, 1, 0, 0x816817}, ++ {297000000, 371250000, 4, 495, 1, 2, 0, 1, 3, 1, 1, 0, 0}, ++ {593407000, 296703500, 1, 98, 0, 1, 1, 1, 0, 2, 1, 0, 0xE6AE6B}, ++ {594000000, 297000000, 1, 99, 0, 1, 1, 1, 0, 2, 1, 0, 0}, ++ {593407000, 370879375, 4, 494, 1, 2, 0, 1, 3, 1, 1, 1, 0x816817}, ++ {594000000, 371250000, 4, 495, 1, 2, 0, 1, 3, 1, 1, 1, 0}, ++ {593407000, 593407000, 1, 98, 0, 2, 0, 1, 0, 1, 1, 0, 0xE6AE6B}, ++ {594000000, 594000000, 1, 99, 0, 2, 0, 1, 0, 1, 1, 0, 0}, + { /* sentinel */ } + }; + + +From ddc63db13e520a56bf1afbe6c5ebd3d9935f282f Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Sun, 3 May 2020 16:51:31 +0000 +Subject: [PATCH] drm/rockchip: vop: filter modes outside 0.5% pixel clock + tolerance + +Signed-off-by: Jonas Karlman +--- + drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 33 +++++++++++++++++++++ + 1 file changed, 33 insertions(+) + +diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +index c80f7d9fd13f..6cbdb4672a4b 100644 +--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c ++++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +@@ -1142,6 +1142,38 @@ static void vop_crtc_disable_vblank(struct drm_crtc *crtc) + spin_unlock_irqrestore(&vop->irq_lock, flags); + } + ++/* ++ * The VESA DMT standard specifies a 0.5% pixel clock frequency tolerance. ++ * The CVT spec reuses that tolerance in its examples. ++ */ ++#define CLOCK_TOLERANCE_PER_MILLE 5 ++ ++static enum drm_mode_status vop_crtc_mode_valid(struct drm_crtc *crtc, ++ const struct drm_display_mode *mode) ++{ ++ struct vop *vop = to_vop(crtc); ++ struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc->state); ++ long rounded_rate; ++ long lowest, highest; ++ ++ if (s->output_type != DRM_MODE_CONNECTOR_HDMIA) ++ return MODE_OK; ++ ++ rounded_rate = clk_round_rate(vop->dclk, mode->clock * 1000 + 999); ++ if (rounded_rate < 0) ++ return MODE_NOCLOCK; ++ ++ lowest = mode->clock * (1000 - CLOCK_TOLERANCE_PER_MILLE); ++ if (rounded_rate < lowest) ++ return MODE_CLOCK_LOW; ++ ++ highest = mode->clock * (1000 + CLOCK_TOLERANCE_PER_MILLE); ++ if (rounded_rate > highest) ++ return MODE_CLOCK_HIGH; ++ ++ return MODE_OK; ++} ++ + static bool vop_crtc_mode_fixup(struct drm_crtc *crtc, + const struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +@@ -1512,6 +1544,7 @@ static void vop_crtc_atomic_flush(struct drm_crtc *crtc, + } + + static const struct drm_crtc_helper_funcs vop_crtc_helper_funcs = { ++ .mode_valid = vop_crtc_mode_valid, + .mode_fixup = vop_crtc_mode_fixup, + .atomic_check = vop_crtc_atomic_check, + .atomic_begin = vop_crtc_atomic_begin, + +From 204bb448d3adbe5597d94ddf15ab7fa927931685 Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Mon, 20 Jul 2020 11:46:16 +0000 +Subject: [PATCH] WIP: drm/rockchip: vop: max_output + +--- + drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 5 +++++ + drivers/gpu/drm/rockchip/rockchip_drm_vop.h | 6 ++++++ + drivers/gpu/drm/rockchip/rockchip_vop_reg.c | 7 +++++++ + 3 files changed, 18 insertions(+) + +diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +index 6cbdb4672a4b..106b38ea12df 100644 +--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c ++++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +@@ -1152,6 +1152,7 @@ static enum drm_mode_status vop_crtc_mode_valid(struct drm_crtc *crtc, + const struct drm_display_mode *mode) + { + struct vop *vop = to_vop(crtc); ++ const struct vop_rect *max_output = &vop->data->max_output; + struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc->state); + long rounded_rate; + long lowest, highest; +@@ -1171,6 +1172,10 @@ static enum drm_mode_status vop_crtc_mode_valid(struct drm_crtc *crtc, + if (rounded_rate > highest) + return MODE_CLOCK_HIGH; + ++ if (max_output->width && max_output->height) ++ return drm_mode_validate_size(mode, max_output->width, ++ max_output->height); ++ + return MODE_OK; + } + +diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h +index 4a2099cb582e..1516231bbf93 100644 +--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h ++++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h +@@ -185,6 +185,11 @@ struct vop_win_data { + enum drm_plane_type type; + }; + ++struct vop_rect { ++ int width; ++ int height; ++}; ++ + struct vop_data { + uint32_t version; + const struct vop_intr *intr; +@@ -197,6 +202,7 @@ struct vop_data { + const struct vop_win_data *win; + unsigned int win_size; + unsigned int lut_size; ++ struct vop_rect max_output; + + #define VOP_FEATURE_OUTPUT_RGB10 BIT(0) + #define VOP_FEATURE_INTERNAL_RGB BIT(1) +diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c +index 80053d91a301..57c36e9207c1 100644 +--- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c ++++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c +@@ -682,6 +682,7 @@ static const struct vop_intr rk3288_vop_intr = { + static const struct vop_data rk3288_vop = { + .version = VOP_VERSION(3, 1), + .feature = VOP_FEATURE_OUTPUT_RGB10, ++ .max_output = { 3840, 2160 }, + .intr = &rk3288_vop_intr, + .common = &rk3288_common, + .modeset = &rk3288_modeset, +@@ -782,6 +783,7 @@ static const struct vop_misc rk3368_misc = { + + static const struct vop_data rk3368_vop = { + .version = VOP_VERSION(3, 2), ++ .max_output = { 4096, 2160 }, + .intr = &rk3368_vop_intr, + .common = &rk3288_common, + .modeset = &rk3288_modeset, +@@ -803,6 +805,7 @@ static const struct vop_intr rk3366_vop_intr = { + + static const struct vop_data rk3366_vop = { + .version = VOP_VERSION(3, 4), ++ .max_output = { 4096, 2160 }, + .intr = &rk3366_vop_intr, + .common = &rk3288_common, + .modeset = &rk3288_modeset, +@@ -909,6 +912,7 @@ static const struct vop_afbc rk3399_vop_afbc = { + static const struct vop_data rk3399_vop_big = { + .version = VOP_VERSION(3, 5), + .feature = VOP_FEATURE_OUTPUT_RGB10, ++ .max_output = { 4096, 2160 }, + .intr = &rk3366_vop_intr, + .common = &rk3288_common, + .modeset = &rk3288_modeset, +@@ -935,6 +939,7 @@ static const struct vop_win_yuv2yuv_data rk3399_vop_lit_win_yuv2yuv_data[] = { + + static const struct vop_data rk3399_vop_lit = { + .version = VOP_VERSION(3, 6), ++ .max_output = { 2560, 1600 }, + .intr = &rk3366_vop_intr, + .common = &rk3288_common, + .modeset = &rk3288_modeset, +@@ -955,6 +960,7 @@ static const struct vop_win_data rk3228_vop_win_data[] = { + static const struct vop_data rk3228_vop = { + .version = VOP_VERSION(3, 7), + .feature = VOP_FEATURE_OUTPUT_RGB10, ++ .max_output = { 4096, 2160 }, + .intr = &rk3366_vop_intr, + .common = &rk3288_common, + .modeset = &rk3288_modeset, +@@ -1026,6 +1032,7 @@ static const struct vop_win_data rk3328_vop_win_data[] = { + static const struct vop_data rk3328_vop = { + .version = VOP_VERSION(3, 8), + .feature = VOP_FEATURE_OUTPUT_RGB10, ++ .max_output = { 4096, 2160 }, + .intr = &rk3328_vop_intr, + .common = &rk3328_common, + .modeset = &rk3328_modeset, + +From 77dae737d6b7ab099707e746311bf683729b662b Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Wed, 8 Jan 2020 21:07:51 +0000 +Subject: [PATCH] arm64: dts: rockchip: increase vop clock rate on rk3328 + +The VOP on RK3328 needs to run at higher rate in order to +produce a proper 3840x2160 signal. + +Signed-off-by: Jonas Karlman +--- + arch/arm64/boot/dts/rockchip/rk3328.dtsi | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/arch/arm64/boot/dts/rockchip/rk3328.dtsi b/arch/arm64/boot/dts/rockchip/rk3328.dtsi +index bbdb19a3e85d..6547e2b4b617 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3328.dtsi ++++ b/arch/arm64/boot/dts/rockchip/rk3328.dtsi +@@ -802,8 +802,8 @@ cru: clock-controller@ff440000 { + <0>, <24000000>, + <24000000>, <24000000>, + <15000000>, <15000000>, +- <100000000>, <100000000>, +- <100000000>, <100000000>, ++ <300000000>, <100000000>, ++ <400000000>, <100000000>, + <50000000>, <100000000>, + <100000000>, <100000000>, + <50000000>, <50000000>, + +From 8312c58922e497f6d26c0845597bd23dbeba95d7 Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Wed, 8 Jan 2020 21:07:49 +0000 +Subject: [PATCH] drm/rockchip: dw-hdmi: allow high tmds bit rates + +Prepare support for High TMDS Bit Rates used by HDMI2.0 display modes. + +Signed-off-by: Jonas Karlman +--- + drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +index 23de359a1dec..cdf953850873 100644 +--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c ++++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +@@ -317,6 +317,8 @@ static int dw_hdmi_rockchip_genphy_init(struct dw_hdmi *dw_hdmi, void *data, + { + struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data; + ++ dw_hdmi_set_high_tmds_clock_ratio(dw_hdmi, display); ++ + return phy_power_on(hdmi->phy); + } + + +From 1638ed24fb959926267f59a590e61b04c1050b96 Mon Sep 17 00:00:00 2001 +From: Yakir Yang +Date: Mon, 11 Jul 2016 19:05:39 +0800 +Subject: [PATCH] drm/rockchip: dw_hdmi: adjust cklvl & txlvl for RF/EMI + +Dut to the high HDMI signal voltage driver, Mickey have meet +a serious RF/EMI problem, so we decided to reduce HDMI signal +voltage to a proper value. + +The default params for phy is cklvl = 20 & txlvl = 13 (RF/EMI failed) + ck: lvl = 13, term=100, vlo = 2.71, vhi=3.14, vswing = 0.43 + tx: lvl = 20, term=100, vlo = 2.81, vhi=3.16, vswing = 0.35 + +1. We decided to reduce voltage value to lower, but VSwing still +keep high, RF/EMI have been improved but still failed. + ck: lvl = 6, term=100, vlo = 2.61, vhi=3.11, vswing = 0.50 + tx: lvl = 6, term=100, vlo = 2.61, vhi=3.11, vswing = 0.50 + +2. We try to keep voltage value and vswing both lower, then RF/EMI +test all passed ;) + ck: lvl = 11, term= 66, vlo = 2.68, vhi=3.09, vswing = 0.40 + tx: lvl = 11, term= 66, vlo = 2.68, vhi=3.09, vswing = 0.40 +When we back to run HDMI different test and single-end test, we see +different test passed, but signle-end test failed. The oscilloscope +show that simgle-end clock's VL value is 1.78v (which remind LowLimit +should not lower then 2.6v). + +3. That's to say there are some different between PHY document and +measure value. And according to experiment 2 results, we need to +higher clock voltage and lower data voltage, then we can keep RF/EMI +satisfied and single-end & differen test passed. + ck: lvl = 9, term=100, vlo = 2.65, vhi=3.12, vswing = 0.47 + tx: lvl = 16, term=100, vlo = 2.75, vhi=3.15, vswing = 0.39 + +Signed-off-by: Yakir Yang +Signed-off-by: Jonas Karlman +--- + drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +index cdf953850873..4652c0e0dcd6 100644 +--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c ++++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +@@ -181,7 +181,7 @@ static const struct dw_hdmi_curr_ctrl rockchip_cur_ctr[] = { + static const struct dw_hdmi_phy_config rockchip_phy_config[] = { + /*pixelclk symbol term vlev*/ + { 74250000, 0x8009, 0x0004, 0x0272}, +- { 148500000, 0x802b, 0x0004, 0x028d}, ++ { 165000000, 0x802b, 0x0004, 0x0209}, + { 297000000, 0x8039, 0x0005, 0x028d}, + { ~0UL, 0x0000, 0x0000, 0x0000} + }; + +From f60a4b188ee2e3bfcc44dd8d1fa3b5fa19f90720 Mon Sep 17 00:00:00 2001 +From: Nickey Yang +Date: Mon, 13 Feb 2017 15:40:29 +0800 +Subject: [PATCH] drm/rockchip: dw_hdmi: add phy_config for 594Mhz pixel clock + +Add phy_config for 594Mhz pixel clock used for 4K@60hz + +Signed-off-by: Nickey Yang +Signed-off-by: Jonas Karlman +--- + drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +index 4652c0e0dcd6..10c3dc521cbd 100644 +--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c ++++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +@@ -183,6 +183,7 @@ static const struct dw_hdmi_phy_config rockchip_phy_config[] = { + { 74250000, 0x8009, 0x0004, 0x0272}, + { 165000000, 0x802b, 0x0004, 0x0209}, + { 297000000, 0x8039, 0x0005, 0x028d}, ++ { 594000000, 0x8039, 0x0000, 0x019d}, + { ~0UL, 0x0000, 0x0000, 0x0000} + }; + + +From 6835093bddcc3634ba0ebd98deb72ab59d916f9c Mon Sep 17 00:00:00 2001 +From: Douglas Anderson +Date: Mon, 11 Jul 2016 19:05:36 +0800 +Subject: [PATCH] drm/rockchip: dw_hdmi: Set cur_ctr to 0 always + +Jitter was improved by lowering the MPLL bandwidth to account for high +frequency noise in the rk3288 PLL. In each case MPLL bandwidth was +lowered only enough to get us a comfortable margin. We believe that +lowering the bandwidth like this is safe given sufficient testing. + +Signed-off-by: Douglas Anderson +Signed-off-by: Yakir Yang +Signed-off-by: Jonas Karlman +--- + drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 16 ++-------------- + 1 file changed, 2 insertions(+), 14 deletions(-) + +diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +index 10c3dc521cbd..cc7675638e4f 100644 +--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c ++++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +@@ -160,20 +160,8 @@ static const struct dw_hdmi_mpll_config rockchip_mpll_cfg[] = { + static const struct dw_hdmi_curr_ctrl rockchip_cur_ctr[] = { + /* pixelclk bpp8 bpp10 bpp12 */ + { +- 40000000, { 0x0018, 0x0018, 0x0018 }, +- }, { +- 65000000, { 0x0028, 0x0028, 0x0028 }, +- }, { +- 66000000, { 0x0038, 0x0038, 0x0038 }, +- }, { +- 74250000, { 0x0028, 0x0038, 0x0038 }, +- }, { +- 83500000, { 0x0028, 0x0038, 0x0038 }, +- }, { +- 146250000, { 0x0038, 0x0038, 0x0038 }, +- }, { +- 148500000, { 0x0000, 0x0038, 0x0038 }, +- }, { ++ 600000000, { 0x0000, 0x0000, 0x0000 }, ++ }, { + ~0UL, { 0x0000, 0x0000, 0x0000}, + } + }; + +From da024b1ee785c2443d32a955321dbae7e5b280d3 Mon Sep 17 00:00:00 2001 +From: Douglas Anderson +Date: Mon, 11 Jul 2016 19:05:42 +0800 +Subject: [PATCH] drm/rockchip: dw_hdmi: Use auto-generated tables + +The previous tables for mpll_cfg and curr_ctrl were created using the +20-pages of example settings provided by the PHY vendor. Those +example settings weren't particularly dense, so there were places +where we were guessing what the settings would be for 10-bit and +12-bit (not that we use those anyway). It was also always a lot of +extra work every time we wanted to add a new clock rate since we had +to cross-reference several tables. + +In I've gone through the work to figure +out how to generate this table automatically. Let's now use the +automatically generated table and then we'll never need to look at it +again. + +We only support 8-bit mode right now and only support a small number +of clock rates and and I've verified that the only 8-bit rate that was +affected was 148.5. That mode appears to have been wrong in the old +table. + +Signed-off-by: Douglas Anderson +Signed-off-by: Yakir Yang +Signed-off-by: Jonas Karlman +--- + drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 130 +++++++++++--------- + 1 file changed, 69 insertions(+), 61 deletions(-) + +diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +index cc7675638e4f..c4c158106ca4 100644 +--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c ++++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +@@ -79,80 +79,88 @@ struct rockchip_hdmi { + + static const struct dw_hdmi_mpll_config rockchip_mpll_cfg[] = { + { +- 27000000, { +- { 0x00b3, 0x0000}, +- { 0x2153, 0x0000}, +- { 0x40f3, 0x0000} ++ 30666000, { ++ { 0x00b3, 0x0000 }, ++ { 0x2153, 0x0000 }, ++ { 0x40f3, 0x0000 }, + }, +- }, { +- 36000000, { +- { 0x00b3, 0x0000}, +- { 0x2153, 0x0000}, +- { 0x40f3, 0x0000} ++ }, { ++ 36800000, { ++ { 0x00b3, 0x0000 }, ++ { 0x2153, 0x0000 }, ++ { 0x40a2, 0x0001 }, + }, +- }, { +- 40000000, { +- { 0x00b3, 0x0000}, +- { 0x2153, 0x0000}, +- { 0x40f3, 0x0000} ++ }, { ++ 46000000, { ++ { 0x00b3, 0x0000 }, ++ { 0x2142, 0x0001 }, ++ { 0x40a2, 0x0001 }, + }, +- }, { +- 54000000, { +- { 0x0072, 0x0001}, +- { 0x2142, 0x0001}, +- { 0x40a2, 0x0001}, ++ }, { ++ 61333000, { ++ { 0x0072, 0x0001 }, ++ { 0x2142, 0x0001 }, ++ { 0x40a2, 0x0001 }, + }, +- }, { +- 65000000, { +- { 0x0072, 0x0001}, +- { 0x2142, 0x0001}, +- { 0x40a2, 0x0001}, ++ }, { ++ 73600000, { ++ { 0x0072, 0x0001 }, ++ { 0x2142, 0x0001 }, ++ { 0x4061, 0x0002 }, + }, +- }, { +- 66000000, { +- { 0x013e, 0x0003}, +- { 0x217e, 0x0002}, +- { 0x4061, 0x0002} ++ }, { ++ 92000000, { ++ { 0x0072, 0x0001 }, ++ { 0x2145, 0x0002 }, ++ { 0x4061, 0x0002 }, ++ }, ++ }, { ++ 122666000, { ++ { 0x0051, 0x0002 }, ++ { 0x2145, 0x0002 }, ++ { 0x4061, 0x0002 }, + }, +- }, { +- 74250000, { +- { 0x0072, 0x0001}, +- { 0x2145, 0x0002}, +- { 0x4061, 0x0002} ++ }, { ++ 147200000, { ++ { 0x0051, 0x0002 }, ++ { 0x2145, 0x0002 }, ++ { 0x4064, 0x0003 }, + }, +- }, { +- 83500000, { +- { 0x0072, 0x0001}, ++ }, { ++ 184000000, { ++ { 0x0051, 0x0002 }, ++ { 0x214c, 0x0003 }, ++ { 0x4064, 0x0003 }, + }, +- }, { +- 108000000, { +- { 0x0051, 0x0002}, +- { 0x2145, 0x0002}, +- { 0x4061, 0x0002} ++ }, { ++ 226666000, { ++ { 0x0040, 0x0003 }, ++ { 0x214c, 0x0003 }, ++ { 0x4064, 0x0003 }, + }, +- }, { +- 106500000, { +- { 0x0051, 0x0002}, +- { 0x2145, 0x0002}, +- { 0x4061, 0x0002} ++ }, { ++ 272000000, { ++ { 0x0040, 0x0003 }, ++ { 0x214c, 0x0003 }, ++ { 0x5a64, 0x0003 }, + }, +- }, { +- 146250000, { +- { 0x0051, 0x0002}, +- { 0x2145, 0x0002}, +- { 0x4061, 0x0002} ++ }, { ++ 340000000, { ++ { 0x0040, 0x0003 }, ++ { 0x3b4c, 0x0003 }, ++ { 0x5a64, 0x0003 }, + }, +- }, { +- 148500000, { +- { 0x0051, 0x0003}, +- { 0x214c, 0x0003}, +- { 0x4064, 0x0003} ++ }, { ++ 600000000, { ++ { 0x1a40, 0x0003 }, ++ { 0x3b4c, 0x0003 }, ++ { 0x5a64, 0x0003 }, + }, +- }, { ++ }, { + ~0UL, { +- { 0x00a0, 0x000a }, +- { 0x2001, 0x000f }, +- { 0x4002, 0x000f }, ++ { 0x0000, 0x0000 }, ++ { 0x0000, 0x0000 }, ++ { 0x0000, 0x0000 }, + }, + } + }; + +From 45e1a78887ebd640f8518afc1cfd5b2f2beb3ba4 Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Wed, 8 Jan 2020 21:07:52 +0000 +Subject: [PATCH] drm/rockchip: dw-hdmi: limit tmds to 340mhz + +RK3228/RK3328 does not provide a stable hdmi signal at TMDS rates +above 371.25MHz (340MHz pixel clock). + +Limit the pixel clock rate to 340MHz to provide a stable signal. +Also limit the pixel clock to the display reported max tmds clock. + +This also enables use of pixel clocks up to 340MHz on RK3288/RK3399. + +Signed-off-by: Jonas Karlman +--- + drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 16 ++++------------ + 1 file changed, 4 insertions(+), 12 deletions(-) + +diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +index c4c158106ca4..b62d8f4fc9a8 100644 +--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c ++++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +@@ -221,19 +221,11 @@ dw_hdmi_rockchip_mode_valid(struct dw_hdmi *hdmi, void *data, + const struct drm_display_info *info, + const struct drm_display_mode *mode) + { +- const struct dw_hdmi_mpll_config *mpll_cfg = rockchip_mpll_cfg; +- int pclk = mode->clock * 1000; +- bool valid = false; +- int i; +- +- for (i = 0; mpll_cfg[i].mpixelclock != (~0UL); i++) { +- if (pclk == mpll_cfg[i].mpixelclock) { +- valid = true; +- break; +- } +- } ++ if (mode->clock > 340000 || ++ (info->max_tmds_clock && mode->clock > info->max_tmds_clock)) ++ return MODE_CLOCK_HIGH; + +- return (valid) ? MODE_OK : MODE_BAD; ++ return MODE_OK; + } + + static void dw_hdmi_rockchip_encoder_disable(struct drm_encoder *encoder) + +From 13fdba7d97013c909f5574dea1d006ae8380de82 Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Sun, 3 May 2020 22:36:23 +0000 +Subject: [PATCH] drm/rockchip: dw-hdmi: limit resolution to 3840x2160 + +Signed-off-by: Jonas Karlman +--- + drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +index b62d8f4fc9a8..6f7641fbe6cc 100644 +--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c ++++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +@@ -225,7 +225,7 @@ dw_hdmi_rockchip_mode_valid(struct dw_hdmi *hdmi, void *data, + (info->max_tmds_clock && mode->clock > info->max_tmds_clock)) + return MODE_CLOCK_HIGH; + +- return MODE_OK; ++ return drm_mode_validate_size(mode, 3840, 2160); + } + + static void dw_hdmi_rockchip_encoder_disable(struct drm_encoder *encoder) + +From af4d3cc6fbed0adca1b20bf25929b37c980c8b96 Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Wed, 8 Jan 2020 21:07:52 +0000 +Subject: [PATCH] drm/rockchip: dw-hdmi: remove unused plat_data on + rk3228/rk3328 + +mpll_cfg/cur_ctr/phy_config is not used when phy_force_vendor is true, +lets remove them. + +Signed-off-by: Jonas Karlman +--- + drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 6 ------ + 1 file changed, 6 deletions(-) + +diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +index 6f7641fbe6cc..cc20a83fa9b8 100644 +--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c ++++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +@@ -396,9 +396,6 @@ static struct rockchip_hdmi_chip_data rk3228_chip_data = { + + static const struct dw_hdmi_plat_data rk3228_hdmi_drv_data = { + .mode_valid = dw_hdmi_rockchip_mode_valid, +- .mpll_cfg = rockchip_mpll_cfg, +- .cur_ctr = rockchip_cur_ctr, +- .phy_config = rockchip_phy_config, + .phy_data = &rk3228_chip_data, + .phy_ops = &rk3228_hdmi_phy_ops, + .phy_name = "inno_dw_hdmi_phy2", +@@ -433,9 +430,6 @@ static struct rockchip_hdmi_chip_data rk3328_chip_data = { + + static const struct dw_hdmi_plat_data rk3328_hdmi_drv_data = { + .mode_valid = dw_hdmi_rockchip_mode_valid, +- .mpll_cfg = rockchip_mpll_cfg, +- .cur_ctr = rockchip_cur_ctr, +- .phy_config = rockchip_phy_config, + .phy_data = &rk3328_chip_data, + .phy_ops = &rk3328_hdmi_phy_ops, + .phy_name = "inno_dw_hdmi_phy2", + +From 8b696168a0ff4acd7b1add7ea689a51f9259f294 Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Wed, 8 Jan 2020 21:07:50 +0000 +Subject: [PATCH] clk: rockchip: set parent rate for DCLK_VOP clock on rk3228 + +Signed-off-by: Jonas Karlman +--- + drivers/clk/rockchip/clk-rk3228.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/clk/rockchip/clk-rk3228.c b/drivers/clk/rockchip/clk-rk3228.c +index d7243c09cc84..dd414c8255e3 100644 +--- a/drivers/clk/rockchip/clk-rk3228.c ++++ b/drivers/clk/rockchip/clk-rk3228.c +@@ -408,7 +408,7 @@ static struct rockchip_clk_branch rk3228_clk_branches[] __initdata = { + RK2928_CLKSEL_CON(29), 0, 3, DFLAGS), + DIV(0, "sclk_vop_pre", "sclk_vop_src", 0, + RK2928_CLKSEL_CON(27), 8, 8, DFLAGS), +- MUX(DCLK_VOP, "dclk_vop", mux_dclk_vop_p, 0, ++ MUX(DCLK_VOP, "dclk_vop", mux_dclk_vop_p, CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT, + RK2928_CLKSEL_CON(27), 1, 1, MFLAGS), + + FACTOR(0, "xin12m", "xin24m", 0, 1, 2), + +From 41fdeaa849dcebfd9a9c9e5d3d48fc146dc1e789 Mon Sep 17 00:00:00 2001 +From: Nickey Yang +Date: Mon, 17 Jul 2017 16:35:34 +0800 +Subject: [PATCH] HACK: clk: rockchip: rk3288: dedicate npll for vopb and hdmi + use + +MINIARM: set npll be used for hdmi only + +Signed-off-by: Nickey Yang +Signed-off-by: Jonas Karlman +--- + arch/arm/boot/dts/rk3288.dtsi | 2 ++ + drivers/clk/rockchip/clk-rk3288.c | 4 ++-- + 2 files changed, 4 insertions(+), 2 deletions(-) + +diff --git a/arch/arm/boot/dts/rk3288.dtsi b/arch/arm/boot/dts/rk3288.dtsi +index 68d5a58cfe88..a376dea3bb1b 100644 +--- a/arch/arm/boot/dts/rk3288.dtsi ++++ b/arch/arm/boot/dts/rk3288.dtsi +@@ -1046,6 +1046,8 @@ vopb: vop@ff930000 { + resets = <&cru SRST_LCDC0_AXI>, <&cru SRST_LCDC0_AHB>, <&cru SRST_LCDC0_DCLK>; + reset-names = "axi", "ahb", "dclk"; + iommus = <&vopb_mmu>; ++ assigned-clocks = <&cru DCLK_VOP0>; ++ assigned-clock-parents = <&cru PLL_NPLL>; + status = "disabled"; + + vopb_out: port { +diff --git a/drivers/clk/rockchip/clk-rk3288.c b/drivers/clk/rockchip/clk-rk3288.c +index 93c794695c46..db6c8bbb35f4 100644 +--- a/drivers/clk/rockchip/clk-rk3288.c ++++ b/drivers/clk/rockchip/clk-rk3288.c +@@ -231,7 +231,7 @@ static struct rockchip_pll_clock rk3288_pll_clks[] __initdata = { + [gpll] = PLL(pll_rk3066, PLL_GPLL, "gpll", mux_pll_p, 0, RK3288_PLL_CON(12), + RK3288_MODE_CON, 12, 8, ROCKCHIP_PLL_SYNC_RATE, rk3288_pll_rates), + [npll] = PLL(pll_rk3066, PLL_NPLL, "npll", mux_pll_p, 0, RK3288_PLL_CON(16), +- RK3288_MODE_CON, 14, 9, ROCKCHIP_PLL_SYNC_RATE, rk3288_pll_rates), ++ RK3288_MODE_CON, 14, 9, 0, rk3288_pll_rates), + }; + + static struct clk_div_table div_hclk_cpu_t[] = { +@@ -441,7 +441,7 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = { + RK3288_CLKSEL_CON(30), 14, 2, MFLAGS, 8, 5, DFLAGS, + RK3288_CLKGATE_CON(3), 4, GFLAGS), + +- COMPOSITE(DCLK_VOP0, "dclk_vop0", mux_pll_src_cpll_gpll_npll_p, 0, ++ COMPOSITE(DCLK_VOP0, "dclk_vop0", mux_pll_src_cpll_gpll_npll_p, CLK_SET_RATE_NO_REPARENT | CLK_SET_RATE_PARENT, + RK3288_CLKSEL_CON(27), 0, 2, MFLAGS, 8, 8, DFLAGS, + RK3288_CLKGATE_CON(3), 1, GFLAGS), + COMPOSITE(DCLK_VOP1, "dclk_vop1", mux_pll_src_cpll_gpll_npll_p, 0, + +From 0a33b20a1a890158d704b8a2cc759036952a09e2 Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Sat, 4 Aug 2018 14:51:14 +0200 +Subject: [PATCH] HACK: clk: rockchip: rk3288: use npll table to to improve + HDMI compatibility + +Based on https://github.com/TinkerBoard/debian_kernel/commit/3d90870530b8a2901681f7b7fa598ee7381e49f3 + +Signed-off-by: Jonas Karlman +--- + drivers/clk/rockchip/clk-rk3288.c | 23 ++++++++++++++++++++++- + 1 file changed, 22 insertions(+), 1 deletion(-) + +diff --git a/drivers/clk/rockchip/clk-rk3288.c b/drivers/clk/rockchip/clk-rk3288.c +index db6c8bbb35f4..426309f5dd44 100644 +--- a/drivers/clk/rockchip/clk-rk3288.c ++++ b/drivers/clk/rockchip/clk-rk3288.c +@@ -121,6 +121,27 @@ static struct rockchip_pll_rate_table rk3288_pll_rates[] = { + { /* sentinel */ }, + }; + ++static struct rockchip_pll_rate_table rk3288_npll_rates[] = { ++ RK3066_PLL_RATE_NB(594000000, 1, 99, 4, 32), ++ RK3066_PLL_RATE_NB(585000000, 6, 585, 4, 32), ++ RK3066_PLL_RATE_NB(432000000, 3, 216, 4, 32), ++ RK3066_PLL_RATE_NB(426000000, 3, 213, 4, 32), ++ RK3066_PLL_RATE_NB(400000000, 1, 100, 6, 32), ++ RK3066_PLL_RATE_NB(342000000, 3, 171, 4, 32), ++ RK3066_PLL_RATE_NB(297000000, 2, 198, 8, 16), ++ RK3066_PLL_RATE_NB(270000000, 1, 135, 12, 32), ++ RK3066_PLL_RATE_NB(260000000, 1, 130, 12, 32), ++ RK3066_PLL_RATE_NB(148500000, 1, 99, 16, 32), ++ RK3066_PLL_RATE(148352000, 13, 1125, 14), ++ RK3066_PLL_RATE_NB(146250000, 6, 585, 16, 32), ++ RK3066_PLL_RATE_NB(108000000, 1, 54, 12, 32), ++ RK3066_PLL_RATE_NB(106500000, 4, 213, 12, 32), ++ RK3066_PLL_RATE_NB(85500000, 4, 171, 12, 32), ++ RK3066_PLL_RATE_NB(74250000, 4, 198, 16, 32), ++ RK3066_PLL_RATE(74176000, 26, 1125, 14), ++ { /* sentinel */ }, ++}; ++ + #define RK3288_DIV_ACLK_CORE_M0_MASK 0xf + #define RK3288_DIV_ACLK_CORE_M0_SHIFT 0 + #define RK3288_DIV_ACLK_CORE_MP_MASK 0xf +@@ -231,7 +252,7 @@ static struct rockchip_pll_clock rk3288_pll_clks[] __initdata = { + [gpll] = PLL(pll_rk3066, PLL_GPLL, "gpll", mux_pll_p, 0, RK3288_PLL_CON(12), + RK3288_MODE_CON, 12, 8, ROCKCHIP_PLL_SYNC_RATE, rk3288_pll_rates), + [npll] = PLL(pll_rk3066, PLL_NPLL, "npll", mux_pll_p, 0, RK3288_PLL_CON(16), +- RK3288_MODE_CON, 14, 9, 0, rk3288_pll_rates), ++ RK3288_MODE_CON, 14, 9, 0, rk3288_npll_rates), + }; + + static struct clk_div_table div_hclk_cpu_t[] = { + +From 5c8dac1f946b2a4f2ec3e605a221d5cba56ee59f Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Sun, 28 Oct 2018 21:43:01 +0100 +Subject: [PATCH] HACK: clk: rockchip: rk3288: add more npll clocks + +Fixes 2560x1440@60Hz, 1600x1200@60Hz, 1920x1200@60Hz, 1680x1050@60Hz and 1440x900@60Hz modes on my monitor + +Signed-off-by: Jonas Karlman +--- + drivers/clk/rockchip/clk-rk3288.c | 16 ++++++++++++++++ + 1 file changed, 16 insertions(+) + +diff --git a/drivers/clk/rockchip/clk-rk3288.c b/drivers/clk/rockchip/clk-rk3288.c +index 426309f5dd44..b3247a3a7290 100644 +--- a/drivers/clk/rockchip/clk-rk3288.c ++++ b/drivers/clk/rockchip/clk-rk3288.c +@@ -127,18 +127,34 @@ static struct rockchip_pll_rate_table rk3288_npll_rates[] = { + RK3066_PLL_RATE_NB(432000000, 3, 216, 4, 32), + RK3066_PLL_RATE_NB(426000000, 3, 213, 4, 32), + RK3066_PLL_RATE_NB(400000000, 1, 100, 6, 32), ++ RK3066_PLL_RATE(348500000, 8, 697, 6), + RK3066_PLL_RATE_NB(342000000, 3, 171, 4, 32), + RK3066_PLL_RATE_NB(297000000, 2, 198, 8, 16), + RK3066_PLL_RATE_NB(270000000, 1, 135, 12, 32), + RK3066_PLL_RATE_NB(260000000, 1, 130, 12, 32), ++ RK3066_PLL_RATE(241500000, 2, 161, 8), ++ RK3066_PLL_RATE(162000000, 1, 81, 12), ++ RK3066_PLL_RATE(154000000, 6, 539, 14), + RK3066_PLL_RATE_NB(148500000, 1, 99, 16, 32), + RK3066_PLL_RATE(148352000, 13, 1125, 14), + RK3066_PLL_RATE_NB(146250000, 6, 585, 16, 32), ++ RK3066_PLL_RATE(121750000, 6, 487, 16), ++ RK3066_PLL_RATE(119000000, 3, 238, 16), + RK3066_PLL_RATE_NB(108000000, 1, 54, 12, 32), + RK3066_PLL_RATE_NB(106500000, 4, 213, 12, 32), ++ RK3066_PLL_RATE(101000000, 3, 202, 16), ++ RK3066_PLL_RATE(88750000, 6, 355, 16), + RK3066_PLL_RATE_NB(85500000, 4, 171, 12, 32), ++ RK3066_PLL_RATE(83500000, 3, 167, 16), ++ RK3066_PLL_RATE(79500000, 1, 53, 16), + RK3066_PLL_RATE_NB(74250000, 4, 198, 16, 32), + RK3066_PLL_RATE(74176000, 26, 1125, 14), ++ RK3066_PLL_RATE(72000000, 1, 48, 16), ++ RK3066_PLL_RATE(71000000, 3, 142, 16), ++ RK3066_PLL_RATE(68250000, 2, 91, 16), ++ RK3066_PLL_RATE(65000000, 3, 130, 16), ++ RK3066_PLL_RATE(40000000, 3, 80, 16), ++ RK3066_PLL_RATE(33750000, 2, 45, 16), + { /* sentinel */ }, + }; + + +From bcdd0b34aa22e3bf3d5750d003267cc072fed5db Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Mon, 25 May 2020 20:36:45 +0000 +Subject: [PATCH] HACK: clk: rockchip: rk3399: dedicate vpll for vopb and hdmi + use + +Signed-off-by: Jonas Karlman +--- + drivers/clk/rockchip/clk-rk3399.c | 32 +++++++++++++++++++++++++------ + 1 file changed, 26 insertions(+), 6 deletions(-) + +diff --git a/drivers/clk/rockchip/clk-rk3399.c b/drivers/clk/rockchip/clk-rk3399.c +index ce1d2446f142..f75df0afa2bd 100644 +--- a/drivers/clk/rockchip/clk-rk3399.c ++++ b/drivers/clk/rockchip/clk-rk3399.c +@@ -103,6 +103,25 @@ static struct rockchip_pll_rate_table rk3399_pll_rates[] = { + { /* sentinel */ }, + }; + ++static struct rockchip_pll_rate_table rk3399_vpll_rates[] = { ++ /* _mhz, _refdiv, _fbdiv, _postdiv1, _postdiv2, _dsmpd, _frac */ ++ RK3036_PLL_RATE( 594000000, 1, 123, 5, 1, 0, 12582912), /* vco = 2970000000 */ ++ RK3036_PLL_RATE( 593406592, 1, 123, 5, 1, 0, 10508804), /* vco = 2967032965 */ ++ RK3036_PLL_RATE( 297000000, 1, 123, 5, 2, 0, 12582912), /* vco = 2970000000 */ ++ RK3036_PLL_RATE( 296703296, 1, 123, 5, 2, 0, 10508807), /* vco = 2967032970 */ ++ RK3036_PLL_RATE( 148500000, 1, 129, 7, 3, 0, 15728640), /* vco = 3118500000 */ ++ RK3036_PLL_RATE( 148351648, 1, 123, 5, 4, 0, 10508800), /* vco = 2967032960 */ ++ RK3036_PLL_RATE( 106500000, 1, 124, 7, 4, 0, 4194304), /* vco = 2982000000 */ ++ RK3036_PLL_RATE( 74250000, 1, 129, 7, 6, 0, 15728640), /* vco = 3118500000 */ ++ RK3036_PLL_RATE( 74175824, 1, 129, 7, 6, 0, 13550823), /* vco = 3115384608 */ ++ RK3036_PLL_RATE( 65000000, 1, 113, 7, 6, 0, 12582912), /* vco = 2730000000 */ ++ RK3036_PLL_RATE( 59340659, 1, 121, 7, 7, 0, 2581098), /* vco = 2907692291 */ ++ RK3036_PLL_RATE( 54000000, 1, 110, 7, 7, 0, 4194304), /* vco = 2646000000 */ ++ RK3036_PLL_RATE( 27000000, 1, 55, 7, 7, 0, 2097152), /* vco = 1323000000 */ ++ RK3036_PLL_RATE( 26973026, 1, 55, 7, 7, 0, 1173232), /* vco = 1321678323 */ ++ { /* sentinel */ }, ++}; ++ + /* CRU parents */ + PNAME(mux_pll_p) = { "xin24m", "xin32k" }; + +@@ -121,7 +140,7 @@ PNAME(mux_ddrclk_p) = { "clk_ddrc_lpll_src", + PNAME(mux_aclk_cci_p) = { "cpll_aclk_cci_src", + "gpll_aclk_cci_src", + "npll_aclk_cci_src", +- "vpll_aclk_cci_src" }; ++ "prevent:vpll" }; + PNAME(mux_cci_trace_p) = { "cpll_cci_trace", + "gpll_cci_trace" }; + PNAME(mux_cs_p) = { "cpll_cs", "gpll_cs", +@@ -148,9 +167,10 @@ PNAME(mux_pll_src_cpll_gpll_npll_ppll_upll_24m_p) = { "cpll", "gpll", "npll", + "ppll", "upll", "xin24m" }; + + PNAME(mux_pll_src_vpll_cpll_gpll_p) = { "vpll", "cpll", "gpll" }; +-PNAME(mux_pll_src_vpll_cpll_gpll_npll_p) = { "vpll", "cpll", "gpll", ++ ++PNAME(mux_pll_src_vpll_cpll_gpll_npll_p) = { "prevent:vpll", "cpll", "gpll", + "npll" }; +-PNAME(mux_pll_src_vpll_cpll_gpll_24m_p) = { "vpll", "cpll", "gpll", ++PNAME(mux_pll_src_vpll_cpll_gpll_24m_p) = { "prevent:vpll", "cpll", "gpll", + "xin24m" }; + + PNAME(mux_dclk_vop0_p) = { "dclk_vop0_div", +@@ -227,7 +247,7 @@ static struct rockchip_pll_clock rk3399_pll_clks[] __initdata = { + [npll] = PLL(pll_rk3399, PLL_NPLL, "npll", mux_pll_p, 0, RK3399_PLL_CON(40), + RK3399_PLL_CON(43), 8, 31, ROCKCHIP_PLL_SYNC_RATE, rk3399_pll_rates), + [vpll] = PLL(pll_rk3399, PLL_VPLL, "vpll", mux_pll_p, 0, RK3399_PLL_CON(48), +- RK3399_PLL_CON(51), 8, 31, ROCKCHIP_PLL_SYNC_RATE, rk3399_pll_rates), ++ RK3399_PLL_CON(51), 8, 31, ROCKCHIP_PLL_SYNC_RATE, rk3399_vpll_rates), + }; + + static struct rockchip_pll_clock rk3399_pmu_pll_clks[] __initdata = { +@@ -277,7 +297,7 @@ static struct rockchip_clk_branch rk3399_uart4_pmu_fracmux __initdata = + RK3399_PMU_CLKSEL_CON(5), 8, 2, MFLAGS); + + static struct rockchip_clk_branch rk3399_dclk_vop0_fracmux __initdata = +- MUX(DCLK_VOP0, "dclk_vop0", mux_dclk_vop0_p, CLK_SET_RATE_PARENT, ++ MUX(DCLK_VOP0, "dclk_vop0", mux_dclk_vop0_p, CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT, + RK3399_CLKSEL_CON(49), 11, 1, MFLAGS); + + static struct rockchip_clk_branch rk3399_dclk_vop1_fracmux __initdata = +@@ -1158,7 +1178,7 @@ static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = { + GATE(HCLK_VOP0_NOC, "hclk_vop0_noc", "hclk_vop0_pre", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(28), 0, GFLAGS), + +- COMPOSITE(DCLK_VOP0_DIV, "dclk_vop0_div", mux_pll_src_vpll_cpll_gpll_p, 0, ++ COMPOSITE(DCLK_VOP0_DIV, "dclk_vop0_div", mux_pll_src_vpll_cpll_gpll_p, CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT, + RK3399_CLKSEL_CON(49), 8, 2, MFLAGS, 0, 8, DFLAGS, + RK3399_CLKGATE_CON(10), 12, GFLAGS), + + +From 1178026ac93b4a05b643d9e68b7c98d0434b8b0e Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Sun, 19 Jul 2020 16:35:11 +0000 +Subject: [PATCH] HACK: dts: rockchip: do not use vopl for hdmi + +--- + arch/arm/boot/dts/rk3288.dtsi | 9 --------- + arch/arm64/boot/dts/rockchip/rk3399.dtsi | 9 --------- + 2 files changed, 18 deletions(-) + +diff --git a/arch/arm/boot/dts/rk3288.dtsi b/arch/arm/boot/dts/rk3288.dtsi +index a376dea3bb1b..9757976d6e8a 100644 +--- a/arch/arm/boot/dts/rk3288.dtsi ++++ b/arch/arm/boot/dts/rk3288.dtsi +@@ -1104,11 +1104,6 @@ vopl_out: port { + #address-cells = <1>; + #size-cells = <0>; + +- vopl_out_hdmi: endpoint@0 { +- reg = <0>; +- remote-endpoint = <&hdmi_in_vopl>; +- }; +- + vopl_out_edp: endpoint@1 { + reg = <1>; + remote-endpoint = <&edp_in_vopl>; +@@ -1249,10 +1244,6 @@ hdmi_in_vopb: endpoint@0 { + reg = <0>; + remote-endpoint = <&vopb_out_hdmi>; + }; +- hdmi_in_vopl: endpoint@1 { +- reg = <1>; +- remote-endpoint = <&vopl_out_hdmi>; +- }; + }; + }; + }; +diff --git a/arch/arm64/boot/dts/rockchip/rk3399.dtsi b/arch/arm64/boot/dts/rockchip/rk3399.dtsi +index ada724b12f01..8973bf68d652 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3399.dtsi ++++ b/arch/arm64/boot/dts/rockchip/rk3399.dtsi +@@ -1637,11 +1637,6 @@ vopl_out_edp: endpoint@1 { + remote-endpoint = <&edp_in_vopl>; + }; + +- vopl_out_hdmi: endpoint@2 { +- reg = <2>; +- remote-endpoint = <&hdmi_in_vopl>; +- }; +- + vopl_out_mipi1: endpoint@3 { + reg = <3>; + remote-endpoint = <&mipi1_in_vopl>; +@@ -1787,10 +1782,6 @@ hdmi_in_vopb: endpoint@0 { + reg = <0>; + remote-endpoint = <&vopb_out_hdmi>; + }; +- hdmi_in_vopl: endpoint@1 { +- reg = <1>; +- remote-endpoint = <&vopl_out_hdmi>; +- }; + }; + }; + }; + +From df6bdd1b82221a3d03736963bdc1845222ff3b5c Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Tue, 26 Feb 2019 20:45:14 +0000 +Subject: [PATCH] WIP: dw-hdmi-cec: sleep 100ms on error + +Signed-off-by: Jonas Karlman +--- + drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c | 19 +++++++++++++++++-- + 1 file changed, 17 insertions(+), 2 deletions(-) + +diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c +index 70ab4fbdc23e..f6a85f73b90d 100644 +--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c ++++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c +@@ -4,6 +4,7 @@ + * + * Copyright (C) 2015-2017 Russell King. + */ ++#include + #include + #include + #include +@@ -129,8 +130,16 @@ static irqreturn_t dw_hdmi_cec_hardirq(int irq, void *data) + + dw_hdmi_write(cec, stat, HDMI_IH_CEC_STAT0); + +- if (stat & CEC_STAT_ERROR_INIT) { +- cec->tx_status = CEC_TX_STATUS_ERROR; ++ /* ++ * Status with both done and error_initiator bits have been seen ++ * on Rockchip RK3328 devices, transmit attempt seems to have failed ++ * when this happens, report as low drive and block cec-framework ++ * 100ms before core retransmits the failed message, this seems to ++ * mitigate the issue with failed transmit attempts. ++ */ ++ if ((stat & (CEC_STAT_DONE|CEC_STAT_ERROR_INIT)) == (CEC_STAT_DONE|CEC_STAT_ERROR_INIT)) { ++ pr_info("dw_hdmi_cec_hardirq: stat=%02x LOW_DRIVE\n", stat); ++ cec->tx_status = CEC_TX_STATUS_LOW_DRIVE; + cec->tx_done = true; + ret = IRQ_WAKE_THREAD; + } else if (stat & CEC_STAT_DONE) { +@@ -141,6 +150,10 @@ static irqreturn_t dw_hdmi_cec_hardirq(int irq, void *data) + cec->tx_status = CEC_TX_STATUS_NACK; + cec->tx_done = true; + ret = IRQ_WAKE_THREAD; ++ } else if (stat & CEC_STAT_ERROR_INIT) { ++ cec->tx_status = CEC_TX_STATUS_ERROR; ++ cec->tx_done = true; ++ ret = IRQ_WAKE_THREAD; + } + + if (stat & CEC_STAT_EOM) { +@@ -173,6 +186,8 @@ static irqreturn_t dw_hdmi_cec_thread(int irq, void *data) + + if (cec->tx_done) { + cec->tx_done = false; ++ if (cec->tx_status == CEC_TX_STATUS_LOW_DRIVE) ++ msleep(100); + cec_transmit_attempt_done(adap, cec->tx_status); + } + if (cec->rx_done) { + +From f482feeeeedc41f34892a05a0594d23924a0571a Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Sat, 18 Jul 2020 20:54:38 +0000 +Subject: [PATCH] asdf + +--- + drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c | 36 +++++++++++++++---- + drivers/media/cec/core/cec-adap.c | 2 +- + 2 files changed, 30 insertions(+), 8 deletions(-) + +diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c +index f6a85f73b90d..e6953219beee 100644 +--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c ++++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c +@@ -58,6 +58,7 @@ struct dw_hdmi_cec { + u32 addresses; + struct cec_adapter *adap; + struct cec_msg rx_msg; ++ unsigned int tx_attempts; + unsigned int tx_status; + bool tx_done; + bool rx_done; +@@ -96,6 +97,8 @@ static int dw_hdmi_cec_transmit(struct cec_adapter *adap, u8 attempts, + struct dw_hdmi_cec *cec = cec_get_drvdata(adap); + unsigned int i, ctrl; + ++ pr_info("%s: attempts=%u signal_free_time=%u msg=%*ph (sequence: %u)\n", __func__, attempts, signal_free_time, msg->len, msg->msg, msg->sequence); ++ + switch (signal_free_time) { + case CEC_SIGNAL_FREE_TIME_RETRY: + ctrl = CEC_CTRL_RETRY; +@@ -131,26 +134,35 @@ static irqreturn_t dw_hdmi_cec_hardirq(int irq, void *data) + dw_hdmi_write(cec, stat, HDMI_IH_CEC_STAT0); + + /* +- * Status with both done and error_initiator bits have been seen +- * on Rockchip RK3328 devices, transmit attempt seems to have failed +- * when this happens, report as low drive and block cec-framework ++ * Status with both done and error_initiator bits have been observed ++ * on Rockchip RK3328/RK3399 devices, transmit attempt seems to have ++ * failed when this happens, report as low drive and block cec-framework + * 100ms before core retransmits the failed message, this seems to + * mitigate the issue with failed transmit attempts. + */ + if ((stat & (CEC_STAT_DONE|CEC_STAT_ERROR_INIT)) == (CEC_STAT_DONE|CEC_STAT_ERROR_INIT)) { +- pr_info("dw_hdmi_cec_hardirq: stat=%02x LOW_DRIVE\n", stat); ++ if (!cec->tx_attempts) ++ cec->tx_attempts = 2; + cec->tx_status = CEC_TX_STATUS_LOW_DRIVE; + cec->tx_done = true; + ret = IRQ_WAKE_THREAD; ++ } else if (stat & CEC_STAT_ARBLOST) { ++ cec->tx_attempts = 0; ++ cec->tx_status = CEC_TX_STATUS_ARB_LOST; ++ cec->tx_done = true; ++ ret = IRQ_WAKE_THREAD; + } else if (stat & CEC_STAT_DONE) { ++ cec->tx_attempts = 0; + cec->tx_status = CEC_TX_STATUS_OK; + cec->tx_done = true; + ret = IRQ_WAKE_THREAD; + } else if (stat & CEC_STAT_NACK) { ++ cec->tx_attempts = 0; + cec->tx_status = CEC_TX_STATUS_NACK; + cec->tx_done = true; + ret = IRQ_WAKE_THREAD; + } else if (stat & CEC_STAT_ERROR_INIT) { ++ cec->tx_attempts = 0; + cec->tx_status = CEC_TX_STATUS_ERROR; + cec->tx_done = true; + ret = IRQ_WAKE_THREAD; +@@ -176,6 +188,8 @@ static irqreturn_t dw_hdmi_cec_hardirq(int irq, void *data) + ret = IRQ_WAKE_THREAD; + } + ++ pr_info("%s: stat=%x ret=%x tx_done=%d rx_done=%d tx_status=%u tx_attempts=%u\n", __func__, stat, ret, cec->tx_done, cec->rx_done, cec->tx_status, cec->tx_attempts); ++ + return ret; + } + +@@ -184,11 +198,19 @@ static irqreturn_t dw_hdmi_cec_thread(int irq, void *data) + struct cec_adapter *adap = data; + struct dw_hdmi_cec *cec = cec_get_drvdata(adap); + ++ //pr_info("%s: tx_done=%d rx_done=%d tx_status=%u tx_attempts=%u\n", __func__, cec->tx_done, cec->rx_done, cec->tx_status, cec->tx_attempts); ++ + if (cec->tx_done) { + cec->tx_done = false; + if (cec->tx_status == CEC_TX_STATUS_LOW_DRIVE) + msleep(100); +- cec_transmit_attempt_done(adap, cec->tx_status); ++ if (cec->tx_attempts > 1) { ++ cec->tx_attempts--; ++ dw_hdmi_write(cec, CEC_CTRL_RETRY | CEC_CTRL_START, HDMI_CEC_CTRL); ++ } else { ++ cec->tx_attempts = 0; ++ cec_transmit_attempt_done(adap, cec->tx_status); ++ } + } + if (cec->rx_done) { + cec->rx_done = false; +@@ -219,8 +241,8 @@ static int dw_hdmi_cec_enable(struct cec_adapter *adap, bool enable) + + cec->ops->enable(cec->hdmi); + +- irqs = CEC_STAT_ERROR_INIT | CEC_STAT_NACK | CEC_STAT_EOM | +- CEC_STAT_DONE; ++ irqs = CEC_STAT_ERROR_INIT | CEC_STAT_ARBLOST | CEC_STAT_NACK | ++ CEC_STAT_EOM | CEC_STAT_DONE; + dw_hdmi_write(cec, irqs, HDMI_CEC_POLARITY); + dw_hdmi_write(cec, ~irqs, HDMI_CEC_MASK); + dw_hdmi_write(cec, ~irqs, HDMI_IH_MUTE_CEC_STAT0); +diff --git a/drivers/media/cec/core/cec-adap.c b/drivers/media/cec/core/cec-adap.c +index 6a04d19a96b2..3d12f9d30bd0 100644 +--- a/drivers/media/cec/core/cec-adap.c ++++ b/drivers/media/cec/core/cec-adap.c +@@ -599,7 +599,6 @@ void cec_transmit_done_ts(struct cec_adapter *adap, u8 status, + unsigned int attempts_made = arb_lost_cnt + nack_cnt + + low_drive_cnt + error_cnt; + +- dprintk(2, "%s: status 0x%02x\n", __func__, status); + if (attempts_made < 1) + attempts_made = 1; + +@@ -620,6 +619,7 @@ void cec_transmit_done_ts(struct cec_adapter *adap, u8 status, + adap->transmit_in_progress = false; + + msg = &data->msg; ++ dprintk(2, "%s: %*ph (sequence: %u, attempts: %d, status: %02x)\n", __func__, msg->len, msg->msg, msg->sequence, attempts_made, status); + + /* Drivers must fill in the status! */ + WARN_ON(status == 0); + +From 7abf7a462dd2e503dd816277628ed09a46dc8c55 Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Mon, 20 Jul 2020 11:44:01 +0000 +Subject: [PATCH] cec dprintk revert + +--- + drivers/media/cec/core/cec-adap.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/media/cec/core/cec-adap.c b/drivers/media/cec/core/cec-adap.c +index 3d12f9d30bd0..6a04d19a96b2 100644 +--- a/drivers/media/cec/core/cec-adap.c ++++ b/drivers/media/cec/core/cec-adap.c +@@ -599,6 +599,7 @@ void cec_transmit_done_ts(struct cec_adapter *adap, u8 status, + unsigned int attempts_made = arb_lost_cnt + nack_cnt + + low_drive_cnt + error_cnt; + ++ dprintk(2, "%s: status 0x%02x\n", __func__, status); + if (attempts_made < 1) + attempts_made = 1; + +@@ -619,7 +620,6 @@ void cec_transmit_done_ts(struct cec_adapter *adap, u8 status, + adap->transmit_in_progress = false; + + msg = &data->msg; +- dprintk(2, "%s: %*ph (sequence: %u, attempts: %d, status: %02x)\n", __func__, msg->len, msg->msg, msg->sequence, attempts_made, status); + + /* Drivers must fill in the status! */ + WARN_ON(status == 0); + +From 8ca2d36b31a5921a9f7e0e1deba847915eac55bf Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Mon, 20 Jul 2020 12:33:01 +0000 +Subject: [PATCH] Revert "fixup! WIP: drm/rockchip: vop: max_output" + +This reverts commit c69612ca6820500cd1a0a3e4f8eb8c6f7b971cda. +--- + drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +index 106b38ea12df..138f449924f8 100644 +--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c ++++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +@@ -1184,8 +1184,19 @@ static bool vop_crtc_mode_fixup(struct drm_crtc *crtc, + struct drm_display_mode *adjusted_mode) + { + struct vop *vop = to_vop(crtc); ++ const struct vop_rect *max_output = &vop->data->max_output; + unsigned long rate; + ++ if (max_output->width && max_output->height) { ++ enum drm_mode_status status; ++ ++ status = drm_mode_validate_size(adjusted_mode, ++ max_output->width, ++ max_output->height); ++ if (status != MODE_OK) ++ return false; ++ } ++ + /* + * Clock craziness. + * + +From fff7adceb4d87d2fa0b4f108dbcd39748dfd0689 Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Wed, 15 Jul 2020 15:24:47 +0000 +Subject: [PATCH] drm/rockchip: vop: fix crtc duplicate state + +Signed-off-by: Jonas Karlman +--- + drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +index 138f449924f8..0a25de483515 100644 +--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c ++++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +@@ -1578,7 +1578,11 @@ static struct drm_crtc_state *vop_crtc_duplicate_state(struct drm_crtc *crtc) + { + struct rockchip_crtc_state *rockchip_state; + +- rockchip_state = kzalloc(sizeof(*rockchip_state), GFP_KERNEL); ++ if (WARN_ON(!crtc->state)) ++ return NULL; ++ ++ rockchip_state = kmemdup(to_rockchip_crtc_state(crtc->state), ++ sizeof(*rockchip_state), GFP_KERNEL); + if (!rockchip_state) + return NULL; + + +From 36a518702d98bb3c22276352f648ee1d206db475 Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Mon, 20 Jul 2020 15:15:50 +0000 +Subject: [PATCH] WIP: drm/rockchip: vop: filter interlaced modes + +--- + drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +index 0a25de483515..5ab1412173a7 100644 +--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c ++++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +@@ -1160,6 +1160,9 @@ static enum drm_mode_status vop_crtc_mode_valid(struct drm_crtc *crtc, + if (s->output_type != DRM_MODE_CONNECTOR_HDMIA) + return MODE_OK; + ++ if (mode->flags & DRM_MODE_FLAG_INTERLACE) ++ return MODE_NO_INTERLACE; ++ + rounded_rate = clk_round_rate(vop->dclk, mode->clock * 1000 + 999); + if (rounded_rate < 0) + return MODE_NOCLOCK; + +From 14ba7a75af03d8e3fd7274cfe8a21dd867b23ce5 Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Fri, 20 Dec 2019 08:12:42 +0000 +Subject: [PATCH] drm/rockchip: dw-hdmi: add bridge and switch to + drm_bridge_funcs + +Switch the dw-hdmi driver to drm_bridge_funcs by implementing +a new local bridge, connecting it to the dw-hdmi bridge. + +Also enable bridge format negotiation by implementing +atomic_get_input_bus_fmts and support for 8-bit RGB 4:4:4. + +Signed-off-by: Jonas Karlman +--- + drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 138 ++++++++++++++------ + 1 file changed, 95 insertions(+), 43 deletions(-) + +diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +index cc20a83fa9b8..745fd1c13cef 100644 +--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c ++++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +@@ -68,6 +68,7 @@ struct rockchip_hdmi { + struct device *dev; + struct regmap *regmap; + struct drm_encoder encoder; ++ struct drm_bridge bridge; + const struct rockchip_hdmi_chip_data *chip_data; + struct clk *vpll_clk; + struct clk *grf_clk; +@@ -228,30 +229,20 @@ dw_hdmi_rockchip_mode_valid(struct dw_hdmi *hdmi, void *data, + return drm_mode_validate_size(mode, 3840, 2160); + } + +-static void dw_hdmi_rockchip_encoder_disable(struct drm_encoder *encoder) ++static void ++dw_hdmi_rockchip_bridge_mode_set(struct drm_bridge *bridge, ++ const struct drm_display_mode *mode, ++ const struct drm_display_mode *adjusted_mode) + { +-} ++ struct rockchip_hdmi *hdmi = to_rockchip_hdmi(bridge); + +-static bool +-dw_hdmi_rockchip_encoder_mode_fixup(struct drm_encoder *encoder, +- const struct drm_display_mode *mode, +- struct drm_display_mode *adj_mode) +-{ +- return true; ++ clk_set_rate(hdmi->vpll_clk, adjusted_mode->clock * 1000); + } + +-static void dw_hdmi_rockchip_encoder_mode_set(struct drm_encoder *encoder, +- struct drm_display_mode *mode, +- struct drm_display_mode *adj_mode) ++static void dw_hdmi_rockchip_bridge_enable(struct drm_bridge *bridge) + { +- struct rockchip_hdmi *hdmi = to_rockchip_hdmi(encoder); +- +- clk_set_rate(hdmi->vpll_clk, adj_mode->clock * 1000); +-} +- +-static void dw_hdmi_rockchip_encoder_enable(struct drm_encoder *encoder) +-{ +- struct rockchip_hdmi *hdmi = to_rockchip_hdmi(encoder); ++ struct rockchip_hdmi *hdmi = to_rockchip_hdmi(bridge); ++ struct drm_encoder *encoder = bridge->encoder; + u32 val; + int ret; + +@@ -279,10 +270,21 @@ static void dw_hdmi_rockchip_encoder_enable(struct drm_encoder *encoder) + ret ? "LIT" : "BIG"); + } + ++static bool is_rgb(u32 format) ++{ ++ switch (format) { ++ case MEDIA_BUS_FMT_RGB888_1X24: ++ return true; ++ default: ++ return false; ++ } ++} ++ + static int +-dw_hdmi_rockchip_encoder_atomic_check(struct drm_encoder *encoder, +- struct drm_crtc_state *crtc_state, +- struct drm_connector_state *conn_state) ++dw_hdmi_rockchip_bridge_atomic_check(struct drm_bridge *bridge, ++ struct drm_bridge_state *bridge_state, ++ struct drm_crtc_state *crtc_state, ++ struct drm_connector_state *conn_state) + { + struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc_state); + +@@ -292,12 +294,38 @@ dw_hdmi_rockchip_encoder_atomic_check(struct drm_encoder *encoder, + return 0; + } + +-static const struct drm_encoder_helper_funcs dw_hdmi_rockchip_encoder_helper_funcs = { +- .mode_fixup = dw_hdmi_rockchip_encoder_mode_fixup, +- .mode_set = dw_hdmi_rockchip_encoder_mode_set, +- .enable = dw_hdmi_rockchip_encoder_enable, +- .disable = dw_hdmi_rockchip_encoder_disable, +- .atomic_check = dw_hdmi_rockchip_encoder_atomic_check, ++static u32 *dw_hdmi_rockchip_get_input_bus_fmts(struct drm_bridge *bridge, ++ struct drm_bridge_state *bridge_state, ++ struct drm_crtc_state *crtc_state, ++ struct drm_connector_state *conn_state, ++ u32 output_fmt, ++ unsigned int *num_input_fmts) ++{ ++ u32 *input_fmt; ++ ++ *num_input_fmts = 0; ++ ++ if (!is_rgb(output_fmt)) ++ return NULL; ++ ++ input_fmt = kzalloc(sizeof(*input_fmt), GFP_KERNEL); ++ if (!input_fmt) ++ return NULL; ++ ++ *num_input_fmts = 1; ++ *input_fmt = output_fmt; ++ ++ return input_fmt; ++} ++ ++static const struct drm_bridge_funcs dw_hdmi_rockchip_bridge_funcs = { ++ .mode_set = dw_hdmi_rockchip_bridge_mode_set, ++ .enable = dw_hdmi_rockchip_bridge_enable, ++ .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, ++ .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, ++ .atomic_get_input_bus_fmts = dw_hdmi_rockchip_get_input_bus_fmts, ++ .atomic_check = dw_hdmi_rockchip_bridge_atomic_check, ++ .atomic_reset = drm_atomic_helper_bridge_reset, + }; + + static int dw_hdmi_rockchip_genphy_init(struct dw_hdmi *dw_hdmi, void *data, +@@ -476,6 +504,7 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master, + struct dw_hdmi_plat_data *plat_data; + const struct of_device_id *match; + struct drm_device *drm = data; ++ struct drm_bridge *next_bridge; + struct drm_encoder *encoder; + struct rockchip_hdmi *hdmi; + int ret; +@@ -516,8 +545,7 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master, + + ret = clk_prepare_enable(hdmi->vpll_clk); + if (ret) { +- DRM_DEV_ERROR(hdmi->dev, "Failed to enable HDMI vpll: %d\n", +- ret); ++ DRM_DEV_ERROR(hdmi->dev, "Failed to enable vpll: %d\n", ret); + return ret; + } + +@@ -525,27 +553,51 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master, + if (IS_ERR(hdmi->phy)) { + ret = PTR_ERR(hdmi->phy); + if (ret != -EPROBE_DEFER) +- DRM_DEV_ERROR(hdmi->dev, "failed to get phy\n"); +- return ret; ++ DRM_DEV_ERROR(hdmi->dev, "Failed to get phy: %d\n", ret); ++ goto err_disable_clk; + } + +- drm_encoder_helper_add(encoder, &dw_hdmi_rockchip_encoder_helper_funcs); +- drm_simple_encoder_init(drm, encoder, DRM_MODE_ENCODER_TMDS); ++ ret = drm_simple_encoder_init(drm, encoder, DRM_MODE_ENCODER_TMDS); ++ if (ret) { ++ DRM_DEV_ERROR(hdmi->dev, "Failed to init encoder: %d\n", ret); ++ goto err_disable_clk; ++ } + +- platform_set_drvdata(pdev, hdmi); ++ hdmi->bridge.funcs = &dw_hdmi_rockchip_bridge_funcs; ++ drm_bridge_attach(encoder, &hdmi->bridge, NULL, 0); + +- hdmi->hdmi = dw_hdmi_bind(pdev, encoder, plat_data); ++ platform_set_drvdata(pdev, hdmi); + +- /* +- * If dw_hdmi_bind() fails we'll never call dw_hdmi_unbind(), +- * which would have called the encoder cleanup. Do it manually. +- */ ++ hdmi->hdmi = dw_hdmi_probe(pdev, plat_data); + if (IS_ERR(hdmi->hdmi)) { + ret = PTR_ERR(hdmi->hdmi); +- drm_encoder_cleanup(encoder); +- clk_disable_unprepare(hdmi->vpll_clk); ++ if (ret != -EPROBE_DEFER) ++ DRM_DEV_ERROR(hdmi->dev, "Failed to init dw-hdmi bridge: %d\n", ret); ++ goto err_encoder_cleanup; ++ } ++ ++ next_bridge = of_drm_find_bridge(pdev->dev.of_node); ++ if (!next_bridge) { ++ ret = -EPROBE_DEFER; ++ goto err_dw_hdmi_remove; ++ } ++ ++ ret = drm_bridge_attach(encoder, next_bridge, &hdmi->bridge, 0); ++ if (ret) { ++ if (ret != -EPROBE_DEFER) ++ DRM_DEV_ERROR(hdmi->dev, "Failed to attach dw-hdmi bridge: %d\n", ret); ++ goto err_dw_hdmi_remove; + } + ++ return 0; ++ ++err_dw_hdmi_remove: ++ dw_hdmi_remove(hdmi->hdmi); ++err_encoder_cleanup: ++ drm_encoder_cleanup(encoder); ++err_disable_clk: ++ clk_disable_unprepare(hdmi->vpll_clk); ++ + return ret; + } + +@@ -554,7 +606,7 @@ static void dw_hdmi_rockchip_unbind(struct device *dev, struct device *master, + { + struct rockchip_hdmi *hdmi = dev_get_drvdata(dev); + +- dw_hdmi_unbind(hdmi->hdmi); ++ dw_hdmi_remove(hdmi->hdmi); + clk_disable_unprepare(hdmi->vpll_clk); + } + + +From ffded51c4e7a79cca7d97b4fe0d98ee4b0b74e34 Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Mon, 20 Jul 2020 18:00:44 +0000 +Subject: [PATCH] drm/bridge: dw-hdmi: add mtmdsclock parameter to phy + configure ops + +Signed-off-by: Jonas Karlman +--- + drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 10 ++++++---- + drivers/gpu/drm/rcar-du/rcar_dw_hdmi.c | 3 ++- + include/drm/bridge/dw_hdmi.h | 3 ++- + 3 files changed, 10 insertions(+), 6 deletions(-) + +diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +index 748df1cacd2b..c25d5ac7bb07 100644 +--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c ++++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +@@ -137,7 +137,8 @@ struct dw_hdmi_phy_data { + bool has_svsret; + int (*configure)(struct dw_hdmi *hdmi, + const struct dw_hdmi_plat_data *pdata, +- unsigned long mpixelclock); ++ unsigned long mpixelclock, ++ unsigned long mtmdsclock); + }; + + struct dw_hdmi { +@@ -1441,7 +1442,8 @@ static int dw_hdmi_phy_power_on(struct dw_hdmi *hdmi) + */ + static int hdmi_phy_configure_dwc_hdmi_3d_tx(struct dw_hdmi *hdmi, + const struct dw_hdmi_plat_data *pdata, +- unsigned long mpixelclock) ++ unsigned long mpixelclock, ++ unsigned long mtmdsclock) + { + const struct dw_hdmi_mpll_config *mpll_config = pdata->mpll_cfg; + const struct dw_hdmi_curr_ctrl *curr_ctrl = pdata->cur_ctr; +@@ -1516,9 +1518,9 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi, + + /* Write to the PHY as configured by the platform */ + if (pdata->configure_phy) +- ret = pdata->configure_phy(hdmi, pdata->priv_data, mpixelclock); ++ ret = pdata->configure_phy(hdmi, pdata->priv_data, mpixelclock, mtmdsclock); + else +- ret = phy->configure(hdmi, pdata, mpixelclock); ++ ret = phy->configure(hdmi, pdata, mpixelclock, mtmdsclock); + if (ret) { + dev_err(hdmi->dev, "PHY configuration failed (clock %lu)\n", + mpixelclock); +diff --git a/drivers/gpu/drm/rcar-du/rcar_dw_hdmi.c b/drivers/gpu/drm/rcar-du/rcar_dw_hdmi.c +index 7b8ec8310699..539d86131fd4 100644 +--- a/drivers/gpu/drm/rcar-du/rcar_dw_hdmi.c ++++ b/drivers/gpu/drm/rcar-du/rcar_dw_hdmi.c +@@ -53,7 +53,8 @@ rcar_hdmi_mode_valid(struct dw_hdmi *hdmi, void *data, + } + + static int rcar_hdmi_phy_configure(struct dw_hdmi *hdmi, void *data, +- unsigned long mpixelclock) ++ unsigned long mpixelclock, ++ unsigned long mtmdsclock) + { + const struct rcar_hdmi_phy_params *params = rcar_hdmi_phy_params; + +diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h +index ea34ca146b82..4f61ede6486d 100644 +--- a/include/drm/bridge/dw_hdmi.h ++++ b/include/drm/bridge/dw_hdmi.h +@@ -152,7 +152,8 @@ struct dw_hdmi_plat_data { + const struct dw_hdmi_curr_ctrl *cur_ctr; + const struct dw_hdmi_phy_config *phy_config; + int (*configure_phy)(struct dw_hdmi *hdmi, void *data, +- unsigned long mpixelclock); ++ unsigned long mpixelclock, ++ unsigned long mtmdsclock); + }; + + struct dw_hdmi *dw_hdmi_probe(struct platform_device *pdev, + +From e3c32df45f5d84f541586a6c382008be538528ba Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Mon, 20 Jul 2020 21:34:48 +0000 +Subject: [PATCH] drm/bridge: dw-hdmi: support configuring phy for deep color + +Q: Should we rename dw_hdmi_curr_ctrl and dw_hdmi_phy_config mpixelclock to mtmdsclock ? + +Signed-off-by: Jonas Karlman +--- + drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 17 ++++++++++++----- + 1 file changed, 12 insertions(+), 5 deletions(-) + +diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +index c25d5ac7bb07..bcdd823907c2 100644 +--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c ++++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +@@ -1448,6 +1448,7 @@ static int hdmi_phy_configure_dwc_hdmi_3d_tx(struct dw_hdmi *hdmi, + const struct dw_hdmi_mpll_config *mpll_config = pdata->mpll_cfg; + const struct dw_hdmi_curr_ctrl *curr_ctrl = pdata->cur_ctr; + const struct dw_hdmi_phy_config *phy_config = pdata->phy_config; ++ int depth; + + /* TOFIX Will need 420 specific PHY configuration tables */ + +@@ -1457,11 +1458,11 @@ static int hdmi_phy_configure_dwc_hdmi_3d_tx(struct dw_hdmi *hdmi, + break; + + for (; curr_ctrl->mpixelclock != ~0UL; curr_ctrl++) +- if (mpixelclock <= curr_ctrl->mpixelclock) ++ if (mtmdsclock <= curr_ctrl->mpixelclock) + break; + + for (; phy_config->mpixelclock != ~0UL; phy_config++) +- if (mpixelclock <= phy_config->mpixelclock) ++ if (mtmdsclock <= phy_config->mpixelclock) + break; + + if (mpll_config->mpixelclock == ~0UL || +@@ -1469,11 +1470,17 @@ static int hdmi_phy_configure_dwc_hdmi_3d_tx(struct dw_hdmi *hdmi, + phy_config->mpixelclock == ~0UL) + return -EINVAL; + +- dw_hdmi_phy_i2c_write(hdmi, mpll_config->res[0].cpce, ++ depth = hdmi_bus_fmt_color_depth(hdmi->hdmi_data.enc_out_bus_format); ++ if (depth > 8 && mpixelclock != mtmdsclock) ++ depth = fls(depth - 8) - 1; ++ else ++ depth = 0; ++ ++ dw_hdmi_phy_i2c_write(hdmi, mpll_config->res[depth].cpce, + HDMI_3D_TX_PHY_CPCE_CTRL); +- dw_hdmi_phy_i2c_write(hdmi, mpll_config->res[0].gmp, ++ dw_hdmi_phy_i2c_write(hdmi, mpll_config->res[depth].gmp, + HDMI_3D_TX_PHY_GMPCTRL); +- dw_hdmi_phy_i2c_write(hdmi, curr_ctrl->curr[0], ++ dw_hdmi_phy_i2c_write(hdmi, curr_ctrl->curr[depth], + HDMI_3D_TX_PHY_CURRCTRL); + + dw_hdmi_phy_i2c_write(hdmi, 0, HDMI_3D_TX_PHY_PLLPHBYCTRL); + +From d391dfb202b03bad6d52efe7d0aa46225febe3c5 Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Mon, 20 Jul 2020 22:25:15 +0000 +Subject: [PATCH] drm/bridge: dw-hdmi: add mpll_cfg_420 for ycbcr420 mode + +Signed-off-by: Jonas Karlman +--- + drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 4 +++- + include/drm/bridge/dw_hdmi.h | 1 + + 2 files changed, 4 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +index bcdd823907c2..f5d048adf649 100644 +--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c ++++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +@@ -1450,7 +1450,9 @@ static int hdmi_phy_configure_dwc_hdmi_3d_tx(struct dw_hdmi *hdmi, + const struct dw_hdmi_phy_config *phy_config = pdata->phy_config; + int depth; + +- /* TOFIX Will need 420 specific PHY configuration tables */ ++ if (hdmi_bus_fmt_is_yuv420(hdmi->hdmi_data.enc_out_bus_format) && ++ pdata->mpll_cfg_420) ++ mpll_config = pdata->mpll_cfg_420; + + /* PLL/MPLL Cfg - always match on final entry */ + for (; mpll_config->mpixelclock != ~0UL; mpll_config++) +diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h +index 4f61ede6486d..0ebe01835d2a 100644 +--- a/include/drm/bridge/dw_hdmi.h ++++ b/include/drm/bridge/dw_hdmi.h +@@ -149,6 +149,7 @@ struct dw_hdmi_plat_data { + + /* Synopsys PHY support */ + const struct dw_hdmi_mpll_config *mpll_cfg; ++ const struct dw_hdmi_mpll_config *mpll_cfg_420; + const struct dw_hdmi_curr_ctrl *cur_ctr; + const struct dw_hdmi_phy_config *phy_config; + int (*configure_phy)(struct dw_hdmi *hdmi, void *data, + +From 08b2f123efe8bb641671ad038dd0dc37f877794d Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Wed, 15 Jul 2020 09:49:21 +0000 +Subject: [PATCH] drm/rockchip: dw-hdmi: mode_valid: allow 420 clock rate + +Signed-off-by: Jonas Karlman +--- + drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 12 ++++++++++-- + 1 file changed, 10 insertions(+), 2 deletions(-) + +diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +index 745fd1c13cef..9784111ea746 100644 +--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c ++++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +@@ -222,8 +222,15 @@ dw_hdmi_rockchip_mode_valid(struct dw_hdmi *hdmi, void *data, + const struct drm_display_info *info, + const struct drm_display_mode *mode) + { +- if (mode->clock > 340000 || +- (info->max_tmds_clock && mode->clock > info->max_tmds_clock)) ++ struct dw_hdmi_plat_data *pdata = (struct dw_hdmi_plat_data *)data; ++ int clock = mode->clock; ++ ++ if (pdata->ycbcr_420_allowed && drm_mode_is_420(info, mode) && ++ (info->color_formats & DRM_COLOR_FORMAT_YCRCB420)) ++ clock /= 2; ++ ++ if (clock > 340000 || ++ (info->max_tmds_clock && clock > info->max_tmds_clock)) + return MODE_CLOCK_HIGH; + + return drm_mode_validate_size(mode, 3840, 2160); +@@ -524,6 +531,7 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master, + + hdmi->dev = &pdev->dev; + hdmi->chip_data = plat_data->phy_data; ++ plat_data->priv_data = plat_data; + plat_data->phy_data = hdmi; + encoder = &hdmi->encoder; + + +From e8f87de2fef5c2be3110fcd23fa1b09325bbd041 Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Mon, 20 Jul 2020 22:26:19 +0000 +Subject: [PATCH] drm/rockchip: dw-hdmi: rk3399: add mpll_cfg_420 + +Signed-off-by: Jonas Karlman +--- + drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 41 +++++++++++++++++++++ + 1 file changed, 41 insertions(+) + +diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +index 9784111ea746..e7fbeb9132fb 100644 +--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c ++++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +@@ -166,6 +166,46 @@ static const struct dw_hdmi_mpll_config rockchip_mpll_cfg[] = { + } + }; + ++static const struct dw_hdmi_mpll_config rockchip_mpll_cfg_420[] = { ++ { ++ 30666000, { ++ { 0x00b7, 0x0000 }, ++ { 0x2157, 0x0000 }, ++ { 0x40f7, 0x0000 }, ++ }, ++ }, { ++ 92000000, { ++ { 0x00b7, 0x0000 }, ++ { 0x2143, 0x0001 }, ++ { 0x40a3, 0x0001 }, ++ }, ++ }, { ++ 184000000, { ++ { 0x0073, 0x0001 }, ++ { 0x2146, 0x0002 }, ++ { 0x4062, 0x0002 }, ++ }, ++ }, { ++ 340000000, { ++ { 0x0052, 0x0003 }, ++ { 0x214d, 0x0003 }, ++ { 0x4065, 0x0003 }, ++ }, ++ }, { ++ 600000000, { ++ { 0x0041, 0x0003 }, ++ { 0x3b4d, 0x0003 }, ++ { 0x5a65, 0x0003 }, ++ }, ++ }, { ++ ~0UL, { ++ { 0x0000, 0x0000 }, ++ { 0x0000, 0x0000 }, ++ { 0x0000, 0x0000 }, ++ }, ++ } ++}; ++ + static const struct dw_hdmi_curr_ctrl rockchip_cur_ctr[] = { + /* pixelclk bpp8 bpp10 bpp12 */ + { +@@ -481,6 +521,7 @@ static struct rockchip_hdmi_chip_data rk3399_chip_data = { + static const struct dw_hdmi_plat_data rk3399_hdmi_drv_data = { + .mode_valid = dw_hdmi_rockchip_mode_valid, + .mpll_cfg = rockchip_mpll_cfg, ++ .mpll_cfg_420 = rockchip_mpll_cfg_420, + .cur_ctr = rockchip_cur_ctr, + .phy_config = rockchip_phy_config, + .phy_data = &rk3399_chip_data, + +From 90cd0a2b9a02f11488bddcc9fe7dad15c04a8d36 Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Fri, 20 Dec 2019 08:12:43 +0000 +Subject: [PATCH] WIP: drm/bridge: dw-hdmi: limit mode and bus format to + max_tmds_clock + +--- + drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 120 ++++++++++++++-------- + 1 file changed, 76 insertions(+), 44 deletions(-) + +diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +index f5d048adf649..26c64cf2d00a 100644 +--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c ++++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +@@ -1859,6 +1859,21 @@ static void hdmi_config_drm_infoframe(struct dw_hdmi *hdmi, + HDMI_FC_PACKET_TX_EN_DRM_MASK, HDMI_FC_PACKET_TX_EN); + } + ++static unsigned int ++hdmi_get_tmdsclock(unsigned int bus_format, unsigned int pixelclock) ++{ ++ int color_depth = hdmi_bus_fmt_color_depth(bus_format); ++ unsigned int tmdsclock = pixelclock; ++ ++ if (!hdmi_bus_fmt_is_yuv422(bus_format) && color_depth > 8) ++ tmdsclock = (u64)pixelclock * color_depth / 8; ++ ++ if (hdmi_bus_fmt_is_yuv420(bus_format)) ++ tmdsclock /= 2; ++ ++ return tmdsclock; ++} ++ + static void hdmi_av_composer(struct dw_hdmi *hdmi, + const struct drm_display_info *display, + const struct drm_display_mode *mode) +@@ -1870,29 +1885,11 @@ static void hdmi_av_composer(struct dw_hdmi *hdmi, + unsigned int vdisplay, hdisplay; + + vmode->mpixelclock = mode->clock * 1000; ++ vmode->mtmdsclock = ++ hdmi_get_tmdsclock(hdmi->hdmi_data.enc_out_bus_format, ++ vmode->mpixelclock); + + dev_dbg(hdmi->dev, "final pixclk = %d\n", vmode->mpixelclock); +- +- vmode->mtmdsclock = vmode->mpixelclock; +- +- if (!hdmi_bus_fmt_is_yuv422(hdmi->hdmi_data.enc_out_bus_format)) { +- switch (hdmi_bus_fmt_color_depth( +- hdmi->hdmi_data.enc_out_bus_format)) { +- case 16: +- vmode->mtmdsclock = vmode->mpixelclock * 2; +- break; +- case 12: +- vmode->mtmdsclock = vmode->mpixelclock * 3 / 2; +- break; +- case 10: +- vmode->mtmdsclock = vmode->mpixelclock * 5 / 4; +- break; +- } +- } +- +- if (hdmi_bus_fmt_is_yuv420(hdmi->hdmi_data.enc_out_bus_format)) +- vmode->mtmdsclock /= 2; +- + dev_dbg(hdmi->dev, "final tmdsclock = %d\n", vmode->mtmdsclock); + + /* Set up HDMI_FC_INVIDCONF */ +@@ -2550,8 +2547,21 @@ static int dw_hdmi_connector_create(struct dw_hdmi *hdmi) + * - MEDIA_BUS_FMT_RGB888_1X24, + */ + +-/* Can return a maximum of 11 possible output formats for a mode/connector */ +-#define MAX_OUTPUT_SEL_FORMATS 11 ++/* Can return a maximum of 15 possible output formats for a mode/connector */ ++#define MAX_OUTPUT_SEL_FORMATS 15 ++ ++static bool is_tmds_allowed(struct drm_display_info *info, ++ struct drm_display_mode *mode, ++ u32 bus_format) ++{ ++ unsigned long tmdsclock = hdmi_get_tmdsclock(bus_format, mode->clock); ++ int max_tmds_clock = info->max_tmds_clock ? info->max_tmds_clock : 340000; ++ ++ if (max_tmds_clock >= tmdsclock) ++ return true; ++ ++ return false; ++} + + static u32 *dw_hdmi_bridge_atomic_get_output_bus_fmts(struct drm_bridge *bridge, + struct drm_bridge_state *bridge_state, +@@ -2563,8 +2573,6 @@ static u32 *dw_hdmi_bridge_atomic_get_output_bus_fmts(struct drm_bridge *bridge, + struct drm_display_info *info = &conn->display_info; + struct drm_display_mode *mode = &crtc_state->mode; + u8 max_bpc = conn_state->max_requested_bpc; +- bool is_hdmi2_sink = info->hdmi.scdc.supported || +- (info->color_formats & DRM_COLOR_FORMAT_YCRCB420); + u32 *output_fmts; + unsigned int i = 0; + +@@ -2587,29 +2595,33 @@ static u32 *dw_hdmi_bridge_atomic_get_output_bus_fmts(struct drm_bridge *bridge, + * If the current mode enforces 4:2:0, force the output but format + * to 4:2:0 and do not add the YUV422/444/RGB formats + */ +- if (conn->ycbcr_420_allowed && +- (drm_mode_is_420_only(info, mode) || +- (is_hdmi2_sink && drm_mode_is_420_also(info, mode)))) { ++ if (conn->ycbcr_420_allowed && drm_mode_is_420(info, mode) && ++ (info->color_formats & DRM_COLOR_FORMAT_YCRCB420)) { + + /* Order bus formats from 16bit to 8bit if supported */ + if (max_bpc >= 16 && info->bpc == 16 && +- (info->hdmi.y420_dc_modes & DRM_EDID_YCBCR420_DC_48)) ++ (info->hdmi.y420_dc_modes & DRM_EDID_YCBCR420_DC_48) && ++ is_tmds_allowed(info, mode, MEDIA_BUS_FMT_UYYVYY16_0_5X48)) + output_fmts[i++] = MEDIA_BUS_FMT_UYYVYY16_0_5X48; + + if (max_bpc >= 12 && info->bpc >= 12 && +- (info->hdmi.y420_dc_modes & DRM_EDID_YCBCR420_DC_36)) ++ (info->hdmi.y420_dc_modes & DRM_EDID_YCBCR420_DC_36) && ++ is_tmds_allowed(info, mode, MEDIA_BUS_FMT_UYYVYY12_0_5X36)) + output_fmts[i++] = MEDIA_BUS_FMT_UYYVYY12_0_5X36; + + if (max_bpc >= 10 && info->bpc >= 10 && +- (info->hdmi.y420_dc_modes & DRM_EDID_YCBCR420_DC_30)) ++ (info->hdmi.y420_dc_modes & DRM_EDID_YCBCR420_DC_30) && ++ is_tmds_allowed(info, mode, MEDIA_BUS_FMT_UYYVYY10_0_5X30)) + output_fmts[i++] = MEDIA_BUS_FMT_UYYVYY10_0_5X30; + + /* Default 8bit fallback */ +- output_fmts[i++] = MEDIA_BUS_FMT_UYYVYY8_0_5X24; ++ if (is_tmds_allowed(info, mode, MEDIA_BUS_FMT_UYYVYY8_0_5X24)) ++ output_fmts[i++] = MEDIA_BUS_FMT_UYYVYY8_0_5X24; + + *num_output_fmts = i; + +- return output_fmts; ++ if (drm_mode_is_420_only(info, mode)) ++ return output_fmts; + } + + /* +@@ -2618,40 +2630,51 @@ static u32 *dw_hdmi_bridge_atomic_get_output_bus_fmts(struct drm_bridge *bridge, + */ + + if (max_bpc >= 16 && info->bpc == 16) { +- if (info->color_formats & DRM_COLOR_FORMAT_YCRCB444) ++ if ((info->color_formats & DRM_COLOR_FORMAT_YCRCB444) && ++ is_tmds_allowed(info, mode, MEDIA_BUS_FMT_YUV16_1X48)) + output_fmts[i++] = MEDIA_BUS_FMT_YUV16_1X48; + +- output_fmts[i++] = MEDIA_BUS_FMT_RGB161616_1X48; ++ if (is_tmds_allowed(info, mode, MEDIA_BUS_FMT_RGB161616_1X48)) ++ output_fmts[i++] = MEDIA_BUS_FMT_RGB161616_1X48; + } + + if (max_bpc >= 12 && info->bpc >= 12) { +- if (info->color_formats & DRM_COLOR_FORMAT_YCRCB422) ++ if ((info->color_formats & DRM_COLOR_FORMAT_YCRCB422) && ++ is_tmds_allowed(info, mode, MEDIA_BUS_FMT_UYVY12_1X24)) + output_fmts[i++] = MEDIA_BUS_FMT_UYVY12_1X24; + +- if (info->color_formats & DRM_COLOR_FORMAT_YCRCB444) ++ if ((info->color_formats & DRM_COLOR_FORMAT_YCRCB444) && ++ is_tmds_allowed(info, mode, MEDIA_BUS_FMT_YUV12_1X36)) + output_fmts[i++] = MEDIA_BUS_FMT_YUV12_1X36; + +- output_fmts[i++] = MEDIA_BUS_FMT_RGB121212_1X36; ++ if (is_tmds_allowed(info, mode, MEDIA_BUS_FMT_RGB121212_1X36)) ++ output_fmts[i++] = MEDIA_BUS_FMT_RGB121212_1X36; + } + + if (max_bpc >= 10 && info->bpc >= 10) { +- if (info->color_formats & DRM_COLOR_FORMAT_YCRCB422) ++ if ((info->color_formats & DRM_COLOR_FORMAT_YCRCB422) && ++ is_tmds_allowed(info, mode, MEDIA_BUS_FMT_UYVY10_1X20)) + output_fmts[i++] = MEDIA_BUS_FMT_UYVY10_1X20; + +- if (info->color_formats & DRM_COLOR_FORMAT_YCRCB444) ++ if ((info->color_formats & DRM_COLOR_FORMAT_YCRCB444) && ++ is_tmds_allowed(info, mode, MEDIA_BUS_FMT_YUV10_1X30)) + output_fmts[i++] = MEDIA_BUS_FMT_YUV10_1X30; + +- output_fmts[i++] = MEDIA_BUS_FMT_RGB101010_1X30; ++ if (is_tmds_allowed(info, mode, MEDIA_BUS_FMT_RGB101010_1X30)) ++ output_fmts[i++] = MEDIA_BUS_FMT_RGB101010_1X30; + } + +- if (info->color_formats & DRM_COLOR_FORMAT_YCRCB422) ++ if ((info->color_formats & DRM_COLOR_FORMAT_YCRCB422) && ++ is_tmds_allowed(info, mode, MEDIA_BUS_FMT_UYVY8_1X16)) + output_fmts[i++] = MEDIA_BUS_FMT_UYVY8_1X16; + +- if (info->color_formats & DRM_COLOR_FORMAT_YCRCB444) ++ if ((info->color_formats & DRM_COLOR_FORMAT_YCRCB444) && ++ is_tmds_allowed(info, mode, MEDIA_BUS_FMT_YUV8_1X24)) + output_fmts[i++] = MEDIA_BUS_FMT_YUV8_1X24; + + /* Default 8bit RGB fallback */ +- output_fmts[i++] = MEDIA_BUS_FMT_RGB888_1X24; ++ if (is_tmds_allowed(info, mode, MEDIA_BUS_FMT_RGB888_1X24)) ++ output_fmts[i++] = MEDIA_BUS_FMT_RGB888_1X24; + + *num_output_fmts = i; + +@@ -2831,11 +2854,20 @@ dw_hdmi_bridge_mode_valid(struct drm_bridge *bridge, + struct dw_hdmi *hdmi = bridge->driver_private; + const struct dw_hdmi_plat_data *pdata = hdmi->plat_data; + enum drm_mode_status mode_status = MODE_OK; ++ int max_tmds_clock = info->max_tmds_clock ? info->max_tmds_clock : 340000; ++ int clock = mode->clock; + + /* We don't support double-clocked modes */ + if (mode->flags & DRM_MODE_FLAG_DBLCLK) + return MODE_BAD; + ++ if (pdata->ycbcr_420_allowed && drm_mode_is_420(info, mode) && ++ (info->color_formats & DRM_COLOR_FORMAT_YCRCB420)) ++ clock /= 2; ++ ++ if (clock > max_tmds_clock) ++ return MODE_CLOCK_HIGH; ++ + if (pdata->mode_valid) + mode_status = pdata->mode_valid(hdmi, pdata->priv_data, info, + mode); + +From 2960613151591dd65e3b7dac4bc760ad0cddd4b6 Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Fri, 20 Dec 2019 08:12:42 +0000 +Subject: [PATCH] WIP: drm/rockchip: dw_hdmi: add 10-bit rgb bus format + +--- + drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 41 +++++++++++++++++++++ + drivers/gpu/drm/rockchip/rockchip_drm_drv.h | 2 + + 2 files changed, 43 insertions(+) + +diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +index e7fbeb9132fb..cd87ee8a65c3 100644 +--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c ++++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +@@ -77,6 +77,7 @@ struct rockchip_hdmi { + }; + + #define to_rockchip_hdmi(x) container_of(x, struct rockchip_hdmi, x) ++#define to_crtc_state(x) container_of(x, struct drm_crtc_state, x) + + static const struct dw_hdmi_mpll_config rockchip_mpll_cfg[] = { + { +@@ -282,6 +283,11 @@ dw_hdmi_rockchip_bridge_mode_set(struct drm_bridge *bridge, + const struct drm_display_mode *adjusted_mode) + { + struct rockchip_hdmi *hdmi = to_rockchip_hdmi(bridge); ++ struct drm_crtc_state *crtc_state = to_crtc_state(adjusted_mode); ++ struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc_state); ++ ++ if (hdmi->phy) ++ phy_set_bus_width(hdmi->phy, s->bus_width); + + clk_set_rate(hdmi->vpll_clk, adjusted_mode->clock * 1000); + } +@@ -320,6 +326,7 @@ static void dw_hdmi_rockchip_bridge_enable(struct drm_bridge *bridge) + static bool is_rgb(u32 format) + { + switch (format) { ++ case MEDIA_BUS_FMT_RGB101010_1X30: + case MEDIA_BUS_FMT_RGB888_1X24: + return true; + default: +@@ -327,6 +334,16 @@ static bool is_rgb(u32 format) + } + } + ++static bool is_10bit(u32 format) ++{ ++ switch (format) { ++ case MEDIA_BUS_FMT_RGB101010_1X30: ++ return true; ++ default: ++ return false; ++ } ++} ++ + static int + dw_hdmi_rockchip_bridge_atomic_check(struct drm_bridge *bridge, + struct drm_bridge_state *bridge_state, +@@ -334,9 +351,24 @@ dw_hdmi_rockchip_bridge_atomic_check(struct drm_bridge *bridge, + struct drm_connector_state *conn_state) + { + struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc_state); ++ struct drm_atomic_state *state = bridge_state->base.state; ++ struct drm_crtc_state *old_crtc_state; ++ struct rockchip_crtc_state *old_state; ++ u32 format = bridge_state->output_bus_cfg.format; + + s->output_mode = ROCKCHIP_OUT_MODE_AAAA; + s->output_type = DRM_MODE_CONNECTOR_HDMIA; ++ s->output_bpc = 10; ++ s->bus_format = format; ++ s->bus_width = is_10bit(format) ? 10 : 8; ++ ++ old_crtc_state = drm_atomic_get_old_crtc_state(state, conn_state->crtc); ++ if (old_crtc_state && !crtc_state->mode_changed) { ++ old_state = to_rockchip_crtc_state(old_crtc_state); ++ if (s->bus_format != old_state->bus_format || ++ s->bus_width != old_state->bus_width) ++ crtc_state->mode_changed = true; ++ } + + return 0; + } +@@ -348,10 +380,19 @@ static u32 *dw_hdmi_rockchip_get_input_bus_fmts(struct drm_bridge *bridge, + u32 output_fmt, + unsigned int *num_input_fmts) + { ++ struct rockchip_hdmi *hdmi = to_rockchip_hdmi(bridge); ++ struct drm_encoder *encoder = bridge->encoder; + u32 *input_fmt; ++ bool has_10bit = true; + + *num_input_fmts = 0; + ++ if (drm_of_encoder_active_endpoint_id(hdmi->dev->of_node, encoder)) ++ has_10bit = false; ++ ++ if (!has_10bit && is_10bit(output_fmt)) ++ return NULL; ++ + if (!is_rgb(output_fmt)) + return NULL; + +diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h +index e33c2dcd0d4b..03944e08b6c7 100644 +--- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h ++++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h +@@ -31,6 +31,8 @@ struct rockchip_crtc_state { + int output_bpc; + int output_flags; + bool enable_afbc; ++ u32 bus_format; ++ int bus_width; + }; + #define to_rockchip_crtc_state(s) \ + container_of(s, struct rockchip_crtc_state, base) + +From 7eda226a69e0c2b4fd8ab41b51ddff08da682073 Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Sun, 8 Dec 2019 23:42:44 +0000 +Subject: [PATCH] WIP: drm: dw-hdmi: add content type connector property + +Signed-off-by: Jonas Karlman +--- + drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +index 26c64cf2d00a..ffb72e6874c8 100644 +--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c ++++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +@@ -1646,6 +1646,7 @@ static void hdmi_config_AVI(struct dw_hdmi *hdmi, + const struct drm_connector *connector, + const struct drm_display_mode *mode) + { ++ const struct drm_connector_state *conn_state = connector->state; + struct hdmi_avi_infoframe frame; + u8 val; + +@@ -1703,6 +1704,8 @@ static void hdmi_config_AVI(struct dw_hdmi *hdmi, + HDMI_EXTENDED_COLORIMETRY_XV_YCC_601; + } + ++ drm_hdmi_avi_infoframe_content_type(&frame, conn_state); ++ + /* + * The Designware IP uses a different byte format from standard + * AVI info frames, though generally the bits are in the correct +@@ -2437,7 +2440,8 @@ static int dw_hdmi_connector_atomic_check(struct drm_connector *connector, + if (!crtc) + return 0; + +- if (!hdr_metadata_equal(old_state, new_state)) { ++ if (!hdr_metadata_equal(old_state, new_state) || ++ old_state->content_type != new_state->content_type) { + crtc_state = drm_atomic_get_crtc_state(state, crtc); + if (IS_ERR(crtc_state)) + return PTR_ERR(crtc_state); +@@ -2505,6 +2509,8 @@ static int dw_hdmi_connector_create(struct dw_hdmi *hdmi) + + drm_connector_attach_max_bpc_property(connector, 8, 16); + ++ drm_connector_attach_content_type_property(connector); ++ + if (hdmi->version >= 0x200a && hdmi->plat_data->use_drm_infoframe) + drm_object_attach_property(&connector->base, + connector->dev->mode_config.hdr_output_metadata_property, 0); + +From 8e94faae53df05c7466387b65edc808218f15277 Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Fri, 20 Dec 2019 08:12:43 +0000 +Subject: [PATCH] WIP: drm/rockchip: add yuv444 support + +--- + drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 30 ++++++++++++++++++++- + drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 29 ++++++++++++++++++++ + drivers/gpu/drm/rockchip/rockchip_drm_vop.h | 6 +++++ + drivers/gpu/drm/rockchip/rockchip_vop_reg.c | 14 ++++++++++ + 4 files changed, 78 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +index cd87ee8a65c3..436a9223e5e4 100644 +--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c ++++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +@@ -62,6 +62,7 @@ struct rockchip_hdmi_chip_data { + int lcdsel_grf_reg; + u32 lcdsel_big; + u32 lcdsel_lit; ++ bool ycbcr_444_allowed; + }; + + struct rockchip_hdmi { +@@ -334,10 +335,22 @@ static bool is_rgb(u32 format) + } + } + ++static bool is_yuv444(u32 format) ++{ ++ switch (format) { ++ case MEDIA_BUS_FMT_YUV10_1X30: ++ case MEDIA_BUS_FMT_YUV8_1X24: ++ return true; ++ default: ++ return false; ++ } ++} ++ + static bool is_10bit(u32 format) + { + switch (format) { + case MEDIA_BUS_FMT_RGB101010_1X30: ++ case MEDIA_BUS_FMT_YUV10_1X30: + return true; + default: + return false; +@@ -354,12 +367,22 @@ dw_hdmi_rockchip_bridge_atomic_check(struct drm_bridge *bridge, + struct drm_atomic_state *state = bridge_state->base.state; + struct drm_crtc_state *old_crtc_state; + struct rockchip_crtc_state *old_state; ++ struct drm_bridge *next_bridge; ++ struct drm_bridge_state *next_bridge_state; + u32 format = bridge_state->output_bus_cfg.format; + + s->output_mode = ROCKCHIP_OUT_MODE_AAAA; + s->output_type = DRM_MODE_CONNECTOR_HDMIA; + s->output_bpc = 10; + s->bus_format = format; ++ ++ next_bridge = drm_bridge_get_next_bridge(bridge); ++ if (next_bridge) { ++ next_bridge_state = drm_atomic_get_new_bridge_state(state, ++ next_bridge); ++ format = next_bridge_state->output_bus_cfg.format; ++ } ++ + s->bus_width = is_10bit(format) ? 10 : 8; + + old_crtc_state = drm_atomic_get_old_crtc_state(state, conn_state->crtc); +@@ -393,7 +416,10 @@ static u32 *dw_hdmi_rockchip_get_input_bus_fmts(struct drm_bridge *bridge, + if (!has_10bit && is_10bit(output_fmt)) + return NULL; + +- if (!is_rgb(output_fmt)) ++ if (is_yuv444(output_fmt)) { ++ if (!hdmi->chip_data->ycbcr_444_allowed) ++ return NULL; ++ } else if (!is_rgb(output_fmt)) + return NULL; + + input_fmt = kzalloc(sizeof(*input_fmt), GFP_KERNEL); +@@ -542,6 +568,7 @@ static const struct dw_hdmi_phy_ops rk3328_hdmi_phy_ops = { + + static struct rockchip_hdmi_chip_data rk3328_chip_data = { + .lcdsel_grf_reg = -1, ++ .ycbcr_444_allowed = true, + }; + + static const struct dw_hdmi_plat_data rk3328_hdmi_drv_data = { +@@ -557,6 +584,7 @@ static struct rockchip_hdmi_chip_data rk3399_chip_data = { + .lcdsel_grf_reg = RK3399_GRF_SOC_CON20, + .lcdsel_big = HIWORD_UPDATE(0, RK3399_HDMI_LCDC_SEL), + .lcdsel_lit = HIWORD_UPDATE(RK3399_HDMI_LCDC_SEL, RK3399_HDMI_LCDC_SEL), ++ .ycbcr_444_allowed = true, + }; + + static const struct dw_hdmi_plat_data rk3399_hdmi_drv_data = { +diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +index 5ab1412173a7..a17bd4e90ba7 100644 +--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c ++++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +@@ -310,6 +310,17 @@ static int vop_convert_afbc_format(uint32_t format) + return -EINVAL; + } + ++static bool is_yuv_output(uint32_t bus_format) ++{ ++ switch (bus_format) { ++ case MEDIA_BUS_FMT_YUV8_1X24: ++ case MEDIA_BUS_FMT_YUV10_1X30: ++ return true; ++ default: ++ return false; ++ } ++} ++ + static uint16_t scl_vop_cal_scale(enum scale_mode mode, uint32_t src, + uint32_t dst, bool is_horizontal, + int vsu_mode, int *vskiplines) +@@ -1329,6 +1340,7 @@ static void vop_crtc_atomic_enable(struct drm_crtc *crtc, + u16 vact_end = vact_st + vdisplay; + uint32_t pin_pol, val; + int dither_bpc = s->output_bpc ? s->output_bpc : 10; ++ bool yuv_output = is_yuv_output(s->bus_format); + int ret; + + if (old_state && old_state->self_refresh_active) { +@@ -1402,6 +1414,8 @@ static void vop_crtc_atomic_enable(struct drm_crtc *crtc, + !(vop_data->feature & VOP_FEATURE_OUTPUT_RGB10)) + s->output_mode = ROCKCHIP_OUT_MODE_P888; + ++ VOP_REG_SET(vop, common, dsp_data_swap, yuv_output ? 2 : 0); ++ + if (s->output_mode == ROCKCHIP_OUT_MODE_AAAA && dither_bpc <= 8) + VOP_REG_SET(vop, common, pre_dither_down, 1); + else +@@ -1417,6 +1431,21 @@ static void vop_crtc_atomic_enable(struct drm_crtc *crtc, + + VOP_REG_SET(vop, common, out_mode, s->output_mode); + ++ VOP_REG_SET(vop, common, overlay_mode, yuv_output); ++ VOP_REG_SET(vop, common, dsp_out_yuv, yuv_output); ++ ++ /* ++ * Background color is 10bit depth if vop version >= 3.5 ++ */ ++ if (!yuv_output) ++ val = 0; ++ else if (VOP_MAJOR(vop_data->version) == 3 && ++ VOP_MINOR(vop_data->version) >= 5) ++ val = 0x20010200; ++ else ++ val = 0x801080; ++ VOP_REG_SET(vop, common, dsp_background, val); ++ + VOP_REG_SET(vop, modeset, htotal_pw, (htotal << 16) | hsync_len); + val = hact_st << 16; + val |= hact_end; +diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h +index 1516231bbf93..b820ad3fa091 100644 +--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h ++++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h +@@ -92,10 +92,16 @@ struct vop_common { + struct vop_reg mmu_en; + struct vop_reg out_mode; + struct vop_reg standby; ++ ++ struct vop_reg overlay_mode; ++ struct vop_reg dsp_data_swap; ++ struct vop_reg dsp_out_yuv; ++ struct vop_reg dsp_background; + }; + + struct vop_misc { + struct vop_reg global_regdone_en; ++ struct vop_reg win_channel[4]; + }; + + struct vop_intr { +diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c +index 57c36e9207c1..800b9341dd42 100644 +--- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c ++++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c +@@ -644,6 +644,11 @@ static const struct vop_common rk3288_common = { + .dsp_blank = VOP_REG(RK3288_DSP_CTRL0, 0x3, 18), + .out_mode = VOP_REG(RK3288_DSP_CTRL0, 0xf, 0), + .cfg_done = VOP_REG_SYNC(RK3288_REG_CFG_DONE, 0x1, 0), ++ ++ .overlay_mode = VOP_REG(RK3288_SYS_CTRL, 0x1, 16), ++ .dsp_data_swap = VOP_REG(RK3288_DSP_CTRL0, 0x1f, 12), ++ .dsp_out_yuv = VOP_REG(RK3288_POST_SCL_CTRL, 0x1, 2), ++ .dsp_background = VOP_REG(RK3288_DSP_BG, 0xffffffff, 0), + }; + + /* +@@ -996,6 +1001,10 @@ static const struct vop_output rk3328_output = { + + static const struct vop_misc rk3328_misc = { + .global_regdone_en = VOP_REG(RK3328_SYS_CTRL, 0x1, 11), ++ ++ .win_channel[0] = VOP_REG(RK3328_WIN0_CTRL2, 0xff, 0), ++ .win_channel[1] = VOP_REG(RK3328_WIN1_CTRL2, 0xff, 0), ++ .win_channel[2] = VOP_REG(RK3328_WIN2_CTRL2, 0xff, 0), + }; + + static const struct vop_common rk3328_common = { +@@ -1008,6 +1017,11 @@ static const struct vop_common rk3328_common = { + .dsp_blank = VOP_REG(RK3328_DSP_CTRL0, 0x3, 18), + .out_mode = VOP_REG(RK3328_DSP_CTRL0, 0xf, 0), + .cfg_done = VOP_REG_SYNC(RK3328_REG_CFG_DONE, 0x1, 0), ++ ++ .overlay_mode = VOP_REG(RK3328_SYS_CTRL, 0x1, 16), ++ .dsp_data_swap = VOP_REG(RK3328_DSP_CTRL0, 0x1f, 12), ++ .dsp_out_yuv = VOP_REG(RK3328_POST_SCL_CTRL, 0x1, 2), ++ .dsp_background = VOP_REG(RK3328_DSP_BG, 0xffffffff, 0), + }; + + static const struct vop_intr rk3328_vop_intr = { + +From d5563c9163f1a691e73c1b027d39c78672ff3e17 Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Fri, 20 Dec 2019 08:12:43 +0000 +Subject: [PATCH] WIP: drm/rockchip: add yuv420 support + +--- + drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 23 +++++++++++++++++++++ + drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 18 +++++++++++++++- + drivers/gpu/drm/rockchip/rockchip_drm_vop.h | 10 +++++---- + drivers/gpu/drm/rockchip/rockchip_vop_reg.c | 2 ++ + 4 files changed, 48 insertions(+), 5 deletions(-) + +diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +index 436a9223e5e4..1abc46a023a4 100644 +--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c ++++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +@@ -346,9 +346,21 @@ static bool is_yuv444(u32 format) + } + } + ++static bool is_yuv420(u32 format) ++{ ++ switch (format) { ++ case MEDIA_BUS_FMT_UYYVYY10_0_5X30: ++ case MEDIA_BUS_FMT_UYYVYY8_0_5X24: ++ return true; ++ default: ++ return false; ++ } ++} ++ + static bool is_10bit(u32 format) + { + switch (format) { ++ case MEDIA_BUS_FMT_UYYVYY10_0_5X30: + case MEDIA_BUS_FMT_RGB101010_1X30: + case MEDIA_BUS_FMT_YUV10_1X30: + return true; +@@ -385,6 +397,11 @@ dw_hdmi_rockchip_bridge_atomic_check(struct drm_bridge *bridge, + + s->bus_width = is_10bit(format) ? 10 : 8; + ++ if (is_yuv420(format)) { ++ s->output_mode = ROCKCHIP_OUT_MODE_YUV420; ++ s->bus_width /= 2; ++ } ++ + old_crtc_state = drm_atomic_get_old_crtc_state(state, conn_state->crtc); + if (old_crtc_state && !crtc_state->mode_changed) { + old_state = to_rockchip_crtc_state(old_crtc_state); +@@ -405,6 +422,7 @@ static u32 *dw_hdmi_rockchip_get_input_bus_fmts(struct drm_bridge *bridge, + { + struct rockchip_hdmi *hdmi = to_rockchip_hdmi(bridge); + struct drm_encoder *encoder = bridge->encoder; ++ struct drm_connector *connector = conn_state->connector; + u32 *input_fmt; + bool has_10bit = true; + +@@ -419,6 +437,9 @@ static u32 *dw_hdmi_rockchip_get_input_bus_fmts(struct drm_bridge *bridge, + if (is_yuv444(output_fmt)) { + if (!hdmi->chip_data->ycbcr_444_allowed) + return NULL; ++ } else if (is_yuv420(output_fmt)) { ++ if (!connector->ycbcr_420_allowed) ++ return NULL; + } else if (!is_rgb(output_fmt)) + return NULL; + +@@ -578,6 +599,7 @@ static const struct dw_hdmi_plat_data rk3328_hdmi_drv_data = { + .phy_name = "inno_dw_hdmi_phy2", + .phy_force_vendor = true, + .use_drm_infoframe = true, ++ .ycbcr_420_allowed = true, + }; + + static struct rockchip_hdmi_chip_data rk3399_chip_data = { +@@ -595,6 +617,7 @@ static const struct dw_hdmi_plat_data rk3399_hdmi_drv_data = { + .phy_config = rockchip_phy_config, + .phy_data = &rk3399_chip_data, + .use_drm_infoframe = true, ++ .ycbcr_420_allowed = true, + }; + + static const struct of_device_id dw_hdmi_rockchip_dt_ids[] = { +diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +index a17bd4e90ba7..5ea8031eb0f7 100644 +--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c ++++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +@@ -311,6 +311,19 @@ static int vop_convert_afbc_format(uint32_t format) + } + + static bool is_yuv_output(uint32_t bus_format) ++{ ++ switch (bus_format) { ++ case MEDIA_BUS_FMT_YUV8_1X24: ++ case MEDIA_BUS_FMT_YUV10_1X30: ++ case MEDIA_BUS_FMT_UYYVYY8_0_5X24: ++ case MEDIA_BUS_FMT_UYYVYY10_0_5X30: ++ return true; ++ default: ++ return false; ++ } ++} ++ ++static bool has_uv_swapped(uint32_t bus_format) + { + switch (bus_format) { + case MEDIA_BUS_FMT_YUV8_1X24: +@@ -1414,7 +1427,7 @@ static void vop_crtc_atomic_enable(struct drm_crtc *crtc, + !(vop_data->feature & VOP_FEATURE_OUTPUT_RGB10)) + s->output_mode = ROCKCHIP_OUT_MODE_P888; + +- VOP_REG_SET(vop, common, dsp_data_swap, yuv_output ? 2 : 0); ++ VOP_REG_SET(vop, common, dsp_data_swap, has_uv_swapped(s->bus_format) ? 2 : 0); + + if (s->output_mode == ROCKCHIP_OUT_MODE_AAAA && dither_bpc <= 8) + VOP_REG_SET(vop, common, pre_dither_down, 1); +@@ -1431,6 +1444,9 @@ static void vop_crtc_atomic_enable(struct drm_crtc *crtc, + + VOP_REG_SET(vop, common, out_mode, s->output_mode); + ++ VOP_REG_SET(vop, common, dclk_ddr, ++ s->output_mode == ROCKCHIP_OUT_MODE_YUV420 ? 1 : 0); ++ + VOP_REG_SET(vop, common, overlay_mode, yuv_output); + VOP_REG_SET(vop, common, dsp_out_yuv, yuv_output); + +diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h +index b820ad3fa091..8e6e999e5163 100644 +--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h ++++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h +@@ -94,6 +94,7 @@ struct vop_common { + struct vop_reg standby; + + struct vop_reg overlay_mode; ++ struct vop_reg dclk_ddr; + struct vop_reg dsp_data_swap; + struct vop_reg dsp_out_yuv; + struct vop_reg dsp_background; +@@ -257,11 +258,12 @@ struct vop_data { + /* + * display output interface supported by rockchip lcdc + */ +-#define ROCKCHIP_OUT_MODE_P888 0 +-#define ROCKCHIP_OUT_MODE_P666 1 +-#define ROCKCHIP_OUT_MODE_P565 2 ++#define ROCKCHIP_OUT_MODE_P888 0 ++#define ROCKCHIP_OUT_MODE_P666 1 ++#define ROCKCHIP_OUT_MODE_P565 2 ++#define ROCKCHIP_OUT_MODE_YUV420 14 + /* for use special outface */ +-#define ROCKCHIP_OUT_MODE_AAAA 15 ++#define ROCKCHIP_OUT_MODE_AAAA 15 + + /* output flags */ + #define ROCKCHIP_OUTPUT_DSI_DUAL BIT(0) +diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c +index 800b9341dd42..dd4546f9f410 100644 +--- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c ++++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c +@@ -646,6 +646,7 @@ static const struct vop_common rk3288_common = { + .cfg_done = VOP_REG_SYNC(RK3288_REG_CFG_DONE, 0x1, 0), + + .overlay_mode = VOP_REG(RK3288_SYS_CTRL, 0x1, 16), ++ .dclk_ddr = VOP_REG(RK3288_DSP_CTRL0, 0x1, 8), + .dsp_data_swap = VOP_REG(RK3288_DSP_CTRL0, 0x1f, 12), + .dsp_out_yuv = VOP_REG(RK3288_POST_SCL_CTRL, 0x1, 2), + .dsp_background = VOP_REG(RK3288_DSP_BG, 0xffffffff, 0), +@@ -1019,6 +1020,7 @@ static const struct vop_common rk3328_common = { + .cfg_done = VOP_REG_SYNC(RK3328_REG_CFG_DONE, 0x1, 0), + + .overlay_mode = VOP_REG(RK3328_SYS_CTRL, 0x1, 16), ++ .dclk_ddr = VOP_REG(RK3328_DSP_CTRL0, 0x1, 8), + .dsp_data_swap = VOP_REG(RK3328_DSP_CTRL0, 0x1f, 12), + .dsp_out_yuv = VOP_REG(RK3328_POST_SCL_CTRL, 0x1, 2), + .dsp_background = VOP_REG(RK3328_DSP_BG, 0xffffffff, 0), + +From 1b47a0a13f295cff2a50f6b4af272b7ee1f01534 Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Sun, 7 Jun 2020 20:25:25 +0000 +Subject: [PATCH] drm: drm_fourcc: add NV20 and NV30 YUV formats + +DRM_FORMAT_NV20 and DRM_FORMAT_NV30 formats is the 2x1 and non-subsampled +variant of NV15, a 10-bit 2-plane YUV format that has no padding between +components. Instead, luminance and chrominance samples are grouped into 4s +so that each group is packed into an integer number of bytes: + +YYYY = UVUV = 4 * 10 bits = 40 bits = 5 bytes + +The '20' and '30' suffix refers to the optimum effective bits per pixel +which is achieved when the total number of luminance samples is a multiple +of 4. + +V2: Added NV30 format + +Signed-off-by: Jonas Karlman +--- + drivers/gpu/drm/drm_fourcc.c | 8 ++++++++ + include/uapi/drm/drm_fourcc.h | 2 ++ + 2 files changed, 10 insertions(+) + +diff --git a/drivers/gpu/drm/drm_fourcc.c b/drivers/gpu/drm/drm_fourcc.c +index 722c7ebe4e88..2daf8a304b53 100644 +--- a/drivers/gpu/drm/drm_fourcc.c ++++ b/drivers/gpu/drm/drm_fourcc.c +@@ -278,6 +278,14 @@ const struct drm_format_info *__drm_format_info(u32 format) + .num_planes = 2, .char_per_block = { 5, 5, 0 }, + .block_w = { 4, 2, 0 }, .block_h = { 1, 1, 0 }, .hsub = 2, + .vsub = 2, .is_yuv = true }, ++ { .format = DRM_FORMAT_NV20, .depth = 0, ++ .num_planes = 2, .char_per_block = { 5, 5, 0 }, ++ .block_w = { 4, 2, 0 }, .block_h = { 1, 1, 0 }, .hsub = 2, ++ .vsub = 1, .is_yuv = true }, ++ { .format = DRM_FORMAT_NV30, .depth = 0, ++ .num_planes = 2, .char_per_block = { 5, 5, 0 }, ++ .block_w = { 4, 2, 0 }, .block_h = { 1, 1, 0 }, .hsub = 1, ++ .vsub = 1, .is_yuv = true }, + { .format = DRM_FORMAT_Q410, .depth = 0, + .num_planes = 3, .char_per_block = { 2, 2, 2 }, + .block_w = { 1, 1, 1 }, .block_h = { 1, 1, 1 }, .hsub = 0, +diff --git a/include/uapi/drm/drm_fourcc.h b/include/uapi/drm/drm_fourcc.h +index 82f327801267..d8e6159213dc 100644 +--- a/include/uapi/drm/drm_fourcc.h ++++ b/include/uapi/drm/drm_fourcc.h +@@ -242,6 +242,8 @@ extern "C" { + * index 1 = Cr:Cb plane, [39:0] Cr1:Cb1:Cr0:Cb0 little endian + */ + #define DRM_FORMAT_NV15 fourcc_code('N', 'V', '1', '5') /* 2x2 subsampled Cr:Cb plane */ ++#define DRM_FORMAT_NV20 fourcc_code('N', 'V', '2', '0') /* 2x1 subsampled Cr:Cb plane */ ++#define DRM_FORMAT_NV30 fourcc_code('N', 'V', '3', '0') /* non-subsampled Cr:Cb plane */ + + /* + * 2 plane YCbCr MSB aligned + +From 6c52f23c9f8215a7a5a99d6ac299701baa85a8cb Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Sun, 7 Jun 2020 20:25:26 +0000 +Subject: [PATCH] drm: rockchip: add NV15, NV20 and NV30 support + +Add support for displaying 10-bit 4:2:0 and 4:2:2 formats produced by the +Rockchip Video Decoder on RK322X, RK3288, RK3328, RK3368 and RK3399. +Also add support for 10-bit 4:4:4 format while at it. + +V2: Added NV30 support + +Signed-off-by: Jonas Karlman +--- + drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 29 +++++++++++++++++-- + drivers/gpu/drm/rockchip/rockchip_drm_vop.h | 1 + + drivers/gpu/drm/rockchip/rockchip_vop_reg.c | 32 +++++++++++++++++---- + 3 files changed, 54 insertions(+), 8 deletions(-) + +diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +index 5ea8031eb0f7..413534cf1a93 100644 +--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c ++++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +@@ -261,6 +261,18 @@ static bool has_rb_swapped(uint32_t format) + } + } + ++static bool is_fmt_10(uint32_t format) ++{ ++ switch (format) { ++ case DRM_FORMAT_NV15: ++ case DRM_FORMAT_NV20: ++ case DRM_FORMAT_NV30: ++ return true; ++ default: ++ return false; ++ } ++} ++ + static enum vop_data_format vop_convert_format(uint32_t format) + { + switch (format) { +@@ -276,10 +288,13 @@ static enum vop_data_format vop_convert_format(uint32_t format) + case DRM_FORMAT_BGR565: + return VOP_FMT_RGB565; + case DRM_FORMAT_NV12: ++ case DRM_FORMAT_NV15: + return VOP_FMT_YUV420SP; + case DRM_FORMAT_NV16: ++ case DRM_FORMAT_NV20: + return VOP_FMT_YUV422SP; + case DRM_FORMAT_NV24: ++ case DRM_FORMAT_NV30: + return VOP_FMT_YUV444SP; + default: + DRM_ERROR("unsupported format[%08x]\n", format); +@@ -946,7 +961,12 @@ static void vop_plane_atomic_update(struct drm_plane *plane, + dsp_sty = dest->y1 + crtc->mode.vtotal - crtc->mode.vsync_start; + dsp_st = dsp_sty << 16 | (dsp_stx & 0xffff); + +- offset = (src->x1 >> 16) * fb->format->cpp[0]; ++ if (fb->format->block_w[0]) ++ offset = (src->x1 >> 16) * fb->format->char_per_block[0] / ++ fb->format->block_w[0]; ++ else ++ offset = (src->x1 >> 16) * fb->format->cpp[0]; ++ + offset += (src->y1 >> 16) * fb->pitches[0]; + dma_addr = rk_obj->dma_addr + offset + fb->offsets[0]; + +@@ -972,6 +992,7 @@ static void vop_plane_atomic_update(struct drm_plane *plane, + } + + VOP_WIN_SET(vop, win, format, format); ++ VOP_WIN_SET(vop, win, fmt_10, is_fmt_10(fb->format->format)); + VOP_WIN_SET(vop, win, yrgb_vir, DIV_ROUND_UP(fb->pitches[0], 4)); + VOP_WIN_SET(vop, win, yrgb_mst, dma_addr); + VOP_WIN_YUV2YUV_SET(vop, win_yuv2yuv, y2r_en, is_yuv); +@@ -988,7 +1009,11 @@ static void vop_plane_atomic_update(struct drm_plane *plane, + uv_obj = fb->obj[1]; + rk_uv_obj = to_rockchip_obj(uv_obj); + +- offset = (src->x1 >> 16) * bpp / hsub; ++ if (fb->format->block_w[1]) ++ offset = (src->x1 >> 16) * bpp / ++ fb->format->block_w[1] / hsub; ++ else ++ offset = (src->x1 >> 16) * bpp / hsub; + offset += (src->y1 >> 16) * fb->pitches[1] / vsub; + + dma_addr = rk_uv_obj->dma_addr + offset + fb->offsets[1]; +diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h +index 8e6e999e5163..9f50e0e00127 100644 +--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h ++++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h +@@ -161,6 +161,7 @@ struct vop_win_phy { + struct vop_reg enable; + struct vop_reg gate; + struct vop_reg format; ++ struct vop_reg fmt_10; + struct vop_reg rb_swap; + struct vop_reg act_info; + struct vop_reg dsp_info; +diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c +index dd4546f9f410..7d5191421ddf 100644 +--- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c ++++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c +@@ -50,6 +50,23 @@ static const uint32_t formats_win_full[] = { + DRM_FORMAT_NV24, + }; + ++static const uint32_t formats_win_full_10[] = { ++ DRM_FORMAT_XRGB8888, ++ DRM_FORMAT_ARGB8888, ++ DRM_FORMAT_XBGR8888, ++ DRM_FORMAT_ABGR8888, ++ DRM_FORMAT_RGB888, ++ DRM_FORMAT_BGR888, ++ DRM_FORMAT_RGB565, ++ DRM_FORMAT_BGR565, ++ DRM_FORMAT_NV12, ++ DRM_FORMAT_NV16, ++ DRM_FORMAT_NV24, ++ DRM_FORMAT_NV15, ++ DRM_FORMAT_NV20, ++ DRM_FORMAT_NV30, ++}; ++ + static const uint64_t format_modifiers_win_full[] = { + DRM_FORMAT_MOD_LINEAR, + DRM_FORMAT_MOD_INVALID, +@@ -579,11 +596,12 @@ static const struct vop_scl_regs rk3288_win_full_scl = { + + static const struct vop_win_phy rk3288_win01_data = { + .scl = &rk3288_win_full_scl, +- .data_formats = formats_win_full, +- .nformats = ARRAY_SIZE(formats_win_full), ++ .data_formats = formats_win_full_10, ++ .nformats = ARRAY_SIZE(formats_win_full_10), + .format_modifiers = format_modifiers_win_full, + .enable = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 0), + .format = VOP_REG(RK3288_WIN0_CTRL0, 0x7, 1), ++ .fmt_10 = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 4), + .rb_swap = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 12), + .act_info = VOP_REG(RK3288_WIN0_ACT_INFO, 0x1fff1fff, 0), + .dsp_info = VOP_REG(RK3288_WIN0_DSP_INFO, 0x0fff0fff, 0), +@@ -720,11 +738,12 @@ static const struct vop_intr rk3368_vop_intr = { + + static const struct vop_win_phy rk3368_win01_data = { + .scl = &rk3288_win_full_scl, +- .data_formats = formats_win_full, +- .nformats = ARRAY_SIZE(formats_win_full), ++ .data_formats = formats_win_full_10, ++ .nformats = ARRAY_SIZE(formats_win_full_10), + .format_modifiers = format_modifiers_win_full, + .enable = VOP_REG(RK3368_WIN0_CTRL0, 0x1, 0), + .format = VOP_REG(RK3368_WIN0_CTRL0, 0x7, 1), ++ .fmt_10 = VOP_REG(RK3368_WIN0_CTRL0, 0x1, 4), + .rb_swap = VOP_REG(RK3368_WIN0_CTRL0, 0x1, 12), + .x_mir_en = VOP_REG(RK3368_WIN0_CTRL0, 0x1, 21), + .y_mir_en = VOP_REG(RK3368_WIN0_CTRL0, 0x1, 22), +@@ -871,11 +890,12 @@ static const struct vop_win_yuv2yuv_data rk3399_vop_big_win_yuv2yuv_data[] = { + + static const struct vop_win_phy rk3399_win01_data = { + .scl = &rk3288_win_full_scl, +- .data_formats = formats_win_full, +- .nformats = ARRAY_SIZE(formats_win_full), ++ .data_formats = formats_win_full_10, ++ .nformats = ARRAY_SIZE(formats_win_full_10), + .format_modifiers = format_modifiers_win_full_afbc, + .enable = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 0), + .format = VOP_REG(RK3288_WIN0_CTRL0, 0x7, 1), ++ .fmt_10 = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 4), + .rb_swap = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 12), + .y_mir_en = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 22), + .act_info = VOP_REG(RK3288_WIN0_ACT_INFO, 0x1fff1fff, 0), + +From 82b749d252ad0a50a36ad7ca93335e8d8e5416b7 Mon Sep 17 00:00:00 2001 +From: Alex Bee +Date: Sat, 15 Aug 2020 21:11:08 +0200 +Subject: [PATCH] drm/rockchip: rk3368's vop does not support 10-bit formats - + neither as input nor as output + +--- + drivers/gpu/drm/rockchip/rockchip_vop_reg.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c +index 7d5191421ddf..20c3e6248ec7 100644 +--- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c ++++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c +@@ -738,8 +738,8 @@ static const struct vop_intr rk3368_vop_intr = { + + static const struct vop_win_phy rk3368_win01_data = { + .scl = &rk3288_win_full_scl, +- .data_formats = formats_win_full_10, +- .nformats = ARRAY_SIZE(formats_win_full_10), ++ .data_formats = formats_win_full, ++ .nformats = ARRAY_SIZE(formats_win_full), + .format_modifiers = format_modifiers_win_full, + .enable = VOP_REG(RK3368_WIN0_CTRL0, 0x1, 0), + .format = VOP_REG(RK3368_WIN0_CTRL0, 0x7, 1), + +From 74b287a1526a234bd9450461087f7b3ae53ead5f Mon Sep 17 00:00:00 2001 +From: Alex Bee +Date: Sat, 15 Aug 2020 23:20:34 +0200 +Subject: [PATCH] drm/rockchip: enable ycbcr_420_allowed and ycbcr_444_allowed + for RK3228 + +--- + drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +index 1abc46a023a4..64a79b33ff18 100644 +--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c ++++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +@@ -555,6 +555,7 @@ static const struct dw_hdmi_phy_ops rk3228_hdmi_phy_ops = { + + static struct rockchip_hdmi_chip_data rk3228_chip_data = { + .lcdsel_grf_reg = -1, ++ .ycbcr_444_allowed = true, + }; + + static const struct dw_hdmi_plat_data rk3228_hdmi_drv_data = { +@@ -563,6 +564,7 @@ static const struct dw_hdmi_plat_data rk3228_hdmi_drv_data = { + .phy_ops = &rk3228_hdmi_phy_ops, + .phy_name = "inno_dw_hdmi_phy2", + .phy_force_vendor = true, ++ .ycbcr_420_allowed = true, + }; + + static struct rockchip_hdmi_chip_data rk3288_chip_data = { + +From 93f930ae209a684210098a2612df72b19b8db88a Mon Sep 17 00:00:00 2001 +From: Alex Bee +Date: Wed, 22 Jul 2020 20:13:28 +0200 +Subject: [PATCH] drm: rockchip: add scaling for RK3036 win1 + +Add the registers needed to make scaling work on RK3036's win1. + +Signed-off-by: Alex Bee +--- + drivers/gpu/drm/rockchip/rockchip_vop_reg.c | 10 ++++++++-- + 1 file changed, 8 insertions(+), 2 deletions(-) + +diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c +index 20c3e6248ec7..93a00b6ac295 100644 +--- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c ++++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c +@@ -94,15 +94,20 @@ static const uint64_t format_modifiers_win_lite[] = { + DRM_FORMAT_MOD_INVALID, + }; + +-static const struct vop_scl_regs rk3036_win_scl = { ++static const struct vop_scl_regs rk3036_win0_scl = { + .scale_yrgb_x = VOP_REG(RK3036_WIN0_SCL_FACTOR_YRGB, 0xffff, 0x0), + .scale_yrgb_y = VOP_REG(RK3036_WIN0_SCL_FACTOR_YRGB, 0xffff, 16), + .scale_cbcr_x = VOP_REG(RK3036_WIN0_SCL_FACTOR_CBR, 0xffff, 0x0), + .scale_cbcr_y = VOP_REG(RK3036_WIN0_SCL_FACTOR_CBR, 0xffff, 16), + }; + ++static const struct vop_scl_regs rk3036_win1_scl = { ++ .scale_yrgb_x = VOP_REG(RK3036_WIN1_SCL_FACTOR_YRGB, 0xffff, 0x0), ++ .scale_yrgb_y = VOP_REG(RK3036_WIN1_SCL_FACTOR_YRGB, 0xffff, 16), ++}; ++ + static const struct vop_win_phy rk3036_win0_data = { +- .scl = &rk3036_win_scl, ++ .scl = &rk3036_win0_scl, + .data_formats = formats_win_full, + .nformats = ARRAY_SIZE(formats_win_full), + .format_modifiers = format_modifiers_win_full, +@@ -119,6 +124,7 @@ static const struct vop_win_phy rk3036_win0_data = { + }; + + static const struct vop_win_phy rk3036_win1_data = { ++ .scl = &rk3036_win1_scl, + .data_formats = formats_win_lite, + .nformats = ARRAY_SIZE(formats_win_lite), + .format_modifiers = format_modifiers_win_lite, + +From 5251b3cefd51bbf0c28da354b8e59e4f540d4b94 Mon Sep 17 00:00:00 2001 +From: Alex Bee +Date: Wed, 22 Jul 2020 20:13:29 +0200 +Subject: [PATCH] drm: rockchip: add missing registers for RK3188 + +Add dither_up, dsp_lut_en and data_blank registers to enable their +respective functionality for RK3188's VOP. + +Signed-off-by: Alex Bee +--- + drivers/gpu/drm/rockchip/rockchip_vop_reg.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c +index 93a00b6ac295..2638d084f9ce 100644 +--- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c ++++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c +@@ -529,6 +529,9 @@ static const struct vop_common rk3188_common = { + .dither_down_en = VOP_REG(RK3188_DSP_CTRL0, 0x1, 11), + .dither_down_mode = VOP_REG(RK3188_DSP_CTRL0, 0x1, 10), + .dsp_blank = VOP_REG(RK3188_DSP_CTRL1, 0x3, 24), ++ .dither_up = VOP_REG(RK3188_DSP_CTRL0, 0x1, 9), ++ .dsp_lut_en = VOP_REG(RK3188_SYS_CTRL, 0x1, 28), ++ .data_blank = VOP_REG(RK3188_DSP_CTRL1, 0x1, 25), + }; + + static const struct vop_win_data rk3188_vop_win_data[] = { + +From cb6d552767e2ce4b79be85cdb3a1526869d11ce4 Mon Sep 17 00:00:00 2001 +From: Alex Bee +Date: Wed, 22 Jul 2020 20:13:30 +0200 +Subject: [PATCH] drm: rockchip: add alpha support for RK3036, RK3066, RK3126 + and RK3188 + +With commit 2aae8ed1f390 +("drm/rockchip: Add per-pixel alpha support for the PX30 VOP") alpha +support was introduced for PX30's VOP. +RK3036, RK3066, RK3126 and RK3188 VOPs support alpha blending in the +same manner. +With the exception of RK3066 all of them support pre-multiplied alpha. + +Lets add these registers to make this work for those VOPs as well. + +Signed-off-by: Alex Bee +--- + drivers/gpu/drm/rockchip/rockchip_vop_reg.c | 21 +++++++++++++++++++++ + drivers/gpu/drm/rockchip/rockchip_vop_reg.h | 1 + + 2 files changed, 22 insertions(+) + +diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c +index 2638d084f9ce..e1db4e57c51a 100644 +--- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c ++++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c +@@ -121,6 +121,9 @@ static const struct vop_win_phy rk3036_win0_data = { + .uv_mst = VOP_REG(RK3036_WIN0_CBR_MST, 0xffffffff, 0), + .yrgb_vir = VOP_REG(RK3036_WIN0_VIR, 0xffff, 0), + .uv_vir = VOP_REG(RK3036_WIN0_VIR, 0x1fff, 16), ++ .alpha_mode = VOP_REG(RK3036_DSP_CTRL0, 0x1, 18), ++ .alpha_en = VOP_REG(RK3036_ALPHA_CTRL, 0x1, 0), ++ .alpha_pre_mul = VOP_REG(RK3036_DSP_CTRL0, 0x1, 29), + }; + + static const struct vop_win_phy rk3036_win1_data = { +@@ -136,6 +139,9 @@ static const struct vop_win_phy rk3036_win1_data = { + .dsp_st = VOP_REG(RK3036_WIN1_DSP_ST, 0x1fff1fff, 0), + .yrgb_mst = VOP_REG(RK3036_WIN1_MST, 0xffffffff, 0), + .yrgb_vir = VOP_REG(RK3036_WIN1_VIR, 0xffff, 0), ++ .alpha_mode = VOP_REG(RK3036_DSP_CTRL0, 0x1, 19), ++ .alpha_en = VOP_REG(RK3036_ALPHA_CTRL, 0x1, 1), ++ .alpha_pre_mul = VOP_REG(RK3036_DSP_CTRL0, 0x1, 29), + }; + + static const struct vop_win_data rk3036_vop_win_data[] = { +@@ -202,6 +208,9 @@ static const struct vop_win_phy rk3126_win1_data = { + .dsp_st = VOP_REG(RK3126_WIN1_DSP_ST, 0x1fff1fff, 0), + .yrgb_mst = VOP_REG(RK3126_WIN1_MST, 0xffffffff, 0), + .yrgb_vir = VOP_REG(RK3036_WIN1_VIR, 0xffff, 0), ++ .alpha_mode = VOP_REG(RK3036_DSP_CTRL0, 0x1, 19), ++ .alpha_en = VOP_REG(RK3036_ALPHA_CTRL, 0x1, 1), ++ .alpha_pre_mul = VOP_REG(RK3036_DSP_CTRL0, 0x1, 29), + }; + + static const struct vop_win_data rk3126_vop_win_data[] = { +@@ -381,6 +390,8 @@ static const struct vop_win_phy rk3066_win0_data = { + .uv_mst = VOP_REG(RK3066_WIN0_CBR_MST0, 0xffffffff, 0), + .yrgb_vir = VOP_REG(RK3066_WIN0_VIR, 0xffff, 0), + .uv_vir = VOP_REG(RK3066_WIN0_VIR, 0x1fff, 16), ++ .alpha_mode = VOP_REG(RK3066_DSP_CTRL0, 0x1, 21), ++ .alpha_en = VOP_REG(RK3066_BLEND_CTRL, 0x1, 0), + }; + + static const struct vop_win_phy rk3066_win1_data = { +@@ -398,6 +409,8 @@ static const struct vop_win_phy rk3066_win1_data = { + .uv_mst = VOP_REG(RK3066_WIN1_CBR_MST, 0xffffffff, 0), + .yrgb_vir = VOP_REG(RK3066_WIN1_VIR, 0xffff, 0), + .uv_vir = VOP_REG(RK3066_WIN1_VIR, 0x1fff, 16), ++ .alpha_mode = VOP_REG(RK3066_DSP_CTRL0, 0x1, 22), ++ .alpha_en = VOP_REG(RK3066_BLEND_CTRL, 0x1, 1), + }; + + static const struct vop_win_phy rk3066_win2_data = { +@@ -411,6 +424,8 @@ static const struct vop_win_phy rk3066_win2_data = { + .dsp_st = VOP_REG(RK3066_WIN2_DSP_ST, 0x1fff1fff, 0), + .yrgb_mst = VOP_REG(RK3066_WIN2_MST, 0xffffffff, 0), + .yrgb_vir = VOP_REG(RK3066_WIN2_VIR, 0xffff, 0), ++ .alpha_mode = VOP_REG(RK3066_DSP_CTRL0, 0x1, 23), ++ .alpha_en = VOP_REG(RK3066_BLEND_CTRL, 0x1, 2), + }; + + static const struct vop_modeset rk3066_modeset = { +@@ -493,6 +508,9 @@ static const struct vop_win_phy rk3188_win0_data = { + .yrgb_mst = VOP_REG(RK3188_WIN0_YRGB_MST0, 0xffffffff, 0), + .uv_mst = VOP_REG(RK3188_WIN0_CBR_MST0, 0xffffffff, 0), + .yrgb_vir = VOP_REG(RK3188_WIN_VIR, 0x1fff, 0), ++ .alpha_mode = VOP_REG(RK3188_DSP_CTRL0, 0x1, 18), ++ .alpha_en = VOP_REG(RK3188_ALPHA_CTRL, 0x1, 0), ++ .alpha_pre_mul = VOP_REG(RK3188_DSP_CTRL0, 0x1, 29), + }; + + static const struct vop_win_phy rk3188_win1_data = { +@@ -507,6 +525,9 @@ static const struct vop_win_phy rk3188_win1_data = { + .dsp_st = VOP_REG(RK3188_WIN1_DSP_ST, 0x0fff0fff, 0), + .yrgb_mst = VOP_REG(RK3188_WIN1_MST, 0xffffffff, 0), + .yrgb_vir = VOP_REG(RK3188_WIN_VIR, 0x1fff, 16), ++ .alpha_mode = VOP_REG(RK3188_DSP_CTRL0, 0x1, 19), ++ .alpha_en = VOP_REG(RK3188_ALPHA_CTRL, 0x1, 1), ++ .alpha_pre_mul = VOP_REG(RK3188_DSP_CTRL0, 0x1, 29), + }; + + static const struct vop_modeset rk3188_modeset = { +diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.h b/drivers/gpu/drm/rockchip/rockchip_vop_reg.h +index 6e9fa5815d4d..0b3cd65ba5c1 100644 +--- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.h ++++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.h +@@ -955,6 +955,7 @@ + #define RK3188_DSP_CTRL0 0x04 + #define RK3188_DSP_CTRL1 0x08 + #define RK3188_INT_STATUS 0x10 ++#define RK3188_ALPHA_CTRL 0x14 + #define RK3188_WIN0_YRGB_MST0 0x20 + #define RK3188_WIN0_CBR_MST0 0x24 + #define RK3188_WIN0_YRGB_MST1 0x28 + +From 931fd5e26f3b2dd7a758124dc9c024e944eeedb4 Mon Sep 17 00:00:00 2001 +From: Alex Bee +Date: Wed, 22 Jul 2020 20:13:31 +0200 +Subject: [PATCH] drm: rockchip: set alpha_en to 0 if it is not used + +alpha_en should be set to 0 if it is not used, i.e. to disable alpha +blending if it was enabled before and should be disabled now. + +Fixes: 2aae8ed1f390 ("drm/rockchip: Add per-pixel alpha support for the PX30 VOP") + +Signed-off-by: Alex Bee +--- + drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +index 413534cf1a93..9b1cc0f413fc 100644 +--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c ++++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +@@ -1062,6 +1062,7 @@ static void vop_plane_atomic_update(struct drm_plane *plane, + VOP_WIN_SET(vop, win, alpha_en, 1); + } else { + VOP_WIN_SET(vop, win, src_alpha_ctl, SRC_ALPHA_EN(0)); ++ VOP_WIN_SET(vop, win, alpha_en, 0); + } + + VOP_WIN_SET(vop, win, enable, 1); + +From 87f111b8511eb1236c53ea4369502cf4c6847303 Mon Sep 17 00:00:00 2001 +From: Alex Bee +Date: Sat, 15 Aug 2020 23:38:05 +0200 +Subject: [PATCH] rockchip/drm: add dsp_data_swap register for RK3188 + +--- + drivers/gpu/drm/rockchip/rockchip_vop_reg.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c +index e1db4e57c51a..e10cb2d33951 100644 +--- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c ++++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c +@@ -553,6 +553,7 @@ static const struct vop_common rk3188_common = { + .dither_up = VOP_REG(RK3188_DSP_CTRL0, 0x1, 9), + .dsp_lut_en = VOP_REG(RK3188_SYS_CTRL, 0x1, 28), + .data_blank = VOP_REG(RK3188_DSP_CTRL1, 0x1, 25), ++ .dsp_data_swap = VOP_REG(RK3188_DSP_CTRL1, 0x1f, 26), + }; + + static const struct vop_win_data rk3188_vop_win_data[] = { + +From 75e43e951351c5f0d269d7b788a9469a1ccadb48 Mon Sep 17 00:00:00 2001 +From: Alex Bee +Date: Sun, 16 Aug 2020 00:55:19 +0200 +Subject: [PATCH] drm/rockchip: inno hdmi - add audio support - add required + aclk - fix video timing - fix phy pre-emphasis + +--- + .../display/rockchip/inno_hdmi-rockchip.txt | 6 +- + arch/arm/boot/dts/rk3036.dtsi | 24 +- + drivers/gpu/drm/rockchip/inno_hdmi.c | 266 +++++++++++++++++- + drivers/gpu/drm/rockchip/inno_hdmi.h | 2 + + 4 files changed, 279 insertions(+), 19 deletions(-) + +diff --git a/Documentation/devicetree/bindings/display/rockchip/inno_hdmi-rockchip.txt b/Documentation/devicetree/bindings/display/rockchip/inno_hdmi-rockchip.txt +index cec21714f0e0..b022c931e186 100644 +--- a/Documentation/devicetree/bindings/display/rockchip/inno_hdmi-rockchip.txt ++++ b/Documentation/devicetree/bindings/display/rockchip/inno_hdmi-rockchip.txt +@@ -7,7 +7,7 @@ Required properties: + - reg: + Physical base address and length of the controller's registers. + - clocks, clock-names: +- Phandle to hdmi controller clock, name should be "pclk" ++ Phandle to hdmi controller clock, name should be "aclk" and "pclk". + - interrupts: + HDMI interrupt number + - ports: +@@ -21,8 +21,8 @@ hdmi: hdmi@20034000 { + compatible = "rockchip,rk3036-inno-hdmi"; + reg = <0x20034000 0x4000>; + interrupts = ; +- clocks = <&cru PCLK_HDMI>; +- clock-names = "pclk"; ++ clocks = <&cru ACLK_VIO>, <&cru PCLK_HDMI>; ++ clock-names = "aclk", "pclk"; + pinctrl-names = "default"; + pinctrl-0 = <&hdmi_ctl>; + +diff --git a/arch/arm/boot/dts/rk3036.dtsi b/arch/arm/boot/dts/rk3036.dtsi +index dda5a1f79aca..6be6d9d134fe 100644 +--- a/arch/arm/boot/dts/rk3036.dtsi ++++ b/arch/arm/boot/dts/rk3036.dtsi +@@ -344,11 +344,14 @@ hdmi: hdmi@20034000 { + compatible = "rockchip,rk3036-inno-hdmi"; + reg = <0x20034000 0x4000>; + interrupts = ; +- clocks = <&cru PCLK_HDMI>; +- clock-names = "pclk"; ++ clocks = <&cru ACLK_VIO>, <&cru PCLK_HDMI>; ++ clock-names = "aclk", "pclk"; + rockchip,grf = <&grf>; + pinctrl-names = "default"; + pinctrl-0 = <&hdmi_ctl>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ #sound-dai-cells = <0>; + status = "disabled"; + + hdmi_in: port { +@@ -361,6 +364,23 @@ hdmi_in_vop: endpoint@0 { + }; + }; + ++ hdmi_sound: hdmi-sound { ++ compatible = "simple-audio-card"; ++ simple-audio-card,name = "HDMI"; ++ status = "disabled"; ++ ++ simple-audio-card,dai-link { ++ format = "i2s"; ++ mclk-fs = <256>; ++ cpu { ++ sound-dai = <&i2s>; ++ }; ++ codec { ++ sound-dai = <&hdmi>; ++ }; ++ }; ++ }; ++ + timer: timer@20044000 { + compatible = "rockchip,rk3036-timer", "rockchip,rk3288-timer"; + reg = <0x20044000 0x20>; +diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c b/drivers/gpu/drm/rockchip/inno_hdmi.c +index 7afdc54eb3ec..7e93208609a0 100644 +--- a/drivers/gpu/drm/rockchip/inno_hdmi.c ++++ b/drivers/gpu/drm/rockchip/inno_hdmi.c +@@ -14,6 +14,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -21,6 +22,8 @@ + #include + #include + ++#include ++ + #include "rockchip_drm_drv.h" + #include "rockchip_drm_vop.h" + +@@ -28,6 +31,12 @@ + + #define to_inno_hdmi(x) container_of(x, struct inno_hdmi, x) + ++struct audio_info { ++ int sample_rate; ++ int channels; ++ int sample_width; ++}; ++ + struct hdmi_data_info { + int vic; + bool sink_is_hdmi; +@@ -52,8 +61,10 @@ struct inno_hdmi { + struct drm_device *drm_dev; + + int irq; ++ struct clk *aclk; + struct clk *pclk; + void __iomem *regs; ++ struct regmap *regmap; + + struct drm_connector connector; + struct drm_encoder encoder; +@@ -63,6 +74,9 @@ struct inno_hdmi { + + unsigned int tmds_rate; + ++ struct platform_device *audio_pdev; ++ bool audio_enable; ++ + struct hdmi_data_info hdmi_data; + struct drm_display_mode previous_mode; + }; +@@ -189,11 +203,17 @@ static void inno_hdmi_sys_power(struct inno_hdmi *hdmi, bool enable) + + static void inno_hdmi_set_pwr_mode(struct inno_hdmi *hdmi, int mode) + { ++ ++ u8 value; ++ + switch (mode) { + case NORMAL: + inno_hdmi_sys_power(hdmi, false); +- +- hdmi_writeb(hdmi, HDMI_PHY_PRE_EMPHASIS, 0x6f); ++ if (hdmi->tmds_rate > 140000000) ++ value = 0x6f; ++ else ++ value = 0x3f; ++ hdmi_writeb(hdmi, HDMI_PHY_PRE_EMPHASIS, value); + hdmi_writeb(hdmi, HDMI_PHY_DRIVER, 0xbb); + + hdmi_writeb(hdmi, HDMI_PHY_SYS_CTL, 0x15); +@@ -301,6 +321,21 @@ static int inno_hdmi_config_video_avi(struct inno_hdmi *hdmi, + return inno_hdmi_upload_frame(hdmi, rc, &frame, INFOFRAME_AVI, 0, 0, 0); + } + ++static int inno_hdmi_config_audio_aai(struct inno_hdmi *hdmi, ++ struct audio_info *audio) ++{ ++ struct hdmi_audio_infoframe *faudio; ++ union hdmi_infoframe frame; ++ int rc; ++ ++ rc = hdmi_audio_infoframe_init(&frame.audio); ++ faudio = (struct hdmi_audio_infoframe *)&frame; ++ ++ faudio->channels = audio->channels; ++ ++ return inno_hdmi_upload_frame(hdmi, rc, &frame, INFOFRAME_AAI, 0, 0, 0); ++} ++ + static int inno_hdmi_config_video_csc(struct inno_hdmi *hdmi) + { + struct hdmi_data_info *data = &hdmi->hdmi_data; +@@ -383,6 +418,11 @@ static int inno_hdmi_config_video_timing(struct inno_hdmi *hdmi, + { + int value; + ++ value = BIT(20) | BIT(21); ++ value |= mode->flags & DRM_MODE_FLAG_PHSYNC ? BIT(4) : 0; ++ value |= mode->flags & DRM_MODE_FLAG_PVSYNC ? BIT(5) : 0; ++ regmap_write(hdmi->regmap, 0x148, value); ++ + /* Set detail external video timing polarity and interlace mode */ + value = v_EXTERANL_VIDEO(1); + value |= mode->flags & DRM_MODE_FLAG_PHSYNC ? +@@ -402,7 +442,7 @@ static int inno_hdmi_config_video_timing(struct inno_hdmi *hdmi, + hdmi_writeb(hdmi, HDMI_VIDEO_EXT_HBLANK_L, value & 0xFF); + hdmi_writeb(hdmi, HDMI_VIDEO_EXT_HBLANK_H, (value >> 8) & 0xFF); + +- value = mode->hsync_start - mode->hdisplay; ++ value = mode->htotal - mode->hsync_start; + hdmi_writeb(hdmi, HDMI_VIDEO_EXT_HDELAY_L, value & 0xFF); + hdmi_writeb(hdmi, HDMI_VIDEO_EXT_HDELAY_H, (value >> 8) & 0xFF); + +@@ -417,7 +457,7 @@ static int inno_hdmi_config_video_timing(struct inno_hdmi *hdmi, + value = mode->vtotal - mode->vdisplay; + hdmi_writeb(hdmi, HDMI_VIDEO_EXT_VBLANK, value & 0xFF); + +- value = mode->vsync_start - mode->vdisplay; ++ value = mode->vtotal - mode->vsync_start; + hdmi_writeb(hdmi, HDMI_VIDEO_EXT_VDELAY, value & 0xFF); + + value = mode->vsync_end - mode->vsync_start; +@@ -473,8 +513,9 @@ static int inno_hdmi_setup(struct inno_hdmi *hdmi, + inno_hdmi_i2c_init(hdmi); + + /* Unmute video and audio output */ +- hdmi_modb(hdmi, HDMI_AV_MUTE, m_AUDIO_MUTE | m_VIDEO_BLACK, +- v_AUDIO_MUTE(0) | v_VIDEO_MUTE(0)); ++ hdmi_modb(hdmi, HDMI_AV_MUTE, m_VIDEO_BLACK, v_VIDEO_MUTE(0)); ++ if (hdmi->audio_enable) ++ hdmi_modb(hdmi, HDMI_AV_MUTE, m_AUDIO_MUTE, v_AUDIO_MUTE(0)); + + return 0; + } +@@ -521,6 +562,7 @@ inno_hdmi_encoder_atomic_check(struct drm_encoder *encoder, + + s->output_mode = ROCKCHIP_OUT_MODE_P888; + s->output_type = DRM_MODE_CONNECTOR_HDMIA; ++ s->bus_format = MEDIA_BUS_FMT_RGB888_1X24; + + return 0; + } +@@ -597,6 +639,175 @@ static struct drm_connector_helper_funcs inno_hdmi_connector_helper_funcs = { + .mode_valid = inno_hdmi_connector_mode_valid, + }; + ++int inno_hdmi_audio_config_set(struct inno_hdmi *hdmi, struct audio_info *audio) ++{ ++ int rate, N, channel; ++ ++ if (audio->channels < 3) ++ channel = I2S_CHANNEL_1_2; ++ else if (audio->channels < 5) ++ channel = I2S_CHANNEL_3_4; ++ else if (audio->channels < 7) ++ channel = I2S_CHANNEL_5_6; ++ else ++ channel = I2S_CHANNEL_7_8; ++ ++ switch (audio->sample_rate) { ++ case 32000: ++ rate = AUDIO_32K; ++ N = N_32K; ++ break; ++ case 44100: ++ rate = AUDIO_441K; ++ N = N_441K; ++ break; ++ case 48000: ++ rate = AUDIO_48K; ++ N = N_48K; ++ break; ++ case 88200: ++ rate = AUDIO_882K; ++ N = N_882K; ++ break; ++ case 96000: ++ rate = AUDIO_96K; ++ N = N_96K; ++ break; ++ case 176400: ++ rate = AUDIO_1764K; ++ N = N_1764K; ++ break; ++ case 192000: ++ rate = AUDIO_192K; ++ N = N_192K; ++ break; ++ default: ++ dev_err(hdmi->dev, "[%s] not support such sample rate %d\n", ++ __func__, audio->sample_rate); ++ return -ENOENT; ++ } ++ ++ /* set_audio source I2S */ ++ hdmi_writeb(hdmi, HDMI_AUDIO_CTRL1, 0x01); ++ hdmi_writeb(hdmi, AUDIO_SAMPLE_RATE, rate); ++ hdmi_writeb(hdmi, AUDIO_I2S_MODE, v_I2S_MODE(I2S_STANDARD) | ++ v_I2S_CHANNEL(channel)); ++ ++ hdmi_writeb(hdmi, AUDIO_I2S_MAP, 0x00); ++ hdmi_writeb(hdmi, AUDIO_I2S_SWAPS_SPDIF, 0); ++ ++ /* Set N value */ ++ hdmi_writeb(hdmi, AUDIO_N_H, (N >> 16) & 0x0F); ++ hdmi_writeb(hdmi, AUDIO_N_M, (N >> 8) & 0xFF); ++ hdmi_writeb(hdmi, AUDIO_N_L, N & 0xFF); ++ ++ /*Set hdmi nlpcm mode to support hdmi bitstream*/ ++ hdmi_writeb(hdmi, HDMI_AUDIO_CHANNEL_STATUS, v_AUDIO_STATUS_NLPCM(0)); ++ ++ return inno_hdmi_config_audio_aai(hdmi, audio); ++} ++ ++static int inno_hdmi_audio_hw_params(struct device *dev, void *data, ++ struct hdmi_codec_daifmt *daifmt, ++ struct hdmi_codec_params *params) ++{ ++ struct inno_hdmi *hdmi = dev_get_drvdata(dev); ++ struct audio_info audio = { ++ .sample_width = params->sample_width, ++ .sample_rate = params->sample_rate, ++ .channels = params->channels, ++ }; ++ ++ if (!hdmi->hdmi_data.sink_has_audio) { ++ dev_err(hdmi->dev, "Sink do not support audio!\n"); ++ return -ENODEV; ++ } ++ ++ if (!hdmi->encoder.crtc) ++ return -ENODEV; ++ ++ switch (daifmt->fmt) { ++ case HDMI_I2S: ++ break; ++ default: ++ dev_err(dev, "%s: Invalid format %d\n", __func__, daifmt->fmt); ++ return -EINVAL; ++ } ++ ++ return inno_hdmi_audio_config_set(hdmi, &audio); ++} ++ ++static void inno_hdmi_audio_shutdown(struct device *dev, void *data) ++{ ++ /* do nothing */ ++} ++ ++static int inno_hdmi_audio_digital_mute(struct device *dev, void *data, bool mute) ++{ ++ struct inno_hdmi *hdmi = dev_get_drvdata(dev); ++ ++ if (!hdmi->hdmi_data.sink_has_audio) { ++ dev_err(hdmi->dev, "Sink do not support audio!\n"); ++ return -ENODEV; ++ } ++ ++ hdmi->audio_enable = !mute; ++ ++ if (mute) ++ hdmi_modb(hdmi, HDMI_AV_MUTE, m_AUDIO_MUTE | m_AUDIO_PD, ++ v_AUDIO_MUTE(1) | v_AUDIO_PD(1)); ++ else ++ hdmi_modb(hdmi, HDMI_AV_MUTE, m_AUDIO_MUTE | m_AUDIO_PD, ++ v_AUDIO_MUTE(0) | v_AUDIO_PD(0)); ++ ++ return 0; ++} ++ ++static int inno_hdmi_audio_get_eld(struct device *dev, void *data, ++ uint8_t *buf, size_t len) ++{ ++ struct inno_hdmi *hdmi = dev_get_drvdata(dev); ++ struct drm_mode_config *config = &hdmi->encoder.dev->mode_config; ++ struct drm_connector *connector; ++ int ret = -ENODEV; ++ ++ mutex_lock(&config->mutex); ++ list_for_each_entry(connector, &config->connector_list, head) { ++ if (&hdmi->encoder == connector->encoder) { ++ memcpy(buf, connector->eld, ++ min(sizeof(connector->eld), len)); ++ ret = 0; ++ } ++ } ++ mutex_unlock(&config->mutex); ++ ++ return ret; ++} ++ ++static const struct hdmi_codec_ops audio_codec_ops = { ++ .hw_params = inno_hdmi_audio_hw_params, ++ .audio_shutdown = inno_hdmi_audio_shutdown, ++ .digital_mute = inno_hdmi_audio_digital_mute, ++ .get_eld = inno_hdmi_audio_get_eld, ++}; ++ ++static int inno_hdmi_audio_codec_init(struct inno_hdmi *hdmi, ++ struct device *dev) ++{ ++ struct hdmi_codec_pdata codec_data = { ++ .i2s = 1, ++ .ops = &audio_codec_ops, ++ .max_i2s_channels = 8, ++ }; ++ ++ hdmi->audio_enable = false; ++ hdmi->audio_pdev = platform_device_register_data( ++ dev, HDMI_CODEC_DRV_NAME, PLATFORM_DEVID_NONE, ++ &codec_data, sizeof(codec_data)); ++ ++ return PTR_ERR_OR_ZERO(hdmi->audio_pdev); ++} ++ + static int inno_hdmi_register(struct drm_device *drm, struct inno_hdmi *hdmi) + { + struct drm_encoder *encoder = &hdmi->encoder; +@@ -627,6 +838,8 @@ static int inno_hdmi_register(struct drm_device *drm, struct inno_hdmi *hdmi) + + drm_connector_attach_encoder(&hdmi->connector, encoder); + ++ inno_hdmi_audio_codec_init(hdmi, dev); ++ + return 0; + } + +@@ -826,23 +1039,44 @@ static int inno_hdmi_bind(struct device *dev, struct device *master, + if (IS_ERR(hdmi->regs)) + return PTR_ERR(hdmi->regs); + ++ irq = platform_get_irq(pdev, 0); ++ if (irq < 0) ++ return irq; ++ ++ hdmi->aclk = devm_clk_get(hdmi->dev, "aclk"); ++ if (IS_ERR(hdmi->aclk)) { ++ dev_err(hdmi->dev, "Unable to get HDMI aclk clk\n"); ++ return PTR_ERR(hdmi->aclk); ++ } ++ + hdmi->pclk = devm_clk_get(hdmi->dev, "pclk"); + if (IS_ERR(hdmi->pclk)) { + DRM_DEV_ERROR(hdmi->dev, "Unable to get HDMI pclk clk\n"); + return PTR_ERR(hdmi->pclk); + } + ++ ret = clk_prepare_enable(hdmi->aclk); ++ if (ret) { ++ DRM_DEV_ERROR(hdmi->dev, ++ "Cannot enable HDMI aclk clock: %d\n", ret); ++ return ret; ++ } ++ ++ + ret = clk_prepare_enable(hdmi->pclk); + if (ret) { + DRM_DEV_ERROR(hdmi->dev, + "Cannot enable HDMI pclk clock: %d\n", ret); +- return ret; ++ goto err_disable_aclk; + } + +- irq = platform_get_irq(pdev, 0); +- if (irq < 0) { +- ret = irq; +- goto err_disable_clk; ++ hdmi->regmap = ++ syscon_regmap_lookup_by_phandle(hdmi->dev->of_node, ++ "rockchip,grf"); ++ if (IS_ERR(hdmi->regmap)) { ++ dev_err(hdmi->dev, "Unable to get rockchip,grf\n"); ++ ret = PTR_ERR(hdmi->regmap); ++ goto err_disable_aclk; + } + + inno_hdmi_reset(hdmi); +@@ -851,7 +1085,7 @@ static int inno_hdmi_bind(struct device *dev, struct device *master, + if (IS_ERR(hdmi->ddc)) { + ret = PTR_ERR(hdmi->ddc); + hdmi->ddc = NULL; +- goto err_disable_clk; ++ goto err_disable_pclk; + } + + /* +@@ -884,9 +1118,12 @@ static int inno_hdmi_bind(struct device *dev, struct device *master, + hdmi->encoder.funcs->destroy(&hdmi->encoder); + err_put_adapter: + i2c_put_adapter(hdmi->ddc); +-err_disable_clk: ++err_disable_pclk: + clk_disable_unprepare(hdmi->pclk); +- return ret; ++err_disable_aclk: ++ clk_disable_unprepare(hdmi->aclk); ++ ++return ret; + } + + static void inno_hdmi_unbind(struct device *dev, struct device *master, +@@ -899,6 +1136,7 @@ static void inno_hdmi_unbind(struct device *dev, struct device *master, + + i2c_put_adapter(hdmi->ddc); + clk_disable_unprepare(hdmi->pclk); ++ clk_disable_unprepare(hdmi->aclk); + } + + static const struct component_ops inno_hdmi_ops = { +diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.h b/drivers/gpu/drm/rockchip/inno_hdmi.h +index 93245b55f967..b722afc4e41f 100644 +--- a/drivers/gpu/drm/rockchip/inno_hdmi.h ++++ b/drivers/gpu/drm/rockchip/inno_hdmi.h +@@ -96,11 +96,13 @@ enum { + #define HDMI_AV_MUTE 0x05 + #define m_AVMUTE_CLEAR (1 << 7) + #define m_AVMUTE_ENABLE (1 << 6) ++#define m_AUDIO_PD (1 << 2) + #define m_AUDIO_MUTE (1 << 1) + #define m_VIDEO_BLACK (1 << 0) + #define v_AVMUTE_CLEAR(n) (n << 7) + #define v_AVMUTE_ENABLE(n) (n << 6) + #define v_AUDIO_MUTE(n) (n << 1) ++#define v_AUDIO_PD(n) (n << 2) + #define v_VIDEO_MUTE(n) (n << 0) + + #define HDMI_VIDEO_TIMING_CTL 0x08 + +From fd3c78e6eec709b6a70af8a175c6965d0112f372 Mon Sep 17 00:00:00 2001 +From: Phong LE +Date: Wed, 11 Mar 2020 13:51:33 +0100 +Subject: [PATCH] dt-bindings: display: bridge: add it66121 bindings + +Add the ITE bridge HDMI it66121 bindings. + +Signed-off-by: Phong LE +--- + .../bindings/display/bridge/ite,it66121.yaml | 98 +++++++++++++++++++ + 1 file changed, 98 insertions(+) + create mode 100644 Documentation/devicetree/bindings/display/bridge/ite,it66121.yaml + +diff --git a/Documentation/devicetree/bindings/display/bridge/ite,it66121.yaml b/Documentation/devicetree/bindings/display/bridge/ite,it66121.yaml +new file mode 100644 +index 000000000000..1717e880d130 +--- /dev/null ++++ b/Documentation/devicetree/bindings/display/bridge/ite,it66121.yaml +@@ -0,0 +1,98 @@ ++# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/display/bridge/ite,it66121.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: ITE it66121 HDMI bridge Device Tree Bindings ++ ++maintainers: ++ - Phong LE ++ - Neil Armstrong ++ ++description: | ++ The IT66121 is a high-performance and low-power single channel HDMI ++ transmitter, fully compliant with HDMI 1.3a, HDCP 1.2 and backward compatible ++ to DVI 1.0 specifications. ++ ++properties: ++ compatible: ++ const: ite,it66121 ++ ++ reg: ++ maxItems: 1 ++ description: base I2C address of the device ++ ++ reset-gpios: ++ maxItems: 1 ++ description: GPIO connected to active low reset ++ ++ vrf12-supply: ++ maxItems: 1 ++ description: Regulator for 1.2V analog core power. ++ ++ vcn33-supply: ++ maxItems: 1 ++ description: Regulator for 3.3V digital core power. ++ ++ vcn18-supply: ++ maxItems: 1 ++ description: Regulator for 1.8V IO core power. ++ ++ interrupts: ++ maxItems: 1 ++ ++ pclk-dual-edge: ++ maxItems: 1 ++ description: enable pclk dual edge mode. ++ ++ port: ++ type: object ++ ++ properties: ++ endpoint: ++ type: object ++ description: | ++ Input endpoints of the bridge. ++ ++ required: ++ - endpoint ++ ++required: ++ - compatible ++ - reg ++ - reset-gpios ++ - vrf12-supply ++ - vcn33-supply ++ - vcn18-supply ++ - interrupts ++ - port ++ ++additionalProperties: false ++ ++examples: ++ - | ++ i2c6 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ it66121hdmitx: it66121hdmitx@4c { ++ compatible = "ite,it66121"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&ite_pins_default>; ++ vcn33-supply = <&mt6358_vcn33_wifi_reg>; ++ vcn18-supply = <&mt6358_vcn18_reg>; ++ vrf12-supply = <&mt6358_vrf12_reg>; ++ reset-gpios = <&pio 160 1 /* GPIO_ACTIVE_LOW */>; ++ interrupt-parent = <&pio>; ++ interrupts = <4 8 /* IRQ_TYPE_LEVEL_LOW */>; ++ reg = <0x4c>; ++ pclk-dual-edge; ++ ++ port { ++ it66121_in: endpoint { ++ remote-endpoint = <&display_out>; ++ }; ++ }; ++ }; ++ }; + +From 28d8fb9319bee0252c3b756966298a065bfa16c5 Mon Sep 17 00:00:00 2001 +From: Phong LE +Date: Wed, 11 Mar 2020 13:51:34 +0100 +Subject: [PATCH] drm: bridge: add it66121 driver + +This commit is a simple driver for bridge HMDI it66121. +The input format is RBG and there is no color conversion. +Audio, HDCP and CEC are not supported yet. + +Signed-off-by: Phong LE +--- + drivers/gpu/drm/bridge/Kconfig | 8 + + drivers/gpu/drm/bridge/Makefile | 1 + + drivers/gpu/drm/bridge/ite-it66121.c | 997 +++++++++++++++++++++++++++ + 3 files changed, 1006 insertions(+) + create mode 100644 drivers/gpu/drm/bridge/ite-it66121.c + +diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig +index 43271c21d3fc..204246d65f44 100644 +--- a/drivers/gpu/drm/bridge/Kconfig ++++ b/drivers/gpu/drm/bridge/Kconfig +@@ -48,6 +48,14 @@ config DRM_DISPLAY_CONNECTOR + on ARM-based platforms. Saying Y here when this driver is not needed + will not cause any issue. + ++config DRM_ITE_IT66121 ++ tristate "ITE IT66121 HDMI bridge" ++ depends on OF ++ select DRM_KMS_HELPER ++ select REGMAP_I2C ++ help ++ Support for ITE IT66121 HDMI bridge. ++ + config DRM_LVDS_CODEC + tristate "Transparent LVDS encoders and decoders support" + depends on OF +diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile +index d63d4b7e4347..ffa91a5a6bda 100644 +--- a/drivers/gpu/drm/bridge/Makefile ++++ b/drivers/gpu/drm/bridge/Makefile +@@ -2,6 +2,7 @@ + obj-$(CONFIG_DRM_CDNS_DSI) += cdns-dsi.o + obj-$(CONFIG_DRM_CHRONTEL_CH7033) += chrontel-ch7033.o + obj-$(CONFIG_DRM_DISPLAY_CONNECTOR) += display-connector.o ++obj-$(CONFIG_DRM_ITE_IT66121) += ite-it66121.o + obj-$(CONFIG_DRM_LVDS_CODEC) += lvds-codec.o + obj-$(CONFIG_DRM_MEGACHIPS_STDPXXXX_GE_B850V3_FW) += megachips-stdpxxxx-ge-b850v3-fw.o + obj-$(CONFIG_DRM_NXP_PTN3460) += nxp-ptn3460.o +diff --git a/drivers/gpu/drm/bridge/ite-it66121.c b/drivers/gpu/drm/bridge/ite-it66121.c +new file mode 100644 +index 000000000000..7e1a90319a6a +--- /dev/null ++++ b/drivers/gpu/drm/bridge/ite-it66121.c +@@ -0,0 +1,997 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* ++ * Copyright (C) 2020 BayLibre, SAS ++ * Author: Phong LE ++ * Copyright (C) 2018-2019, Artem Mygaiev ++ * Copyright (C) 2017, Fresco Logic, Incorporated. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define IT66121_MASTER_SEL_REG 0x10 ++#define IT66121_MASTER_SEL_HOST BIT(0) ++ ++#define IT66121_AFE_DRV_REG 0x61 ++#define IT66121_AFE_DRV_RST BIT(4) ++#define IT66121_AFE_DRV_PWD BIT(5) ++ ++#define IT66121_INPUT_MODE_REG 0x70 ++#define IT66121_INPUT_MODE_RGB (0 << 6) ++#define IT66121_INPUT_MODE_YUV422 BIT(6) ++#define IT66121_INPUT_MODE_YUV444 (2 << 6) ++#define IT66121_INPUT_MODE_CCIR656 BIT(4) ++#define IT66121_INPUT_MODE_SYNCEMB BIT(3) ++#define IT66121_INPUT_MODE_DDR BIT(2) ++ ++#define IT66121_INPUT_CSC_REG 0x72 ++#define IT66121_INPUT_CSC_ENDITHER BIT(7) ++#define IT66121_INPUT_CSC_ENUDFILTER BIT(6) ++#define IT66121_INPUT_CSC_DNFREE_GO BIT(5) ++#define IT66121_INPUT_CSC_RGB_TO_YUV 0x02 ++#define IT66121_INPUT_CSC_YUV_TO_RGB 0x03 ++#define IT66121_INPUT_CSC_NO_CONV 0x00 ++ ++#define IT66121_AFE_XP_REG 0x62 ++#define IT66121_AFE_XP_GAINBIT BIT(7) ++#define IT66121_AFE_XP_PWDPLL BIT(6) ++#define IT66121_AFE_XP_ENI BIT(5) ++#define IT66121_AFE_XP_ENO BIT(4) ++#define IT66121_AFE_XP_RESETB BIT(3) ++#define IT66121_AFE_XP_PWDI BIT(2) ++ ++#define IT66121_AFE_IP_REG 0x64 ++#define IT66121_AFE_IP_GAINBIT BIT(7) ++#define IT66121_AFE_IP_PWDPLL BIT(6) ++#define IT66121_AFE_IP_CKSEL_05 (0 << 4) ++#define IT66121_AFE_IP_CKSEL_1 BIT(4) ++#define IT66121_AFE_IP_CKSEL_2 (2 << 4) ++#define IT66121_AFE_IP_CKSEL_2OR4 (3 << 4) ++#define IT66121_AFE_IP_ER0 BIT(3) ++#define IT66121_AFE_IP_RESETB BIT(2) ++#define IT66121_AFE_IP_ENC BIT(1) ++#define IT66121_AFE_IP_EC1 BIT(0) ++ ++#define IT66121_AFE_XP_EC1_REG 0x68 ++#define IT66121_AFE_XP_EC1_LOWCLK BIT(4) ++ ++#define IT66121_SW_RST_REG 0x04 ++#define IT66121_SW_RST_REF BIT(5) ++#define IT66121_SW_RST_AREF BIT(4) ++#define IT66121_SW_RST_VID BIT(3) ++#define IT66121_SW_RST_AUD BIT(2) ++#define IT66121_SW_RST_HDCP BIT(0) ++ ++#define IT66121_DDC_COMMAND_REG 0x15 ++#define IT66121_DDC_COMMAND_BURST_READ 0x0 ++#define IT66121_DDC_COMMAND_EDID_READ 0x3 ++#define IT66121_DDC_COMMAND_FIFO_CLR 0x9 ++#define IT66121_DDC_COMMAND_SCL_PULSE 0xA ++#define IT66121_DDC_COMMAND_ABORT 0xF ++ ++#define IT66121_HDCP_REG 0x20 ++#define IT66121_HDCP_CPDESIRED BIT(0) ++#define IT66121_HDCP_EN1P1FEAT BIT(1) ++ ++#define IT66121_INT_STATUS1_REG 0x06 ++#define IT66121_INT_STATUS1_AUD_OVF BIT(7) ++#define IT66121_INT_STATUS1_DDC_NOACK BIT(5) ++#define IT66121_INT_STATUS1_DDC_FIFOERR BIT(4) ++#define IT66121_INT_STATUS1_DDC_BUSHANG BIT(2) ++#define IT66121_INT_STATUS1_RX_SENS_STATUS BIT(1) ++#define IT66121_INT_STATUS1_HPD_STATUS BIT(0) ++ ++#define IT66121_DDC_HEADER_REG 0x11 ++#define IT66121_DDC_HEADER_HDCP 0x74 ++#define IT66121_DDC_HEADER_EDID 0xA0 ++ ++#define IT66121_DDC_OFFSET_REG 0x12 ++#define IT66121_DDC_BYTE_REG 0x13 ++#define IT66121_DDC_SEGMENT_REG 0x14 ++#define IT66121_DDC_RD_FIFO_REG 0x17 ++ ++#define IT66121_CLK_BANK_REG 0x0F ++#define IT66121_CLK_BANK_PWROFF_RCLK BIT(6) ++#define IT66121_CLK_BANK_PWROFF_ACLK BIT(5) ++#define IT66121_CLK_BANK_PWROFF_TXCLK BIT(4) ++#define IT66121_CLK_BANK_PWROFF_CRCLK BIT(3) ++#define IT66121_CLK_BANK_0 0 ++#define IT66121_CLK_BANK_1 1 ++ ++#define IT66121_INT_REG 0x05 ++#define IT66121_INT_ACTIVE_HIGH BIT(7) ++#define IT66121_INT_OPEN_DRAIN BIT(6) ++#define IT66121_INT_TX_CLK_OFF BIT(0) ++ ++#define IT66121_INT_MASK1_REG 0x09 ++#define IT66121_INT_MASK1_AUD_OVF BIT(7) ++#define IT66121_INT_MASK1_DDC_NOACK BIT(5) ++#define IT66121_INT_MASK1_DDC_FIFOERR BIT(4) ++#define IT66121_INT_MASK1_DDC_BUSHANG BIT(2) ++#define IT66121_INT_MASK1_RX_SENS BIT(1) ++#define IT66121_INT_MASK1_HPD BIT(0) ++ ++#define IT66121_INT_CLR1_REG 0x0C ++#define IT66121_INT_CLR1_PKTACP BIT(7) ++#define IT66121_INT_CLR1_PKTNULL BIT(6) ++#define IT66121_INT_CLR1_PKTGEN BIT(5) ++#define IT66121_INT_CLR1_KSVLISTCHK BIT(4) ++#define IT66121_INT_CLR1_AUTHDONE BIT(3) ++#define IT66121_INT_CLR1_AUTHFAIL BIT(2) ++#define IT66121_INT_CLR1_RX_SENS BIT(1) ++#define IT66121_INT_CLR1_HPD BIT(0) ++ ++#define IT66121_AV_MUTE_REG 0xC1 ++#define IT66121_AV_MUTE_ON BIT(0) ++#define IT66121_AV_MUTE_BLUESCR BIT(1) ++ ++#define IT66121_PKT_GEN_CTRL_REG 0xC6 ++#define IT66121_PKT_GEN_CTRL_ON BIT(0) ++#define IT66121_PKT_GEN_CTRL_RPT BIT(1) ++ ++#define IT66121_AVIINFO_DB1_REG 0x158 ++#define IT66121_AVIINFO_DB2_REG 0x159 ++#define IT66121_AVIINFO_DB3_REG 0x15A ++#define IT66121_AVIINFO_DB4_REG 0x15B ++#define IT66121_AVIINFO_DB5_REG 0x15C ++#define IT66121_AVIINFO_CSUM_REG 0x15D ++#define IT66121_AVIINFO_DB6_REG 0x15E ++#define IT66121_AVIINFO_DB7_REG 0x15F ++#define IT66121_AVIINFO_DB8_REG 0x160 ++#define IT66121_AVIINFO_DB9_REG 0x161 ++#define IT66121_AVIINFO_DB10_REG 0x162 ++#define IT66121_AVIINFO_DB11_REG 0x163 ++#define IT66121_AVIINFO_DB12_REG 0x164 ++#define IT66121_AVIINFO_DB13_REG 0x165 ++ ++#define IT66121_AVI_INFO_PKT_REG 0xCD ++#define IT66121_AVI_INFO_PKT_ON BIT(0) ++#define IT66121_AVI_INFO_PKT_RPT BIT(1) ++ ++#define IT66121_HDMI_MODE_REG 0xC0 ++#define IT66121_HDMI_MODE_HDMI BIT(0) ++ ++#define IT66121_SYS_STATUS_REG 0x0E ++#define IT66121_SYS_STATUS_ACTIVE_IRQ BIT(7) ++#define IT66121_SYS_STATUS_HPDETECT BIT(6) ++#define IT66121_SYS_STATUS_SENDECTECT BIT(5) ++#define IT66121_SYS_STATUS_VID_STABLE BIT(4) ++#define IT66121_SYS_STATUS_AUD_CTS_CLR BIT(1) ++#define IT66121_SYS_STATUS_CLEAR_IRQ BIT(0) ++ ++#define IT66121_DDC_STATUS_REG 0x16 ++#define IT66121_DDC_STATUS_TX_DONE BIT(7) ++#define IT66121_DDC_STATUS_ACTIVE BIT(6) ++#define IT66121_DDC_STATUS_NOACK BIT(5) ++#define IT66121_DDC_STATUS_WAIT_BUS BIT(4) ++#define IT66121_DDC_STATUS_ARBI_LOSE BIT(3) ++#define IT66121_DDC_STATUS_FIFO_FULL BIT(2) ++#define IT66121_DDC_STATUS_FIFO_EMPTY BIT(1) ++#define IT66121_DDC_STATUS_FIFO_VALID BIT(0) ++ ++#define IT66121_VENDOR_ID0 0x54 ++#define IT66121_VENDOR_ID1 0x49 ++#define IT66121_DEVICE_ID0 0x12 ++#define IT66121_DEVICE_ID1 0x06 ++#define IT66121_DEVICE_MASK 0x0F ++#define IT66121_EDID_SLEEP 20000 ++#define IT66121_EDID_TIMEOUT 200000 ++#define IT66121_EDID_FIFO_SIZE 32 ++#define IT66121_AFE_CLK_HIGH 80000 ++ ++struct it66121_conf { ++ unsigned int input_mode_reg; ++ unsigned int input_conversion_reg; ++}; ++ ++struct it66121_ctx { ++ struct regmap *regmap; ++ struct drm_bridge bridge; ++ struct drm_connector connector; ++ struct device *dev; ++ struct gpio_desc *gpio_reset; ++ struct i2c_client *client; ++ struct regulator_bulk_data supplies[3]; ++ bool dual_edge; ++ const struct it66121_conf *conf; ++ struct mutex lock; /* Protects fields below and device registers */ ++ struct edid *edid; ++ struct hdmi_avi_infoframe hdmi_avi_infoframe; ++}; ++ ++static const struct regmap_range_cfg it66121_regmap_banks[] = { ++ { ++ .name = "it66121", ++ .range_min = 0x00, ++ .range_max = 0x1FF, ++ .selector_reg = IT66121_CLK_BANK_REG, ++ .selector_mask = 0x1, ++ .selector_shift = 0, ++ .window_start = 0x00, ++ .window_len = 0x130, ++ }, ++}; ++ ++static const struct regmap_config it66121_regmap_config = { ++ .val_bits = 8, ++ .reg_bits = 8, ++ .max_register = 0x1FF, ++ .ranges = it66121_regmap_banks, ++ .num_ranges = ARRAY_SIZE(it66121_regmap_banks), ++}; ++ ++static const struct it66121_conf it66121_conf_simple = { ++ .input_mode_reg = IT66121_INPUT_MODE_RGB | IT66121_INPUT_MODE_DDR, ++ .input_conversion_reg = IT66121_INPUT_CSC_NO_CONV, ++}; ++ ++static void it66121_hw_reset(struct it66121_ctx *ctx) ++{ ++ gpiod_set_value(ctx->gpio_reset, 1); ++ msleep(20); ++ gpiod_set_value(ctx->gpio_reset, 0); ++} ++ ++static int ite66121_power_on(struct it66121_ctx *ctx) ++{ ++ return regulator_bulk_enable(ARRAY_SIZE(ctx->supplies), ctx->supplies); ++} ++ ++static int ite66121_power_off(struct it66121_ctx *ctx) ++{ ++ return regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies); ++} ++ ++static int it66121_preamble_ddc(struct it66121_ctx *ctx) ++{ ++ return regmap_write(ctx->regmap, IT66121_MASTER_SEL_REG, ++ IT66121_MASTER_SEL_HOST); ++} ++ ++static int it66121_fire_afe(struct it66121_ctx *ctx) ++{ ++ return regmap_write(ctx->regmap, IT66121_AFE_DRV_REG, 0); ++} ++ ++static int it66121_configure_input(struct it66121_ctx *ctx) ++{ ++ int ret; ++ ++ ret = regmap_write(ctx->regmap, IT66121_INPUT_MODE_REG, ++ ctx->conf->input_mode_reg); ++ if (ret) ++ return ret; ++ ++ return regmap_write(ctx->regmap, IT66121_INPUT_CSC_REG, ++ ctx->conf->input_conversion_reg); ++} ++ ++/** ++ * it66121_configure_afe() - Configure the analog front end ++ * @ctx: it66121_ctx object ++ * ++ * RETURNS: ++ * zero if success, a negative error code otherwise. ++ */ ++static int it66121_configure_afe(struct it66121_ctx *ctx, ++ const struct drm_display_mode *mode) ++{ ++ int ret; ++ ++ ret = regmap_write(ctx->regmap, IT66121_AFE_DRV_REG, ++ IT66121_AFE_DRV_RST); ++ if (ret) ++ return ret; ++ ++ if (mode->clock > IT66121_AFE_CLK_HIGH) { ++ ret = regmap_write_bits(ctx->regmap, IT66121_AFE_XP_REG, ++ IT66121_AFE_XP_GAINBIT | ++ IT66121_AFE_XP_ENO, ++ IT66121_AFE_XP_GAINBIT); ++ if (ret) ++ return ret; ++ ++ ret = regmap_write_bits(ctx->regmap, IT66121_AFE_IP_REG, ++ IT66121_AFE_IP_GAINBIT | ++ IT66121_AFE_IP_ER0 | ++ IT66121_AFE_IP_EC1, ++ IT66121_AFE_IP_GAINBIT); ++ if (ret) ++ return ret; ++ ++ ret = regmap_write_bits(ctx->regmap, IT66121_AFE_XP_EC1_REG, ++ IT66121_AFE_XP_EC1_LOWCLK, 0x80); ++ if (ret) ++ return ret; ++ } else { ++ ret = regmap_write_bits(ctx->regmap, IT66121_AFE_XP_REG, ++ IT66121_AFE_XP_GAINBIT | ++ IT66121_AFE_XP_ENO, ++ IT66121_AFE_XP_ENO); ++ if (ret) ++ return ret; ++ ++ ret = regmap_write_bits(ctx->regmap, IT66121_AFE_IP_REG, ++ IT66121_AFE_IP_GAINBIT | ++ IT66121_AFE_IP_ER0 | ++ IT66121_AFE_IP_EC1, IT66121_AFE_IP_ER0 | ++ IT66121_AFE_IP_EC1); ++ if (ret) ++ return ret; ++ ++ ret = regmap_write_bits(ctx->regmap, IT66121_AFE_XP_EC1_REG, ++ IT66121_AFE_XP_EC1_LOWCLK, ++ IT66121_AFE_XP_EC1_LOWCLK); ++ if (ret) ++ return ret; ++ } ++ ++ /* Clear reset flags */ ++ ret = regmap_write_bits(ctx->regmap, IT66121_SW_RST_REG, ++ IT66121_SW_RST_REF | IT66121_SW_RST_VID, ++ ~(IT66121_SW_RST_REF | IT66121_SW_RST_VID) & ++ 0xFF); ++ if (ret) ++ return ret; ++ ++ return it66121_fire_afe(ctx); ++} ++ ++static inline int it66121_wait_ddc_ready(struct it66121_ctx *ctx) ++{ ++ int ret, val; ++ ++ ret = regmap_read_poll_timeout(ctx->regmap, IT66121_DDC_STATUS_REG, ++ val, true, ++ IT66121_EDID_SLEEP, ++ IT66121_EDID_TIMEOUT); ++ if (ret) ++ return ret; ++ ++ if (val & (IT66121_DDC_STATUS_NOACK | IT66121_DDC_STATUS_WAIT_BUS | ++ IT66121_DDC_STATUS_ARBI_LOSE)) ++ return -EAGAIN; ++ ++ return 0; ++} ++ ++static int it66121_clear_ddc_fifo(struct it66121_ctx *ctx) ++{ ++ int ret; ++ ++ ret = it66121_preamble_ddc(ctx); ++ if (ret) ++ return ret; ++ ++ return regmap_write(ctx->regmap, IT66121_DDC_COMMAND_REG, ++ IT66121_DDC_COMMAND_FIFO_CLR); ++} ++ ++static int it66121_abort_ddc_ops(struct it66121_ctx *ctx) ++{ ++ int ret; ++ unsigned int swreset, cpdesire; ++ ++ ret = regmap_read(ctx->regmap, IT66121_SW_RST_REG, &swreset); ++ if (ret) ++ return ret; ++ ++ ret = regmap_read(ctx->regmap, IT66121_HDCP_REG, &cpdesire); ++ if (ret) ++ return ret; ++ ++ ret = regmap_write(ctx->regmap, IT66121_HDCP_REG, ++ cpdesire & (~IT66121_HDCP_CPDESIRED & 0xFF)); ++ if (ret) ++ return ret; ++ ++ ret = regmap_write(ctx->regmap, IT66121_SW_RST_REG, ++ swreset | IT66121_SW_RST_HDCP); ++ if (ret) ++ return ret; ++ ++ ret = it66121_preamble_ddc(ctx); ++ if (ret) ++ return ret; ++ ++ ret = regmap_write(ctx->regmap, IT66121_DDC_COMMAND_REG, ++ IT66121_DDC_COMMAND_ABORT); ++ if (ret) ++ return ret; ++ ++ return it66121_wait_ddc_ready(ctx); ++} ++ ++static int it66121_get_edid_block(void *context, u8 *buf, ++ unsigned int block, size_t len) ++{ ++ struct it66121_ctx *ctx = context; ++ unsigned int val; ++ int remain = len; ++ int offset = 0; ++ int ret, cnt; ++ ++ offset = (block % 2) * len; ++ block = block / 2; ++ ++ ret = regmap_read(ctx->regmap, IT66121_INT_STATUS1_REG, &val); ++ if (ret) ++ return ret; ++ ++ if (val & IT66121_INT_STATUS1_DDC_BUSHANG) { ++ ret = it66121_abort_ddc_ops(ctx); ++ if (ret) ++ return ret; ++ } ++ ++ ret = it66121_clear_ddc_fifo(ctx); ++ if (ret) ++ return ret; ++ ++ while (remain > 0) { ++ cnt = (remain > IT66121_EDID_FIFO_SIZE) ? ++ IT66121_EDID_FIFO_SIZE : remain; ++ ret = it66121_preamble_ddc(ctx); ++ if (ret) ++ return ret; ++ ++ ret = regmap_write(ctx->regmap, IT66121_DDC_COMMAND_REG, ++ IT66121_DDC_COMMAND_FIFO_CLR); ++ if (ret) ++ return ret; ++ ++ ret = it66121_wait_ddc_ready(ctx); ++ if (ret) ++ return ret; ++ ++ ret = regmap_read(ctx->regmap, IT66121_INT_STATUS1_REG, &val); ++ if (ret) ++ return ret; ++ ++ if (val & IT66121_INT_STATUS1_DDC_BUSHANG) { ++ ret = it66121_abort_ddc_ops(ctx); ++ if (ret) ++ return ret; ++ } ++ ++ ret = it66121_preamble_ddc(ctx); ++ if (ret) ++ return ret; ++ ++ ret = regmap_write(ctx->regmap, IT66121_DDC_HEADER_REG, ++ IT66121_DDC_HEADER_EDID); ++ if (ret) ++ return ret; ++ ++ ret = regmap_write(ctx->regmap, IT66121_DDC_OFFSET_REG, offset); ++ if (ret) ++ return ret; ++ ++ ret = regmap_write(ctx->regmap, IT66121_DDC_BYTE_REG, cnt); ++ if (ret) ++ return ret; ++ ++ ret = regmap_write(ctx->regmap, IT66121_DDC_SEGMENT_REG, block); ++ if (ret) ++ return ret; ++ ++ ret = regmap_write(ctx->regmap, IT66121_DDC_COMMAND_REG, ++ IT66121_DDC_COMMAND_EDID_READ); ++ if (ret) ++ return ret; ++ ++ offset += cnt; ++ remain -= cnt; ++ msleep(20); ++ ++ ret = it66121_wait_ddc_ready(ctx); ++ if (ret) ++ return ret; ++ ++ do { ++ ret = regmap_read(ctx->regmap, ++ IT66121_DDC_RD_FIFO_REG, &val); ++ if (ret) ++ return ret; ++ *(buf++) = val; ++ cnt--; ++ } while (cnt > 0); ++ } ++ ++ return 0; ++} ++ ++static int it66121_connector_get_modes(struct drm_connector *connector) ++{ ++ int ret, num_modes = 0; ++ struct it66121_ctx *ctx = container_of(connector, struct it66121_ctx, ++ connector); ++ ++ if (ctx->edid) ++ return drm_add_edid_modes(connector, ctx->edid); ++ ++ mutex_lock(&ctx->lock); ++ ++ ctx->edid = drm_do_get_edid(connector, it66121_get_edid_block, ctx); ++ if (!ctx->edid) { ++ DRM_ERROR("Failed to read EDID\n"); ++ goto unlock; ++ } ++ ++ ret = drm_connector_update_edid_property(connector, ++ ctx->edid); ++ if (ret) { ++ DRM_ERROR("Failed to update EDID property: %d\n", ret); ++ goto unlock; ++ } ++ ++ num_modes = drm_add_edid_modes(connector, ctx->edid); ++ ++unlock: ++ mutex_unlock(&ctx->lock); ++ ++ return num_modes; ++} ++ ++static bool it66121_is_hpd_detect(struct it66121_ctx *ctx) ++{ ++ int val; ++ ++ if (regmap_read(ctx->regmap, IT66121_SYS_STATUS_REG, &val)) ++ return false; ++ ++ return (val & IT66121_SYS_STATUS_HPDETECT); ++} ++ ++static int it66121_connector_detect_ctx(struct drm_connector *connector, ++ struct drm_modeset_acquire_ctx *c, ++ bool force) ++{ ++ struct it66121_ctx *ctx = container_of(connector, struct it66121_ctx, ++ connector); ++ ++ return (it66121_is_hpd_detect(ctx)) ? ++ connector_status_connected : connector_status_disconnected; ++} ++ ++static enum drm_mode_status ++it66121_connector_mode_valid(struct drm_connector *connector, ++ struct drm_display_mode *mode) ++{ ++ unsigned long max_clock; ++ struct it66121_ctx *ctx = container_of(connector, struct it66121_ctx, ++ connector); ++ ++ max_clock = ctx->dual_edge ? 74250 : 148500; ++ ++ if (mode->clock > max_clock) ++ return MODE_CLOCK_HIGH; ++ ++ if (mode->clock < 25000) ++ return MODE_CLOCK_LOW; ++ ++ return MODE_OK; ++} ++ ++static struct drm_connector_helper_funcs it66121_connector_helper_funcs = { ++ .get_modes = it66121_connector_get_modes, ++ .detect_ctx = it66121_connector_detect_ctx, ++ .mode_valid = it66121_connector_mode_valid, ++}; ++ ++static const struct drm_connector_funcs it66121_connector_funcs = { ++ .reset = drm_atomic_helper_connector_reset, ++ .fill_modes = drm_helper_probe_single_connector_modes, ++ .destroy = drm_connector_cleanup, ++ .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, ++ .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, ++}; ++ ++static int it66121_bridge_attach(struct drm_bridge *bridge, ++ enum drm_bridge_attach_flags flags) ++{ ++ int ret; ++ struct it66121_ctx *ctx = container_of(bridge, struct it66121_ctx, ++ bridge); ++ ++ if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR) { ++ DRM_ERROR("Fix bridge driver to make connector optional!"); ++ return -EINVAL; ++ } ++ ++ if (!bridge->encoder) { ++ DRM_ERROR("Parent encoder object not found"); ++ return -ENODEV; ++ } ++ ++ ret = regmap_write_bits(ctx->regmap, IT66121_CLK_BANK_REG, ++ IT66121_CLK_BANK_PWROFF_RCLK, 0); ++ if (ret) ++ return ret; ++ ++ ret = regmap_write_bits(ctx->regmap, IT66121_INT_REG, ++ IT66121_INT_TX_CLK_OFF, 0); ++ if (ret) ++ return ret; ++ ++ ret = regmap_write_bits(ctx->regmap, IT66121_AFE_DRV_REG, ++ IT66121_AFE_DRV_PWD, 0); ++ if (ret) ++ return ret; ++ ++ ret = regmap_write_bits(ctx->regmap, IT66121_AFE_XP_REG, ++ IT66121_AFE_XP_PWDI | IT66121_AFE_XP_PWDPLL, 0); ++ if (ret) ++ return ret; ++ ++ ret = regmap_write_bits(ctx->regmap, IT66121_AFE_IP_REG, ++ IT66121_AFE_IP_PWDPLL, 0); ++ if (ret) ++ return ret; ++ ++ ret = regmap_write_bits(ctx->regmap, IT66121_AFE_DRV_REG, ++ IT66121_AFE_DRV_RST, 0); ++ if (ret) ++ return ret; ++ ++ ret = regmap_write_bits(ctx->regmap, IT66121_AFE_XP_REG, ++ IT66121_AFE_XP_RESETB, IT66121_AFE_XP_RESETB); ++ if (ret) ++ return ret; ++ ++ ret = regmap_write_bits(ctx->regmap, IT66121_AFE_IP_REG, ++ IT66121_AFE_IP_RESETB, IT66121_AFE_IP_RESETB); ++ if (ret) ++ return ret; ++ ++ ret = regmap_write_bits(ctx->regmap, IT66121_SW_RST_REG, ++ IT66121_SW_RST_REF, ++ IT66121_SW_RST_REF); ++ if (ret) ++ return ret; ++ ++ msleep(50); ++ ++ ret = drm_connector_init(bridge->dev, &ctx->connector, ++ &it66121_connector_funcs, ++ DRM_MODE_CONNECTOR_HDMIA); ++ if (ret) ++ return ret; ++ ++ ctx->connector.polled = DRM_CONNECTOR_POLL_HPD; ++ drm_connector_helper_add(&ctx->connector, ++ &it66121_connector_helper_funcs); ++ ++ ret = drm_connector_attach_encoder(&ctx->connector, bridge->encoder); ++ if (ret) ++ return ret; ++ ++ ret = drm_connector_register(&ctx->connector); ++ if (ret) ++ return ret; ++ ++ /* Start interrupts */ ++ return regmap_write_bits(ctx->regmap, IT66121_INT_MASK1_REG, ++ IT66121_INT_MASK1_DDC_NOACK | ++ IT66121_INT_MASK1_HPD | ++ IT66121_INT_MASK1_DDC_FIFOERR | ++ IT66121_INT_MASK1_DDC_BUSHANG, ++ ~(IT66121_INT_MASK1_DDC_NOACK | ++ IT66121_INT_MASK1_HPD | ++ IT66121_INT_MASK1_DDC_FIFOERR | ++ IT66121_INT_MASK1_DDC_BUSHANG) & 0xFF); ++} ++ ++static int it66121_set_mute(struct it66121_ctx *ctx, bool mute) ++{ ++ int ret; ++ unsigned int val; ++ ++ val = mute ? IT66121_AV_MUTE_ON : (~IT66121_AV_MUTE_ON & 0xFF); ++ ret = regmap_write_bits(ctx->regmap, IT66121_AV_MUTE_REG, ++ IT66121_AV_MUTE_ON, val); ++ if (ret) ++ return ret; ++ ++ return regmap_write(ctx->regmap, IT66121_PKT_GEN_CTRL_REG, ++ IT66121_PKT_GEN_CTRL_ON | ++ IT66121_PKT_GEN_CTRL_RPT); ++} ++ ++static void it66121_bridge_enable(struct drm_bridge *bridge) ++{ ++ struct it66121_ctx *ctx = container_of(bridge, struct it66121_ctx, ++ bridge); ++ ++ it66121_set_mute(ctx, false); ++} ++ ++static void it66121_bridge_disable(struct drm_bridge *bridge) ++{ ++ struct it66121_ctx *ctx = container_of(bridge, struct it66121_ctx, ++ bridge); ++ ++ it66121_set_mute(ctx, true); ++} ++ ++static ++void it66121_bridge_mode_set(struct drm_bridge *bridge, ++ const struct drm_display_mode *mode, ++ const struct drm_display_mode *adjusted_mode) ++{ ++ int ret, i; ++ u8 buf[HDMI_INFOFRAME_SIZE(AVI)]; ++ struct it66121_ctx *ctx = container_of(bridge, struct it66121_ctx, ++ bridge); ++ const u16 aviinfo_reg[HDMI_AVI_INFOFRAME_SIZE] = { ++ IT66121_AVIINFO_DB1_REG, ++ IT66121_AVIINFO_DB2_REG, ++ IT66121_AVIINFO_DB3_REG, ++ IT66121_AVIINFO_DB4_REG, ++ IT66121_AVIINFO_DB5_REG, ++ IT66121_AVIINFO_DB6_REG, ++ IT66121_AVIINFO_DB7_REG, ++ IT66121_AVIINFO_DB8_REG, ++ IT66121_AVIINFO_DB9_REG, ++ IT66121_AVIINFO_DB10_REG, ++ IT66121_AVIINFO_DB11_REG, ++ IT66121_AVIINFO_DB12_REG, ++ IT66121_AVIINFO_DB13_REG ++ }; ++ ++ mutex_lock(&ctx->lock); ++ ++ hdmi_avi_infoframe_init(&ctx->hdmi_avi_infoframe); ++ ++ ret = drm_hdmi_avi_infoframe_from_display_mode(&ctx->hdmi_avi_infoframe, ++ &ctx->connector, ++ adjusted_mode); ++ if (ret) { ++ DRM_ERROR("Failed to setup AVI infoframe: %d\n", ret); ++ goto unlock; ++ } ++ ++ ret = hdmi_avi_infoframe_pack(&ctx->hdmi_avi_infoframe, buf, ++ sizeof(buf)); ++ if (ret < 0) { ++ DRM_ERROR("Failed to pack infoframe: %d\n", ret); ++ goto unlock; ++ } ++ ++ /* Write new AVI infoframe packet */ ++ for (i = 0; i < HDMI_AVI_INFOFRAME_SIZE; i++) { ++ if (regmap_write(ctx->regmap, aviinfo_reg[i], ++ buf[i + HDMI_INFOFRAME_HEADER_SIZE])) ++ goto unlock; ++ } ++ if (regmap_write(ctx->regmap, IT66121_AVIINFO_CSUM_REG, buf[3])) ++ goto unlock; ++ ++ /* Enable AVI infoframe */ ++ if (regmap_write(ctx->regmap, IT66121_AVI_INFO_PKT_REG, ++ IT66121_AVI_INFO_PKT_ON | ++ IT66121_AVI_INFO_PKT_RPT)) ++ goto unlock; ++ ++ /* Set TX mode to HDMI */ ++ if (regmap_write(ctx->regmap, IT66121_HDMI_MODE_REG, ++ IT66121_HDMI_MODE_HDMI)) ++ goto unlock; ++ ++ if (regmap_write_bits(ctx->regmap, IT66121_CLK_BANK_REG, ++ IT66121_CLK_BANK_PWROFF_TXCLK, ++ IT66121_CLK_BANK_PWROFF_TXCLK)) ++ goto unlock; ++ ++ if (it66121_configure_input(ctx)) ++ goto unlock; ++ ++ if (it66121_configure_afe(ctx, adjusted_mode)) ++ goto unlock; ++ ++ regmap_write_bits(ctx->regmap, IT66121_CLK_BANK_REG, ++ IT66121_CLK_BANK_PWROFF_TXCLK, ++ ~IT66121_CLK_BANK_PWROFF_TXCLK & 0xFF); ++ ++unlock: ++ mutex_unlock(&ctx->lock); ++} ++ ++static const struct drm_bridge_funcs it66121_bridge_funcs = { ++ .attach = it66121_bridge_attach, ++ .enable = it66121_bridge_enable, ++ .disable = it66121_bridge_disable, ++ .mode_set = it66121_bridge_mode_set, ++}; ++ ++static irqreturn_t it66121_irq_threaded_handler(int irq, void *dev_id) ++{ ++ int ret; ++ unsigned int val; ++ struct it66121_ctx *ctx = dev_id; ++ struct device *dev = ctx->dev; ++ bool event = false; ++ ++ mutex_lock(&ctx->lock); ++ ++ ret = regmap_read(ctx->regmap, IT66121_SYS_STATUS_REG, &val); ++ if (ret) ++ goto unlock; ++ ++ if (val & IT66121_SYS_STATUS_ACTIVE_IRQ) { ++ ret = regmap_read(ctx->regmap, IT66121_INT_STATUS1_REG, &val); ++ if (ret) { ++ dev_err(dev, "Cannot read STATUS1_REG %d\n", ret); ++ } else { ++ if (val & IT66121_INT_STATUS1_DDC_FIFOERR) ++ it66121_clear_ddc_fifo(ctx); ++ if (val & (IT66121_INT_STATUS1_DDC_BUSHANG | ++ IT66121_INT_STATUS1_DDC_NOACK)) ++ it66121_abort_ddc_ops(ctx); ++ if (val & IT66121_INT_STATUS1_HPD_STATUS) { ++ regmap_write_bits(ctx->regmap, ++ IT66121_INT_CLR1_REG, ++ IT66121_INT_CLR1_HPD, ++ IT66121_INT_CLR1_HPD); ++ ++ if (!it66121_is_hpd_detect(ctx)) { ++ kfree(ctx->edid); ++ ctx->edid = NULL; ++ } ++ event = true; ++ } ++ } ++ ++ regmap_write_bits(ctx->regmap, IT66121_SYS_STATUS_REG, ++ IT66121_SYS_STATUS_CLEAR_IRQ, ++ IT66121_SYS_STATUS_CLEAR_IRQ); ++ } ++ ++unlock: ++ mutex_unlock(&ctx->lock); ++ ++ if (event) ++ drm_helper_hpd_irq_event(ctx->bridge.dev); ++ ++ return IRQ_HANDLED; ++} ++ ++static int it66121_probe(struct i2c_client *client, ++ const struct i2c_device_id *id) ++{ ++ u8 ids[4]; ++ int i, ret; ++ struct it66121_ctx *ctx; ++ struct device *dev = &client->dev; ++ ++ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { ++ dev_err(dev, "I2C check functionality failed.\n"); ++ return -ENXIO; ++ } ++ ++ ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); ++ if (!ctx) ++ return -ENOMEM; ++ ++ ctx->dev = dev; ++ ctx->client = client; ++ i2c_set_clientdata(client, ctx); ++ mutex_init(&ctx->lock); ++ ctx->conf = (struct it66121_conf *)of_device_get_match_data(dev); ++ if (!ctx->conf) ++ return -ENODEV; ++ ++ ctx->supplies[0].supply = "vcn33"; ++ ctx->supplies[1].supply = "vcn18"; ++ ctx->supplies[2].supply = "vrf12"; ++ ret = devm_regulator_bulk_get(ctx->dev, 3, ctx->supplies); ++ if (ret) { ++ dev_err(ctx->dev, "regulator_bulk failed\n"); ++ return ret; ++ } ++ ++ ctx->dual_edge = of_property_read_bool(dev->of_node, "pclk-dual-edge"); ++ ++ ret = ite66121_power_on(ctx); ++ if (ret) ++ return ret; ++ ++ it66121_hw_reset(ctx); ++ ++ ctx->regmap = devm_regmap_init_i2c(client, &it66121_regmap_config); ++ if (IS_ERR(ctx->regmap)) { ++ ite66121_power_off(ctx); ++ return PTR_ERR(ctx); ++ } ++ ++ for (i = 0; i < 4; i++) { ++ regmap_read(ctx->regmap, i, &ret); ++ ids[i] = ret; ++ } ++ ++ if (ids[0] != IT66121_VENDOR_ID0 || ++ ids[1] != IT66121_VENDOR_ID1 || ++ ids[2] != IT66121_DEVICE_ID0 || ++ ((ids[3] & IT66121_DEVICE_MASK) != IT66121_DEVICE_ID1)) { ++ ite66121_power_off(ctx); ++ return -ENODEV; ++ } ++ ++ ctx->bridge.funcs = &it66121_bridge_funcs; ++ ctx->bridge.of_node = dev->of_node; ++ ++ ret = devm_request_threaded_irq(dev, client->irq, NULL, ++ it66121_irq_threaded_handler, ++ IRQF_SHARED | IRQF_TRIGGER_LOW | ++ IRQF_ONESHOT, ++ dev_name(dev), ++ ctx); ++ if (ret < 0) { ++ dev_err(dev, "Failed to request irq %d:%d\n", client->irq, ret); ++ ite66121_power_off(ctx); ++ return ret; ++ } ++ ++ drm_bridge_add(&ctx->bridge); ++ ++ return 0; ++} ++ ++static int it66121_remove(struct i2c_client *client) ++{ ++ struct it66121_ctx *ctx = i2c_get_clientdata(client); ++ ++ ite66121_power_off(ctx); ++ drm_bridge_remove(&ctx->bridge); ++ kfree(ctx->edid); ++ mutex_destroy(&ctx->lock); ++ ++ return 0; ++} ++ ++static const struct of_device_id it66121_dt_match[] = { ++ { .compatible = "ite,it66121", ++ .data = &it66121_conf_simple, ++ }, ++ { }, ++}; ++MODULE_DEVICE_TABLE(of, it66121_dt_match); ++ ++static const struct i2c_device_id it66121_id[] = { ++ { "it66121", 0 }, ++ { }, ++}; ++MODULE_DEVICE_TABLE(i2c, it66121_id); ++ ++static struct i2c_driver it66121_driver = { ++ .driver = { ++ .name = "it66121", ++ .of_match_table = it66121_dt_match, ++ }, ++ .probe = it66121_probe, ++ .remove = it66121_remove, ++ .id_table = it66121_id, ++}; ++ ++module_i2c_driver(it66121_driver); ++ ++MODULE_AUTHOR("Phong LE"); ++MODULE_DESCRIPTION("IT66121 HDMI transmitter driver"); ++MODULE_LICENSE("GPL v2"); + +From ec5271e4d8d6d57545a284ee5bd365f17990fdc6 Mon Sep 17 00:00:00 2001 +From: Phong LE +Date: Wed, 11 Mar 2020 13:51:35 +0100 +Subject: [PATCH] MAINTAINERS: add it66121 HDMI bridge driver entry + +Add Neil Armstrong and myself as maintainers + +Signed-off-by: Phong LE +--- + MAINTAINERS | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/MAINTAINERS b/MAINTAINERS +index db98a799f409..5a34ca2f0e11 100644 +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -9193,6 +9193,14 @@ Q: http://patchwork.linuxtv.org/project/linux-media/list/ + T: git git://linuxtv.org/anttip/media_tree.git + F: drivers/media/tuners/it913x* + ++ITE IT66121 HDMI BRIDGE DRIVER ++M: Phong LE ++M: Neil Armstrong ++S: Maintained ++F: drivers/gpu/drm/bridge/ite-it66121.c ++T: git git://anongit.freedesktop.org/drm/drm-misc ++F: Documentation/devicetree/bindings/display/bridge/ite,it66121.yaml ++ + IVTV VIDEO4LINUX DRIVER + M: Andy Walls + L: linux-media@vger.kernel.org + +From b8f225a1145ac25cd5df830d557e5be6d212a798 Mon Sep 17 00:00:00 2001 +From: Alex Bee +Date: Tue, 26 May 2020 13:48:12 +0200 +Subject: [PATCH] drm: bridge: it66121: add IT66121FN variant + +--- + drivers/gpu/drm/bridge/ite-it66121.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/drivers/gpu/drm/bridge/ite-it66121.c b/drivers/gpu/drm/bridge/ite-it66121.c +index 7e1a90319a6a..68f7e50fdddd 100644 +--- a/drivers/gpu/drm/bridge/ite-it66121.c ++++ b/drivers/gpu/drm/bridge/ite-it66121.c +@@ -242,6 +242,11 @@ static const struct it66121_conf it66121_conf_simple = { + .input_conversion_reg = IT66121_INPUT_CSC_NO_CONV, + }; + ++static const struct it66121_conf it66121fn_conf_simple = { ++ .input_mode_reg = IT66121_INPUT_MODE_RGB, ++ .input_conversion_reg = IT66121_INPUT_CSC_NO_CONV, ++}; ++ + static void it66121_hw_reset(struct it66121_ctx *ctx) + { + gpiod_set_value(ctx->gpio_reset, 1); +@@ -970,6 +975,9 @@ static const struct of_device_id it66121_dt_match[] = { + { .compatible = "ite,it66121", + .data = &it66121_conf_simple, + }, ++ { .compatible = "ite,it66121fn", ++ .data = &it66121fn_conf_simple, ++ }, + { }, + }; + MODULE_DEVICE_TABLE(of, it66121_dt_match); + +From e7ebcc04f15308b5ece1b5f99689d8577be2625d Mon Sep 17 00:00:00 2001 +From: Alex Bee +Date: Sun, 16 Aug 2020 23:40:24 +0200 +Subject: [PATCH] WIP: ARM: dts: rockchip add vpll clock to RK322Xs hdmi node + +--- + arch/arm/boot/dts/rk322x.dtsi | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/arch/arm/boot/dts/rk322x.dtsi b/arch/arm/boot/dts/rk322x.dtsi +index 48e6e8d44a1a..b69b5be110c3 100644 +--- a/arch/arm/boot/dts/rk322x.dtsi ++++ b/arch/arm/boot/dts/rk322x.dtsi +@@ -644,8 +644,8 @@ hdmi: hdmi@200a0000 { + interrupts = ; + assigned-clocks = <&cru SCLK_HDMI_PHY>; + assigned-clock-parents = <&hdmi_phy>; +- clocks = <&cru SCLK_HDMI_HDCP>, <&cru PCLK_HDMI_CTRL>, <&cru SCLK_HDMI_CEC>; +- clock-names = "isfr", "iahb", "cec"; ++ clocks = <&cru SCLK_HDMI_HDCP>, <&cru PCLK_HDMI_CTRL>, <&hdmi_phy>, <&cru SCLK_HDMI_CEC>; ++ clock-names = "isfr", "iahb", "vpll", "cec"; + pinctrl-names = "default"; + pinctrl-0 = <&hdmii2c_xfer &hdmi_hpd &hdmi_cec>; + resets = <&cru SRST_HDMI_P>; + +From e1dd22643e8fc82021c3ed8f5355bffa33899b9c Mon Sep 17 00:00:00 2001 +From: Alex Bee +Date: Tue, 18 Aug 2020 11:19:53 +0200 +Subject: [PATCH] drm/bridge: !cleanup: remove pr_infos + +--- + drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c | 6 ------ + 1 file changed, 6 deletions(-) + +diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c +index e6953219beee..2cfd5b418c05 100644 +--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c ++++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c +@@ -97,8 +97,6 @@ static int dw_hdmi_cec_transmit(struct cec_adapter *adap, u8 attempts, + struct dw_hdmi_cec *cec = cec_get_drvdata(adap); + unsigned int i, ctrl; + +- pr_info("%s: attempts=%u signal_free_time=%u msg=%*ph (sequence: %u)\n", __func__, attempts, signal_free_time, msg->len, msg->msg, msg->sequence); +- + switch (signal_free_time) { + case CEC_SIGNAL_FREE_TIME_RETRY: + ctrl = CEC_CTRL_RETRY; +@@ -188,8 +186,6 @@ static irqreturn_t dw_hdmi_cec_hardirq(int irq, void *data) + ret = IRQ_WAKE_THREAD; + } + +- pr_info("%s: stat=%x ret=%x tx_done=%d rx_done=%d tx_status=%u tx_attempts=%u\n", __func__, stat, ret, cec->tx_done, cec->rx_done, cec->tx_status, cec->tx_attempts); +- + return ret; + } + +@@ -198,8 +194,6 @@ static irqreturn_t dw_hdmi_cec_thread(int irq, void *data) + struct cec_adapter *adap = data; + struct dw_hdmi_cec *cec = cec_get_drvdata(adap); + +- //pr_info("%s: tx_done=%d rx_done=%d tx_status=%u tx_attempts=%u\n", __func__, cec->tx_done, cec->rx_done, cec->tx_status, cec->tx_attempts); +- + if (cec->tx_done) { + cec->tx_done = false; + if (cec->tx_status == CEC_TX_STATUS_LOW_DRIVE) diff --git a/patch/kernel/rk322x-current/01-linux-3000-rockchip-v4l-wip.patch b/patch/kernel/rk322x-current/01-linux-3000-rockchip-v4l-wip.patch new file mode 100644 index 000000000..e19954c6d --- /dev/null +++ b/patch/kernel/rk322x-current/01-linux-3000-rockchip-v4l-wip.patch @@ -0,0 +1,4647 @@ +From d9d1bb6e72ad344280be5887718444f110aec86f Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Fri, 22 May 2020 20:42:11 +0000 +Subject: [PATCH] fixup! media: rkvdec: Fix .buf_prepare + +--- + drivers/staging/media/rkvdec/rkvdec.c | 10 ++++------ + 1 file changed, 4 insertions(+), 6 deletions(-) + +diff --git a/drivers/staging/media/rkvdec/rkvdec.c b/drivers/staging/media/rkvdec/rkvdec.c +index f0f28f6a68cf..9edaea98a483 100644 +--- a/drivers/staging/media/rkvdec/rkvdec.c ++++ b/drivers/staging/media/rkvdec/rkvdec.c +@@ -599,13 +599,11 @@ static int rkvdec_buf_prepare(struct vb2_buffer *vb) + } + + /* +- * Buffer's bytesused is written by the driver for CAPTURE buffers, +- * or if the application passed zero bytesused on an OUTPUT buffer. ++ * Buffer's bytesused is written by the driver for CAPTURE buffers. + */ +- if (!V4L2_TYPE_IS_OUTPUT(vq->type) || +- (V4L2_TYPE_IS_OUTPUT(vq->type) && !vb2_get_plane_payload(vb, 0))) +- vb2_set_plane_payload(vb, 0, +- f->fmt.pix_mp.plane_fmt[0].sizeimage); ++ if (!V4L2_TYPE_IS_OUTPUT(vq->type)) ++ vb2_set_plane_payload(vb, 0, f->fmt.pix_mp.plane_fmt[0].sizeimage); ++ + return 0; + } + + +From e5c9031e74c1ff2c597654f172c9f1e856810544 Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Sat, 15 Aug 2020 08:28:56 +0000 +Subject: [PATCH] fixup! media: rkvdec: Add the VP9 backend + +--- + drivers/staging/media/rkvdec/rkvdec.c | 5 ----- + 1 file changed, 5 deletions(-) + +diff --git a/drivers/staging/media/rkvdec/rkvdec.c b/drivers/staging/media/rkvdec/rkvdec.c +index 9edaea98a483..9accbe889040 100644 +--- a/drivers/staging/media/rkvdec/rkvdec.c ++++ b/drivers/staging/media/rkvdec/rkvdec.c +@@ -161,24 +161,19 @@ static const u32 rkvdec_h264_decoded_fmts[] = { + + static const struct rkvdec_ctrl_desc rkvdec_vp9_ctrl_descs[] = { + { +- .per_request = true, + .mandatory = true, + .cfg.id = V4L2_CID_MPEG_VIDEO_VP9_FRAME_DECODE_PARAMS, + }, + { +- .mandatory = true, + .cfg.id = V4L2_CID_MPEG_VIDEO_VP9_FRAME_CONTEXT(0), + }, + { +- .mandatory = true, + .cfg.id = V4L2_CID_MPEG_VIDEO_VP9_FRAME_CONTEXT(1), + }, + { +- .mandatory = true, + .cfg.id = V4L2_CID_MPEG_VIDEO_VP9_FRAME_CONTEXT(2), + }, + { +- .mandatory = true, + .cfg.id = V4L2_CID_MPEG_VIDEO_VP9_FRAME_CONTEXT(3), + }, + { + +From 9a9b9efc39a879ef65d7f9bec29fd8f0b8ce89fc Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Sat, 23 May 2020 10:18:16 +0000 +Subject: [PATCH] WIP: media: rkvdec: continue to gate clock when decoding + finish + +Signed-off-by: Jonas Karlman +--- + drivers/staging/media/rkvdec/rkvdec.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/drivers/staging/media/rkvdec/rkvdec.c b/drivers/staging/media/rkvdec/rkvdec.c +index 9accbe889040..a282b7e6d6e8 100644 +--- a/drivers/staging/media/rkvdec/rkvdec.c ++++ b/drivers/staging/media/rkvdec/rkvdec.c +@@ -1079,7 +1079,8 @@ static irqreturn_t rkvdec_irq_handler(int irq, void *priv) + state = (status & RKVDEC_RDY_STA) ? + VB2_BUF_STATE_DONE : VB2_BUF_STATE_ERROR; + +- writel(0, rkvdec->regs + RKVDEC_REG_INTERRUPT); ++ writel(RKVDEC_CONFIG_DEC_CLK_GATE_E, ++ rkvdec->regs + RKVDEC_REG_INTERRUPT); + if (cancel_delayed_work(&rkvdec->watchdog_work)) { + struct rkvdec_ctx *ctx; + +@@ -1100,7 +1101,8 @@ static void rkvdec_watchdog_func(struct work_struct *work) + ctx = v4l2_m2m_get_curr_priv(rkvdec->m2m_dev); + if (ctx) { + dev_err(rkvdec->dev, "Frame processing timed out!\n"); +- writel(RKVDEC_IRQ_DIS, rkvdec->regs + RKVDEC_REG_INTERRUPT); ++ writel(RKVDEC_CONFIG_DEC_CLK_GATE_E | RKVDEC_IRQ_DIS, ++ rkvdec->regs + RKVDEC_REG_INTERRUPT); + writel(0, rkvdec->regs + RKVDEC_REG_SYSCTRL); + rkvdec_job_finish(ctx, VB2_BUF_STATE_ERROR); + } + +From 126fa7ad4de4368fe4938d59b327813a8649ff3b Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Sat, 23 May 2020 10:16:01 +0000 +Subject: [PATCH] WIP: media: rkvdec: pm runtime dont use autosuspend before + disable and cleanup + +Signed-off-by: Jonas Karlman +--- + drivers/staging/media/rkvdec/rkvdec.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/staging/media/rkvdec/rkvdec.c b/drivers/staging/media/rkvdec/rkvdec.c +index a282b7e6d6e8..658fb6028e72 100644 +--- a/drivers/staging/media/rkvdec/rkvdec.c ++++ b/drivers/staging/media/rkvdec/rkvdec.c +@@ -1200,9 +1200,9 @@ static int rkvdec_remove(struct platform_device *pdev) + { + struct rkvdec_dev *rkvdec = platform_get_drvdata(pdev); + +- rkvdec_v4l2_cleanup(rkvdec); +- pm_runtime_disable(&pdev->dev); + pm_runtime_dont_use_autosuspend(&pdev->dev); ++ pm_runtime_disable(&pdev->dev); ++ rkvdec_v4l2_cleanup(rkvdec); + return 0; + } + + +From c7382800a8af054b62ff6edea7d62bc30a160b74 Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Sat, 23 May 2020 11:23:04 +0000 +Subject: [PATCH] WIP: media: rkvdec: h264: return early when no reference + pictures + +NOTE: also change from a switch statement to access reflists from a pointer array, +should simplify once we add support for field reference list + +Signed-off-by: Jonas Karlman +--- + drivers/staging/media/rkvdec/rkvdec-h264.c | 18 +++++------------- + 1 file changed, 5 insertions(+), 13 deletions(-) + +diff --git a/drivers/staging/media/rkvdec/rkvdec-h264.c b/drivers/staging/media/rkvdec/rkvdec-h264.c +index afc695d32186..1716bfb596ae 100644 +--- a/drivers/staging/media/rkvdec/rkvdec-h264.c ++++ b/drivers/staging/media/rkvdec/rkvdec-h264.c +@@ -734,6 +734,7 @@ static void assemble_hw_rps(struct rkvdec_ctx *ctx, + const struct v4l2_ctrl_h264_sps *sps = run->sps; + struct rkvdec_h264_priv_tbl *priv_tbl = h264_ctx->priv_tbl.cpu; + u32 max_frame_num = 1 << (sps->log2_max_frame_num_minus4 + 4); ++ u8 *reflists[3] = { h264_ctx->reflists.p, h264_ctx->reflists.b0, h264_ctx->reflists.b1 }; + + u32 *hw_rps = priv_tbl->rps; + u32 i, j; +@@ -741,6 +742,9 @@ static void assemble_hw_rps(struct rkvdec_ctx *ctx, + + memset(hw_rps, 0, sizeof(priv_tbl->rps)); + ++ if (!h264_ctx->reflists.num_valid) ++ return; ++ + /* + * Assign an invalid pic_num if DPB entry at that position is inactive. + * If we assign 0 in that position hardware will treat that as a real +@@ -763,19 +767,7 @@ static void assemble_hw_rps(struct rkvdec_ctx *ctx, + for (j = 0; j < RKVDEC_NUM_REFLIST; j++) { + for (i = 0; i < h264_ctx->reflists.num_valid; i++) { + u8 dpb_valid = 0; +- u8 idx = 0; +- +- switch (j) { +- case 0: +- idx = h264_ctx->reflists.p[i]; +- break; +- case 1: +- idx = h264_ctx->reflists.b0[i]; +- break; +- case 2: +- idx = h264_ctx->reflists.b1[i]; +- break; +- } ++ u8 idx = reflists[j][i]; + + if (idx >= ARRAY_SIZE(dec_params->dpb)) + continue; + +From 70eb1d9dfa98bf6a6662280de58e01dffa347add Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Sat, 23 May 2020 14:42:27 +0000 +Subject: [PATCH] WIP: media: rkvdec: h264: add field decoding support + +Signed-off-by: Jonas Karlman +--- + drivers/staging/media/rkvdec/rkvdec-h264.c | 79 ++++++++++++++++++---- + 1 file changed, 64 insertions(+), 15 deletions(-) + +diff --git a/drivers/staging/media/rkvdec/rkvdec-h264.c b/drivers/staging/media/rkvdec/rkvdec-h264.c +index 1716bfb596ae..c388bf3da079 100644 +--- a/drivers/staging/media/rkvdec/rkvdec-h264.c ++++ b/drivers/staging/media/rkvdec/rkvdec-h264.c +@@ -737,7 +737,7 @@ static void assemble_hw_rps(struct rkvdec_ctx *ctx, + u8 *reflists[3] = { h264_ctx->reflists.p, h264_ctx->reflists.b0, h264_ctx->reflists.b1 }; + + u32 *hw_rps = priv_tbl->rps; +- u32 i, j; ++ u32 i, j, k; + u16 *p = (u16 *)hw_rps; + + memset(hw_rps, 0, sizeof(priv_tbl->rps)); +@@ -764,18 +764,71 @@ static void assemble_hw_rps(struct rkvdec_ctx *ctx, + p[i] = dpb[i].frame_num - max_frame_num; + } + +- for (j = 0; j < RKVDEC_NUM_REFLIST; j++) { +- for (i = 0; i < h264_ctx->reflists.num_valid; i++) { +- u8 dpb_valid = 0; +- u8 idx = reflists[j][i]; ++ if (!(dec_params->flags & V4L2_H264_DECODE_PARAM_FLAG_FIELD_PIC)) { ++ for (j = 0; j < RKVDEC_NUM_REFLIST; j++) { ++ for (i = 0; i < h264_ctx->reflists.num_valid; i++) { ++ u8 dpb_valid = 0; ++ u8 idx = reflists[j][i]; + +- if (idx >= ARRAY_SIZE(dec_params->dpb)) +- continue; +- dpb_valid = !!(dpb[idx].flags & +- V4L2_H264_DPB_ENTRY_FLAG_ACTIVE); ++ if (idx >= ARRAY_SIZE(dec_params->dpb)) ++ continue; ++ dpb_valid = !!(dpb[idx].flags & ++ V4L2_H264_DPB_ENTRY_FLAG_ACTIVE); + +- set_ps_field(hw_rps, DPB_INFO(i, j), +- idx | dpb_valid << 4); ++ set_ps_field(hw_rps, DPB_INFO(i, j), ++ idx | dpb_valid << 4); ++ } ++ } ++ return; ++ } ++ ++ for (j = 0; j < RKVDEC_NUM_REFLIST; j++) { ++ enum v4l2_h264_field_reference a_parity = ++ (dec_params->flags & V4L2_H264_DECODE_PARAM_FLAG_BOTTOM_FIELD) ++ ? V4L2_H264_BOTTOM_FIELD_REF : V4L2_H264_TOP_FIELD_REF; ++ enum v4l2_h264_field_reference b_parity = ++ (dec_params->flags & V4L2_H264_DECODE_PARAM_FLAG_BOTTOM_FIELD) ++ ? V4L2_H264_TOP_FIELD_REF : V4L2_H264_BOTTOM_FIELD_REF; ++ u32 flags = V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM; ++ i = 0; ++ ++ for (k = 0; k < 2; k++) { ++ u8 a = 0; ++ u8 b = 0; ++ u32 long_term = k ? V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM : 0; ++ ++ while (a < h264_ctx->reflists.num_valid || b < h264_ctx->reflists.num_valid) { ++ for (; a < h264_ctx->reflists.num_valid; a++) { ++ u8 idx = reflists[j][a]; ++ if (idx >= ARRAY_SIZE(dec_params->dpb)) ++ continue; ++ if ((dpb[idx].reference & a_parity) == a_parity && ++ (dpb[idx].flags & flags) == long_term) { ++ set_ps_field(hw_rps, DPB_INFO(i, j), ++ idx | (1 << 4)); ++ set_ps_field(hw_rps, BOTTOM_FLAG(i, j), ++ a_parity == V4L2_H264_BOTTOM_FIELD_REF); ++ i++; ++ a++; ++ break; ++ } ++ } ++ for (; b < h264_ctx->reflists.num_valid; b++) { ++ u8 idx = reflists[j][b]; ++ if (idx >= ARRAY_SIZE(dec_params->dpb)) ++ continue; ++ if ((dpb[idx].reference & b_parity) == b_parity && ++ (dpb[idx].flags & flags) == long_term) { ++ set_ps_field(hw_rps, DPB_INFO(i, j), ++ idx | (1 << 4)); ++ set_ps_field(hw_rps, BOTTOM_FLAG(i, j), ++ b_parity == V4L2_H264_BOTTOM_FIELD_REF); ++ i++; ++ b++; ++ break; ++ } ++ } ++ } + } + } + } +@@ -968,10 +1021,6 @@ static void config_registers(struct rkvdec_ctx *ctx, + rkvdec->regs + RKVDEC_REG_H264_BASE_REFER15); + } + +- /* +- * Since support frame mode only +- * top_field_order_cnt is the same as bottom_field_order_cnt +- */ + reg = RKVDEC_CUR_POC(dec_params->top_field_order_cnt); + writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_CUR_POC0); + + +From 7032b50b559ff869d47ae06ec94cf7b50f7a8eb1 Mon Sep 17 00:00:00 2001 +From: Jernej Skrabec +Date: Sat, 26 Oct 2019 13:55:15 +0200 +Subject: [PATCH] media: uapi: hevc: Add scaling matrix control + +HEVC has a scaling matrix concept. Add support for it. + +Signed-off-by: Jernej Skrabec +--- + .../media/v4l/ext-ctrls-codec.rst | 41 +++++++++++++++++++ + .../media/v4l/pixfmt-compressed.rst | 1 + + drivers/media/v4l2-core/v4l2-ctrls.c | 10 +++++ + include/media/hevc-ctrls.h | 11 +++++ + 4 files changed, 63 insertions(+) + +diff --git a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst +index ca13b141d8c2..578de53ff929 100644 +--- a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst ++++ b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst +@@ -4777,6 +4777,47 @@ enum v4l2_mpeg_video_hevc_size_of_length_field - + - ``padding[6]`` + - Applications and drivers must set this to zero. + ++``V4L2_CID_MPEG_VIDEO_HEVC_SCALING_MATRIX (struct)`` ++ Specifies the scaling matrix (as extracted from the bitstream) for ++ the associated HEVC slice data. The bitstream parameters are ++ defined according to :ref:`hevc`, section 7.4.5 "Scaling list ++ data semantics". For further documentation, refer to the above ++ specification, unless there is an explicit comment stating ++ otherwise. ++ ++ .. note:: ++ ++ This compound control is not yet part of the public kernel API and ++ it is expected to change. ++ ++.. c:type:: v4l2_ctrl_hevc_scaling_matrix ++ ++.. cssclass:: longtable ++ ++.. flat-table:: struct v4l2_ctrl_hevc_scaling_matrix ++ :header-rows: 0 ++ :stub-columns: 0 ++ :widths: 1 1 2 ++ ++ * - __u8 ++ - ``scaling_list_4x4[6][16]`` ++ - ++ * - __u8 ++ - ``scaling_list_8x8[6][64]`` ++ - ++ * - __u8 ++ - ``scaling_list_16x16[6][64]`` ++ - ++ * - __u8 ++ - ``scaling_list_32x32[2][64]`` ++ - ++ * - __u8 ++ - ``scaling_list_dc_coef_16x16[6]`` ++ - ++ * - __u8 ++ - ``scaling_list_dc_coef_32x32[2]`` ++ - ++ + ``V4L2_CID_MPEG_VIDEO_HEVC_DECODE_MODE (enum)`` + Specifies the decoding mode to use. Currently exposes slice-based and + frame-based decoding but new modes might be added later on. +diff --git a/Documentation/userspace-api/media/v4l/pixfmt-compressed.rst b/Documentation/userspace-api/media/v4l/pixfmt-compressed.rst +index 3828bb79225d..a77560204c21 100644 +--- a/Documentation/userspace-api/media/v4l/pixfmt-compressed.rst ++++ b/Documentation/userspace-api/media/v4l/pixfmt-compressed.rst +@@ -207,6 +207,7 @@ Compressed Formats + * ``V4L2_CID_MPEG_VIDEO_HEVC_SPS`` + * ``V4L2_CID_MPEG_VIDEO_HEVC_PPS`` + * ``V4L2_CID_MPEG_VIDEO_HEVC_SLICE_PARAMS`` ++ * ``V4L2_CID_MPEG_VIDEO_HEVC_SCALING_MATRIX`` + See the :ref:`associated Codec Control IDs `. + Buffers associated with this pixel format must contain the appropriate + number of macroblocks to decode a full corresponding frame. +diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c +index 5913088cbc6f..6f7df51cb633 100644 +--- a/drivers/media/v4l2-core/v4l2-ctrls.c ++++ b/drivers/media/v4l2-core/v4l2-ctrls.c +@@ -995,6 +995,7 @@ const char *v4l2_ctrl_get_name(u32 id) + case V4L2_CID_MPEG_VIDEO_HEVC_SPS: return "HEVC Sequence Parameter Set"; + case V4L2_CID_MPEG_VIDEO_HEVC_PPS: return "HEVC Picture Parameter Set"; + case V4L2_CID_MPEG_VIDEO_HEVC_SLICE_PARAMS: return "HEVC Slice Parameters"; ++ case V4L2_CID_MPEG_VIDEO_HEVC_SCALING_MATRIX: return "HEVC Scaling Matrix"; + case V4L2_CID_MPEG_VIDEO_HEVC_DECODE_MODE: return "HEVC Decode Mode"; + case V4L2_CID_MPEG_VIDEO_HEVC_START_CODE: return "HEVC Start Code"; + +@@ -1442,6 +1443,9 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type, + case V4L2_CID_MPEG_VIDEO_HEVC_SLICE_PARAMS: + *type = V4L2_CTRL_TYPE_HEVC_SLICE_PARAMS; + break; ++ case V4L2_CID_MPEG_VIDEO_HEVC_SCALING_MATRIX: ++ *type = V4L2_CTRL_TYPE_HEVC_SCALING_MATRIX; ++ break; + case V4L2_CID_UNIT_CELL_SIZE: + *type = V4L2_CTRL_TYPE_AREA; + *flags |= V4L2_CTRL_FLAG_READ_ONLY; +@@ -2134,6 +2138,9 @@ static int std_validate_compound(const struct v4l2_ctrl *ctrl, u32 idx, + zero_padding(*p_hevc_slice_params); + break; + ++ case V4L2_CTRL_TYPE_HEVC_SCALING_MATRIX: ++ break; ++ + case V4L2_CTRL_TYPE_AREA: + area = p; + if (!area->width || !area->height) +@@ -2832,6 +2839,9 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl, + case V4L2_CTRL_TYPE_HEVC_SLICE_PARAMS: + elem_size = sizeof(struct v4l2_ctrl_hevc_slice_params); + break; ++ case V4L2_CTRL_TYPE_HEVC_SCALING_MATRIX: ++ elem_size = sizeof(struct v4l2_ctrl_hevc_scaling_matrix); ++ break; + case V4L2_CTRL_TYPE_AREA: + elem_size = sizeof(struct v4l2_area); + break; +diff --git a/include/media/hevc-ctrls.h b/include/media/hevc-ctrls.h +index 1009cf0891cc..1592e52c3614 100644 +--- a/include/media/hevc-ctrls.h ++++ b/include/media/hevc-ctrls.h +@@ -19,6 +19,7 @@ + #define V4L2_CID_MPEG_VIDEO_HEVC_SPS (V4L2_CID_MPEG_BASE + 1008) + #define V4L2_CID_MPEG_VIDEO_HEVC_PPS (V4L2_CID_MPEG_BASE + 1009) + #define V4L2_CID_MPEG_VIDEO_HEVC_SLICE_PARAMS (V4L2_CID_MPEG_BASE + 1010) ++#define V4L2_CID_MPEG_VIDEO_HEVC_SCALING_MATRIX (V4L2_CID_MPEG_BASE + 1011) + #define V4L2_CID_MPEG_VIDEO_HEVC_DECODE_MODE (V4L2_CID_MPEG_BASE + 1015) + #define V4L2_CID_MPEG_VIDEO_HEVC_START_CODE (V4L2_CID_MPEG_BASE + 1016) + +@@ -26,6 +27,7 @@ + #define V4L2_CTRL_TYPE_HEVC_SPS 0x0120 + #define V4L2_CTRL_TYPE_HEVC_PPS 0x0121 + #define V4L2_CTRL_TYPE_HEVC_SLICE_PARAMS 0x0122 ++#define V4L2_CTRL_TYPE_HEVC_SCALING_MATRIX 0x0123 + + enum v4l2_mpeg_video_hevc_decode_mode { + V4L2_MPEG_VIDEO_HEVC_DECODE_MODE_SLICE_BASED, +@@ -209,4 +211,13 @@ struct v4l2_ctrl_hevc_slice_params { + __u64 flags; + }; + ++struct v4l2_ctrl_hevc_scaling_matrix { ++ __u8 scaling_list_4x4[6][16]; ++ __u8 scaling_list_8x8[6][64]; ++ __u8 scaling_list_16x16[6][64]; ++ __u8 scaling_list_32x32[2][64]; ++ __u8 scaling_list_dc_coef_16x16[6]; ++ __u8 scaling_list_dc_coef_32x32[2]; ++}; ++ + #endif + +From e8b0441e3d60b0e936b975f2467d1604158a1d6c Mon Sep 17 00:00:00 2001 +From: Jernej Skrabec +Date: Sat, 26 Oct 2019 15:42:28 +0200 +Subject: [PATCH] media: uapi: hevc: Add segment address field + +If HEVC frame consists of multiple slices, segment address has to be +known in order to properly decode it. + +Add segment address field to slice parameters. + +Signed-off-by: Jernej Skrabec +--- + Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst | 5 ++++- + include/media/hevc-ctrls.h | 5 ++++- + 2 files changed, 8 insertions(+), 2 deletions(-) + +diff --git a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst +index 578de53ff929..bca71e38b85d 100644 +--- a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst ++++ b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst +@@ -4572,6 +4572,9 @@ enum v4l2_mpeg_video_hevc_size_of_length_field - + * - __u32 + - ``data_bit_offset`` + - Offset (in bits) to the video data in the current slice data. ++ * - __u32 ++ - ``slice_segment_addr`` ++ - + * - __u8 + - ``nal_unit_type`` + - +@@ -4649,7 +4652,7 @@ enum v4l2_mpeg_video_hevc_size_of_length_field - + - ``num_rps_poc_lt_curr`` + - The number of reference pictures in the long-term set. + * - __u8 +- - ``padding[7]`` ++ - ``padding[5]`` + - Applications and drivers must set this to zero. + * - struct :c:type:`v4l2_hevc_dpb_entry` + - ``dpb[V4L2_HEVC_DPB_ENTRIES_NUM_MAX]`` +diff --git a/include/media/hevc-ctrls.h b/include/media/hevc-ctrls.h +index 1592e52c3614..3e2e32098312 100644 +--- a/include/media/hevc-ctrls.h ++++ b/include/media/hevc-ctrls.h +@@ -167,6 +167,9 @@ struct v4l2_ctrl_hevc_slice_params { + __u32 bit_size; + __u32 data_bit_offset; + ++ /* ISO/IEC 23008-2, ITU-T Rec. H.265: General slice segment header */ ++ __u32 slice_segment_addr; ++ + /* ISO/IEC 23008-2, ITU-T Rec. H.265: NAL unit header */ + __u8 nal_unit_type; + __u8 nuh_temporal_id_plus1; +@@ -200,7 +203,7 @@ struct v4l2_ctrl_hevc_slice_params { + __u8 num_rps_poc_st_curr_after; + __u8 num_rps_poc_lt_curr; + +- __u8 padding; ++ __u8 padding[5]; + + /* ISO/IEC 23008-2, ITU-T Rec. H.265: General slice segment header */ + struct v4l2_hevc_dpb_entry dpb[V4L2_HEVC_DPB_ENTRIES_NUM_MAX]; + +From 180280b4b2e59865227ac90235ae902ce8088369 Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Sat, 23 May 2020 15:03:46 +0000 +Subject: [PATCH] WIP: media: uapi: hevc: add fields needed for rkvdec + +NOTE: these fields are used by rkvdec hevc backend + +Signed-off-by: Jonas Karlman +--- + include/media/hevc-ctrls.h | 16 ++++++++++++---- + 1 file changed, 12 insertions(+), 4 deletions(-) + +diff --git a/include/media/hevc-ctrls.h b/include/media/hevc-ctrls.h +index 3e2e32098312..3cc3b47e1417 100644 +--- a/include/media/hevc-ctrls.h ++++ b/include/media/hevc-ctrls.h +@@ -56,6 +56,9 @@ enum v4l2_mpeg_video_hevc_start_code { + /* The controls are not stable at the moment and will likely be reworked. */ + struct v4l2_ctrl_hevc_sps { + /* ISO/IEC 23008-2, ITU-T Rec. H.265: Sequence parameter set */ ++ __u8 video_parameter_set_id; ++ __u8 seq_parameter_set_id; ++ __u8 chroma_format_idc; + __u16 pic_width_in_luma_samples; + __u16 pic_height_in_luma_samples; + __u8 bit_depth_luma_minus8; +@@ -76,9 +79,8 @@ struct v4l2_ctrl_hevc_sps { + __u8 log2_diff_max_min_pcm_luma_coding_block_size; + __u8 num_short_term_ref_pic_sets; + __u8 num_long_term_ref_pics_sps; +- __u8 chroma_format_idc; + +- __u8 padding; ++ __u8 padding[7]; + + __u64 flags; + }; +@@ -105,7 +107,10 @@ struct v4l2_ctrl_hevc_sps { + + struct v4l2_ctrl_hevc_pps { + /* ISO/IEC 23008-2, ITU-T Rec. H.265: Picture parameter set */ ++ __u8 pic_parameter_set_id; + __u8 num_extra_slice_header_bits; ++ __u8 num_ref_idx_l0_default_active_minus1; ++ __u8 num_ref_idx_l1_default_active_minus1; + __s8 init_qp_minus26; + __u8 diff_cu_qp_delta_depth; + __s8 pps_cb_qp_offset; +@@ -118,7 +123,7 @@ struct v4l2_ctrl_hevc_pps { + __s8 pps_tc_offset_div2; + __u8 log2_parallel_merge_level_minus2; + +- __u8 padding[4]; ++ __u8 padding; + __u64 flags; + }; + +@@ -203,7 +208,10 @@ struct v4l2_ctrl_hevc_slice_params { + __u8 num_rps_poc_st_curr_after; + __u8 num_rps_poc_lt_curr; + +- __u8 padding[5]; ++ __u16 short_term_ref_pic_set_size; ++ __u16 long_term_ref_pic_set_size; ++ ++ __u8 padding; + + /* ISO/IEC 23008-2, ITU-T Rec. H.265: General slice segment header */ + struct v4l2_hevc_dpb_entry dpb[V4L2_HEVC_DPB_ENTRIES_NUM_MAX]; + +From 80ec0ecb1f7555aae1daa174cde084b3d9f42459 Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Sat, 23 May 2020 15:07:15 +0000 +Subject: [PATCH] HACK: media: uapi: hevc: tiles and num_slices + +--- + include/media/hevc-ctrls.h | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/include/media/hevc-ctrls.h b/include/media/hevc-ctrls.h +index 3cc3b47e1417..b33e1a8141e1 100644 +--- a/include/media/hevc-ctrls.h ++++ b/include/media/hevc-ctrls.h +@@ -80,7 +80,8 @@ struct v4l2_ctrl_hevc_sps { + __u8 num_short_term_ref_pic_sets; + __u8 num_long_term_ref_pics_sps; + +- __u8 padding[7]; ++ __u8 num_slices; ++ __u8 padding[6]; + + __u64 flags; + }; +@@ -174,6 +175,7 @@ struct v4l2_ctrl_hevc_slice_params { + + /* ISO/IEC 23008-2, ITU-T Rec. H.265: General slice segment header */ + __u32 slice_segment_addr; ++ __u32 num_entry_point_offsets; + + /* ISO/IEC 23008-2, ITU-T Rec. H.265: NAL unit header */ + __u8 nal_unit_type; +@@ -211,7 +213,9 @@ struct v4l2_ctrl_hevc_slice_params { + __u16 short_term_ref_pic_set_size; + __u16 long_term_ref_pic_set_size; + +- __u8 padding; ++ __u8 padding[5]; ++ ++ __u32 entry_point_offset_minus1[256]; + + /* ISO/IEC 23008-2, ITU-T Rec. H.265: General slice segment header */ + struct v4l2_hevc_dpb_entry dpb[V4L2_HEVC_DPB_ENTRIES_NUM_MAX]; + +From f35f02f322ebb97970d021bc82d9cad0b6432e15 Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Sat, 23 May 2020 15:17:45 +0000 +Subject: [PATCH] WIP: media: rkvdec: add HEVC backend + +NOTE: cabac table and scailing list code is copied 1:1 from mpp +TODO: fix lowdelay flag and rework the scaling list part + +Signed-off-by: Jonas Karlman +--- + drivers/staging/media/rkvdec/Makefile | 2 +- + drivers/staging/media/rkvdec/rkvdec-hevc.c | 2522 ++++++++++++++++++++ + drivers/staging/media/rkvdec/rkvdec-regs.h | 1 + + drivers/staging/media/rkvdec/rkvdec.c | 70 + + drivers/staging/media/rkvdec/rkvdec.h | 1 + + 5 files changed, 2595 insertions(+), 1 deletion(-) + create mode 100644 drivers/staging/media/rkvdec/rkvdec-hevc.c + +diff --git a/drivers/staging/media/rkvdec/Makefile b/drivers/staging/media/rkvdec/Makefile +index cb86b429cfaa..a77122641d14 100644 +--- a/drivers/staging/media/rkvdec/Makefile ++++ b/drivers/staging/media/rkvdec/Makefile +@@ -1,3 +1,3 @@ + obj-$(CONFIG_VIDEO_ROCKCHIP_VDEC) += rockchip-vdec.o + +-rockchip-vdec-y += rkvdec.o rkvdec-h264.o rkvdec-vp9.o ++rockchip-vdec-y += rkvdec.o rkvdec-h264.o rkvdec-hevc.o rkvdec-vp9.o +diff --git a/drivers/staging/media/rkvdec/rkvdec-hevc.c b/drivers/staging/media/rkvdec/rkvdec-hevc.c +new file mode 100644 +index 000000000000..03ba848411c6 +--- /dev/null ++++ b/drivers/staging/media/rkvdec/rkvdec-hevc.c +@@ -0,0 +1,2522 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Rockchip Video Decoder HEVC backend ++ * ++ * Copyright (C) 2019 Collabora, Ltd. ++ * Boris Brezillon ++ * ++ * Copyright (C) 2016 Rockchip Electronics Co., Ltd. ++ * Jeffy Chen ++ */ ++ ++#include ++ ++#include "rkvdec.h" ++#include "rkvdec-regs.h" ++ ++/* Size in u8/u32 units. */ ++#define RKV_CABAC_TABLE_SIZE 27456 ++#define RKV_SCALING_LIST_SIZE 1360 ++#define RKV_PPS_SIZE (80 / 4) ++#define RKV_PPS_LEN 64 ++#define RKV_RPS_SIZE (32 / 4) ++#define RKV_RPS_LEN 600 ++ ++struct rkvdec_sps_pps_packet { ++ u32 info[RKV_PPS_SIZE]; ++}; ++ ++struct rkvdec_rps_packet { ++ u32 info[RKV_RPS_SIZE]; ++}; ++ ++struct rkvdec_ps_field { ++ u16 offset; ++ u8 len; ++}; ++ ++#define PS_FIELD(_offset, _len) \ ++ ((struct rkvdec_ps_field){ _offset, _len }) ++ ++/* SPS */ ++#define VIDEO_PARAMETER_SET_ID PS_FIELD(0, 4) ++#define SEQ_PARAMETER_SET_ID PS_FIELD(4, 4) ++#define CHROMA_FORMAT_IDC PS_FIELD(8, 2) ++#define PIC_WIDTH_IN_LUMA_SAMPLES PS_FIELD(10, 13) ++#define PIC_HEIGHT_IN_LUMA_SAMPLES PS_FIELD(23, 13) ++#define BIT_DEPTH_LUMA PS_FIELD(36, 4) ++#define BIT_DEPTH_CHROMA PS_FIELD(40, 4) ++#define LOG2_MAX_PIC_ORDER_CNT_LSB PS_FIELD(44, 5) ++#define LOG2_DIFF_MAX_MIN_LUMA_CODING_BLOCK_SIZE PS_FIELD(49, 2) ++#define LOG2_MIN_LUMA_CODING_BLOCK_SIZE PS_FIELD(51, 3) ++#define LOG2_MIN_TRANSFORM_BLOCK_SIZE PS_FIELD(54, 3) ++#define LOG2_DIFF_MAX_MIN_LUMA_TRANSFORM_BLOCK_SIZE PS_FIELD(57, 2) ++#define MAX_TRANSFORM_HIERARCHY_DEPTH_INTER PS_FIELD(59, 3) ++#define MAX_TRANSFORM_HIERARCHY_DEPTH_INTRA PS_FIELD(62, 3) ++#define SCALING_LIST_ENABLED_FLAG PS_FIELD(65, 1) ++#define AMP_ENABLED_FLAG PS_FIELD(66, 1) ++#define SAMPLE_ADAPTIVE_OFFSET_ENABLED_FLAG PS_FIELD(67, 1) ++#define PCM_ENABLED_FLAG PS_FIELD(68, 1) ++#define PCM_SAMPLE_BIT_DEPTH_LUMA PS_FIELD(69, 4) ++#define PCM_SAMPLE_BIT_DEPTH_CHROMA PS_FIELD(73, 4) ++#define PCM_LOOP_FILTER_DISABLED_FLAG PS_FIELD(77, 1) ++#define LOG2_DIFF_MAX_MIN_PCM_LUMA_CODING_BLOCK_SIZE PS_FIELD(78, 3) ++#define LOG2_MIN_PCM_LUMA_CODING_BLOCK_SIZE PS_FIELD(81, 3) ++#define NUM_SHORT_TERM_REF_PIC_SETS PS_FIELD(84, 7) ++#define LONG_TERM_REF_PICS_PRESENT_FLAG PS_FIELD(91, 1) ++#define NUM_LONG_TERM_REF_PICS_SPS PS_FIELD(92, 6) ++#define SPS_TEMPORAL_MVP_ENABLED_FLAG PS_FIELD(98, 1) ++#define STRONG_INTRA_SMOOTHING_ENABLED_FLAG PS_FIELD(99, 1) ++/* PPS */ ++#define PIC_PARAMETER_SET_ID PS_FIELD(128, 6) ++#define PPS_SEQ_PARAMETER_SET_ID PS_FIELD(134, 4) ++#define DEPENDENT_SLICE_SEGMENTS_ENABLED_FLAG PS_FIELD(138, 1) ++#define OUTPUT_FLAG_PRESENT_FLAG PS_FIELD(139, 1) ++#define NUM_EXTRA_SLICE_HEADER_BITS PS_FIELD(140, 13) ++#define SIGN_DATA_HIDING_ENABLED_FLAG PS_FIELD(153, 1) ++#define CABAC_INIT_PRESENT_FLAG PS_FIELD(154, 1) ++#define NUM_REF_IDX_L0_DEFAULT_ACTIVE PS_FIELD(155, 4) ++#define NUM_REF_IDX_L1_DEFAULT_ACTIVE PS_FIELD(159, 4) ++#define INIT_QP_MINUS26 PS_FIELD(163, 7) ++#define CONSTRAINED_INTRA_PRED_FLAG PS_FIELD(170, 1) ++#define TRANSFORM_SKIP_ENABLED_FLAG PS_FIELD(171, 1) ++#define CU_QP_DELTA_ENABLED_FLAG PS_FIELD(172, 1) ++#define LOG2_MIN_CU_QP_DELTA_SIZE PS_FIELD(173, 3) ++#define PPS_CB_QP_OFFSET PS_FIELD(176, 5) ++#define PPS_CR_QP_OFFSET PS_FIELD(181, 5) ++#define PPS_SLICE_CHROMA_QP_OFFSETS_PRESENT_FLAG PS_FIELD(186, 1) ++#define WEIGHTED_PRED_FLAG PS_FIELD(187, 1) ++#define WEIGHTED_BIPRED_FLAG PS_FIELD(188, 1) ++#define TRANSQUANT_BYPASS_ENABLED_FLAG PS_FIELD(189, 1) ++#define TILES_ENABLED_FLAG PS_FIELD(190, 1) ++#define ENTROPY_CODING_SYNC_ENABLED_FLAG PS_FIELD(191, 1) ++#define PPS_LOOP_FILTER_ACROSS_SLICES_ENABLED_FLAG PS_FIELD(192, 1) ++#define LOOP_FILTER_ACROSS_TILES_ENABLED_FLAG PS_FIELD(193, 1) ++#define DEBLOCKING_FILTER_OVERRIDE_ENABLED_FLAG PS_FIELD(194, 1) ++#define PPS_DEBLOCKING_FILTER_DISABLED_FLAG PS_FIELD(195, 1) ++#define PPS_BETA_OFFSET_DIV2 PS_FIELD(196, 4) ++#define PPS_TC_OFFSET_DIV2 PS_FIELD(200, 4) ++#define LISTS_MODIFICATION_PRESENT_FLAG PS_FIELD(204, 1) ++#define LOG2_PARALLEL_MERGE_LEVEL PS_FIELD(205, 3) ++#define SLICE_SEGMENT_HEADER_EXTENSION_PRESENT_FLAG PS_FIELD(208, 1) ++#define NUM_TILE_COLUMNS PS_FIELD(212, 5) ++#define NUM_TILE_ROWS PS_FIELD(217, 5) ++#define COLUMN_WIDTH(i) PS_FIELD(256 + (i * 8), 8) ++#define ROW_HEIGHT(i) PS_FIELD(416 + (i * 8), 8) ++#define SCALING_LIST_ADDRESS PS_FIELD(592, 32) ++ ++/* Data structure describing auxiliary buffer format. */ ++struct rkvdec_hevc_priv_tbl { ++ u8 cabac_table[RKV_CABAC_TABLE_SIZE]; ++ u8 scaling_list[RKV_SCALING_LIST_SIZE]; ++ struct rkvdec_sps_pps_packet param_set[RKV_PPS_LEN]; ++ struct rkvdec_rps_packet rps[RKV_RPS_LEN]; ++}; ++ ++struct rkvdec_hevc_run { ++ struct rkvdec_run base; ++ const struct v4l2_ctrl_hevc_slice_params *slices_params; ++ const struct v4l2_ctrl_hevc_sps *sps; ++ const struct v4l2_ctrl_hevc_pps *pps; ++ const struct v4l2_ctrl_hevc_scaling_matrix *scaling_matrix; ++ int num_slices; ++}; ++ ++struct rkvdec_hevc_ctx { ++ struct rkvdec_aux_buf priv_tbl; ++ struct v4l2_ctrl_hevc_scaling_matrix scaling_matrix_cache; ++}; ++ ++// TODO: refactor scaling list code, was copied 1:1 from mpp ++ ++typedef struct ScalingList { ++ /* This is a little wasteful, since sizeID 0 only needs 8 coeffs, ++ * and size ID 3 only has 2 arrays, not 6. */ ++ u8 sl[4][6][64]; ++ u8 sl_dc[2][6]; ++} scalingList_t; ++ ++typedef struct ScalingFactor_Model { ++ u8 scalingfactor0[1248]; ++ u8 scalingfactor1[96]; /*4X4 TU Rotate, total 16X4*/ ++ u8 scalingdc[12]; /*N1005 Vienna Meeting*/ ++ u8 reserverd[4]; /*16Bytes align*/ ++} scalingFactor_t; ++ ++#define SCALING_LIST_SIZE_NUM 4 ++ ++static void ++hal_record_scaling_list(scalingFactor_t *pScalingFactor_out, ++ scalingList_t *pScalingList) ++{ ++ int i; ++ u32 g_scalingListNum_model[SCALING_LIST_SIZE_NUM] = {6, 6, 6, 2}; // from C Model ++ u32 nIndex = 0; ++ u32 sizeId, matrixId, listId; ++ u8 *p = pScalingFactor_out->scalingfactor0; ++ u8 tmpBuf[8 * 8]; ++ ++ //output non-default scalingFactor Table (1248 BYTES) ++ for (sizeId = 0; sizeId < SCALING_LIST_SIZE_NUM; sizeId++) { ++ for (listId = 0; listId < g_scalingListNum_model[sizeId]; listId++) { ++ if (sizeId < 3) { ++ for (i = 0; i < (sizeId == 0 ? 16 : 64); i++) { ++ pScalingFactor_out->scalingfactor0[nIndex++] = (u8)pScalingList->sl[sizeId][listId][i]; ++ } ++ } else { ++ for (i = 0; i < 64; i ++) { ++ pScalingFactor_out->scalingfactor0[nIndex++] = (u8)pScalingList->sl[sizeId][listId][i]; ++ } ++ for (i = 0; i < 128; i ++) { ++ pScalingFactor_out->scalingfactor0[nIndex++] = 0; ++ } ++ } ++ } ++ } ++ //output non-default scalingFactor Table Rotation(96 Bytes) ++ nIndex = 0; ++ for (listId = 0; listId < g_scalingListNum_model[0]; listId++) { ++ u8 temp16[16] = {0}; ++ for (i = 0; i < 16; i ++) { ++ temp16[i] = (u8)pScalingList->sl[0][listId][i]; ++ } ++ for (i = 0; i < 4; i ++) { ++ pScalingFactor_out->scalingfactor1[nIndex++] = temp16[i]; ++ pScalingFactor_out->scalingfactor1[nIndex++] = temp16[i + 4]; ++ pScalingFactor_out->scalingfactor1[nIndex++] = temp16[i + 8]; ++ pScalingFactor_out->scalingfactor1[nIndex++] = temp16[i + 12]; ++ } ++ } ++ //output non-default ScalingList_DC_Coeff (12 BYTES) ++ nIndex = 0; ++ for (listId = 0; listId < g_scalingListNum_model[2]; listId++) { //sizeId = 2 ++ pScalingFactor_out->scalingdc[nIndex++] = (u8)pScalingList->sl_dc[0][listId];// zrh warning: sl_dc differed from scalingList->getScalingListDC ++ } ++ for (listId = 0; listId < g_scalingListNum_model[3]; listId++) { //sizeId = 3 ++ pScalingFactor_out->scalingdc[nIndex++] = (u8)pScalingList->sl_dc[1][listId];// zrh warning: sl_dc differed from scalingList->getScalingListDC ++ pScalingFactor_out->scalingdc[nIndex++] = 0; ++ pScalingFactor_out->scalingdc[nIndex++] = 0; ++ } ++ ++ //align 16X address ++ nIndex = 0; ++ for (i = 0; i < 4; i ++) { ++ pScalingFactor_out->reserverd[nIndex++] = 0; ++ } ++ ++ //----------------------All above code show the normal store way in HM-------------------------- ++ //--------from now on, the scalingfactor0 is rotated 90', the scalingfactor1 is also rotated 90' ++ ++ //sizeId == 0 ++ for (matrixId = 0; matrixId < 6; matrixId++) { ++ p = pScalingFactor_out->scalingfactor0 + matrixId * 16; ++ ++ for (i = 0; i < 4; i++) { ++ tmpBuf[4 * 0 + i] = p[i * 4 + 0]; ++ tmpBuf[4 * 1 + i] = p[i * 4 + 1]; ++ tmpBuf[4 * 2 + i] = p[i * 4 + 2]; ++ tmpBuf[4 * 3 + i] = p[i * 4 + 3]; ++ } ++ memcpy(p, tmpBuf, 4 * 4 * sizeof(u8)); ++ } ++ //sizeId == 1 ++ for (matrixId = 0; matrixId < 6; matrixId++) { ++ p = pScalingFactor_out->scalingfactor0 + 6 * 16 + matrixId * 64; ++ ++ for (i = 0; i < 8; i++) { ++ tmpBuf[8 * 0 + i] = p[i * 8 + 0]; ++ tmpBuf[8 * 1 + i] = p[i * 8 + 1]; ++ tmpBuf[8 * 2 + i] = p[i * 8 + 2]; ++ tmpBuf[8 * 3 + i] = p[i * 8 + 3]; ++ tmpBuf[8 * 4 + i] = p[i * 8 + 4]; ++ tmpBuf[8 * 5 + i] = p[i * 8 + 5]; ++ tmpBuf[8 * 6 + i] = p[i * 8 + 6]; ++ tmpBuf[8 * 7 + i] = p[i * 8 + 7]; ++ } ++ memcpy(p, tmpBuf, 8 * 8 * sizeof(u8)); ++ } ++ //sizeId == 2 ++ for (matrixId = 0; matrixId < 6; matrixId++) { ++ p = pScalingFactor_out->scalingfactor0 + 6 * 16 + 6 * 64 + matrixId * 64; ++ ++ for (i = 0; i < 8; i++) { ++ tmpBuf[8 * 0 + i] = p[i * 8 + 0]; ++ tmpBuf[8 * 1 + i] = p[i * 8 + 1]; ++ tmpBuf[8 * 2 + i] = p[i * 8 + 2]; ++ tmpBuf[8 * 3 + i] = p[i * 8 + 3]; ++ tmpBuf[8 * 4 + i] = p[i * 8 + 4]; ++ tmpBuf[8 * 5 + i] = p[i * 8 + 5]; ++ tmpBuf[8 * 6 + i] = p[i * 8 + 6]; ++ tmpBuf[8 * 7 + i] = p[i * 8 + 7]; ++ } ++ memcpy(p, tmpBuf, 8 * 8 * sizeof(u8)); ++ } ++ //sizeId == 3 ++ for (matrixId = 0; matrixId < 6; matrixId++) { ++ p = pScalingFactor_out->scalingfactor0 + 6 * 16 + 6 * 64 + 6 * 64 + matrixId * 64; ++ ++ for (i = 0; i < 8; i++) { ++ tmpBuf[8 * 0 + i] = p[i * 8 + 0]; ++ tmpBuf[8 * 1 + i] = p[i * 8 + 1]; ++ tmpBuf[8 * 2 + i] = p[i * 8 + 2]; ++ tmpBuf[8 * 3 + i] = p[i * 8 + 3]; ++ tmpBuf[8 * 4 + i] = p[i * 8 + 4]; ++ tmpBuf[8 * 5 + i] = p[i * 8 + 5]; ++ tmpBuf[8 * 6 + i] = p[i * 8 + 6]; ++ tmpBuf[8 * 7 + i] = p[i * 8 + 7]; ++ } ++ memcpy(p, tmpBuf, 8 * 8 * sizeof(u8)); ++ } ++ ++ //sizeId == 0 ++ for (matrixId = 0; matrixId < 6; matrixId++) { ++ p = pScalingFactor_out->scalingfactor1 + matrixId * 16; ++ ++ for (i = 0; i < 4; i++) { ++ tmpBuf[4 * 0 + i] = p[i * 4 + 0]; ++ tmpBuf[4 * 1 + i] = p[i * 4 + 1]; ++ tmpBuf[4 * 2 + i] = p[i * 4 + 2]; ++ tmpBuf[4 * 3 + i] = p[i * 4 + 3]; ++ } ++ memcpy(p, tmpBuf, 4 * 4 * sizeof(u8)); ++ } ++} ++ ++static const u8 rkvdec_hevc_cabac_table[RKV_CABAC_TABLE_SIZE] = { ++ 0x07, 0x0f, 0x48, 0x58, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x0f, 0x40, 0x40, 0x40, 0x0f, 0x68, ++ 0x48, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x40, 0x40, 0x68, ++ 0x58, 0x60, 0x40, 0x1f, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x48, 0x48, 0x60, 0x60, 0x50, 0x58, ++ 0x50, 0x07, 0x58, 0x68, 0x50, 0x58, 0x68, 0x68, 0x68, 0x68, 0x68, 0x50, 0x48, 0x68, 0x60, 0x60, ++ 0x50, 0x58, 0x50, 0x07, 0x58, 0x68, 0x50, 0x58, 0x68, 0x68, 0x68, 0x68, 0x68, 0x50, 0x48, 0x68, ++ 0x48, 0x48, 0x1f, 0x58, 0x68, 0x68, 0x58, 0x60, 0x60, 0x60, 0x50, 0x50, 0x50, 0x48, 0x58, 0x58, ++ 0x37, 0x07, 0x58, 0x48, 0x58, 0x58, 0x37, 0x07, 0x58, 0x48, 0x58, 0x58, 0x37, 0x07, 0x58, 0x50, ++ 0x48, 0x1f, 0x1f, 0x0f, 0x0f, 0x0f, 0x0f, 0x07, 0x0f, 0x48, 0x68, 0x0f, 0x48, 0x68, 0x40, 0x40, ++ 0x50, 0x50, 0x07, 0x40, 0x50, 0x0f, 0x40, 0x48, 0x07, 0x40, 0x27, 0x50, 0x48, 0x48, 0x40, 0x0f, ++ 0x50, 0x37, 0x1f, 0x1f, 0x50, 0x37, 0x40, 0x27, 0x40, 0x07, 0x0f, 0x17, 0x0f, 0x0f, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x0f, 0x47, 0x57, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x0f, 0x40, 0x40, 0x40, 0x0f, 0x66, ++ 0x47, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x00, 0x00, 0x67, ++ 0x57, 0x5e, 0x00, 0x1f, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x47, 0x47, 0x5f, 0x5f, 0x4f, 0x57, ++ 0x4f, 0x07, 0x57, 0x67, 0x4f, 0x57, 0x67, 0x67, 0x67, 0x67, 0x66, 0x4f, 0x47, 0x66, 0x5f, 0x5f, ++ 0x4f, 0x57, 0x4f, 0x07, 0x57, 0x67, 0x4f, 0x57, 0x67, 0x67, 0x67, 0x67, 0x66, 0x4f, 0x47, 0x66, ++ 0x46, 0x48, 0x20, 0x57, 0x67, 0x67, 0x57, 0x5f, 0x5f, 0x5e, 0x4f, 0x4f, 0x4f, 0x47, 0x57, 0x57, ++ 0x37, 0x07, 0x57, 0x47, 0x57, 0x57, 0x37, 0x07, 0x57, 0x47, 0x57, 0x57, 0x37, 0x07, 0x57, 0x4f, ++ 0x47, 0x1f, 0x1f, 0x0f, 0x10, 0x0f, 0x10, 0x07, 0x10, 0x47, 0x67, 0x10, 0x47, 0x67, 0x40, 0x40, ++ 0x4f, 0x4e, 0x08, 0x00, 0x4f, 0x0f, 0x00, 0x47, 0x07, 0x01, 0x27, 0x4e, 0x47, 0x47, 0x00, 0x0f, ++ 0x4f, 0x37, 0x1f, 0x1f, 0x4f, 0x36, 0x00, 0x27, 0x00, 0x07, 0x10, 0x17, 0x0f, 0x0f, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x0e, 0x47, 0x57, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x0e, 0x40, 0x40, 0x40, 0x0e, 0x64, ++ 0x47, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x00, 0x00, 0x66, ++ 0x57, 0x5d, 0x00, 0x1e, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x47, 0x47, 0x5e, 0x5e, 0x4e, 0x56, ++ 0x4f, 0x07, 0x56, 0x66, 0x4f, 0x56, 0x66, 0x67, 0x66, 0x66, 0x64, 0x4e, 0x46, 0x64, 0x5e, 0x5e, ++ 0x4e, 0x56, 0x4f, 0x07, 0x56, 0x66, 0x4f, 0x56, 0x66, 0x67, 0x66, 0x66, 0x64, 0x4e, 0x46, 0x64, ++ 0x45, 0x48, 0x20, 0x57, 0x66, 0x66, 0x56, 0x5e, 0x5e, 0x5d, 0x4e, 0x4e, 0x4e, 0x46, 0x56, 0x57, ++ 0x36, 0x07, 0x56, 0x46, 0x56, 0x57, 0x36, 0x07, 0x56, 0x46, 0x56, 0x57, 0x36, 0x07, 0x56, 0x4f, ++ 0x47, 0x1e, 0x1e, 0x0f, 0x10, 0x0f, 0x10, 0x07, 0x10, 0x47, 0x66, 0x10, 0x47, 0x66, 0x40, 0x40, ++ 0x4f, 0x4d, 0x08, 0x00, 0x4f, 0x0f, 0x00, 0x47, 0x07, 0x03, 0x27, 0x4d, 0x47, 0x46, 0x01, 0x0f, ++ 0x4f, 0x36, 0x1f, 0x1e, 0x4f, 0x34, 0x01, 0x26, 0x00, 0x07, 0x10, 0x17, 0x0f, 0x0f, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x0d, 0x47, 0x57, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x0e, 0x40, 0x40, 0x40, 0x0e, 0x62, ++ 0x47, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x00, 0x00, 0x65, ++ 0x57, 0x5c, 0x00, 0x1e, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x47, 0x47, 0x5d, 0x5d, 0x4e, 0x56, ++ 0x4f, 0x07, 0x56, 0x66, 0x4f, 0x55, 0x65, 0x67, 0x66, 0x65, 0x63, 0x4d, 0x46, 0x62, 0x5d, 0x5d, ++ 0x4e, 0x56, 0x4f, 0x07, 0x56, 0x66, 0x4f, 0x55, 0x65, 0x67, 0x66, 0x65, 0x63, 0x4d, 0x46, 0x62, ++ 0x44, 0x48, 0x20, 0x57, 0x65, 0x65, 0x56, 0x5d, 0x5d, 0x5c, 0x4e, 0x4d, 0x4e, 0x45, 0x56, 0x57, ++ 0x36, 0x07, 0x56, 0x45, 0x56, 0x57, 0x36, 0x07, 0x56, 0x45, 0x56, 0x57, 0x36, 0x07, 0x56, 0x4f, ++ 0x47, 0x1e, 0x1e, 0x0f, 0x10, 0x0f, 0x10, 0x07, 0x10, 0x47, 0x65, 0x10, 0x47, 0x65, 0x40, 0x40, ++ 0x4f, 0x4c, 0x08, 0x00, 0x4f, 0x0f, 0x00, 0x47, 0x07, 0x04, 0x27, 0x4c, 0x47, 0x45, 0x01, 0x0f, ++ 0x4f, 0x36, 0x1f, 0x1e, 0x4f, 0x33, 0x01, 0x25, 0x00, 0x07, 0x10, 0x17, 0x0f, 0x0f, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x0c, 0x46, 0x56, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x0d, 0x40, 0x40, 0x40, 0x0d, 0x60, ++ 0x46, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x01, 0x01, 0x64, ++ 0x56, 0x5b, 0x01, 0x1d, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x46, 0x46, 0x5c, 0x5c, 0x4d, 0x55, ++ 0x4e, 0x07, 0x55, 0x65, 0x4e, 0x54, 0x64, 0x66, 0x65, 0x64, 0x61, 0x4c, 0x45, 0x60, 0x5c, 0x5c, ++ 0x4d, 0x55, 0x4e, 0x07, 0x55, 0x65, 0x4e, 0x54, 0x64, 0x66, 0x65, 0x64, 0x61, 0x4c, 0x45, 0x60, ++ 0x43, 0x49, 0x21, 0x56, 0x64, 0x64, 0x55, 0x5c, 0x5c, 0x5b, 0x4d, 0x4c, 0x4d, 0x44, 0x55, 0x56, ++ 0x35, 0x07, 0x55, 0x44, 0x55, 0x56, 0x35, 0x07, 0x55, 0x44, 0x55, 0x56, 0x35, 0x07, 0x55, 0x4e, ++ 0x46, 0x1d, 0x1d, 0x0f, 0x11, 0x0f, 0x11, 0x07, 0x11, 0x46, 0x64, 0x11, 0x46, 0x64, 0x40, 0x40, ++ 0x4e, 0x4b, 0x09, 0x01, 0x4e, 0x0f, 0x01, 0x46, 0x07, 0x06, 0x27, 0x4b, 0x46, 0x44, 0x02, 0x0f, ++ 0x4e, 0x35, 0x1e, 0x1d, 0x4e, 0x31, 0x02, 0x24, 0x01, 0x07, 0x11, 0x16, 0x0f, 0x0f, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x0b, 0x46, 0x56, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x0c, 0x40, 0x40, 0x40, 0x0c, 0x5e, ++ 0x46, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x01, 0x01, 0x63, ++ 0x56, 0x59, 0x01, 0x1c, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x46, 0x46, 0x5b, 0x5b, 0x4c, 0x54, ++ 0x4e, 0x07, 0x54, 0x64, 0x4e, 0x53, 0x63, 0x66, 0x64, 0x63, 0x60, 0x4b, 0x44, 0x5e, 0x5b, 0x5b, ++ 0x4c, 0x54, 0x4e, 0x07, 0x54, 0x64, 0x4e, 0x53, 0x63, 0x66, 0x64, 0x63, 0x60, 0x4b, 0x44, 0x5e, ++ 0x41, 0x49, 0x21, 0x56, 0x63, 0x63, 0x54, 0x5b, 0x5b, 0x59, 0x4c, 0x4b, 0x4c, 0x43, 0x54, 0x56, ++ 0x34, 0x07, 0x54, 0x43, 0x54, 0x56, 0x34, 0x07, 0x54, 0x43, 0x54, 0x56, 0x34, 0x07, 0x54, 0x4e, ++ 0x46, 0x1c, 0x1c, 0x0f, 0x11, 0x0f, 0x11, 0x07, 0x11, 0x46, 0x63, 0x11, 0x46, 0x63, 0x40, 0x40, ++ 0x4e, 0x49, 0x09, 0x01, 0x4e, 0x0f, 0x01, 0x46, 0x07, 0x07, 0x27, 0x49, 0x46, 0x43, 0x03, 0x0f, ++ 0x4e, 0x34, 0x1e, 0x1c, 0x4e, 0x30, 0x03, 0x23, 0x01, 0x07, 0x11, 0x16, 0x0f, 0x0f, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x0a, 0x46, 0x56, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x0c, 0x40, 0x40, 0x40, 0x0c, 0x5c, ++ 0x46, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x01, 0x01, 0x62, ++ 0x56, 0x58, 0x01, 0x1c, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x46, 0x46, 0x5a, 0x5a, 0x4c, 0x54, ++ 0x4e, 0x07, 0x54, 0x64, 0x4e, 0x52, 0x62, 0x66, 0x64, 0x62, 0x5e, 0x4a, 0x44, 0x5c, 0x5a, 0x5a, ++ 0x4c, 0x54, 0x4e, 0x07, 0x54, 0x64, 0x4e, 0x52, 0x62, 0x66, 0x64, 0x62, 0x5e, 0x4a, 0x44, 0x5c, ++ 0x40, 0x49, 0x21, 0x56, 0x62, 0x62, 0x54, 0x5a, 0x5a, 0x58, 0x4c, 0x4a, 0x4c, 0x42, 0x54, 0x56, ++ 0x34, 0x07, 0x54, 0x42, 0x54, 0x56, 0x34, 0x07, 0x54, 0x42, 0x54, 0x56, 0x34, 0x07, 0x54, 0x4e, ++ 0x46, 0x1c, 0x1c, 0x0f, 0x11, 0x0f, 0x11, 0x07, 0x11, 0x46, 0x62, 0x11, 0x46, 0x62, 0x40, 0x40, ++ 0x4e, 0x48, 0x09, 0x01, 0x4e, 0x0f, 0x01, 0x46, 0x07, 0x09, 0x27, 0x48, 0x46, 0x42, 0x03, 0x0f, ++ 0x4e, 0x34, 0x1e, 0x1c, 0x4e, 0x2e, 0x03, 0x22, 0x01, 0x07, 0x11, 0x16, 0x0f, 0x0f, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x09, 0x45, 0x55, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x0b, 0x40, 0x40, 0x40, 0x0b, 0x5a, ++ 0x45, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x02, 0x02, 0x61, ++ 0x55, 0x57, 0x02, 0x1b, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x45, 0x45, 0x59, 0x59, 0x4b, 0x53, ++ 0x4d, 0x07, 0x53, 0x63, 0x4d, 0x51, 0x61, 0x65, 0x63, 0x61, 0x5d, 0x49, 0x43, 0x5a, 0x59, 0x59, ++ 0x4b, 0x53, 0x4d, 0x07, 0x53, 0x63, 0x4d, 0x51, 0x61, 0x65, 0x63, 0x61, 0x5d, 0x49, 0x43, 0x5a, ++ 0x00, 0x4a, 0x22, 0x55, 0x61, 0x61, 0x53, 0x59, 0x59, 0x57, 0x4b, 0x49, 0x4b, 0x41, 0x53, 0x55, ++ 0x33, 0x07, 0x53, 0x41, 0x53, 0x55, 0x33, 0x07, 0x53, 0x41, 0x53, 0x55, 0x33, 0x07, 0x53, 0x4d, ++ 0x45, 0x1b, 0x1b, 0x0f, 0x12, 0x0f, 0x12, 0x07, 0x12, 0x45, 0x61, 0x12, 0x45, 0x61, 0x40, 0x40, ++ 0x4d, 0x47, 0x0a, 0x02, 0x4d, 0x0f, 0x02, 0x45, 0x07, 0x0a, 0x27, 0x47, 0x45, 0x41, 0x04, 0x0f, ++ 0x4d, 0x33, 0x1d, 0x1b, 0x4d, 0x2d, 0x04, 0x21, 0x02, 0x07, 0x12, 0x15, 0x0f, 0x0f, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x08, 0x45, 0x55, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x0a, 0x40, 0x40, 0x40, 0x0a, 0x59, ++ 0x45, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x02, 0x02, 0x60, ++ 0x55, 0x56, 0x02, 0x1a, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x45, 0x45, 0x58, 0x58, 0x4b, 0x53, ++ 0x4d, 0x07, 0x53, 0x63, 0x4d, 0x50, 0x60, 0x65, 0x63, 0x60, 0x5b, 0x48, 0x43, 0x59, 0x58, 0x58, ++ 0x4b, 0x53, 0x4d, 0x07, 0x53, 0x63, 0x4d, 0x50, 0x60, 0x65, 0x63, 0x60, 0x5b, 0x48, 0x43, 0x59, ++ 0x01, 0x4a, 0x22, 0x55, 0x60, 0x60, 0x53, 0x58, 0x58, 0x56, 0x4b, 0x48, 0x4b, 0x40, 0x53, 0x55, ++ 0x32, 0x07, 0x53, 0x40, 0x53, 0x55, 0x32, 0x07, 0x53, 0x40, 0x53, 0x55, 0x32, 0x07, 0x53, 0x4d, ++ 0x45, 0x1a, 0x1a, 0x0f, 0x12, 0x0f, 0x12, 0x07, 0x12, 0x45, 0x60, 0x12, 0x45, 0x60, 0x40, 0x40, ++ 0x4d, 0x46, 0x0a, 0x02, 0x4d, 0x0f, 0x02, 0x45, 0x07, 0x0c, 0x27, 0x46, 0x45, 0x40, 0x04, 0x0f, ++ 0x4d, 0x32, 0x1d, 0x1a, 0x4d, 0x2b, 0x04, 0x20, 0x02, 0x07, 0x12, 0x15, 0x0f, 0x0f, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x07, 0x45, 0x55, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x0a, 0x40, 0x40, 0x40, 0x0a, 0x57, ++ 0x45, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x02, 0x02, 0x5f, ++ 0x55, 0x54, 0x02, 0x1a, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x45, 0x45, 0x57, 0x57, 0x4a, 0x52, ++ 0x4d, 0x07, 0x52, 0x62, 0x4d, 0x4f, 0x5f, 0x65, 0x62, 0x5f, 0x59, 0x47, 0x42, 0x57, 0x57, 0x57, ++ 0x4a, 0x52, 0x4d, 0x07, 0x52, 0x62, 0x4d, 0x4f, 0x5f, 0x65, 0x62, 0x5f, 0x59, 0x47, 0x42, 0x57, ++ 0x03, 0x4a, 0x22, 0x55, 0x5f, 0x5f, 0x52, 0x57, 0x57, 0x54, 0x4a, 0x47, 0x4a, 0x00, 0x52, 0x55, ++ 0x32, 0x07, 0x52, 0x00, 0x52, 0x55, 0x32, 0x07, 0x52, 0x00, 0x52, 0x55, 0x32, 0x07, 0x52, 0x4d, ++ 0x45, 0x1a, 0x1a, 0x0f, 0x12, 0x0f, 0x12, 0x07, 0x12, 0x45, 0x5f, 0x12, 0x45, 0x5f, 0x40, 0x40, ++ 0x4d, 0x44, 0x0a, 0x02, 0x4d, 0x0f, 0x02, 0x45, 0x07, 0x0e, 0x27, 0x44, 0x45, 0x00, 0x05, 0x0f, ++ 0x4d, 0x32, 0x1d, 0x1a, 0x4d, 0x29, 0x05, 0x1f, 0x02, 0x07, 0x12, 0x15, 0x0f, 0x0f, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x06, 0x44, 0x54, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x09, 0x40, 0x40, 0x40, 0x09, 0x55, ++ 0x44, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x03, 0x03, 0x5e, ++ 0x54, 0x53, 0x03, 0x19, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x44, 0x44, 0x56, 0x56, 0x49, 0x51, ++ 0x4c, 0x07, 0x51, 0x61, 0x4c, 0x4e, 0x5e, 0x64, 0x61, 0x5e, 0x58, 0x46, 0x41, 0x55, 0x56, 0x56, ++ 0x49, 0x51, 0x4c, 0x07, 0x51, 0x61, 0x4c, 0x4e, 0x5e, 0x64, 0x61, 0x5e, 0x58, 0x46, 0x41, 0x55, ++ 0x04, 0x4b, 0x23, 0x54, 0x5e, 0x5e, 0x51, 0x56, 0x56, 0x53, 0x49, 0x46, 0x49, 0x01, 0x51, 0x54, ++ 0x31, 0x07, 0x51, 0x01, 0x51, 0x54, 0x31, 0x07, 0x51, 0x01, 0x51, 0x54, 0x31, 0x07, 0x51, 0x4c, ++ 0x44, 0x19, 0x19, 0x0f, 0x13, 0x0f, 0x13, 0x07, 0x13, 0x44, 0x5e, 0x13, 0x44, 0x5e, 0x40, 0x40, ++ 0x4c, 0x43, 0x0b, 0x03, 0x4c, 0x0f, 0x03, 0x44, 0x07, 0x0f, 0x27, 0x43, 0x44, 0x01, 0x06, 0x0f, ++ 0x4c, 0x31, 0x1c, 0x19, 0x4c, 0x28, 0x06, 0x1e, 0x03, 0x07, 0x13, 0x14, 0x0f, 0x0f, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x05, 0x44, 0x54, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x09, 0x40, 0x40, 0x40, 0x09, 0x53, ++ 0x44, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x03, 0x03, 0x5d, ++ 0x54, 0x52, 0x03, 0x19, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x44, 0x44, 0x55, 0x55, 0x49, 0x51, ++ 0x4c, 0x07, 0x51, 0x61, 0x4c, 0x4d, 0x5d, 0x64, 0x61, 0x5d, 0x56, 0x45, 0x41, 0x53, 0x55, 0x55, ++ 0x49, 0x51, 0x4c, 0x07, 0x51, 0x61, 0x4c, 0x4d, 0x5d, 0x64, 0x61, 0x5d, 0x56, 0x45, 0x41, 0x53, ++ 0x05, 0x4b, 0x23, 0x54, 0x5d, 0x5d, 0x51, 0x55, 0x55, 0x52, 0x49, 0x45, 0x49, 0x02, 0x51, 0x54, ++ 0x31, 0x07, 0x51, 0x02, 0x51, 0x54, 0x31, 0x07, 0x51, 0x02, 0x51, 0x54, 0x31, 0x07, 0x51, 0x4c, ++ 0x44, 0x19, 0x19, 0x0f, 0x13, 0x0f, 0x13, 0x07, 0x13, 0x44, 0x5d, 0x13, 0x44, 0x5d, 0x40, 0x40, ++ 0x4c, 0x42, 0x0b, 0x03, 0x4c, 0x0f, 0x03, 0x44, 0x07, 0x11, 0x27, 0x42, 0x44, 0x02, 0x06, 0x0f, ++ 0x4c, 0x31, 0x1c, 0x19, 0x4c, 0x26, 0x06, 0x1d, 0x03, 0x07, 0x13, 0x14, 0x0f, 0x0f, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x04, 0x44, 0x54, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x08, 0x40, 0x40, 0x40, 0x08, 0x51, ++ 0x44, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x03, 0x03, 0x5c, ++ 0x54, 0x51, 0x03, 0x18, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x44, 0x44, 0x54, 0x54, 0x48, 0x50, ++ 0x4c, 0x07, 0x50, 0x60, 0x4c, 0x4c, 0x5c, 0x64, 0x60, 0x5c, 0x55, 0x44, 0x40, 0x51, 0x54, 0x54, ++ 0x48, 0x50, 0x4c, 0x07, 0x50, 0x60, 0x4c, 0x4c, 0x5c, 0x64, 0x60, 0x5c, 0x55, 0x44, 0x40, 0x51, ++ 0x06, 0x4b, 0x23, 0x54, 0x5c, 0x5c, 0x50, 0x54, 0x54, 0x51, 0x48, 0x44, 0x48, 0x03, 0x50, 0x54, ++ 0x30, 0x07, 0x50, 0x03, 0x50, 0x54, 0x30, 0x07, 0x50, 0x03, 0x50, 0x54, 0x30, 0x07, 0x50, 0x4c, ++ 0x44, 0x18, 0x18, 0x0f, 0x13, 0x0f, 0x13, 0x07, 0x13, 0x44, 0x5c, 0x13, 0x44, 0x5c, 0x40, 0x40, ++ 0x4c, 0x41, 0x0b, 0x03, 0x4c, 0x0f, 0x03, 0x44, 0x07, 0x12, 0x27, 0x41, 0x44, 0x03, 0x07, 0x0f, ++ 0x4c, 0x30, 0x1c, 0x18, 0x4c, 0x25, 0x07, 0x1c, 0x03, 0x07, 0x13, 0x14, 0x0f, 0x0f, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x03, 0x43, 0x53, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x40, 0x40, 0x40, 0x07, 0x4f, ++ 0x43, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x04, 0x04, 0x5b, ++ 0x53, 0x4f, 0x04, 0x17, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x43, 0x43, 0x53, 0x53, 0x47, 0x4f, ++ 0x4b, 0x07, 0x4f, 0x5f, 0x4b, 0x4b, 0x5b, 0x63, 0x5f, 0x5b, 0x53, 0x43, 0x00, 0x4f, 0x53, 0x53, ++ 0x47, 0x4f, 0x4b, 0x07, 0x4f, 0x5f, 0x4b, 0x4b, 0x5b, 0x63, 0x5f, 0x5b, 0x53, 0x43, 0x00, 0x4f, ++ 0x08, 0x4c, 0x24, 0x53, 0x5b, 0x5b, 0x4f, 0x53, 0x53, 0x4f, 0x47, 0x43, 0x47, 0x04, 0x4f, 0x53, ++ 0x2f, 0x07, 0x4f, 0x04, 0x4f, 0x53, 0x2f, 0x07, 0x4f, 0x04, 0x4f, 0x53, 0x2f, 0x07, 0x4f, 0x4b, ++ 0x43, 0x17, 0x17, 0x0f, 0x14, 0x0f, 0x14, 0x07, 0x14, 0x43, 0x5b, 0x14, 0x43, 0x5b, 0x40, 0x40, ++ 0x4b, 0x00, 0x0c, 0x04, 0x4b, 0x0f, 0x04, 0x43, 0x07, 0x14, 0x27, 0x00, 0x43, 0x04, 0x08, 0x0f, ++ 0x4b, 0x2f, 0x1b, 0x17, 0x4b, 0x23, 0x08, 0x1b, 0x04, 0x07, 0x14, 0x13, 0x0f, 0x0f, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x02, 0x43, 0x53, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x40, 0x40, 0x40, 0x07, 0x4d, ++ 0x43, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x04, 0x04, 0x5a, ++ 0x53, 0x4e, 0x04, 0x17, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x43, 0x43, 0x52, 0x52, 0x47, 0x4f, ++ 0x4b, 0x07, 0x4f, 0x5f, 0x4b, 0x4a, 0x5a, 0x63, 0x5f, 0x5a, 0x52, 0x42, 0x00, 0x4d, 0x52, 0x52, ++ 0x47, 0x4f, 0x4b, 0x07, 0x4f, 0x5f, 0x4b, 0x4a, 0x5a, 0x63, 0x5f, 0x5a, 0x52, 0x42, 0x00, 0x4d, ++ 0x09, 0x4c, 0x24, 0x53, 0x5a, 0x5a, 0x4f, 0x52, 0x52, 0x4e, 0x47, 0x42, 0x47, 0x05, 0x4f, 0x53, ++ 0x2f, 0x07, 0x4f, 0x05, 0x4f, 0x53, 0x2f, 0x07, 0x4f, 0x05, 0x4f, 0x53, 0x2f, 0x07, 0x4f, 0x4b, ++ 0x43, 0x17, 0x17, 0x0f, 0x14, 0x0f, 0x14, 0x07, 0x14, 0x43, 0x5a, 0x14, 0x43, 0x5a, 0x40, 0x40, ++ 0x4b, 0x01, 0x0c, 0x04, 0x4b, 0x0f, 0x04, 0x43, 0x07, 0x15, 0x27, 0x01, 0x43, 0x05, 0x08, 0x0f, ++ 0x4b, 0x2f, 0x1b, 0x17, 0x4b, 0x22, 0x08, 0x1a, 0x04, 0x07, 0x14, 0x13, 0x0f, 0x0f, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x01, 0x43, 0x53, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x06, 0x40, 0x40, 0x40, 0x06, 0x4b, ++ 0x43, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x04, 0x04, 0x59, ++ 0x53, 0x4d, 0x04, 0x16, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x43, 0x43, 0x51, 0x51, 0x46, 0x4e, ++ 0x4b, 0x07, 0x4e, 0x5e, 0x4b, 0x49, 0x59, 0x63, 0x5e, 0x59, 0x50, 0x41, 0x01, 0x4b, 0x51, 0x51, ++ 0x46, 0x4e, 0x4b, 0x07, 0x4e, 0x5e, 0x4b, 0x49, 0x59, 0x63, 0x5e, 0x59, 0x50, 0x41, 0x01, 0x4b, ++ 0x0a, 0x4c, 0x24, 0x53, 0x59, 0x59, 0x4e, 0x51, 0x51, 0x4d, 0x46, 0x41, 0x46, 0x06, 0x4e, 0x53, ++ 0x2e, 0x07, 0x4e, 0x06, 0x4e, 0x53, 0x2e, 0x07, 0x4e, 0x06, 0x4e, 0x53, 0x2e, 0x07, 0x4e, 0x4b, ++ 0x43, 0x16, 0x16, 0x0f, 0x14, 0x0f, 0x14, 0x07, 0x14, 0x43, 0x59, 0x14, 0x43, 0x59, 0x40, 0x40, ++ 0x4b, 0x02, 0x0c, 0x04, 0x4b, 0x0f, 0x04, 0x43, 0x07, 0x17, 0x27, 0x02, 0x43, 0x06, 0x09, 0x0f, ++ 0x4b, 0x2e, 0x1b, 0x16, 0x4b, 0x20, 0x09, 0x19, 0x04, 0x07, 0x14, 0x13, 0x0f, 0x0f, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x00, 0x43, 0x53, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x05, 0x40, 0x40, 0x40, 0x05, 0x4a, ++ 0x43, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x04, 0x04, 0x59, ++ 0x53, 0x4c, 0x04, 0x15, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x43, 0x43, 0x51, 0x51, 0x46, 0x4e, ++ 0x4b, 0x07, 0x4e, 0x5e, 0x4b, 0x49, 0x59, 0x63, 0x5e, 0x59, 0x4f, 0x41, 0x01, 0x4a, 0x51, 0x51, ++ 0x46, 0x4e, 0x4b, 0x07, 0x4e, 0x5e, 0x4b, 0x49, 0x59, 0x63, 0x5e, 0x59, 0x4f, 0x41, 0x01, 0x4a, ++ 0x0b, 0x4d, 0x24, 0x53, 0x59, 0x59, 0x4e, 0x51, 0x51, 0x4c, 0x46, 0x41, 0x46, 0x06, 0x4e, 0x53, ++ 0x2d, 0x07, 0x4e, 0x06, 0x4e, 0x53, 0x2d, 0x07, 0x4e, 0x06, 0x4e, 0x53, 0x2d, 0x07, 0x4e, 0x4b, ++ 0x43, 0x15, 0x15, 0x0f, 0x14, 0x0f, 0x14, 0x07, 0x14, 0x43, 0x59, 0x14, 0x43, 0x59, 0x40, 0x40, ++ 0x4b, 0x03, 0x0c, 0x04, 0x4b, 0x0f, 0x04, 0x43, 0x07, 0x18, 0x27, 0x03, 0x43, 0x06, 0x09, 0x0f, ++ 0x4b, 0x2d, 0x1a, 0x15, 0x4b, 0x1e, 0x09, 0x18, 0x04, 0x07, 0x14, 0x12, 0x0f, 0x0f, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x00, 0x42, 0x52, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x05, 0x40, 0x40, 0x40, 0x05, 0x48, ++ 0x42, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x05, 0x05, 0x58, ++ 0x52, 0x4a, 0x05, 0x15, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x42, 0x42, 0x50, 0x50, 0x45, 0x4d, ++ 0x4a, 0x07, 0x4d, 0x5d, 0x4a, 0x48, 0x58, 0x62, 0x5d, 0x58, 0x4d, 0x40, 0x02, 0x48, 0x50, 0x50, ++ 0x45, 0x4d, 0x4a, 0x07, 0x4d, 0x5d, 0x4a, 0x48, 0x58, 0x62, 0x5d, 0x58, 0x4d, 0x40, 0x02, 0x48, ++ 0x0d, 0x4d, 0x25, 0x52, 0x58, 0x58, 0x4d, 0x50, 0x50, 0x4a, 0x45, 0x40, 0x45, 0x07, 0x4d, 0x52, ++ 0x2d, 0x07, 0x4d, 0x07, 0x4d, 0x52, 0x2d, 0x07, 0x4d, 0x07, 0x4d, 0x52, 0x2d, 0x07, 0x4d, 0x4a, ++ 0x42, 0x15, 0x15, 0x0f, 0x15, 0x0f, 0x15, 0x07, 0x15, 0x42, 0x58, 0x15, 0x42, 0x58, 0x40, 0x40, ++ 0x4a, 0x05, 0x0d, 0x05, 0x4a, 0x0f, 0x05, 0x42, 0x07, 0x1a, 0x27, 0x05, 0x42, 0x07, 0x0a, 0x0f, ++ 0x4a, 0x2d, 0x1a, 0x15, 0x4a, 0x1d, 0x0a, 0x18, 0x05, 0x07, 0x15, 0x12, 0x0f, 0x0f, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x40, 0x42, 0x52, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x04, 0x40, 0x40, 0x40, 0x04, 0x46, ++ 0x42, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x05, 0x05, 0x57, ++ 0x52, 0x49, 0x05, 0x14, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x42, 0x42, 0x4f, 0x4f, 0x44, 0x4c, ++ 0x4a, 0x07, 0x4c, 0x5c, 0x4a, 0x47, 0x57, 0x62, 0x5c, 0x57, 0x4b, 0x00, 0x03, 0x46, 0x4f, 0x4f, ++ 0x44, 0x4c, 0x4a, 0x07, 0x4c, 0x5c, 0x4a, 0x47, 0x57, 0x62, 0x5c, 0x57, 0x4b, 0x00, 0x03, 0x46, ++ 0x0e, 0x4d, 0x25, 0x52, 0x57, 0x57, 0x4c, 0x4f, 0x4f, 0x49, 0x44, 0x00, 0x44, 0x08, 0x4c, 0x52, ++ 0x2c, 0x07, 0x4c, 0x08, 0x4c, 0x52, 0x2c, 0x07, 0x4c, 0x08, 0x4c, 0x52, 0x2c, 0x07, 0x4c, 0x4a, ++ 0x42, 0x14, 0x14, 0x0f, 0x15, 0x0f, 0x15, 0x07, 0x15, 0x42, 0x57, 0x15, 0x42, 0x57, 0x40, 0x40, ++ 0x4a, 0x06, 0x0d, 0x05, 0x4a, 0x0f, 0x05, 0x42, 0x07, 0x1c, 0x27, 0x06, 0x42, 0x08, 0x0b, 0x0f, ++ 0x4a, 0x2c, 0x1a, 0x14, 0x4a, 0x1b, 0x0b, 0x17, 0x05, 0x07, 0x15, 0x12, 0x0f, 0x0f, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x41, 0x42, 0x52, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x04, 0x40, 0x40, 0x40, 0x04, 0x44, ++ 0x42, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x05, 0x05, 0x56, ++ 0x52, 0x48, 0x05, 0x14, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x42, 0x42, 0x4e, 0x4e, 0x44, 0x4c, ++ 0x4a, 0x07, 0x4c, 0x5c, 0x4a, 0x46, 0x56, 0x62, 0x5c, 0x56, 0x4a, 0x01, 0x03, 0x44, 0x4e, 0x4e, ++ 0x44, 0x4c, 0x4a, 0x07, 0x4c, 0x5c, 0x4a, 0x46, 0x56, 0x62, 0x5c, 0x56, 0x4a, 0x01, 0x03, 0x44, ++ 0x0f, 0x4d, 0x25, 0x52, 0x56, 0x56, 0x4c, 0x4e, 0x4e, 0x48, 0x44, 0x01, 0x44, 0x09, 0x4c, 0x52, ++ 0x2c, 0x07, 0x4c, 0x09, 0x4c, 0x52, 0x2c, 0x07, 0x4c, 0x09, 0x4c, 0x52, 0x2c, 0x07, 0x4c, 0x4a, ++ 0x42, 0x14, 0x14, 0x0f, 0x15, 0x0f, 0x15, 0x07, 0x15, 0x42, 0x56, 0x15, 0x42, 0x56, 0x40, 0x40, ++ 0x4a, 0x07, 0x0d, 0x05, 0x4a, 0x0f, 0x05, 0x42, 0x07, 0x1d, 0x27, 0x07, 0x42, 0x09, 0x0b, 0x0f, ++ 0x4a, 0x2c, 0x1a, 0x14, 0x4a, 0x1a, 0x0b, 0x16, 0x05, 0x07, 0x15, 0x12, 0x0f, 0x0f, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x42, 0x41, 0x51, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x03, 0x40, 0x40, 0x40, 0x03, 0x42, ++ 0x41, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x06, 0x06, 0x55, ++ 0x51, 0x47, 0x06, 0x13, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x41, 0x41, 0x4d, 0x4d, 0x43, 0x4b, ++ 0x49, 0x07, 0x4b, 0x5b, 0x49, 0x45, 0x55, 0x61, 0x5b, 0x55, 0x48, 0x02, 0x04, 0x42, 0x4d, 0x4d, ++ 0x43, 0x4b, 0x49, 0x07, 0x4b, 0x5b, 0x49, 0x45, 0x55, 0x61, 0x5b, 0x55, 0x48, 0x02, 0x04, 0x42, ++ 0x10, 0x4e, 0x26, 0x51, 0x55, 0x55, 0x4b, 0x4d, 0x4d, 0x47, 0x43, 0x02, 0x43, 0x0a, 0x4b, 0x51, ++ 0x2b, 0x07, 0x4b, 0x0a, 0x4b, 0x51, 0x2b, 0x07, 0x4b, 0x0a, 0x4b, 0x51, 0x2b, 0x07, 0x4b, 0x49, ++ 0x41, 0x13, 0x13, 0x0f, 0x16, 0x0f, 0x16, 0x07, 0x16, 0x41, 0x55, 0x16, 0x41, 0x55, 0x40, 0x40, ++ 0x49, 0x08, 0x0e, 0x06, 0x49, 0x0f, 0x06, 0x41, 0x07, 0x1f, 0x27, 0x08, 0x41, 0x0a, 0x0c, 0x0f, ++ 0x49, 0x2b, 0x19, 0x13, 0x49, 0x18, 0x0c, 0x15, 0x06, 0x07, 0x16, 0x11, 0x0f, 0x0f, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x43, 0x41, 0x51, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x02, 0x40, 0x40, 0x40, 0x02, 0x40, ++ 0x41, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x06, 0x06, 0x54, ++ 0x51, 0x45, 0x06, 0x12, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x41, 0x41, 0x4c, 0x4c, 0x42, 0x4a, ++ 0x49, 0x07, 0x4a, 0x5a, 0x49, 0x44, 0x54, 0x61, 0x5a, 0x54, 0x47, 0x03, 0x05, 0x40, 0x4c, 0x4c, ++ 0x42, 0x4a, 0x49, 0x07, 0x4a, 0x5a, 0x49, 0x44, 0x54, 0x61, 0x5a, 0x54, 0x47, 0x03, 0x05, 0x40, ++ 0x12, 0x4e, 0x26, 0x51, 0x54, 0x54, 0x4a, 0x4c, 0x4c, 0x45, 0x42, 0x03, 0x42, 0x0b, 0x4a, 0x51, ++ 0x2a, 0x07, 0x4a, 0x0b, 0x4a, 0x51, 0x2a, 0x07, 0x4a, 0x0b, 0x4a, 0x51, 0x2a, 0x07, 0x4a, 0x49, ++ 0x41, 0x12, 0x12, 0x0f, 0x16, 0x0f, 0x16, 0x07, 0x16, 0x41, 0x54, 0x16, 0x41, 0x54, 0x40, 0x40, ++ 0x49, 0x0a, 0x0e, 0x06, 0x49, 0x0f, 0x06, 0x41, 0x07, 0x20, 0x27, 0x0a, 0x41, 0x0b, 0x0d, 0x0f, ++ 0x49, 0x2a, 0x19, 0x12, 0x49, 0x17, 0x0d, 0x14, 0x06, 0x07, 0x16, 0x11, 0x0f, 0x0f, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x44, 0x41, 0x51, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x02, 0x40, 0x40, 0x40, 0x02, 0x01, ++ 0x41, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x06, 0x06, 0x53, ++ 0x51, 0x44, 0x06, 0x12, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x41, 0x41, 0x4b, 0x4b, 0x42, 0x4a, ++ 0x49, 0x07, 0x4a, 0x5a, 0x49, 0x43, 0x53, 0x61, 0x5a, 0x53, 0x45, 0x04, 0x05, 0x01, 0x4b, 0x4b, ++ 0x42, 0x4a, 0x49, 0x07, 0x4a, 0x5a, 0x49, 0x43, 0x53, 0x61, 0x5a, 0x53, 0x45, 0x04, 0x05, 0x01, ++ 0x13, 0x4e, 0x26, 0x51, 0x53, 0x53, 0x4a, 0x4b, 0x4b, 0x44, 0x42, 0x04, 0x42, 0x0c, 0x4a, 0x51, ++ 0x2a, 0x07, 0x4a, 0x0c, 0x4a, 0x51, 0x2a, 0x07, 0x4a, 0x0c, 0x4a, 0x51, 0x2a, 0x07, 0x4a, 0x49, ++ 0x41, 0x12, 0x12, 0x0f, 0x16, 0x0f, 0x16, 0x07, 0x16, 0x41, 0x53, 0x16, 0x41, 0x53, 0x40, 0x40, ++ 0x49, 0x0b, 0x0e, 0x06, 0x49, 0x0f, 0x06, 0x41, 0x07, 0x22, 0x27, 0x0b, 0x41, 0x0c, 0x0d, 0x0f, ++ 0x49, 0x2a, 0x19, 0x12, 0x49, 0x15, 0x0d, 0x13, 0x06, 0x07, 0x16, 0x11, 0x0f, 0x0f, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x45, 0x40, 0x50, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x01, 0x40, 0x40, 0x40, 0x01, 0x03, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x07, 0x07, 0x52, ++ 0x50, 0x43, 0x07, 0x11, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x4a, 0x4a, 0x41, 0x49, ++ 0x48, 0x07, 0x49, 0x59, 0x48, 0x42, 0x52, 0x60, 0x59, 0x52, 0x44, 0x05, 0x06, 0x03, 0x4a, 0x4a, ++ 0x41, 0x49, 0x48, 0x07, 0x49, 0x59, 0x48, 0x42, 0x52, 0x60, 0x59, 0x52, 0x44, 0x05, 0x06, 0x03, ++ 0x14, 0x4f, 0x27, 0x50, 0x52, 0x52, 0x49, 0x4a, 0x4a, 0x43, 0x41, 0x05, 0x41, 0x0d, 0x49, 0x50, ++ 0x29, 0x07, 0x49, 0x0d, 0x49, 0x50, 0x29, 0x07, 0x49, 0x0d, 0x49, 0x50, 0x29, 0x07, 0x49, 0x48, ++ 0x40, 0x11, 0x11, 0x0f, 0x17, 0x0f, 0x17, 0x07, 0x17, 0x40, 0x52, 0x17, 0x40, 0x52, 0x40, 0x40, ++ 0x48, 0x0c, 0x0f, 0x07, 0x48, 0x0f, 0x07, 0x40, 0x07, 0x23, 0x27, 0x0c, 0x40, 0x0d, 0x0e, 0x0f, ++ 0x48, 0x29, 0x18, 0x11, 0x48, 0x14, 0x0e, 0x12, 0x07, 0x07, 0x17, 0x10, 0x0f, 0x0f, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x46, 0x40, 0x50, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x40, 0x40, 0x40, 0x00, 0x04, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x07, 0x07, 0x51, ++ 0x50, 0x42, 0x07, 0x10, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x49, 0x49, 0x41, 0x49, ++ 0x48, 0x07, 0x49, 0x59, 0x48, 0x41, 0x51, 0x60, 0x59, 0x51, 0x42, 0x06, 0x06, 0x04, 0x49, 0x49, ++ 0x41, 0x49, 0x48, 0x07, 0x49, 0x59, 0x48, 0x41, 0x51, 0x60, 0x59, 0x51, 0x42, 0x06, 0x06, 0x04, ++ 0x15, 0x4f, 0x27, 0x50, 0x51, 0x51, 0x49, 0x49, 0x49, 0x42, 0x41, 0x06, 0x41, 0x0e, 0x49, 0x50, ++ 0x28, 0x07, 0x49, 0x0e, 0x49, 0x50, 0x28, 0x07, 0x49, 0x0e, 0x49, 0x50, 0x28, 0x07, 0x49, 0x48, ++ 0x40, 0x10, 0x10, 0x0f, 0x17, 0x0f, 0x17, 0x07, 0x17, 0x40, 0x51, 0x17, 0x40, 0x51, 0x40, 0x40, ++ 0x48, 0x0d, 0x0f, 0x07, 0x48, 0x0f, 0x07, 0x40, 0x07, 0x25, 0x27, 0x0d, 0x40, 0x0e, 0x0e, 0x0f, ++ 0x48, 0x28, 0x18, 0x10, 0x48, 0x12, 0x0e, 0x11, 0x07, 0x07, 0x17, 0x10, 0x0f, 0x0f, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x47, 0x40, 0x50, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x40, 0x40, 0x40, 0x00, 0x06, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x07, 0x07, 0x50, ++ 0x50, 0x40, 0x07, 0x10, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x48, 0x48, 0x40, 0x48, ++ 0x48, 0x07, 0x48, 0x58, 0x48, 0x40, 0x50, 0x60, 0x58, 0x50, 0x40, 0x07, 0x07, 0x06, 0x48, 0x48, ++ 0x40, 0x48, 0x48, 0x07, 0x48, 0x58, 0x48, 0x40, 0x50, 0x60, 0x58, 0x50, 0x40, 0x07, 0x07, 0x06, ++ 0x17, 0x4f, 0x27, 0x50, 0x50, 0x50, 0x48, 0x48, 0x48, 0x40, 0x40, 0x07, 0x40, 0x0f, 0x48, 0x50, ++ 0x28, 0x07, 0x48, 0x0f, 0x48, 0x50, 0x28, 0x07, 0x48, 0x0f, 0x48, 0x50, 0x28, 0x07, 0x48, 0x48, ++ 0x40, 0x10, 0x10, 0x0f, 0x17, 0x0f, 0x17, 0x07, 0x17, 0x40, 0x50, 0x17, 0x40, 0x50, 0x40, 0x40, ++ 0x48, 0x0f, 0x0f, 0x07, 0x48, 0x0f, 0x07, 0x40, 0x07, 0x27, 0x27, 0x0f, 0x40, 0x0f, 0x0f, 0x0f, ++ 0x48, 0x28, 0x18, 0x10, 0x48, 0x10, 0x0f, 0x10, 0x07, 0x07, 0x17, 0x10, 0x0f, 0x0f, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x48, 0x00, 0x4f, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x08, ++ 0x00, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x08, 0x08, 0x4f, ++ 0x4f, 0x00, 0x08, 0x0f, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x47, 0x47, 0x00, 0x47, ++ 0x47, 0x07, 0x47, 0x57, 0x47, 0x00, 0x4f, 0x5f, 0x57, 0x4f, 0x00, 0x08, 0x08, 0x08, 0x47, 0x47, ++ 0x00, 0x47, 0x47, 0x07, 0x47, 0x57, 0x47, 0x00, 0x4f, 0x5f, 0x57, 0x4f, 0x00, 0x08, 0x08, 0x08, ++ 0x18, 0x50, 0x28, 0x4f, 0x4f, 0x4f, 0x47, 0x47, 0x47, 0x00, 0x00, 0x08, 0x00, 0x10, 0x47, 0x4f, ++ 0x27, 0x07, 0x47, 0x10, 0x47, 0x4f, 0x27, 0x07, 0x47, 0x10, 0x47, 0x4f, 0x27, 0x07, 0x47, 0x47, ++ 0x00, 0x0f, 0x0f, 0x0f, 0x18, 0x0f, 0x18, 0x07, 0x18, 0x00, 0x4f, 0x18, 0x00, 0x4f, 0x40, 0x40, ++ 0x47, 0x10, 0x10, 0x08, 0x47, 0x0f, 0x08, 0x00, 0x07, 0x28, 0x27, 0x10, 0x00, 0x10, 0x10, 0x0f, ++ 0x47, 0x27, 0x17, 0x0f, 0x47, 0x0f, 0x10, 0x0f, 0x08, 0x07, 0x18, 0x0f, 0x0f, 0x0f, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x49, 0x00, 0x4f, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x0a, ++ 0x00, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x08, 0x08, 0x4e, ++ 0x4f, 0x01, 0x08, 0x0f, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x46, 0x46, 0x00, 0x47, ++ 0x47, 0x07, 0x47, 0x57, 0x47, 0x01, 0x4e, 0x5f, 0x57, 0x4e, 0x02, 0x09, 0x08, 0x0a, 0x46, 0x46, ++ 0x00, 0x47, 0x47, 0x07, 0x47, 0x57, 0x47, 0x01, 0x4e, 0x5f, 0x57, 0x4e, 0x02, 0x09, 0x08, 0x0a, ++ 0x19, 0x50, 0x28, 0x4f, 0x4e, 0x4e, 0x47, 0x46, 0x46, 0x01, 0x00, 0x09, 0x00, 0x11, 0x47, 0x4f, ++ 0x27, 0x07, 0x47, 0x11, 0x47, 0x4f, 0x27, 0x07, 0x47, 0x11, 0x47, 0x4f, 0x27, 0x07, 0x47, 0x47, ++ 0x00, 0x0f, 0x0f, 0x0f, 0x18, 0x0f, 0x18, 0x07, 0x18, 0x00, 0x4e, 0x18, 0x00, 0x4e, 0x40, 0x40, ++ 0x47, 0x11, 0x10, 0x08, 0x47, 0x0f, 0x08, 0x00, 0x07, 0x2a, 0x27, 0x11, 0x00, 0x11, 0x10, 0x0f, ++ 0x47, 0x27, 0x17, 0x0f, 0x47, 0x0d, 0x10, 0x0e, 0x08, 0x07, 0x18, 0x0f, 0x0f, 0x0f, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x4a, 0x00, 0x4f, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x41, 0x40, 0x40, 0x40, 0x41, 0x0c, ++ 0x00, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x08, 0x08, 0x4d, ++ 0x4f, 0x02, 0x08, 0x0e, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x45, 0x45, 0x01, 0x46, ++ 0x47, 0x07, 0x46, 0x56, 0x47, 0x02, 0x4d, 0x5f, 0x56, 0x4d, 0x03, 0x0a, 0x09, 0x0c, 0x45, 0x45, ++ 0x01, 0x46, 0x47, 0x07, 0x46, 0x56, 0x47, 0x02, 0x4d, 0x5f, 0x56, 0x4d, 0x03, 0x0a, 0x09, 0x0c, ++ 0x1a, 0x50, 0x28, 0x4f, 0x4d, 0x4d, 0x46, 0x45, 0x45, 0x02, 0x01, 0x0a, 0x01, 0x12, 0x46, 0x4f, ++ 0x26, 0x07, 0x46, 0x12, 0x46, 0x4f, 0x26, 0x07, 0x46, 0x12, 0x46, 0x4f, 0x26, 0x07, 0x46, 0x47, ++ 0x00, 0x0e, 0x0e, 0x0f, 0x18, 0x0f, 0x18, 0x07, 0x18, 0x00, 0x4d, 0x18, 0x00, 0x4d, 0x40, 0x40, ++ 0x47, 0x12, 0x10, 0x08, 0x47, 0x0f, 0x08, 0x00, 0x07, 0x2b, 0x27, 0x12, 0x00, 0x12, 0x11, 0x0f, ++ 0x47, 0x26, 0x17, 0x0e, 0x47, 0x0c, 0x11, 0x0d, 0x08, 0x07, 0x18, 0x0f, 0x0f, 0x0f, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x4b, 0x01, 0x4e, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x42, 0x40, 0x40, 0x40, 0x42, 0x0e, ++ 0x01, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x09, 0x09, 0x4c, ++ 0x4e, 0x04, 0x09, 0x0d, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x01, 0x01, 0x44, 0x44, 0x02, 0x45, ++ 0x46, 0x07, 0x45, 0x55, 0x46, 0x03, 0x4c, 0x5e, 0x55, 0x4c, 0x05, 0x0b, 0x0a, 0x0e, 0x44, 0x44, ++ 0x02, 0x45, 0x46, 0x07, 0x45, 0x55, 0x46, 0x03, 0x4c, 0x5e, 0x55, 0x4c, 0x05, 0x0b, 0x0a, 0x0e, ++ 0x1c, 0x51, 0x29, 0x4e, 0x4c, 0x4c, 0x45, 0x44, 0x44, 0x04, 0x02, 0x0b, 0x02, 0x13, 0x45, 0x4e, ++ 0x25, 0x07, 0x45, 0x13, 0x45, 0x4e, 0x25, 0x07, 0x45, 0x13, 0x45, 0x4e, 0x25, 0x07, 0x45, 0x46, ++ 0x01, 0x0d, 0x0d, 0x0f, 0x19, 0x0f, 0x19, 0x07, 0x19, 0x01, 0x4c, 0x19, 0x01, 0x4c, 0x40, 0x40, ++ 0x46, 0x14, 0x11, 0x09, 0x46, 0x0f, 0x09, 0x01, 0x07, 0x2d, 0x27, 0x14, 0x01, 0x13, 0x12, 0x0f, ++ 0x46, 0x25, 0x16, 0x0d, 0x46, 0x0a, 0x12, 0x0c, 0x09, 0x07, 0x19, 0x0e, 0x0f, 0x0f, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x4c, 0x01, 0x4e, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x42, 0x40, 0x40, 0x40, 0x42, 0x10, ++ 0x01, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x09, 0x09, 0x4b, ++ 0x4e, 0x05, 0x09, 0x0d, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x01, 0x01, 0x43, 0x43, 0x02, 0x45, ++ 0x46, 0x07, 0x45, 0x55, 0x46, 0x04, 0x4b, 0x5e, 0x55, 0x4b, 0x06, 0x0c, 0x0a, 0x10, 0x43, 0x43, ++ 0x02, 0x45, 0x46, 0x07, 0x45, 0x55, 0x46, 0x04, 0x4b, 0x5e, 0x55, 0x4b, 0x06, 0x0c, 0x0a, 0x10, ++ 0x1d, 0x51, 0x29, 0x4e, 0x4b, 0x4b, 0x45, 0x43, 0x43, 0x05, 0x02, 0x0c, 0x02, 0x14, 0x45, 0x4e, ++ 0x25, 0x07, 0x45, 0x14, 0x45, 0x4e, 0x25, 0x07, 0x45, 0x14, 0x45, 0x4e, 0x25, 0x07, 0x45, 0x46, ++ 0x01, 0x0d, 0x0d, 0x0f, 0x19, 0x0f, 0x19, 0x07, 0x19, 0x01, 0x4b, 0x19, 0x01, 0x4b, 0x40, 0x40, ++ 0x46, 0x15, 0x11, 0x09, 0x46, 0x0f, 0x09, 0x01, 0x07, 0x2e, 0x27, 0x15, 0x01, 0x14, 0x12, 0x0f, ++ 0x46, 0x25, 0x16, 0x0d, 0x46, 0x09, 0x12, 0x0b, 0x09, 0x07, 0x19, 0x0e, 0x0f, 0x0f, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x4d, 0x01, 0x4e, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x43, 0x40, 0x40, 0x40, 0x43, 0x12, ++ 0x01, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x09, 0x09, 0x4a, ++ 0x4e, 0x06, 0x09, 0x0c, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x01, 0x01, 0x42, 0x42, 0x03, 0x44, ++ 0x46, 0x07, 0x44, 0x54, 0x46, 0x05, 0x4a, 0x5e, 0x54, 0x4a, 0x08, 0x0d, 0x0b, 0x12, 0x42, 0x42, ++ 0x03, 0x44, 0x46, 0x07, 0x44, 0x54, 0x46, 0x05, 0x4a, 0x5e, 0x54, 0x4a, 0x08, 0x0d, 0x0b, 0x12, ++ 0x1e, 0x51, 0x29, 0x4e, 0x4a, 0x4a, 0x44, 0x42, 0x42, 0x06, 0x03, 0x0d, 0x03, 0x15, 0x44, 0x4e, ++ 0x24, 0x07, 0x44, 0x15, 0x44, 0x4e, 0x24, 0x07, 0x44, 0x15, 0x44, 0x4e, 0x24, 0x07, 0x44, 0x46, ++ 0x01, 0x0c, 0x0c, 0x0f, 0x19, 0x0f, 0x19, 0x07, 0x19, 0x01, 0x4a, 0x19, 0x01, 0x4a, 0x40, 0x40, ++ 0x46, 0x16, 0x11, 0x09, 0x46, 0x0f, 0x09, 0x01, 0x07, 0x30, 0x27, 0x16, 0x01, 0x15, 0x13, 0x0f, ++ 0x46, 0x24, 0x16, 0x0c, 0x46, 0x07, 0x13, 0x0a, 0x09, 0x07, 0x19, 0x0e, 0x0f, 0x0f, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x4e, 0x01, 0x4e, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x44, 0x40, 0x40, 0x40, 0x44, 0x13, ++ 0x01, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x09, 0x09, 0x4a, ++ 0x4e, 0x07, 0x09, 0x0b, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x01, 0x01, 0x42, 0x42, 0x03, 0x44, ++ 0x46, 0x07, 0x44, 0x54, 0x46, 0x05, 0x4a, 0x5e, 0x54, 0x4a, 0x09, 0x0d, 0x0b, 0x13, 0x42, 0x42, ++ 0x03, 0x44, 0x46, 0x07, 0x44, 0x54, 0x46, 0x05, 0x4a, 0x5e, 0x54, 0x4a, 0x09, 0x0d, 0x0b, 0x13, ++ 0x1f, 0x52, 0x29, 0x4e, 0x4a, 0x4a, 0x44, 0x42, 0x42, 0x07, 0x03, 0x0d, 0x03, 0x15, 0x44, 0x4e, ++ 0x23, 0x07, 0x44, 0x15, 0x44, 0x4e, 0x23, 0x07, 0x44, 0x15, 0x44, 0x4e, 0x23, 0x07, 0x44, 0x46, ++ 0x01, 0x0b, 0x0b, 0x0f, 0x19, 0x0f, 0x19, 0x07, 0x19, 0x01, 0x4a, 0x19, 0x01, 0x4a, 0x40, 0x40, ++ 0x46, 0x17, 0x11, 0x09, 0x46, 0x0f, 0x09, 0x01, 0x07, 0x31, 0x27, 0x17, 0x01, 0x15, 0x13, 0x0f, ++ 0x46, 0x23, 0x15, 0x0b, 0x46, 0x05, 0x13, 0x09, 0x09, 0x07, 0x19, 0x0d, 0x0f, 0x0f, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x4e, 0x02, 0x4d, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x44, 0x40, 0x40, 0x40, 0x44, 0x15, ++ 0x02, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x0a, 0x0a, 0x49, ++ 0x4d, 0x09, 0x0a, 0x0b, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x02, 0x02, 0x41, 0x41, 0x04, 0x43, ++ 0x45, 0x07, 0x43, 0x53, 0x45, 0x06, 0x49, 0x5d, 0x53, 0x49, 0x0b, 0x0e, 0x0c, 0x15, 0x41, 0x41, ++ 0x04, 0x43, 0x45, 0x07, 0x43, 0x53, 0x45, 0x06, 0x49, 0x5d, 0x53, 0x49, 0x0b, 0x0e, 0x0c, 0x15, ++ 0x21, 0x52, 0x2a, 0x4d, 0x49, 0x49, 0x43, 0x41, 0x41, 0x09, 0x04, 0x0e, 0x04, 0x16, 0x43, 0x4d, ++ 0x23, 0x07, 0x43, 0x16, 0x43, 0x4d, 0x23, 0x07, 0x43, 0x16, 0x43, 0x4d, 0x23, 0x07, 0x43, 0x45, ++ 0x02, 0x0b, 0x0b, 0x0f, 0x1a, 0x0f, 0x1a, 0x07, 0x1a, 0x02, 0x49, 0x1a, 0x02, 0x49, 0x40, 0x40, ++ 0x45, 0x19, 0x12, 0x0a, 0x45, 0x0f, 0x0a, 0x02, 0x07, 0x33, 0x27, 0x19, 0x02, 0x16, 0x14, 0x0f, ++ 0x45, 0x23, 0x15, 0x0b, 0x45, 0x04, 0x14, 0x09, 0x0a, 0x07, 0x1a, 0x0d, 0x0f, 0x0f, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x4f, 0x02, 0x4d, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x45, 0x40, 0x40, 0x40, 0x45, 0x17, ++ 0x02, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x0a, 0x0a, 0x48, ++ 0x4d, 0x0a, 0x0a, 0x0a, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x02, 0x02, 0x40, 0x40, 0x05, 0x42, ++ 0x45, 0x07, 0x42, 0x52, 0x45, 0x07, 0x48, 0x5d, 0x52, 0x48, 0x0d, 0x0f, 0x0d, 0x17, 0x40, 0x40, ++ 0x05, 0x42, 0x45, 0x07, 0x42, 0x52, 0x45, 0x07, 0x48, 0x5d, 0x52, 0x48, 0x0d, 0x0f, 0x0d, 0x17, ++ 0x22, 0x52, 0x2a, 0x4d, 0x48, 0x48, 0x42, 0x40, 0x40, 0x0a, 0x05, 0x0f, 0x05, 0x17, 0x42, 0x4d, ++ 0x22, 0x07, 0x42, 0x17, 0x42, 0x4d, 0x22, 0x07, 0x42, 0x17, 0x42, 0x4d, 0x22, 0x07, 0x42, 0x45, ++ 0x02, 0x0a, 0x0a, 0x0f, 0x1a, 0x0f, 0x1a, 0x07, 0x1a, 0x02, 0x48, 0x1a, 0x02, 0x48, 0x40, 0x40, ++ 0x45, 0x1a, 0x12, 0x0a, 0x45, 0x0f, 0x0a, 0x02, 0x07, 0x35, 0x27, 0x1a, 0x02, 0x17, 0x15, 0x0f, ++ 0x45, 0x22, 0x15, 0x0a, 0x45, 0x02, 0x15, 0x08, 0x0a, 0x07, 0x1a, 0x0d, 0x0f, 0x0f, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x50, 0x02, 0x4d, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x45, 0x40, 0x40, 0x40, 0x45, 0x19, ++ 0x02, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x0a, 0x0a, 0x47, ++ 0x4d, 0x0b, 0x0a, 0x0a, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x02, 0x02, 0x00, 0x00, 0x05, 0x42, ++ 0x45, 0x07, 0x42, 0x52, 0x45, 0x08, 0x47, 0x5d, 0x52, 0x47, 0x0e, 0x10, 0x0d, 0x19, 0x00, 0x00, ++ 0x05, 0x42, 0x45, 0x07, 0x42, 0x52, 0x45, 0x08, 0x47, 0x5d, 0x52, 0x47, 0x0e, 0x10, 0x0d, 0x19, ++ 0x23, 0x52, 0x2a, 0x4d, 0x47, 0x47, 0x42, 0x00, 0x00, 0x0b, 0x05, 0x10, 0x05, 0x18, 0x42, 0x4d, ++ 0x22, 0x07, 0x42, 0x18, 0x42, 0x4d, 0x22, 0x07, 0x42, 0x18, 0x42, 0x4d, 0x22, 0x07, 0x42, 0x45, ++ 0x02, 0x0a, 0x0a, 0x0f, 0x1a, 0x0f, 0x1a, 0x07, 0x1a, 0x02, 0x47, 0x1a, 0x02, 0x47, 0x40, 0x40, ++ 0x45, 0x1b, 0x12, 0x0a, 0x45, 0x0f, 0x0a, 0x02, 0x07, 0x36, 0x27, 0x1b, 0x02, 0x18, 0x15, 0x0f, ++ 0x45, 0x22, 0x15, 0x0a, 0x45, 0x01, 0x15, 0x07, 0x0a, 0x07, 0x1a, 0x0d, 0x0f, 0x0f, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x51, 0x03, 0x4c, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x46, 0x40, 0x40, 0x40, 0x46, 0x1b, ++ 0x03, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x0b, 0x0b, 0x46, ++ 0x4c, 0x0c, 0x0b, 0x09, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x03, 0x03, 0x01, 0x01, 0x06, 0x41, ++ 0x44, 0x07, 0x41, 0x51, 0x44, 0x09, 0x46, 0x5c, 0x51, 0x46, 0x10, 0x11, 0x0e, 0x1b, 0x01, 0x01, ++ 0x06, 0x41, 0x44, 0x07, 0x41, 0x51, 0x44, 0x09, 0x46, 0x5c, 0x51, 0x46, 0x10, 0x11, 0x0e, 0x1b, ++ 0x24, 0x53, 0x2b, 0x4c, 0x46, 0x46, 0x41, 0x01, 0x01, 0x0c, 0x06, 0x11, 0x06, 0x19, 0x41, 0x4c, ++ 0x21, 0x07, 0x41, 0x19, 0x41, 0x4c, 0x21, 0x07, 0x41, 0x19, 0x41, 0x4c, 0x21, 0x07, 0x41, 0x44, ++ 0x03, 0x09, 0x09, 0x0f, 0x1b, 0x0f, 0x1b, 0x07, 0x1b, 0x03, 0x46, 0x1b, 0x03, 0x46, 0x40, 0x40, ++ 0x44, 0x1c, 0x13, 0x0b, 0x44, 0x0f, 0x0b, 0x03, 0x07, 0x38, 0x27, 0x1c, 0x03, 0x19, 0x16, 0x0f, ++ 0x44, 0x21, 0x14, 0x09, 0x44, 0x40, 0x16, 0x06, 0x0b, 0x07, 0x1b, 0x0c, 0x0f, 0x0f, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x52, 0x03, 0x4c, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x47, 0x40, 0x40, 0x40, 0x47, 0x1d, ++ 0x03, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x0b, 0x0b, 0x45, ++ 0x4c, 0x0e, 0x0b, 0x08, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x03, 0x03, 0x02, 0x02, 0x07, 0x40, ++ 0x44, 0x07, 0x40, 0x50, 0x44, 0x0a, 0x45, 0x5c, 0x50, 0x45, 0x11, 0x12, 0x0f, 0x1d, 0x02, 0x02, ++ 0x07, 0x40, 0x44, 0x07, 0x40, 0x50, 0x44, 0x0a, 0x45, 0x5c, 0x50, 0x45, 0x11, 0x12, 0x0f, 0x1d, ++ 0x26, 0x53, 0x2b, 0x4c, 0x45, 0x45, 0x40, 0x02, 0x02, 0x0e, 0x07, 0x12, 0x07, 0x1a, 0x40, 0x4c, ++ 0x20, 0x07, 0x40, 0x1a, 0x40, 0x4c, 0x20, 0x07, 0x40, 0x1a, 0x40, 0x4c, 0x20, 0x07, 0x40, 0x44, ++ 0x03, 0x08, 0x08, 0x0f, 0x1b, 0x0f, 0x1b, 0x07, 0x1b, 0x03, 0x45, 0x1b, 0x03, 0x45, 0x40, 0x40, ++ 0x44, 0x1e, 0x13, 0x0b, 0x44, 0x0f, 0x0b, 0x03, 0x07, 0x39, 0x27, 0x1e, 0x03, 0x1a, 0x17, 0x0f, ++ 0x44, 0x20, 0x14, 0x08, 0x44, 0x41, 0x17, 0x05, 0x0b, 0x07, 0x1b, 0x0c, 0x0f, 0x0f, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x53, 0x03, 0x4c, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x47, 0x40, 0x40, 0x40, 0x47, 0x1f, ++ 0x03, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x0b, 0x0b, 0x44, ++ 0x4c, 0x0f, 0x0b, 0x08, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x03, 0x03, 0x03, 0x03, 0x07, 0x40, ++ 0x44, 0x07, 0x40, 0x50, 0x44, 0x0b, 0x44, 0x5c, 0x50, 0x44, 0x13, 0x13, 0x0f, 0x1f, 0x03, 0x03, ++ 0x07, 0x40, 0x44, 0x07, 0x40, 0x50, 0x44, 0x0b, 0x44, 0x5c, 0x50, 0x44, 0x13, 0x13, 0x0f, 0x1f, ++ 0x27, 0x53, 0x2b, 0x4c, 0x44, 0x44, 0x40, 0x03, 0x03, 0x0f, 0x07, 0x13, 0x07, 0x1b, 0x40, 0x4c, ++ 0x20, 0x07, 0x40, 0x1b, 0x40, 0x4c, 0x20, 0x07, 0x40, 0x1b, 0x40, 0x4c, 0x20, 0x07, 0x40, 0x44, ++ 0x03, 0x08, 0x08, 0x0f, 0x1b, 0x0f, 0x1b, 0x07, 0x1b, 0x03, 0x44, 0x1b, 0x03, 0x44, 0x40, 0x40, ++ 0x44, 0x1f, 0x13, 0x0b, 0x44, 0x0f, 0x0b, 0x03, 0x07, 0x3b, 0x27, 0x1f, 0x03, 0x1b, 0x17, 0x0f, ++ 0x44, 0x20, 0x14, 0x08, 0x44, 0x43, 0x17, 0x04, 0x0b, 0x07, 0x1b, 0x0c, 0x0f, 0x0f, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x54, 0x04, 0x4b, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x48, 0x40, 0x40, 0x40, 0x48, 0x21, ++ 0x04, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x0c, 0x0c, 0x43, ++ 0x4b, 0x10, 0x0c, 0x07, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x04, 0x04, 0x04, 0x04, 0x08, 0x00, ++ 0x43, 0x07, 0x00, 0x4f, 0x43, 0x0c, 0x43, 0x5b, 0x4f, 0x43, 0x14, 0x14, 0x10, 0x21, 0x04, 0x04, ++ 0x08, 0x00, 0x43, 0x07, 0x00, 0x4f, 0x43, 0x0c, 0x43, 0x5b, 0x4f, 0x43, 0x14, 0x14, 0x10, 0x21, ++ 0x28, 0x54, 0x2c, 0x4b, 0x43, 0x43, 0x00, 0x04, 0x04, 0x10, 0x08, 0x14, 0x08, 0x1c, 0x00, 0x4b, ++ 0x1f, 0x07, 0x00, 0x1c, 0x00, 0x4b, 0x1f, 0x07, 0x00, 0x1c, 0x00, 0x4b, 0x1f, 0x07, 0x00, 0x43, ++ 0x04, 0x07, 0x07, 0x0f, 0x1c, 0x0f, 0x1c, 0x07, 0x1c, 0x04, 0x43, 0x1c, 0x04, 0x43, 0x40, 0x40, ++ 0x43, 0x20, 0x14, 0x0c, 0x43, 0x0f, 0x0c, 0x04, 0x07, 0x3c, 0x27, 0x20, 0x04, 0x1c, 0x18, 0x0f, ++ 0x43, 0x1f, 0x13, 0x07, 0x43, 0x44, 0x18, 0x03, 0x0c, 0x07, 0x1c, 0x0b, 0x0f, 0x0f, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x55, 0x04, 0x4b, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x49, 0x40, 0x40, 0x40, 0x49, 0x22, ++ 0x04, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x0c, 0x0c, 0x42, ++ 0x4b, 0x11, 0x0c, 0x06, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x04, 0x04, 0x05, 0x05, 0x08, 0x00, ++ 0x43, 0x07, 0x00, 0x4f, 0x43, 0x0d, 0x42, 0x5b, 0x4f, 0x42, 0x16, 0x15, 0x10, 0x22, 0x05, 0x05, ++ 0x08, 0x00, 0x43, 0x07, 0x00, 0x4f, 0x43, 0x0d, 0x42, 0x5b, 0x4f, 0x42, 0x16, 0x15, 0x10, 0x22, ++ 0x29, 0x54, 0x2c, 0x4b, 0x42, 0x42, 0x00, 0x05, 0x05, 0x11, 0x08, 0x15, 0x08, 0x1d, 0x00, 0x4b, ++ 0x1e, 0x07, 0x00, 0x1d, 0x00, 0x4b, 0x1e, 0x07, 0x00, 0x1d, 0x00, 0x4b, 0x1e, 0x07, 0x00, 0x43, ++ 0x04, 0x06, 0x06, 0x0f, 0x1c, 0x0f, 0x1c, 0x07, 0x1c, 0x04, 0x42, 0x1c, 0x04, 0x42, 0x40, 0x40, ++ 0x43, 0x21, 0x14, 0x0c, 0x43, 0x0f, 0x0c, 0x04, 0x07, 0x3e, 0x27, 0x21, 0x04, 0x1d, 0x18, 0x0f, ++ 0x43, 0x1e, 0x13, 0x06, 0x43, 0x46, 0x18, 0x02, 0x0c, 0x07, 0x1c, 0x0b, 0x0f, 0x0f, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x56, 0x04, 0x4b, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x49, 0x40, 0x40, 0x40, 0x49, 0x24, ++ 0x04, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x0c, 0x0c, 0x41, ++ 0x4b, 0x13, 0x0c, 0x06, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x04, 0x04, 0x06, 0x06, 0x09, 0x01, ++ 0x43, 0x07, 0x01, 0x4e, 0x43, 0x0e, 0x41, 0x5b, 0x4e, 0x41, 0x18, 0x16, 0x11, 0x24, 0x06, 0x06, ++ 0x09, 0x01, 0x43, 0x07, 0x01, 0x4e, 0x43, 0x0e, 0x41, 0x5b, 0x4e, 0x41, 0x18, 0x16, 0x11, 0x24, ++ 0x2b, 0x54, 0x2c, 0x4b, 0x41, 0x41, 0x01, 0x06, 0x06, 0x13, 0x09, 0x16, 0x09, 0x1e, 0x01, 0x4b, ++ 0x1e, 0x07, 0x01, 0x1e, 0x01, 0x4b, 0x1e, 0x07, 0x01, 0x1e, 0x01, 0x4b, 0x1e, 0x07, 0x01, 0x43, ++ 0x04, 0x06, 0x06, 0x0f, 0x1c, 0x0f, 0x1c, 0x07, 0x1c, 0x04, 0x41, 0x1c, 0x04, 0x41, 0x40, 0x40, ++ 0x43, 0x23, 0x14, 0x0c, 0x43, 0x0f, 0x0c, 0x04, 0x07, 0x3e, 0x27, 0x23, 0x04, 0x1e, 0x19, 0x0f, ++ 0x43, 0x1e, 0x13, 0x06, 0x43, 0x48, 0x19, 0x01, 0x0c, 0x07, 0x1c, 0x0b, 0x0f, 0x0f, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x57, 0x05, 0x4a, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x4a, 0x40, 0x40, 0x40, 0x4a, 0x26, ++ 0x05, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x0d, 0x0d, 0x40, ++ 0x4a, 0x14, 0x0d, 0x05, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x05, 0x05, 0x07, 0x07, 0x0a, 0x02, ++ 0x42, 0x07, 0x02, 0x4d, 0x42, 0x0f, 0x40, 0x5a, 0x4d, 0x40, 0x19, 0x17, 0x12, 0x26, 0x07, 0x07, ++ 0x0a, 0x02, 0x42, 0x07, 0x02, 0x4d, 0x42, 0x0f, 0x40, 0x5a, 0x4d, 0x40, 0x19, 0x17, 0x12, 0x26, ++ 0x2c, 0x55, 0x2d, 0x4a, 0x40, 0x40, 0x02, 0x07, 0x07, 0x14, 0x0a, 0x17, 0x0a, 0x1f, 0x02, 0x4a, ++ 0x1d, 0x07, 0x02, 0x1f, 0x02, 0x4a, 0x1d, 0x07, 0x02, 0x1f, 0x02, 0x4a, 0x1d, 0x07, 0x02, 0x42, ++ 0x05, 0x05, 0x05, 0x0f, 0x1d, 0x0f, 0x1d, 0x07, 0x1d, 0x05, 0x40, 0x1d, 0x05, 0x40, 0x40, 0x40, ++ 0x42, 0x24, 0x15, 0x0d, 0x42, 0x0f, 0x0d, 0x05, 0x07, 0x3e, 0x27, 0x24, 0x05, 0x1f, 0x1a, 0x0f, ++ 0x42, 0x1d, 0x12, 0x05, 0x42, 0x49, 0x1a, 0x00, 0x0d, 0x07, 0x1d, 0x0a, 0x0f, 0x0f, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x58, 0x05, 0x4a, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x4a, 0x40, 0x40, 0x40, 0x4a, 0x28, ++ 0x05, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x0d, 0x0d, 0x00, ++ 0x4a, 0x15, 0x0d, 0x05, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x05, 0x05, 0x08, 0x08, 0x0a, 0x02, ++ 0x42, 0x07, 0x02, 0x4d, 0x42, 0x10, 0x00, 0x5a, 0x4d, 0x00, 0x1b, 0x18, 0x12, 0x28, 0x08, 0x08, ++ 0x0a, 0x02, 0x42, 0x07, 0x02, 0x4d, 0x42, 0x10, 0x00, 0x5a, 0x4d, 0x00, 0x1b, 0x18, 0x12, 0x28, ++ 0x2d, 0x55, 0x2d, 0x4a, 0x00, 0x00, 0x02, 0x08, 0x08, 0x15, 0x0a, 0x18, 0x0a, 0x20, 0x02, 0x4a, ++ 0x1d, 0x07, 0x02, 0x20, 0x02, 0x4a, 0x1d, 0x07, 0x02, 0x20, 0x02, 0x4a, 0x1d, 0x07, 0x02, 0x42, ++ 0x05, 0x05, 0x05, 0x0f, 0x1d, 0x0f, 0x1d, 0x07, 0x1d, 0x05, 0x00, 0x1d, 0x05, 0x00, 0x40, 0x40, ++ 0x42, 0x25, 0x15, 0x0d, 0x42, 0x0f, 0x0d, 0x05, 0x07, 0x3e, 0x27, 0x25, 0x05, 0x20, 0x1a, 0x0f, ++ 0x42, 0x1d, 0x12, 0x05, 0x42, 0x4b, 0x1a, 0x40, 0x0d, 0x07, 0x1d, 0x0a, 0x0f, 0x0f, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x59, 0x05, 0x4a, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x4b, 0x40, 0x40, 0x40, 0x4b, 0x2a, ++ 0x05, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x0d, 0x0d, 0x01, ++ 0x4a, 0x16, 0x0d, 0x04, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x05, 0x05, 0x09, 0x09, 0x0b, 0x03, ++ 0x42, 0x07, 0x03, 0x4c, 0x42, 0x11, 0x01, 0x5a, 0x4c, 0x01, 0x1c, 0x19, 0x13, 0x2a, 0x09, 0x09, ++ 0x0b, 0x03, 0x42, 0x07, 0x03, 0x4c, 0x42, 0x11, 0x01, 0x5a, 0x4c, 0x01, 0x1c, 0x19, 0x13, 0x2a, ++ 0x2e, 0x55, 0x2d, 0x4a, 0x01, 0x01, 0x03, 0x09, 0x09, 0x16, 0x0b, 0x19, 0x0b, 0x21, 0x03, 0x4a, ++ 0x1c, 0x07, 0x03, 0x21, 0x03, 0x4a, 0x1c, 0x07, 0x03, 0x21, 0x03, 0x4a, 0x1c, 0x07, 0x03, 0x42, ++ 0x05, 0x04, 0x04, 0x0f, 0x1d, 0x0f, 0x1d, 0x07, 0x1d, 0x05, 0x01, 0x1d, 0x05, 0x01, 0x40, 0x40, ++ 0x42, 0x26, 0x15, 0x0d, 0x42, 0x0f, 0x0d, 0x05, 0x07, 0x3e, 0x27, 0x26, 0x05, 0x21, 0x1b, 0x0f, ++ 0x42, 0x1c, 0x12, 0x04, 0x42, 0x4c, 0x1b, 0x41, 0x0d, 0x07, 0x1d, 0x0a, 0x0f, 0x0f, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x5a, 0x06, 0x49, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x4c, 0x40, 0x40, 0x40, 0x4c, 0x2c, ++ 0x06, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x0e, 0x0e, 0x02, ++ 0x49, 0x18, 0x0e, 0x03, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x06, 0x06, 0x0a, 0x0a, 0x0c, 0x04, ++ 0x41, 0x07, 0x04, 0x4b, 0x41, 0x12, 0x02, 0x59, 0x4b, 0x02, 0x1e, 0x1a, 0x14, 0x2c, 0x0a, 0x0a, ++ 0x0c, 0x04, 0x41, 0x07, 0x04, 0x4b, 0x41, 0x12, 0x02, 0x59, 0x4b, 0x02, 0x1e, 0x1a, 0x14, 0x2c, ++ 0x30, 0x56, 0x2e, 0x49, 0x02, 0x02, 0x04, 0x0a, 0x0a, 0x18, 0x0c, 0x1a, 0x0c, 0x22, 0x04, 0x49, ++ 0x1b, 0x07, 0x04, 0x22, 0x04, 0x49, 0x1b, 0x07, 0x04, 0x22, 0x04, 0x49, 0x1b, 0x07, 0x04, 0x41, ++ 0x06, 0x03, 0x03, 0x0f, 0x1e, 0x0f, 0x1e, 0x07, 0x1e, 0x06, 0x02, 0x1e, 0x06, 0x02, 0x40, 0x40, ++ 0x41, 0x28, 0x16, 0x0e, 0x41, 0x0f, 0x0e, 0x06, 0x07, 0x3e, 0x27, 0x28, 0x06, 0x22, 0x1c, 0x0f, ++ 0x41, 0x1b, 0x11, 0x03, 0x41, 0x4e, 0x1c, 0x42, 0x0e, 0x07, 0x1e, 0x09, 0x0f, 0x0f, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x5b, 0x06, 0x49, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x4c, 0x40, 0x40, 0x40, 0x4c, 0x2e, ++ 0x06, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x0e, 0x0e, 0x03, ++ 0x49, 0x19, 0x0e, 0x03, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x06, 0x06, 0x0b, 0x0b, 0x0c, 0x04, ++ 0x41, 0x07, 0x04, 0x4b, 0x41, 0x13, 0x03, 0x59, 0x4b, 0x03, 0x1f, 0x1b, 0x14, 0x2e, 0x0b, 0x0b, ++ 0x0c, 0x04, 0x41, 0x07, 0x04, 0x4b, 0x41, 0x13, 0x03, 0x59, 0x4b, 0x03, 0x1f, 0x1b, 0x14, 0x2e, ++ 0x31, 0x56, 0x2e, 0x49, 0x03, 0x03, 0x04, 0x0b, 0x0b, 0x19, 0x0c, 0x1b, 0x0c, 0x23, 0x04, 0x49, ++ 0x1b, 0x07, 0x04, 0x23, 0x04, 0x49, 0x1b, 0x07, 0x04, 0x23, 0x04, 0x49, 0x1b, 0x07, 0x04, 0x41, ++ 0x06, 0x03, 0x03, 0x0f, 0x1e, 0x0f, 0x1e, 0x07, 0x1e, 0x06, 0x03, 0x1e, 0x06, 0x03, 0x40, 0x40, ++ 0x41, 0x29, 0x16, 0x0e, 0x41, 0x0f, 0x0e, 0x06, 0x07, 0x3e, 0x27, 0x29, 0x06, 0x23, 0x1c, 0x0f, ++ 0x41, 0x1b, 0x11, 0x03, 0x41, 0x4f, 0x1c, 0x43, 0x0e, 0x07, 0x1e, 0x09, 0x0f, 0x0f, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x5c, 0x06, 0x49, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x4d, 0x40, 0x40, 0x40, 0x4d, 0x30, ++ 0x06, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x0e, 0x0e, 0x04, ++ 0x49, 0x1a, 0x0e, 0x02, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x06, 0x06, 0x0c, 0x0c, 0x0d, 0x05, ++ 0x41, 0x07, 0x05, 0x4a, 0x41, 0x14, 0x04, 0x59, 0x4a, 0x04, 0x21, 0x1c, 0x15, 0x30, 0x0c, 0x0c, ++ 0x0d, 0x05, 0x41, 0x07, 0x05, 0x4a, 0x41, 0x14, 0x04, 0x59, 0x4a, 0x04, 0x21, 0x1c, 0x15, 0x30, ++ 0x32, 0x56, 0x2e, 0x49, 0x04, 0x04, 0x05, 0x0c, 0x0c, 0x1a, 0x0d, 0x1c, 0x0d, 0x24, 0x05, 0x49, ++ 0x1a, 0x07, 0x05, 0x24, 0x05, 0x49, 0x1a, 0x07, 0x05, 0x24, 0x05, 0x49, 0x1a, 0x07, 0x05, 0x41, ++ 0x06, 0x02, 0x02, 0x0f, 0x1e, 0x0f, 0x1e, 0x07, 0x1e, 0x06, 0x04, 0x1e, 0x06, 0x04, 0x40, 0x40, ++ 0x41, 0x2a, 0x16, 0x0e, 0x41, 0x0f, 0x0e, 0x06, 0x07, 0x3e, 0x27, 0x2a, 0x06, 0x24, 0x1d, 0x0f, ++ 0x41, 0x1a, 0x11, 0x02, 0x41, 0x51, 0x1d, 0x44, 0x0e, 0x07, 0x1e, 0x09, 0x0f, 0x0f, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x5d, 0x06, 0x49, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x4e, 0x40, 0x40, 0x40, 0x4e, 0x31, ++ 0x06, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x0e, 0x0e, 0x04, ++ 0x49, 0x1b, 0x0e, 0x01, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x06, 0x06, 0x0c, 0x0c, 0x0d, 0x05, ++ 0x41, 0x07, 0x05, 0x4a, 0x41, 0x14, 0x04, 0x59, 0x4a, 0x04, 0x22, 0x1c, 0x15, 0x31, 0x0c, 0x0c, ++ 0x0d, 0x05, 0x41, 0x07, 0x05, 0x4a, 0x41, 0x14, 0x04, 0x59, 0x4a, 0x04, 0x22, 0x1c, 0x15, 0x31, ++ 0x33, 0x57, 0x2e, 0x49, 0x04, 0x04, 0x05, 0x0c, 0x0c, 0x1b, 0x0d, 0x1c, 0x0d, 0x24, 0x05, 0x49, ++ 0x19, 0x07, 0x05, 0x24, 0x05, 0x49, 0x19, 0x07, 0x05, 0x24, 0x05, 0x49, 0x19, 0x07, 0x05, 0x41, ++ 0x06, 0x01, 0x01, 0x0f, 0x1e, 0x0f, 0x1e, 0x07, 0x1e, 0x06, 0x04, 0x1e, 0x06, 0x04, 0x40, 0x40, ++ 0x41, 0x2b, 0x16, 0x0e, 0x41, 0x0f, 0x0e, 0x06, 0x07, 0x3e, 0x27, 0x2b, 0x06, 0x24, 0x1d, 0x0f, ++ 0x41, 0x19, 0x10, 0x01, 0x41, 0x53, 0x1d, 0x45, 0x0e, 0x07, 0x1e, 0x08, 0x0f, 0x0f, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x5d, 0x07, 0x48, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x4e, 0x40, 0x40, 0x40, 0x4e, 0x33, ++ 0x07, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x0f, 0x0f, 0x05, ++ 0x48, 0x1d, 0x0f, 0x01, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x07, 0x0d, 0x0d, 0x0e, 0x06, ++ 0x40, 0x07, 0x06, 0x49, 0x40, 0x15, 0x05, 0x58, 0x49, 0x05, 0x24, 0x1d, 0x16, 0x33, 0x0d, 0x0d, ++ 0x0e, 0x06, 0x40, 0x07, 0x06, 0x49, 0x40, 0x15, 0x05, 0x58, 0x49, 0x05, 0x24, 0x1d, 0x16, 0x33, ++ 0x35, 0x57, 0x2f, 0x48, 0x05, 0x05, 0x06, 0x0d, 0x0d, 0x1d, 0x0e, 0x1d, 0x0e, 0x25, 0x06, 0x48, ++ 0x19, 0x07, 0x06, 0x25, 0x06, 0x48, 0x19, 0x07, 0x06, 0x25, 0x06, 0x48, 0x19, 0x07, 0x06, 0x40, ++ 0x07, 0x01, 0x01, 0x0f, 0x1f, 0x0f, 0x1f, 0x07, 0x1f, 0x07, 0x05, 0x1f, 0x07, 0x05, 0x40, 0x40, ++ 0x40, 0x2d, 0x17, 0x0f, 0x40, 0x0f, 0x0f, 0x07, 0x07, 0x3e, 0x27, 0x2d, 0x07, 0x25, 0x1e, 0x0f, ++ 0x40, 0x19, 0x10, 0x01, 0x40, 0x54, 0x1e, 0x45, 0x0f, 0x07, 0x1f, 0x08, 0x0f, 0x0f, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x5e, 0x07, 0x48, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x4f, 0x40, 0x40, 0x40, 0x4f, 0x35, ++ 0x07, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x0f, 0x0f, 0x06, ++ 0x48, 0x1e, 0x0f, 0x00, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x07, 0x0e, 0x0e, 0x0f, 0x07, ++ 0x40, 0x07, 0x07, 0x48, 0x40, 0x16, 0x06, 0x58, 0x48, 0x06, 0x26, 0x1e, 0x17, 0x35, 0x0e, 0x0e, ++ 0x0f, 0x07, 0x40, 0x07, 0x07, 0x48, 0x40, 0x16, 0x06, 0x58, 0x48, 0x06, 0x26, 0x1e, 0x17, 0x35, ++ 0x36, 0x57, 0x2f, 0x48, 0x06, 0x06, 0x07, 0x0e, 0x0e, 0x1e, 0x0f, 0x1e, 0x0f, 0x26, 0x07, 0x48, ++ 0x18, 0x07, 0x07, 0x26, 0x07, 0x48, 0x18, 0x07, 0x07, 0x26, 0x07, 0x48, 0x18, 0x07, 0x07, 0x40, ++ 0x07, 0x00, 0x00, 0x0f, 0x1f, 0x0f, 0x1f, 0x07, 0x1f, 0x07, 0x06, 0x1f, 0x07, 0x06, 0x40, 0x40, ++ 0x40, 0x2e, 0x17, 0x0f, 0x40, 0x0f, 0x0f, 0x07, 0x07, 0x3e, 0x27, 0x2e, 0x07, 0x26, 0x1f, 0x0f, ++ 0x40, 0x18, 0x10, 0x00, 0x40, 0x56, 0x1f, 0x46, 0x0f, 0x07, 0x1f, 0x08, 0x0f, 0x0f, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x5f, 0x07, 0x48, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x4f, 0x40, 0x40, 0x40, 0x4f, 0x37, ++ 0x07, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x0f, 0x0f, 0x07, ++ 0x48, 0x1f, 0x0f, 0x00, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x07, 0x0f, 0x0f, 0x0f, 0x07, ++ 0x40, 0x07, 0x07, 0x48, 0x40, 0x17, 0x07, 0x58, 0x48, 0x07, 0x27, 0x1f, 0x17, 0x37, 0x0f, 0x0f, ++ 0x0f, 0x07, 0x40, 0x07, 0x07, 0x48, 0x40, 0x17, 0x07, 0x58, 0x48, 0x07, 0x27, 0x1f, 0x17, 0x37, ++ 0x37, 0x57, 0x2f, 0x48, 0x07, 0x07, 0x07, 0x0f, 0x0f, 0x1f, 0x0f, 0x1f, 0x0f, 0x27, 0x07, 0x48, ++ 0x18, 0x07, 0x07, 0x27, 0x07, 0x48, 0x18, 0x07, 0x07, 0x27, 0x07, 0x48, 0x18, 0x07, 0x07, 0x40, ++ 0x07, 0x00, 0x00, 0x0f, 0x1f, 0x0f, 0x1f, 0x07, 0x1f, 0x07, 0x07, 0x1f, 0x07, 0x07, 0x40, 0x40, ++ 0x40, 0x2f, 0x17, 0x0f, 0x40, 0x0f, 0x0f, 0x07, 0x07, 0x3e, 0x27, 0x2f, 0x07, 0x27, 0x1f, 0x0f, ++ 0x40, 0x18, 0x10, 0x00, 0x40, 0x57, 0x1f, 0x47, 0x0f, 0x07, 0x1f, 0x08, 0x0f, 0x0f, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x07, 0x48, 0x48, 0x60, 0x40, 0x27, 0x07, 0x07, 0x27, 0x40, 0x48, 0x40, 0x40, 0x40, 0x0f, ++ 0x48, 0x68, 0x60, 0x40, 0x68, 0x68, 0x68, 0x68, 0x68, 0x07, 0x07, 0x0f, 0x50, 0x40, 0x60, 0x07, ++ 0x68, 0x27, 0x48, 0x17, 0x40, 0x50, 0x1f, 0x40, 0x40, 0x40, 0x48, 0x48, 0x58, 0x60, 0x60, 0x60, ++ 0x68, 0x68, 0x58, 0x68, 0x60, 0x60, 0x60, 0x68, 0x68, 0x68, 0x60, 0x50, 0x48, 0x50, 0x58, 0x60, ++ 0x60, 0x60, 0x68, 0x68, 0x58, 0x68, 0x60, 0x60, 0x60, 0x68, 0x68, 0x68, 0x60, 0x50, 0x48, 0x50, ++ 0x07, 0x50, 0x58, 0x40, 0x48, 0x40, 0x48, 0x07, 0x48, 0x48, 0x48, 0x68, 0x07, 0x1f, 0x17, 0x50, ++ 0x0f, 0x07, 0x40, 0x1f, 0x17, 0x50, 0x0f, 0x07, 0x40, 0x1f, 0x17, 0x50, 0x0f, 0x07, 0x40, 0x40, ++ 0x07, 0x48, 0x48, 0x48, 0x07, 0x48, 0x07, 0x17, 0x17, 0x17, 0x50, 0x17, 0x17, 0x50, 0x40, 0x40, ++ 0x40, 0x2f, 0x2f, 0x17, 0x40, 0x0f, 0x17, 0x1f, 0x1f, 0x1f, 0x27, 0x0f, 0x07, 0x07, 0x0f, 0x07, ++ 0x07, 0x3e, 0x1f, 0x17, 0x40, 0x17, 0x07, 0x1f, 0x48, 0x17, 0x48, 0x40, 0x48, 0x17, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x07, 0x47, 0x47, 0x5f, 0x40, 0x27, 0x07, 0x07, 0x27, 0x40, 0x47, 0x40, 0x40, 0x40, 0x0f, ++ 0x47, 0x66, 0x5f, 0x00, 0x66, 0x66, 0x66, 0x65, 0x65, 0x07, 0x07, 0x0f, 0x4f, 0x00, 0x5e, 0x07, ++ 0x67, 0x27, 0x47, 0x17, 0x40, 0x4f, 0x1f, 0x40, 0x40, 0x40, 0x47, 0x47, 0x57, 0x5f, 0x5e, 0x5f, ++ 0x66, 0x66, 0x57, 0x67, 0x5f, 0x5e, 0x5f, 0x67, 0x67, 0x66, 0x5e, 0x4f, 0x47, 0x4f, 0x57, 0x5f, ++ 0x5e, 0x5f, 0x66, 0x66, 0x57, 0x67, 0x5f, 0x5e, 0x5f, 0x67, 0x67, 0x66, 0x5e, 0x4f, 0x47, 0x4f, ++ 0x08, 0x4f, 0x56, 0x40, 0x48, 0x40, 0x47, 0x07, 0x47, 0x47, 0x47, 0x66, 0x07, 0x1f, 0x17, 0x4f, ++ 0x10, 0x07, 0x40, 0x1f, 0x17, 0x4f, 0x10, 0x07, 0x40, 0x1f, 0x17, 0x4f, 0x10, 0x07, 0x40, 0x40, ++ 0x07, 0x47, 0x47, 0x47, 0x08, 0x47, 0x08, 0x17, 0x17, 0x17, 0x4f, 0x17, 0x17, 0x4f, 0x40, 0x40, ++ 0x40, 0x2f, 0x2f, 0x17, 0x40, 0x0f, 0x17, 0x1f, 0x1f, 0x20, 0x27, 0x10, 0x07, 0x08, 0x10, 0x08, ++ 0x07, 0x3e, 0x1f, 0x17, 0x40, 0x17, 0x08, 0x1f, 0x47, 0x17, 0x46, 0x00, 0x47, 0x17, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x06, 0x46, 0x47, 0x5e, 0x40, 0x26, 0x06, 0x06, 0x27, 0x40, 0x47, 0x40, 0x40, 0x40, 0x0f, ++ 0x47, 0x64, 0x5e, 0x01, 0x65, 0x64, 0x64, 0x63, 0x63, 0x07, 0x07, 0x0f, 0x4e, 0x00, 0x5d, 0x07, ++ 0x66, 0x27, 0x46, 0x17, 0x40, 0x4f, 0x1e, 0x40, 0x40, 0x40, 0x47, 0x47, 0x56, 0x5e, 0x5d, 0x5e, ++ 0x65, 0x64, 0x56, 0x66, 0x5e, 0x5c, 0x5e, 0x66, 0x66, 0x65, 0x5d, 0x4e, 0x46, 0x4e, 0x56, 0x5e, ++ 0x5d, 0x5e, 0x65, 0x64, 0x56, 0x66, 0x5e, 0x5c, 0x5e, 0x66, 0x66, 0x65, 0x5d, 0x4e, 0x46, 0x4e, ++ 0x09, 0x4f, 0x54, 0x40, 0x48, 0x40, 0x47, 0x07, 0x47, 0x46, 0x46, 0x64, 0x07, 0x1f, 0x16, 0x4f, ++ 0x10, 0x07, 0x40, 0x1f, 0x16, 0x4f, 0x10, 0x07, 0x40, 0x1f, 0x16, 0x4f, 0x10, 0x07, 0x40, 0x40, ++ 0x07, 0x46, 0x46, 0x46, 0x09, 0x46, 0x09, 0x17, 0x17, 0x16, 0x4f, 0x17, 0x16, 0x4f, 0x40, 0x40, ++ 0x40, 0x2e, 0x2e, 0x17, 0x40, 0x0f, 0x17, 0x1e, 0x1e, 0x20, 0x27, 0x10, 0x07, 0x09, 0x10, 0x08, ++ 0x07, 0x3e, 0x1f, 0x17, 0x40, 0x17, 0x08, 0x1e, 0x46, 0x17, 0x45, 0x01, 0x46, 0x17, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x06, 0x45, 0x47, 0x5e, 0x40, 0x25, 0x06, 0x05, 0x27, 0x40, 0x47, 0x40, 0x40, 0x40, 0x0f, ++ 0x47, 0x63, 0x5d, 0x01, 0x64, 0x63, 0x62, 0x60, 0x60, 0x07, 0x07, 0x0f, 0x4e, 0x00, 0x5c, 0x07, ++ 0x65, 0x27, 0x45, 0x17, 0x40, 0x4f, 0x1d, 0x40, 0x40, 0x40, 0x47, 0x47, 0x56, 0x5d, 0x5c, 0x5d, ++ 0x64, 0x63, 0x56, 0x65, 0x5d, 0x5b, 0x5d, 0x65, 0x65, 0x64, 0x5c, 0x4d, 0x46, 0x4d, 0x56, 0x5d, ++ 0x5c, 0x5d, 0x64, 0x63, 0x56, 0x65, 0x5d, 0x5b, 0x5d, 0x65, 0x65, 0x64, 0x5c, 0x4d, 0x46, 0x4d, ++ 0x09, 0x4f, 0x52, 0x40, 0x48, 0x40, 0x47, 0x07, 0x47, 0x46, 0x46, 0x62, 0x07, 0x1f, 0x16, 0x4f, ++ 0x10, 0x07, 0x40, 0x1f, 0x16, 0x4f, 0x10, 0x07, 0x40, 0x1f, 0x16, 0x4f, 0x10, 0x07, 0x40, 0x40, ++ 0x07, 0x46, 0x46, 0x45, 0x09, 0x45, 0x09, 0x17, 0x17, 0x16, 0x4f, 0x17, 0x16, 0x4f, 0x40, 0x40, ++ 0x40, 0x2d, 0x2d, 0x17, 0x40, 0x0f, 0x17, 0x1e, 0x1e, 0x20, 0x27, 0x10, 0x07, 0x09, 0x10, 0x08, ++ 0x07, 0x3d, 0x1f, 0x17, 0x40, 0x17, 0x08, 0x1e, 0x45, 0x17, 0x44, 0x01, 0x45, 0x17, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x05, 0x44, 0x46, 0x5d, 0x40, 0x24, 0x05, 0x04, 0x27, 0x40, 0x46, 0x40, 0x40, 0x40, 0x0f, ++ 0x46, 0x61, 0x5c, 0x02, 0x63, 0x61, 0x60, 0x5e, 0x5e, 0x07, 0x07, 0x0e, 0x4d, 0x01, 0x5b, 0x07, ++ 0x64, 0x27, 0x44, 0x16, 0x40, 0x4e, 0x1c, 0x40, 0x40, 0x40, 0x46, 0x46, 0x55, 0x5c, 0x5b, 0x5c, ++ 0x63, 0x61, 0x55, 0x64, 0x5c, 0x59, 0x5c, 0x64, 0x64, 0x63, 0x5b, 0x4c, 0x45, 0x4c, 0x55, 0x5c, ++ 0x5b, 0x5c, 0x63, 0x61, 0x55, 0x64, 0x5c, 0x59, 0x5c, 0x64, 0x64, 0x63, 0x5b, 0x4c, 0x45, 0x4c, ++ 0x0a, 0x4e, 0x50, 0x40, 0x48, 0x40, 0x46, 0x07, 0x46, 0x45, 0x45, 0x60, 0x07, 0x1e, 0x15, 0x4e, ++ 0x11, 0x07, 0x40, 0x1e, 0x15, 0x4e, 0x11, 0x07, 0x40, 0x1e, 0x15, 0x4e, 0x11, 0x07, 0x40, 0x41, ++ 0x07, 0x45, 0x45, 0x44, 0x0a, 0x44, 0x0a, 0x16, 0x17, 0x15, 0x4e, 0x17, 0x15, 0x4e, 0x40, 0x40, ++ 0x40, 0x2c, 0x2c, 0x16, 0x40, 0x0f, 0x16, 0x1d, 0x1d, 0x21, 0x27, 0x11, 0x07, 0x0a, 0x11, 0x09, ++ 0x06, 0x3c, 0x1e, 0x16, 0x40, 0x16, 0x09, 0x1d, 0x44, 0x16, 0x43, 0x02, 0x44, 0x16, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x04, 0x43, 0x46, 0x5c, 0x40, 0x23, 0x04, 0x03, 0x27, 0x40, 0x46, 0x40, 0x40, 0x40, 0x0f, ++ 0x46, 0x60, 0x5b, 0x03, 0x61, 0x60, 0x5e, 0x5b, 0x5b, 0x07, 0x07, 0x0e, 0x4c, 0x01, 0x59, 0x07, ++ 0x63, 0x27, 0x43, 0x16, 0x40, 0x4e, 0x1b, 0x40, 0x40, 0x40, 0x46, 0x46, 0x54, 0x5b, 0x59, 0x5b, ++ 0x61, 0x60, 0x54, 0x63, 0x5b, 0x58, 0x5b, 0x63, 0x63, 0x61, 0x59, 0x4b, 0x44, 0x4b, 0x54, 0x5b, ++ 0x59, 0x5b, 0x61, 0x60, 0x54, 0x63, 0x5b, 0x58, 0x5b, 0x63, 0x63, 0x61, 0x59, 0x4b, 0x44, 0x4b, ++ 0x0b, 0x4e, 0x4e, 0x40, 0x48, 0x40, 0x46, 0x07, 0x46, 0x44, 0x44, 0x5e, 0x07, 0x1e, 0x14, 0x4e, ++ 0x11, 0x07, 0x40, 0x1e, 0x14, 0x4e, 0x11, 0x07, 0x40, 0x1e, 0x14, 0x4e, 0x11, 0x07, 0x40, 0x41, ++ 0x07, 0x44, 0x44, 0x43, 0x0b, 0x43, 0x0b, 0x16, 0x17, 0x14, 0x4e, 0x17, 0x14, 0x4e, 0x40, 0x40, ++ 0x40, 0x2b, 0x2b, 0x16, 0x40, 0x0f, 0x16, 0x1c, 0x1c, 0x21, 0x27, 0x11, 0x07, 0x0b, 0x11, 0x09, ++ 0x06, 0x3b, 0x1e, 0x16, 0x40, 0x16, 0x09, 0x1c, 0x43, 0x16, 0x41, 0x03, 0x43, 0x16, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x04, 0x42, 0x46, 0x5c, 0x40, 0x22, 0x04, 0x02, 0x27, 0x40, 0x46, 0x40, 0x40, 0x40, 0x0f, ++ 0x46, 0x5e, 0x5a, 0x03, 0x60, 0x5e, 0x5c, 0x59, 0x59, 0x07, 0x07, 0x0e, 0x4c, 0x01, 0x58, 0x07, ++ 0x62, 0x27, 0x42, 0x16, 0x40, 0x4e, 0x1a, 0x40, 0x40, 0x40, 0x46, 0x46, 0x54, 0x5a, 0x58, 0x5a, ++ 0x60, 0x5e, 0x54, 0x62, 0x5a, 0x56, 0x5a, 0x62, 0x62, 0x60, 0x58, 0x4a, 0x44, 0x4a, 0x54, 0x5a, ++ 0x58, 0x5a, 0x60, 0x5e, 0x54, 0x62, 0x5a, 0x56, 0x5a, 0x62, 0x62, 0x60, 0x58, 0x4a, 0x44, 0x4a, ++ 0x0b, 0x4e, 0x4c, 0x40, 0x48, 0x40, 0x46, 0x07, 0x46, 0x44, 0x44, 0x5c, 0x07, 0x1e, 0x14, 0x4e, ++ 0x11, 0x07, 0x40, 0x1e, 0x14, 0x4e, 0x11, 0x07, 0x40, 0x1e, 0x14, 0x4e, 0x11, 0x07, 0x40, 0x41, ++ 0x07, 0x44, 0x44, 0x42, 0x0b, 0x42, 0x0b, 0x16, 0x17, 0x14, 0x4e, 0x17, 0x14, 0x4e, 0x40, 0x40, ++ 0x40, 0x2a, 0x2a, 0x16, 0x40, 0x0f, 0x16, 0x1c, 0x1c, 0x21, 0x27, 0x11, 0x07, 0x0b, 0x11, 0x09, ++ 0x06, 0x3a, 0x1e, 0x16, 0x40, 0x16, 0x09, 0x1c, 0x42, 0x16, 0x40, 0x03, 0x42, 0x16, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x03, 0x41, 0x45, 0x5b, 0x40, 0x21, 0x03, 0x01, 0x27, 0x40, 0x45, 0x40, 0x40, 0x40, 0x0f, ++ 0x45, 0x5d, 0x59, 0x04, 0x5f, 0x5d, 0x5a, 0x56, 0x56, 0x07, 0x07, 0x0d, 0x4b, 0x02, 0x57, 0x07, ++ 0x61, 0x27, 0x41, 0x15, 0x40, 0x4d, 0x19, 0x40, 0x40, 0x40, 0x45, 0x45, 0x53, 0x59, 0x57, 0x59, ++ 0x5f, 0x5d, 0x53, 0x61, 0x59, 0x55, 0x59, 0x61, 0x61, 0x5f, 0x57, 0x49, 0x43, 0x49, 0x53, 0x59, ++ 0x57, 0x59, 0x5f, 0x5d, 0x53, 0x61, 0x59, 0x55, 0x59, 0x61, 0x61, 0x5f, 0x57, 0x49, 0x43, 0x49, ++ 0x0c, 0x4d, 0x4a, 0x40, 0x48, 0x40, 0x45, 0x07, 0x45, 0x43, 0x43, 0x5a, 0x07, 0x1d, 0x13, 0x4d, ++ 0x12, 0x07, 0x40, 0x1d, 0x13, 0x4d, 0x12, 0x07, 0x40, 0x1d, 0x13, 0x4d, 0x12, 0x07, 0x40, 0x42, ++ 0x07, 0x43, 0x43, 0x41, 0x0c, 0x41, 0x0c, 0x15, 0x17, 0x13, 0x4d, 0x17, 0x13, 0x4d, 0x40, 0x40, ++ 0x40, 0x29, 0x29, 0x15, 0x40, 0x0f, 0x15, 0x1b, 0x1b, 0x22, 0x27, 0x12, 0x07, 0x0c, 0x12, 0x0a, ++ 0x05, 0x39, 0x1d, 0x15, 0x40, 0x15, 0x0a, 0x1b, 0x41, 0x15, 0x00, 0x04, 0x41, 0x15, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x02, 0x40, 0x45, 0x5b, 0x40, 0x20, 0x02, 0x00, 0x27, 0x40, 0x45, 0x40, 0x40, 0x40, 0x0f, ++ 0x45, 0x5b, 0x58, 0x04, 0x5e, 0x5b, 0x59, 0x54, 0x54, 0x07, 0x07, 0x0d, 0x4b, 0x02, 0x56, 0x07, ++ 0x60, 0x27, 0x40, 0x15, 0x40, 0x4d, 0x18, 0x40, 0x40, 0x40, 0x45, 0x45, 0x53, 0x58, 0x56, 0x58, ++ 0x5e, 0x5b, 0x53, 0x60, 0x58, 0x53, 0x58, 0x60, 0x60, 0x5e, 0x56, 0x48, 0x43, 0x48, 0x53, 0x58, ++ 0x56, 0x58, 0x5e, 0x5b, 0x53, 0x60, 0x58, 0x53, 0x58, 0x60, 0x60, 0x5e, 0x56, 0x48, 0x43, 0x48, ++ 0x0c, 0x4d, 0x49, 0x40, 0x48, 0x40, 0x45, 0x07, 0x45, 0x43, 0x43, 0x59, 0x07, 0x1d, 0x12, 0x4d, ++ 0x12, 0x07, 0x40, 0x1d, 0x12, 0x4d, 0x12, 0x07, 0x40, 0x1d, 0x12, 0x4d, 0x12, 0x07, 0x40, 0x42, ++ 0x07, 0x43, 0x43, 0x40, 0x0c, 0x40, 0x0c, 0x15, 0x17, 0x12, 0x4d, 0x17, 0x12, 0x4d, 0x40, 0x40, ++ 0x40, 0x28, 0x28, 0x15, 0x40, 0x0f, 0x15, 0x1a, 0x1a, 0x22, 0x27, 0x12, 0x07, 0x0c, 0x12, 0x0a, ++ 0x05, 0x38, 0x1d, 0x15, 0x40, 0x15, 0x0a, 0x1a, 0x40, 0x15, 0x01, 0x04, 0x40, 0x15, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x02, 0x00, 0x45, 0x5a, 0x40, 0x1f, 0x02, 0x40, 0x27, 0x40, 0x45, 0x40, 0x40, 0x40, 0x0f, ++ 0x45, 0x59, 0x57, 0x05, 0x5c, 0x59, 0x57, 0x51, 0x51, 0x07, 0x07, 0x0d, 0x4a, 0x02, 0x54, 0x07, ++ 0x5f, 0x27, 0x00, 0x15, 0x40, 0x4d, 0x17, 0x40, 0x40, 0x40, 0x45, 0x45, 0x52, 0x57, 0x54, 0x57, ++ 0x5c, 0x59, 0x52, 0x5f, 0x57, 0x51, 0x57, 0x5f, 0x5f, 0x5c, 0x54, 0x47, 0x42, 0x47, 0x52, 0x57, ++ 0x54, 0x57, 0x5c, 0x59, 0x52, 0x5f, 0x57, 0x51, 0x57, 0x5f, 0x5f, 0x5c, 0x54, 0x47, 0x42, 0x47, ++ 0x0d, 0x4d, 0x47, 0x40, 0x48, 0x40, 0x45, 0x07, 0x45, 0x42, 0x42, 0x57, 0x07, 0x1d, 0x12, 0x4d, ++ 0x12, 0x07, 0x40, 0x1d, 0x12, 0x4d, 0x12, 0x07, 0x40, 0x1d, 0x12, 0x4d, 0x12, 0x07, 0x40, 0x42, ++ 0x07, 0x42, 0x42, 0x00, 0x0d, 0x00, 0x0d, 0x15, 0x17, 0x12, 0x4d, 0x17, 0x12, 0x4d, 0x40, 0x40, ++ 0x40, 0x27, 0x27, 0x15, 0x40, 0x0f, 0x15, 0x1a, 0x1a, 0x22, 0x27, 0x12, 0x07, 0x0d, 0x12, 0x0a, ++ 0x05, 0x37, 0x1d, 0x15, 0x40, 0x15, 0x0a, 0x1a, 0x00, 0x15, 0x03, 0x05, 0x00, 0x15, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x01, 0x01, 0x44, 0x59, 0x40, 0x1e, 0x01, 0x41, 0x27, 0x40, 0x44, 0x40, 0x40, 0x40, 0x0f, ++ 0x44, 0x58, 0x56, 0x06, 0x5b, 0x58, 0x55, 0x4f, 0x4f, 0x07, 0x07, 0x0c, 0x49, 0x03, 0x53, 0x07, ++ 0x5e, 0x27, 0x01, 0x14, 0x40, 0x4c, 0x16, 0x40, 0x40, 0x40, 0x44, 0x44, 0x51, 0x56, 0x53, 0x56, ++ 0x5b, 0x58, 0x51, 0x5e, 0x56, 0x50, 0x56, 0x5e, 0x5e, 0x5b, 0x53, 0x46, 0x41, 0x46, 0x51, 0x56, ++ 0x53, 0x56, 0x5b, 0x58, 0x51, 0x5e, 0x56, 0x50, 0x56, 0x5e, 0x5e, 0x5b, 0x53, 0x46, 0x41, 0x46, ++ 0x0e, 0x4c, 0x45, 0x40, 0x48, 0x40, 0x44, 0x07, 0x44, 0x41, 0x41, 0x55, 0x07, 0x1c, 0x11, 0x4c, ++ 0x13, 0x07, 0x40, 0x1c, 0x11, 0x4c, 0x13, 0x07, 0x40, 0x1c, 0x11, 0x4c, 0x13, 0x07, 0x40, 0x43, ++ 0x07, 0x41, 0x41, 0x01, 0x0e, 0x01, 0x0e, 0x14, 0x17, 0x11, 0x4c, 0x17, 0x11, 0x4c, 0x40, 0x40, ++ 0x40, 0x26, 0x26, 0x14, 0x40, 0x0f, 0x14, 0x19, 0x19, 0x23, 0x27, 0x13, 0x07, 0x0e, 0x13, 0x0b, ++ 0x04, 0x36, 0x1c, 0x14, 0x40, 0x14, 0x0b, 0x19, 0x01, 0x14, 0x04, 0x06, 0x01, 0x14, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x01, 0x02, 0x44, 0x59, 0x40, 0x1d, 0x01, 0x42, 0x27, 0x40, 0x44, 0x40, 0x40, 0x40, 0x0f, ++ 0x44, 0x56, 0x55, 0x06, 0x5a, 0x56, 0x53, 0x4c, 0x4c, 0x07, 0x07, 0x0c, 0x49, 0x03, 0x52, 0x07, ++ 0x5d, 0x27, 0x02, 0x14, 0x40, 0x4c, 0x15, 0x40, 0x40, 0x40, 0x44, 0x44, 0x51, 0x55, 0x52, 0x55, ++ 0x5a, 0x56, 0x51, 0x5d, 0x55, 0x4e, 0x55, 0x5d, 0x5d, 0x5a, 0x52, 0x45, 0x41, 0x45, 0x51, 0x55, ++ 0x52, 0x55, 0x5a, 0x56, 0x51, 0x5d, 0x55, 0x4e, 0x55, 0x5d, 0x5d, 0x5a, 0x52, 0x45, 0x41, 0x45, ++ 0x0e, 0x4c, 0x43, 0x40, 0x48, 0x40, 0x44, 0x07, 0x44, 0x41, 0x41, 0x53, 0x07, 0x1c, 0x11, 0x4c, ++ 0x13, 0x07, 0x40, 0x1c, 0x11, 0x4c, 0x13, 0x07, 0x40, 0x1c, 0x11, 0x4c, 0x13, 0x07, 0x40, 0x43, ++ 0x07, 0x41, 0x41, 0x02, 0x0e, 0x02, 0x0e, 0x14, 0x17, 0x11, 0x4c, 0x17, 0x11, 0x4c, 0x40, 0x40, ++ 0x40, 0x25, 0x25, 0x14, 0x40, 0x0f, 0x14, 0x19, 0x19, 0x23, 0x27, 0x13, 0x07, 0x0e, 0x13, 0x0b, ++ 0x04, 0x35, 0x1c, 0x14, 0x40, 0x14, 0x0b, 0x19, 0x02, 0x14, 0x05, 0x06, 0x02, 0x14, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x00, 0x03, 0x44, 0x58, 0x40, 0x1c, 0x00, 0x43, 0x27, 0x40, 0x44, 0x40, 0x40, 0x40, 0x0f, ++ 0x44, 0x55, 0x54, 0x07, 0x59, 0x55, 0x51, 0x4a, 0x4a, 0x07, 0x07, 0x0c, 0x48, 0x03, 0x51, 0x07, ++ 0x5c, 0x27, 0x03, 0x14, 0x40, 0x4c, 0x14, 0x40, 0x40, 0x40, 0x44, 0x44, 0x50, 0x54, 0x51, 0x54, ++ 0x59, 0x55, 0x50, 0x5c, 0x54, 0x4d, 0x54, 0x5c, 0x5c, 0x59, 0x51, 0x44, 0x40, 0x44, 0x50, 0x54, ++ 0x51, 0x54, 0x59, 0x55, 0x50, 0x5c, 0x54, 0x4d, 0x54, 0x5c, 0x5c, 0x59, 0x51, 0x44, 0x40, 0x44, ++ 0x0f, 0x4c, 0x41, 0x40, 0x48, 0x40, 0x44, 0x07, 0x44, 0x40, 0x40, 0x51, 0x07, 0x1c, 0x10, 0x4c, ++ 0x13, 0x07, 0x40, 0x1c, 0x10, 0x4c, 0x13, 0x07, 0x40, 0x1c, 0x10, 0x4c, 0x13, 0x07, 0x40, 0x43, ++ 0x07, 0x40, 0x40, 0x03, 0x0f, 0x03, 0x0f, 0x14, 0x17, 0x10, 0x4c, 0x17, 0x10, 0x4c, 0x40, 0x40, ++ 0x40, 0x24, 0x24, 0x14, 0x40, 0x0f, 0x14, 0x18, 0x18, 0x23, 0x27, 0x13, 0x07, 0x0f, 0x13, 0x0b, ++ 0x04, 0x34, 0x1c, 0x14, 0x40, 0x14, 0x0b, 0x18, 0x03, 0x14, 0x06, 0x07, 0x03, 0x14, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x40, 0x04, 0x43, 0x57, 0x40, 0x1b, 0x40, 0x44, 0x27, 0x40, 0x43, 0x40, 0x40, 0x40, 0x0f, ++ 0x43, 0x53, 0x53, 0x08, 0x57, 0x53, 0x4f, 0x47, 0x47, 0x07, 0x07, 0x0b, 0x47, 0x04, 0x4f, 0x07, ++ 0x5b, 0x27, 0x04, 0x13, 0x40, 0x4b, 0x13, 0x40, 0x40, 0x40, 0x43, 0x43, 0x4f, 0x53, 0x4f, 0x53, ++ 0x57, 0x53, 0x4f, 0x5b, 0x53, 0x4b, 0x53, 0x5b, 0x5b, 0x57, 0x4f, 0x43, 0x00, 0x43, 0x4f, 0x53, ++ 0x4f, 0x53, 0x57, 0x53, 0x4f, 0x5b, 0x53, 0x4b, 0x53, 0x5b, 0x5b, 0x57, 0x4f, 0x43, 0x00, 0x43, ++ 0x10, 0x4b, 0x00, 0x40, 0x48, 0x40, 0x43, 0x07, 0x43, 0x00, 0x00, 0x4f, 0x07, 0x1b, 0x0f, 0x4b, ++ 0x14, 0x07, 0x40, 0x1b, 0x0f, 0x4b, 0x14, 0x07, 0x40, 0x1b, 0x0f, 0x4b, 0x14, 0x07, 0x40, 0x44, ++ 0x07, 0x00, 0x00, 0x04, 0x10, 0x04, 0x10, 0x13, 0x17, 0x0f, 0x4b, 0x17, 0x0f, 0x4b, 0x40, 0x40, ++ 0x40, 0x23, 0x23, 0x13, 0x40, 0x0f, 0x13, 0x17, 0x17, 0x24, 0x27, 0x14, 0x07, 0x10, 0x14, 0x0c, ++ 0x03, 0x33, 0x1b, 0x13, 0x40, 0x13, 0x0c, 0x17, 0x04, 0x13, 0x08, 0x08, 0x04, 0x13, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x40, 0x05, 0x43, 0x57, 0x40, 0x1a, 0x40, 0x45, 0x27, 0x40, 0x43, 0x40, 0x40, 0x40, 0x0f, ++ 0x43, 0x52, 0x52, 0x08, 0x56, 0x52, 0x4d, 0x45, 0x45, 0x07, 0x07, 0x0b, 0x47, 0x04, 0x4e, 0x07, ++ 0x5a, 0x27, 0x05, 0x13, 0x40, 0x4b, 0x12, 0x40, 0x40, 0x40, 0x43, 0x43, 0x4f, 0x52, 0x4e, 0x52, ++ 0x56, 0x52, 0x4f, 0x5a, 0x52, 0x4a, 0x52, 0x5a, 0x5a, 0x56, 0x4e, 0x42, 0x00, 0x42, 0x4f, 0x52, ++ 0x4e, 0x52, 0x56, 0x52, 0x4f, 0x5a, 0x52, 0x4a, 0x52, 0x5a, 0x5a, 0x56, 0x4e, 0x42, 0x00, 0x42, ++ 0x10, 0x4b, 0x02, 0x40, 0x48, 0x40, 0x43, 0x07, 0x43, 0x00, 0x00, 0x4d, 0x07, 0x1b, 0x0f, 0x4b, ++ 0x14, 0x07, 0x40, 0x1b, 0x0f, 0x4b, 0x14, 0x07, 0x40, 0x1b, 0x0f, 0x4b, 0x14, 0x07, 0x40, 0x44, ++ 0x07, 0x00, 0x00, 0x05, 0x10, 0x05, 0x10, 0x13, 0x17, 0x0f, 0x4b, 0x17, 0x0f, 0x4b, 0x40, 0x40, ++ 0x40, 0x22, 0x22, 0x13, 0x40, 0x0f, 0x13, 0x17, 0x17, 0x24, 0x27, 0x14, 0x07, 0x10, 0x14, 0x0c, ++ 0x03, 0x32, 0x1b, 0x13, 0x40, 0x13, 0x0c, 0x17, 0x05, 0x13, 0x09, 0x08, 0x05, 0x13, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x41, 0x06, 0x43, 0x56, 0x40, 0x19, 0x41, 0x46, 0x27, 0x40, 0x43, 0x40, 0x40, 0x40, 0x0f, ++ 0x43, 0x50, 0x51, 0x09, 0x55, 0x50, 0x4b, 0x42, 0x42, 0x07, 0x07, 0x0b, 0x46, 0x04, 0x4d, 0x07, ++ 0x59, 0x27, 0x06, 0x13, 0x40, 0x4b, 0x11, 0x40, 0x40, 0x40, 0x43, 0x43, 0x4e, 0x51, 0x4d, 0x51, ++ 0x55, 0x50, 0x4e, 0x59, 0x51, 0x48, 0x51, 0x59, 0x59, 0x55, 0x4d, 0x41, 0x01, 0x41, 0x4e, 0x51, ++ 0x4d, 0x51, 0x55, 0x50, 0x4e, 0x59, 0x51, 0x48, 0x51, 0x59, 0x59, 0x55, 0x4d, 0x41, 0x01, 0x41, ++ 0x11, 0x4b, 0x04, 0x40, 0x48, 0x40, 0x43, 0x07, 0x43, 0x01, 0x01, 0x4b, 0x07, 0x1b, 0x0e, 0x4b, ++ 0x14, 0x07, 0x40, 0x1b, 0x0e, 0x4b, 0x14, 0x07, 0x40, 0x1b, 0x0e, 0x4b, 0x14, 0x07, 0x40, 0x44, ++ 0x07, 0x01, 0x01, 0x06, 0x11, 0x06, 0x11, 0x13, 0x17, 0x0e, 0x4b, 0x17, 0x0e, 0x4b, 0x40, 0x40, ++ 0x40, 0x21, 0x21, 0x13, 0x40, 0x0f, 0x13, 0x16, 0x16, 0x24, 0x27, 0x14, 0x07, 0x11, 0x14, 0x0c, ++ 0x03, 0x31, 0x1b, 0x13, 0x40, 0x13, 0x0c, 0x16, 0x06, 0x13, 0x0a, 0x09, 0x06, 0x13, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x42, 0x06, 0x43, 0x56, 0x40, 0x18, 0x42, 0x47, 0x27, 0x40, 0x43, 0x40, 0x40, 0x40, 0x0f, ++ 0x43, 0x4f, 0x51, 0x09, 0x54, 0x4f, 0x4a, 0x40, 0x40, 0x07, 0x07, 0x0a, 0x46, 0x04, 0x4c, 0x07, ++ 0x59, 0x27, 0x06, 0x12, 0x40, 0x4b, 0x10, 0x40, 0x40, 0x40, 0x43, 0x43, 0x4e, 0x51, 0x4c, 0x51, ++ 0x54, 0x4f, 0x4e, 0x59, 0x51, 0x47, 0x51, 0x59, 0x59, 0x54, 0x4c, 0x41, 0x01, 0x41, 0x4e, 0x51, ++ 0x4c, 0x51, 0x54, 0x4f, 0x4e, 0x59, 0x51, 0x47, 0x51, 0x59, 0x59, 0x54, 0x4c, 0x41, 0x01, 0x41, ++ 0x11, 0x4b, 0x05, 0x40, 0x48, 0x40, 0x43, 0x07, 0x43, 0x01, 0x01, 0x4a, 0x07, 0x1a, 0x0d, 0x4b, ++ 0x14, 0x07, 0x40, 0x1a, 0x0d, 0x4b, 0x14, 0x07, 0x40, 0x1a, 0x0d, 0x4b, 0x14, 0x07, 0x40, 0x45, ++ 0x07, 0x01, 0x01, 0x06, 0x11, 0x06, 0x11, 0x12, 0x17, 0x0d, 0x4b, 0x17, 0x0d, 0x4b, 0x40, 0x40, ++ 0x40, 0x20, 0x20, 0x12, 0x40, 0x0f, 0x12, 0x15, 0x15, 0x24, 0x27, 0x14, 0x07, 0x11, 0x14, 0x0c, ++ 0x02, 0x30, 0x1a, 0x12, 0x40, 0x12, 0x0c, 0x15, 0x06, 0x12, 0x0b, 0x09, 0x06, 0x12, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x42, 0x07, 0x42, 0x55, 0x40, 0x18, 0x42, 0x47, 0x27, 0x40, 0x42, 0x40, 0x40, 0x40, 0x0f, ++ 0x42, 0x4d, 0x50, 0x0a, 0x52, 0x4d, 0x48, 0x02, 0x02, 0x07, 0x07, 0x0a, 0x45, 0x05, 0x4a, 0x07, ++ 0x58, 0x27, 0x07, 0x12, 0x40, 0x4a, 0x10, 0x40, 0x40, 0x40, 0x42, 0x42, 0x4d, 0x50, 0x4a, 0x50, ++ 0x52, 0x4d, 0x4d, 0x58, 0x50, 0x45, 0x50, 0x58, 0x58, 0x52, 0x4a, 0x40, 0x02, 0x40, 0x4d, 0x50, ++ 0x4a, 0x50, 0x52, 0x4d, 0x4d, 0x58, 0x50, 0x45, 0x50, 0x58, 0x58, 0x52, 0x4a, 0x40, 0x02, 0x40, ++ 0x12, 0x4a, 0x07, 0x40, 0x48, 0x40, 0x42, 0x07, 0x42, 0x02, 0x02, 0x48, 0x07, 0x1a, 0x0d, 0x4a, ++ 0x15, 0x07, 0x40, 0x1a, 0x0d, 0x4a, 0x15, 0x07, 0x40, 0x1a, 0x0d, 0x4a, 0x15, 0x07, 0x40, 0x45, ++ 0x07, 0x02, 0x02, 0x07, 0x12, 0x07, 0x12, 0x12, 0x17, 0x0d, 0x4a, 0x17, 0x0d, 0x4a, 0x40, 0x40, ++ 0x40, 0x20, 0x20, 0x12, 0x40, 0x0f, 0x12, 0x15, 0x15, 0x25, 0x27, 0x15, 0x07, 0x12, 0x15, 0x0d, ++ 0x02, 0x30, 0x1a, 0x12, 0x40, 0x12, 0x0d, 0x15, 0x07, 0x12, 0x0d, 0x0a, 0x07, 0x12, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x43, 0x08, 0x42, 0x54, 0x40, 0x17, 0x43, 0x48, 0x27, 0x40, 0x42, 0x40, 0x40, 0x40, 0x0f, ++ 0x42, 0x4b, 0x4f, 0x0b, 0x51, 0x4b, 0x46, 0x04, 0x04, 0x07, 0x07, 0x0a, 0x44, 0x05, 0x49, 0x07, ++ 0x57, 0x27, 0x08, 0x12, 0x40, 0x4a, 0x0f, 0x40, 0x40, 0x40, 0x42, 0x42, 0x4c, 0x4f, 0x49, 0x4f, ++ 0x51, 0x4b, 0x4c, 0x57, 0x4f, 0x43, 0x4f, 0x57, 0x57, 0x51, 0x49, 0x00, 0x03, 0x00, 0x4c, 0x4f, ++ 0x49, 0x4f, 0x51, 0x4b, 0x4c, 0x57, 0x4f, 0x43, 0x4f, 0x57, 0x57, 0x51, 0x49, 0x00, 0x03, 0x00, ++ 0x13, 0x4a, 0x09, 0x40, 0x48, 0x40, 0x42, 0x07, 0x42, 0x03, 0x03, 0x46, 0x07, 0x1a, 0x0c, 0x4a, ++ 0x15, 0x07, 0x40, 0x1a, 0x0c, 0x4a, 0x15, 0x07, 0x40, 0x1a, 0x0c, 0x4a, 0x15, 0x07, 0x40, 0x45, ++ 0x07, 0x03, 0x03, 0x08, 0x13, 0x08, 0x13, 0x12, 0x17, 0x0c, 0x4a, 0x17, 0x0c, 0x4a, 0x40, 0x40, ++ 0x40, 0x1f, 0x1f, 0x12, 0x40, 0x0f, 0x12, 0x14, 0x14, 0x25, 0x27, 0x15, 0x07, 0x13, 0x15, 0x0d, ++ 0x02, 0x2f, 0x1a, 0x12, 0x40, 0x12, 0x0d, 0x14, 0x08, 0x12, 0x0e, 0x0b, 0x08, 0x12, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x43, 0x09, 0x42, 0x54, 0x40, 0x16, 0x43, 0x49, 0x27, 0x40, 0x42, 0x40, 0x40, 0x40, 0x0f, ++ 0x42, 0x4a, 0x4e, 0x0b, 0x50, 0x4a, 0x44, 0x07, 0x07, 0x07, 0x07, 0x0a, 0x44, 0x05, 0x48, 0x07, ++ 0x56, 0x27, 0x09, 0x12, 0x40, 0x4a, 0x0e, 0x40, 0x40, 0x40, 0x42, 0x42, 0x4c, 0x4e, 0x48, 0x4e, ++ 0x50, 0x4a, 0x4c, 0x56, 0x4e, 0x42, 0x4e, 0x56, 0x56, 0x50, 0x48, 0x01, 0x03, 0x01, 0x4c, 0x4e, ++ 0x48, 0x4e, 0x50, 0x4a, 0x4c, 0x56, 0x4e, 0x42, 0x4e, 0x56, 0x56, 0x50, 0x48, 0x01, 0x03, 0x01, ++ 0x13, 0x4a, 0x0b, 0x40, 0x48, 0x40, 0x42, 0x07, 0x42, 0x03, 0x03, 0x44, 0x07, 0x1a, 0x0c, 0x4a, ++ 0x15, 0x07, 0x40, 0x1a, 0x0c, 0x4a, 0x15, 0x07, 0x40, 0x1a, 0x0c, 0x4a, 0x15, 0x07, 0x40, 0x45, ++ 0x07, 0x03, 0x03, 0x09, 0x13, 0x09, 0x13, 0x12, 0x17, 0x0c, 0x4a, 0x17, 0x0c, 0x4a, 0x40, 0x40, ++ 0x40, 0x1e, 0x1e, 0x12, 0x40, 0x0f, 0x12, 0x14, 0x14, 0x25, 0x27, 0x15, 0x07, 0x13, 0x15, 0x0d, ++ 0x02, 0x2e, 0x1a, 0x12, 0x40, 0x12, 0x0d, 0x14, 0x09, 0x12, 0x0f, 0x0b, 0x09, 0x12, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x44, 0x0a, 0x41, 0x53, 0x40, 0x15, 0x44, 0x4a, 0x27, 0x40, 0x41, 0x40, 0x40, 0x40, 0x0f, ++ 0x41, 0x48, 0x4d, 0x0c, 0x4f, 0x48, 0x42, 0x09, 0x09, 0x07, 0x07, 0x09, 0x43, 0x06, 0x47, 0x07, ++ 0x55, 0x27, 0x0a, 0x11, 0x40, 0x49, 0x0d, 0x40, 0x40, 0x40, 0x41, 0x41, 0x4b, 0x4d, 0x47, 0x4d, ++ 0x4f, 0x48, 0x4b, 0x55, 0x4d, 0x40, 0x4d, 0x55, 0x55, 0x4f, 0x47, 0x02, 0x04, 0x02, 0x4b, 0x4d, ++ 0x47, 0x4d, 0x4f, 0x48, 0x4b, 0x55, 0x4d, 0x40, 0x4d, 0x55, 0x55, 0x4f, 0x47, 0x02, 0x04, 0x02, ++ 0x14, 0x49, 0x0d, 0x40, 0x48, 0x40, 0x41, 0x07, 0x41, 0x04, 0x04, 0x42, 0x07, 0x19, 0x0b, 0x49, ++ 0x16, 0x07, 0x40, 0x19, 0x0b, 0x49, 0x16, 0x07, 0x40, 0x19, 0x0b, 0x49, 0x16, 0x07, 0x40, 0x46, ++ 0x07, 0x04, 0x04, 0x0a, 0x14, 0x0a, 0x14, 0x11, 0x17, 0x0b, 0x49, 0x17, 0x0b, 0x49, 0x40, 0x40, ++ 0x40, 0x1d, 0x1d, 0x11, 0x40, 0x0f, 0x11, 0x13, 0x13, 0x26, 0x27, 0x16, 0x07, 0x14, 0x16, 0x0e, ++ 0x01, 0x2d, 0x19, 0x11, 0x40, 0x11, 0x0e, 0x13, 0x0a, 0x11, 0x10, 0x0c, 0x0a, 0x11, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x45, 0x0b, 0x41, 0x52, 0x40, 0x14, 0x45, 0x4b, 0x27, 0x40, 0x41, 0x40, 0x40, 0x40, 0x0f, ++ 0x41, 0x47, 0x4c, 0x0d, 0x4d, 0x47, 0x40, 0x0c, 0x0c, 0x07, 0x07, 0x09, 0x42, 0x06, 0x45, 0x07, ++ 0x54, 0x27, 0x0b, 0x11, 0x40, 0x49, 0x0c, 0x40, 0x40, 0x40, 0x41, 0x41, 0x4a, 0x4c, 0x45, 0x4c, ++ 0x4d, 0x47, 0x4a, 0x54, 0x4c, 0x00, 0x4c, 0x54, 0x54, 0x4d, 0x45, 0x03, 0x05, 0x03, 0x4a, 0x4c, ++ 0x45, 0x4c, 0x4d, 0x47, 0x4a, 0x54, 0x4c, 0x00, 0x4c, 0x54, 0x54, 0x4d, 0x45, 0x03, 0x05, 0x03, ++ 0x15, 0x49, 0x0f, 0x40, 0x48, 0x40, 0x41, 0x07, 0x41, 0x05, 0x05, 0x40, 0x07, 0x19, 0x0a, 0x49, ++ 0x16, 0x07, 0x40, 0x19, 0x0a, 0x49, 0x16, 0x07, 0x40, 0x19, 0x0a, 0x49, 0x16, 0x07, 0x40, 0x46, ++ 0x07, 0x05, 0x05, 0x0b, 0x15, 0x0b, 0x15, 0x11, 0x17, 0x0a, 0x49, 0x17, 0x0a, 0x49, 0x40, 0x40, ++ 0x40, 0x1c, 0x1c, 0x11, 0x40, 0x0f, 0x11, 0x12, 0x12, 0x26, 0x27, 0x16, 0x07, 0x15, 0x16, 0x0e, ++ 0x01, 0x2c, 0x19, 0x11, 0x40, 0x11, 0x0e, 0x12, 0x0b, 0x11, 0x12, 0x0d, 0x0b, 0x11, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x45, 0x0c, 0x41, 0x52, 0x40, 0x13, 0x45, 0x4c, 0x27, 0x40, 0x41, 0x40, 0x40, 0x40, 0x0f, ++ 0x41, 0x45, 0x4b, 0x0d, 0x4c, 0x45, 0x01, 0x0e, 0x0e, 0x07, 0x07, 0x09, 0x42, 0x06, 0x44, 0x07, ++ 0x53, 0x27, 0x0c, 0x11, 0x40, 0x49, 0x0b, 0x40, 0x40, 0x40, 0x41, 0x41, 0x4a, 0x4b, 0x44, 0x4b, ++ 0x4c, 0x45, 0x4a, 0x53, 0x4b, 0x02, 0x4b, 0x53, 0x53, 0x4c, 0x44, 0x04, 0x05, 0x04, 0x4a, 0x4b, ++ 0x44, 0x4b, 0x4c, 0x45, 0x4a, 0x53, 0x4b, 0x02, 0x4b, 0x53, 0x53, 0x4c, 0x44, 0x04, 0x05, 0x04, ++ 0x15, 0x49, 0x11, 0x40, 0x48, 0x40, 0x41, 0x07, 0x41, 0x05, 0x05, 0x01, 0x07, 0x19, 0x0a, 0x49, ++ 0x16, 0x07, 0x40, 0x19, 0x0a, 0x49, 0x16, 0x07, 0x40, 0x19, 0x0a, 0x49, 0x16, 0x07, 0x40, 0x46, ++ 0x07, 0x05, 0x05, 0x0c, 0x15, 0x0c, 0x15, 0x11, 0x17, 0x0a, 0x49, 0x17, 0x0a, 0x49, 0x40, 0x40, ++ 0x40, 0x1b, 0x1b, 0x11, 0x40, 0x0f, 0x11, 0x12, 0x12, 0x26, 0x27, 0x16, 0x07, 0x15, 0x16, 0x0e, ++ 0x01, 0x2b, 0x19, 0x11, 0x40, 0x11, 0x0e, 0x12, 0x0c, 0x11, 0x13, 0x0d, 0x0c, 0x11, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x46, 0x0d, 0x40, 0x51, 0x40, 0x12, 0x46, 0x4d, 0x27, 0x40, 0x40, 0x40, 0x40, 0x40, 0x0f, ++ 0x40, 0x44, 0x4a, 0x0e, 0x4b, 0x44, 0x03, 0x11, 0x11, 0x07, 0x07, 0x08, 0x41, 0x07, 0x43, 0x07, ++ 0x52, 0x27, 0x0d, 0x10, 0x40, 0x48, 0x0a, 0x40, 0x40, 0x40, 0x40, 0x40, 0x49, 0x4a, 0x43, 0x4a, ++ 0x4b, 0x44, 0x49, 0x52, 0x4a, 0x03, 0x4a, 0x52, 0x52, 0x4b, 0x43, 0x05, 0x06, 0x05, 0x49, 0x4a, ++ 0x43, 0x4a, 0x4b, 0x44, 0x49, 0x52, 0x4a, 0x03, 0x4a, 0x52, 0x52, 0x4b, 0x43, 0x05, 0x06, 0x05, ++ 0x16, 0x48, 0x13, 0x40, 0x48, 0x40, 0x40, 0x07, 0x40, 0x06, 0x06, 0x03, 0x07, 0x18, 0x09, 0x48, ++ 0x17, 0x07, 0x40, 0x18, 0x09, 0x48, 0x17, 0x07, 0x40, 0x18, 0x09, 0x48, 0x17, 0x07, 0x40, 0x47, ++ 0x07, 0x06, 0x06, 0x0d, 0x16, 0x0d, 0x16, 0x10, 0x17, 0x09, 0x48, 0x17, 0x09, 0x48, 0x40, 0x40, ++ 0x40, 0x1a, 0x1a, 0x10, 0x40, 0x0f, 0x10, 0x11, 0x11, 0x27, 0x27, 0x17, 0x07, 0x16, 0x17, 0x0f, ++ 0x00, 0x2a, 0x18, 0x10, 0x40, 0x10, 0x0f, 0x11, 0x0d, 0x10, 0x14, 0x0e, 0x0d, 0x10, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x47, 0x0e, 0x40, 0x51, 0x40, 0x11, 0x47, 0x4e, 0x27, 0x40, 0x40, 0x40, 0x40, 0x40, 0x0f, ++ 0x40, 0x42, 0x49, 0x0e, 0x4a, 0x42, 0x04, 0x13, 0x13, 0x07, 0x07, 0x08, 0x41, 0x07, 0x42, 0x07, ++ 0x51, 0x27, 0x0e, 0x10, 0x40, 0x48, 0x09, 0x40, 0x40, 0x40, 0x40, 0x40, 0x49, 0x49, 0x42, 0x49, ++ 0x4a, 0x42, 0x49, 0x51, 0x49, 0x05, 0x49, 0x51, 0x51, 0x4a, 0x42, 0x06, 0x06, 0x06, 0x49, 0x49, ++ 0x42, 0x49, 0x4a, 0x42, 0x49, 0x51, 0x49, 0x05, 0x49, 0x51, 0x51, 0x4a, 0x42, 0x06, 0x06, 0x06, ++ 0x16, 0x48, 0x14, 0x40, 0x48, 0x40, 0x40, 0x07, 0x40, 0x06, 0x06, 0x04, 0x07, 0x18, 0x08, 0x48, ++ 0x17, 0x07, 0x40, 0x18, 0x08, 0x48, 0x17, 0x07, 0x40, 0x18, 0x08, 0x48, 0x17, 0x07, 0x40, 0x47, ++ 0x07, 0x06, 0x06, 0x0e, 0x16, 0x0e, 0x16, 0x10, 0x17, 0x08, 0x48, 0x17, 0x08, 0x48, 0x40, 0x40, ++ 0x40, 0x19, 0x19, 0x10, 0x40, 0x0f, 0x10, 0x10, 0x10, 0x27, 0x27, 0x17, 0x07, 0x16, 0x17, 0x0f, ++ 0x00, 0x29, 0x18, 0x10, 0x40, 0x10, 0x0f, 0x10, 0x0e, 0x10, 0x15, 0x0e, 0x0e, 0x10, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x47, 0x0f, 0x40, 0x50, 0x40, 0x10, 0x47, 0x4f, 0x27, 0x40, 0x40, 0x40, 0x40, 0x40, 0x0f, ++ 0x40, 0x40, 0x48, 0x0f, 0x48, 0x40, 0x06, 0x16, 0x16, 0x07, 0x07, 0x08, 0x40, 0x07, 0x40, 0x07, ++ 0x50, 0x27, 0x0f, 0x10, 0x40, 0x48, 0x08, 0x40, 0x40, 0x40, 0x40, 0x40, 0x48, 0x48, 0x40, 0x48, ++ 0x48, 0x40, 0x48, 0x50, 0x48, 0x07, 0x48, 0x50, 0x50, 0x48, 0x40, 0x07, 0x07, 0x07, 0x48, 0x48, ++ 0x40, 0x48, 0x48, 0x40, 0x48, 0x50, 0x48, 0x07, 0x48, 0x50, 0x50, 0x48, 0x40, 0x07, 0x07, 0x07, ++ 0x17, 0x48, 0x16, 0x40, 0x48, 0x40, 0x40, 0x07, 0x40, 0x07, 0x07, 0x06, 0x07, 0x18, 0x08, 0x48, ++ 0x17, 0x07, 0x40, 0x18, 0x08, 0x48, 0x17, 0x07, 0x40, 0x18, 0x08, 0x48, 0x17, 0x07, 0x40, 0x47, ++ 0x07, 0x07, 0x07, 0x0f, 0x17, 0x0f, 0x17, 0x10, 0x17, 0x08, 0x48, 0x17, 0x08, 0x48, 0x40, 0x40, ++ 0x40, 0x18, 0x18, 0x10, 0x40, 0x0f, 0x10, 0x10, 0x10, 0x27, 0x27, 0x17, 0x07, 0x17, 0x17, 0x0f, ++ 0x00, 0x28, 0x18, 0x10, 0x40, 0x10, 0x0f, 0x10, 0x0f, 0x10, 0x17, 0x0f, 0x0f, 0x10, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x48, 0x10, 0x00, 0x4f, 0x40, 0x0f, 0x48, 0x50, 0x27, 0x40, 0x00, 0x40, 0x40, 0x40, 0x0f, ++ 0x00, 0x00, 0x47, 0x10, 0x47, 0x00, 0x08, 0x18, 0x18, 0x07, 0x07, 0x07, 0x00, 0x08, 0x00, 0x07, ++ 0x4f, 0x27, 0x10, 0x0f, 0x40, 0x47, 0x07, 0x40, 0x40, 0x40, 0x00, 0x00, 0x47, 0x47, 0x00, 0x47, ++ 0x47, 0x00, 0x47, 0x4f, 0x47, 0x08, 0x47, 0x4f, 0x4f, 0x47, 0x00, 0x08, 0x08, 0x08, 0x47, 0x47, ++ 0x00, 0x47, 0x47, 0x00, 0x47, 0x4f, 0x47, 0x08, 0x47, 0x4f, 0x4f, 0x47, 0x00, 0x08, 0x08, 0x08, ++ 0x18, 0x47, 0x18, 0x40, 0x48, 0x40, 0x00, 0x07, 0x00, 0x08, 0x08, 0x08, 0x07, 0x17, 0x07, 0x47, ++ 0x18, 0x07, 0x40, 0x17, 0x07, 0x47, 0x18, 0x07, 0x40, 0x17, 0x07, 0x47, 0x18, 0x07, 0x40, 0x48, ++ 0x07, 0x08, 0x08, 0x10, 0x18, 0x10, 0x18, 0x0f, 0x17, 0x07, 0x47, 0x17, 0x07, 0x47, 0x40, 0x40, ++ 0x40, 0x17, 0x17, 0x0f, 0x40, 0x0f, 0x0f, 0x0f, 0x0f, 0x28, 0x27, 0x18, 0x07, 0x18, 0x18, 0x10, ++ 0x40, 0x27, 0x17, 0x0f, 0x40, 0x0f, 0x10, 0x0f, 0x10, 0x0f, 0x18, 0x10, 0x10, 0x0f, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x48, 0x11, 0x00, 0x4f, 0x40, 0x0e, 0x48, 0x51, 0x27, 0x40, 0x00, 0x40, 0x40, 0x40, 0x0f, ++ 0x00, 0x02, 0x46, 0x10, 0x46, 0x02, 0x0a, 0x1b, 0x1b, 0x07, 0x07, 0x07, 0x00, 0x08, 0x01, 0x07, ++ 0x4e, 0x27, 0x11, 0x0f, 0x40, 0x47, 0x06, 0x40, 0x40, 0x40, 0x00, 0x00, 0x47, 0x46, 0x01, 0x46, ++ 0x46, 0x02, 0x47, 0x4e, 0x46, 0x0a, 0x46, 0x4e, 0x4e, 0x46, 0x01, 0x09, 0x08, 0x09, 0x47, 0x46, ++ 0x01, 0x46, 0x46, 0x02, 0x47, 0x4e, 0x46, 0x0a, 0x46, 0x4e, 0x4e, 0x46, 0x01, 0x09, 0x08, 0x09, ++ 0x18, 0x47, 0x1a, 0x40, 0x48, 0x40, 0x00, 0x07, 0x00, 0x08, 0x08, 0x0a, 0x07, 0x17, 0x07, 0x47, ++ 0x18, 0x07, 0x40, 0x17, 0x07, 0x47, 0x18, 0x07, 0x40, 0x17, 0x07, 0x47, 0x18, 0x07, 0x40, 0x48, ++ 0x07, 0x08, 0x08, 0x11, 0x18, 0x11, 0x18, 0x0f, 0x17, 0x07, 0x47, 0x17, 0x07, 0x47, 0x40, 0x40, ++ 0x40, 0x16, 0x16, 0x0f, 0x40, 0x0f, 0x0f, 0x0f, 0x0f, 0x28, 0x27, 0x18, 0x07, 0x18, 0x18, 0x10, ++ 0x40, 0x26, 0x17, 0x0f, 0x40, 0x0f, 0x10, 0x0f, 0x11, 0x0f, 0x19, 0x10, 0x11, 0x0f, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x49, 0x12, 0x00, 0x4e, 0x40, 0x0d, 0x49, 0x52, 0x27, 0x40, 0x00, 0x40, 0x40, 0x40, 0x0f, ++ 0x00, 0x03, 0x45, 0x11, 0x45, 0x03, 0x0c, 0x1d, 0x1d, 0x07, 0x07, 0x07, 0x01, 0x08, 0x02, 0x07, ++ 0x4d, 0x27, 0x12, 0x0f, 0x40, 0x47, 0x05, 0x40, 0x40, 0x40, 0x00, 0x00, 0x46, 0x45, 0x02, 0x45, ++ 0x45, 0x03, 0x46, 0x4d, 0x45, 0x0b, 0x45, 0x4d, 0x4d, 0x45, 0x02, 0x0a, 0x09, 0x0a, 0x46, 0x45, ++ 0x02, 0x45, 0x45, 0x03, 0x46, 0x4d, 0x45, 0x0b, 0x45, 0x4d, 0x4d, 0x45, 0x02, 0x0a, 0x09, 0x0a, ++ 0x19, 0x47, 0x1c, 0x40, 0x48, 0x40, 0x00, 0x07, 0x00, 0x09, 0x09, 0x0c, 0x07, 0x17, 0x06, 0x47, ++ 0x18, 0x07, 0x40, 0x17, 0x06, 0x47, 0x18, 0x07, 0x40, 0x17, 0x06, 0x47, 0x18, 0x07, 0x40, 0x48, ++ 0x07, 0x09, 0x09, 0x12, 0x19, 0x12, 0x19, 0x0f, 0x17, 0x06, 0x47, 0x17, 0x06, 0x47, 0x40, 0x40, ++ 0x40, 0x15, 0x15, 0x0f, 0x40, 0x0f, 0x0f, 0x0e, 0x0e, 0x28, 0x27, 0x18, 0x07, 0x19, 0x18, 0x10, ++ 0x40, 0x25, 0x17, 0x0f, 0x40, 0x0f, 0x10, 0x0e, 0x12, 0x0f, 0x1a, 0x11, 0x12, 0x0f, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x4a, 0x13, 0x01, 0x4d, 0x40, 0x0c, 0x4a, 0x53, 0x27, 0x40, 0x01, 0x40, 0x40, 0x40, 0x0f, ++ 0x01, 0x05, 0x44, 0x12, 0x43, 0x05, 0x0e, 0x20, 0x20, 0x07, 0x07, 0x06, 0x02, 0x09, 0x04, 0x07, ++ 0x4c, 0x27, 0x13, 0x0e, 0x40, 0x46, 0x04, 0x40, 0x40, 0x40, 0x01, 0x01, 0x45, 0x44, 0x04, 0x44, ++ 0x43, 0x05, 0x45, 0x4c, 0x44, 0x0d, 0x44, 0x4c, 0x4c, 0x43, 0x04, 0x0b, 0x0a, 0x0b, 0x45, 0x44, ++ 0x04, 0x44, 0x43, 0x05, 0x45, 0x4c, 0x44, 0x0d, 0x44, 0x4c, 0x4c, 0x43, 0x04, 0x0b, 0x0a, 0x0b, ++ 0x1a, 0x46, 0x1e, 0x40, 0x48, 0x40, 0x01, 0x07, 0x01, 0x0a, 0x0a, 0x0e, 0x07, 0x16, 0x05, 0x46, ++ 0x19, 0x07, 0x40, 0x16, 0x05, 0x46, 0x19, 0x07, 0x40, 0x16, 0x05, 0x46, 0x19, 0x07, 0x40, 0x49, ++ 0x07, 0x0a, 0x0a, 0x13, 0x1a, 0x13, 0x1a, 0x0e, 0x17, 0x05, 0x46, 0x17, 0x05, 0x46, 0x40, 0x40, ++ 0x40, 0x14, 0x14, 0x0e, 0x40, 0x0f, 0x0e, 0x0d, 0x0d, 0x29, 0x27, 0x19, 0x07, 0x1a, 0x19, 0x11, ++ 0x41, 0x24, 0x16, 0x0e, 0x40, 0x0e, 0x11, 0x0d, 0x13, 0x0e, 0x1c, 0x12, 0x13, 0x0e, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x4a, 0x14, 0x01, 0x4d, 0x40, 0x0b, 0x4a, 0x54, 0x27, 0x40, 0x01, 0x40, 0x40, 0x40, 0x0f, ++ 0x01, 0x06, 0x43, 0x12, 0x42, 0x06, 0x10, 0x22, 0x22, 0x07, 0x07, 0x06, 0x02, 0x09, 0x05, 0x07, ++ 0x4b, 0x27, 0x14, 0x0e, 0x40, 0x46, 0x03, 0x40, 0x40, 0x40, 0x01, 0x01, 0x45, 0x43, 0x05, 0x43, ++ 0x42, 0x06, 0x45, 0x4b, 0x43, 0x0e, 0x43, 0x4b, 0x4b, 0x42, 0x05, 0x0c, 0x0a, 0x0c, 0x45, 0x43, ++ 0x05, 0x43, 0x42, 0x06, 0x45, 0x4b, 0x43, 0x0e, 0x43, 0x4b, 0x4b, 0x42, 0x05, 0x0c, 0x0a, 0x0c, ++ 0x1a, 0x46, 0x20, 0x40, 0x48, 0x40, 0x01, 0x07, 0x01, 0x0a, 0x0a, 0x10, 0x07, 0x16, 0x05, 0x46, ++ 0x19, 0x07, 0x40, 0x16, 0x05, 0x46, 0x19, 0x07, 0x40, 0x16, 0x05, 0x46, 0x19, 0x07, 0x40, 0x49, ++ 0x07, 0x0a, 0x0a, 0x14, 0x1a, 0x14, 0x1a, 0x0e, 0x17, 0x05, 0x46, 0x17, 0x05, 0x46, 0x40, 0x40, ++ 0x40, 0x13, 0x13, 0x0e, 0x40, 0x0f, 0x0e, 0x0d, 0x0d, 0x29, 0x27, 0x19, 0x07, 0x1a, 0x19, 0x11, ++ 0x41, 0x23, 0x16, 0x0e, 0x40, 0x0e, 0x11, 0x0d, 0x14, 0x0e, 0x1d, 0x12, 0x14, 0x0e, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x4b, 0x15, 0x01, 0x4c, 0x40, 0x0a, 0x4b, 0x55, 0x27, 0x40, 0x01, 0x40, 0x40, 0x40, 0x0f, ++ 0x01, 0x08, 0x42, 0x13, 0x41, 0x08, 0x12, 0x25, 0x25, 0x07, 0x07, 0x06, 0x03, 0x09, 0x06, 0x07, ++ 0x4a, 0x27, 0x15, 0x0e, 0x40, 0x46, 0x02, 0x40, 0x40, 0x40, 0x01, 0x01, 0x44, 0x42, 0x06, 0x42, ++ 0x41, 0x08, 0x44, 0x4a, 0x42, 0x10, 0x42, 0x4a, 0x4a, 0x41, 0x06, 0x0d, 0x0b, 0x0d, 0x44, 0x42, ++ 0x06, 0x42, 0x41, 0x08, 0x44, 0x4a, 0x42, 0x10, 0x42, 0x4a, 0x4a, 0x41, 0x06, 0x0d, 0x0b, 0x0d, ++ 0x1b, 0x46, 0x22, 0x40, 0x48, 0x40, 0x01, 0x07, 0x01, 0x0b, 0x0b, 0x12, 0x07, 0x16, 0x04, 0x46, ++ 0x19, 0x07, 0x40, 0x16, 0x04, 0x46, 0x19, 0x07, 0x40, 0x16, 0x04, 0x46, 0x19, 0x07, 0x40, 0x49, ++ 0x07, 0x0b, 0x0b, 0x15, 0x1b, 0x15, 0x1b, 0x0e, 0x17, 0x04, 0x46, 0x17, 0x04, 0x46, 0x40, 0x40, ++ 0x40, 0x12, 0x12, 0x0e, 0x40, 0x0f, 0x0e, 0x0c, 0x0c, 0x29, 0x27, 0x19, 0x07, 0x1b, 0x19, 0x11, ++ 0x41, 0x22, 0x16, 0x0e, 0x40, 0x0e, 0x11, 0x0c, 0x15, 0x0e, 0x1e, 0x13, 0x15, 0x0e, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x4c, 0x15, 0x01, 0x4c, 0x40, 0x09, 0x4c, 0x56, 0x27, 0x40, 0x01, 0x40, 0x40, 0x40, 0x0f, ++ 0x01, 0x09, 0x42, 0x13, 0x40, 0x09, 0x13, 0x27, 0x27, 0x07, 0x07, 0x05, 0x03, 0x09, 0x07, 0x07, ++ 0x4a, 0x27, 0x15, 0x0d, 0x40, 0x46, 0x01, 0x40, 0x40, 0x40, 0x01, 0x01, 0x44, 0x42, 0x07, 0x42, ++ 0x40, 0x09, 0x44, 0x4a, 0x42, 0x11, 0x42, 0x4a, 0x4a, 0x40, 0x07, 0x0d, 0x0b, 0x0d, 0x44, 0x42, ++ 0x07, 0x42, 0x40, 0x09, 0x44, 0x4a, 0x42, 0x11, 0x42, 0x4a, 0x4a, 0x40, 0x07, 0x0d, 0x0b, 0x0d, ++ 0x1b, 0x46, 0x23, 0x40, 0x48, 0x40, 0x01, 0x07, 0x01, 0x0b, 0x0b, 0x13, 0x07, 0x15, 0x03, 0x46, ++ 0x19, 0x07, 0x40, 0x15, 0x03, 0x46, 0x19, 0x07, 0x40, 0x15, 0x03, 0x46, 0x19, 0x07, 0x40, 0x4a, ++ 0x07, 0x0b, 0x0b, 0x15, 0x1b, 0x15, 0x1b, 0x0d, 0x17, 0x03, 0x46, 0x17, 0x03, 0x46, 0x40, 0x40, ++ 0x40, 0x11, 0x11, 0x0d, 0x40, 0x0f, 0x0d, 0x0b, 0x0b, 0x29, 0x27, 0x19, 0x07, 0x1b, 0x19, 0x11, ++ 0x42, 0x21, 0x15, 0x0d, 0x40, 0x0d, 0x11, 0x0b, 0x15, 0x0d, 0x1f, 0x13, 0x15, 0x0d, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x4c, 0x16, 0x02, 0x4b, 0x40, 0x09, 0x4c, 0x56, 0x27, 0x40, 0x02, 0x40, 0x40, 0x40, 0x0f, ++ 0x02, 0x0b, 0x41, 0x14, 0x01, 0x0b, 0x15, 0x2a, 0x2a, 0x07, 0x07, 0x05, 0x04, 0x0a, 0x09, 0x07, ++ 0x49, 0x27, 0x16, 0x0d, 0x40, 0x45, 0x01, 0x40, 0x40, 0x40, 0x02, 0x02, 0x43, 0x41, 0x09, 0x41, ++ 0x01, 0x0b, 0x43, 0x49, 0x41, 0x13, 0x41, 0x49, 0x49, 0x01, 0x09, 0x0e, 0x0c, 0x0e, 0x43, 0x41, ++ 0x09, 0x41, 0x01, 0x0b, 0x43, 0x49, 0x41, 0x13, 0x41, 0x49, 0x49, 0x01, 0x09, 0x0e, 0x0c, 0x0e, ++ 0x1c, 0x45, 0x25, 0x40, 0x48, 0x40, 0x02, 0x07, 0x02, 0x0c, 0x0c, 0x15, 0x07, 0x15, 0x03, 0x45, ++ 0x1a, 0x07, 0x40, 0x15, 0x03, 0x45, 0x1a, 0x07, 0x40, 0x15, 0x03, 0x45, 0x1a, 0x07, 0x40, 0x4a, ++ 0x07, 0x0c, 0x0c, 0x16, 0x1c, 0x16, 0x1c, 0x0d, 0x17, 0x03, 0x45, 0x17, 0x03, 0x45, 0x40, 0x40, ++ 0x40, 0x11, 0x11, 0x0d, 0x40, 0x0f, 0x0d, 0x0b, 0x0b, 0x2a, 0x27, 0x1a, 0x07, 0x1c, 0x1a, 0x12, ++ 0x42, 0x21, 0x15, 0x0d, 0x40, 0x0d, 0x12, 0x0b, 0x16, 0x0d, 0x21, 0x14, 0x16, 0x0d, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x4d, 0x17, 0x02, 0x4a, 0x40, 0x08, 0x4d, 0x57, 0x27, 0x40, 0x02, 0x40, 0x40, 0x40, 0x0f, ++ 0x02, 0x0d, 0x40, 0x15, 0x02, 0x0d, 0x17, 0x2c, 0x2c, 0x07, 0x07, 0x05, 0x05, 0x0a, 0x0a, 0x07, ++ 0x48, 0x27, 0x17, 0x0d, 0x40, 0x45, 0x00, 0x40, 0x40, 0x40, 0x02, 0x02, 0x42, 0x40, 0x0a, 0x40, ++ 0x02, 0x0d, 0x42, 0x48, 0x40, 0x15, 0x40, 0x48, 0x48, 0x02, 0x0a, 0x0f, 0x0d, 0x0f, 0x42, 0x40, ++ 0x0a, 0x40, 0x02, 0x0d, 0x42, 0x48, 0x40, 0x15, 0x40, 0x48, 0x48, 0x02, 0x0a, 0x0f, 0x0d, 0x0f, ++ 0x1d, 0x45, 0x27, 0x40, 0x48, 0x40, 0x02, 0x07, 0x02, 0x0d, 0x0d, 0x17, 0x07, 0x15, 0x02, 0x45, ++ 0x1a, 0x07, 0x40, 0x15, 0x02, 0x45, 0x1a, 0x07, 0x40, 0x15, 0x02, 0x45, 0x1a, 0x07, 0x40, 0x4a, ++ 0x07, 0x0d, 0x0d, 0x17, 0x1d, 0x17, 0x1d, 0x0d, 0x17, 0x02, 0x45, 0x17, 0x02, 0x45, 0x40, 0x40, ++ 0x40, 0x10, 0x10, 0x0d, 0x40, 0x0f, 0x0d, 0x0a, 0x0a, 0x2a, 0x27, 0x1a, 0x07, 0x1d, 0x1a, 0x12, ++ 0x42, 0x20, 0x15, 0x0d, 0x40, 0x0d, 0x12, 0x0a, 0x17, 0x0d, 0x22, 0x15, 0x17, 0x0d, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x4d, 0x18, 0x02, 0x4a, 0x40, 0x07, 0x4d, 0x58, 0x27, 0x40, 0x02, 0x40, 0x40, 0x40, 0x0f, ++ 0x02, 0x0e, 0x00, 0x15, 0x03, 0x0e, 0x19, 0x2f, 0x2f, 0x07, 0x07, 0x05, 0x05, 0x0a, 0x0b, 0x07, ++ 0x47, 0x27, 0x18, 0x0d, 0x40, 0x45, 0x40, 0x40, 0x40, 0x40, 0x02, 0x02, 0x42, 0x00, 0x0b, 0x00, ++ 0x03, 0x0e, 0x42, 0x47, 0x00, 0x16, 0x00, 0x47, 0x47, 0x03, 0x0b, 0x10, 0x0d, 0x10, 0x42, 0x00, ++ 0x0b, 0x00, 0x03, 0x0e, 0x42, 0x47, 0x00, 0x16, 0x00, 0x47, 0x47, 0x03, 0x0b, 0x10, 0x0d, 0x10, ++ 0x1d, 0x45, 0x29, 0x40, 0x48, 0x40, 0x02, 0x07, 0x02, 0x0d, 0x0d, 0x19, 0x07, 0x15, 0x02, 0x45, ++ 0x1a, 0x07, 0x40, 0x15, 0x02, 0x45, 0x1a, 0x07, 0x40, 0x15, 0x02, 0x45, 0x1a, 0x07, 0x40, 0x4a, ++ 0x07, 0x0d, 0x0d, 0x18, 0x1d, 0x18, 0x1d, 0x0d, 0x17, 0x02, 0x45, 0x17, 0x02, 0x45, 0x40, 0x40, ++ 0x40, 0x0f, 0x0f, 0x0d, 0x40, 0x0f, 0x0d, 0x0a, 0x0a, 0x2a, 0x27, 0x1a, 0x07, 0x1d, 0x1a, 0x12, ++ 0x42, 0x1f, 0x15, 0x0d, 0x40, 0x0d, 0x12, 0x0a, 0x18, 0x0d, 0x23, 0x15, 0x18, 0x0d, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x4e, 0x19, 0x03, 0x49, 0x40, 0x06, 0x4e, 0x59, 0x27, 0x40, 0x03, 0x40, 0x40, 0x40, 0x0f, ++ 0x03, 0x10, 0x01, 0x16, 0x04, 0x10, 0x1b, 0x31, 0x31, 0x07, 0x07, 0x04, 0x06, 0x0b, 0x0c, 0x07, ++ 0x46, 0x27, 0x19, 0x0c, 0x40, 0x44, 0x41, 0x40, 0x40, 0x40, 0x03, 0x03, 0x41, 0x01, 0x0c, 0x01, ++ 0x04, 0x10, 0x41, 0x46, 0x01, 0x18, 0x01, 0x46, 0x46, 0x04, 0x0c, 0x11, 0x0e, 0x11, 0x41, 0x01, ++ 0x0c, 0x01, 0x04, 0x10, 0x41, 0x46, 0x01, 0x18, 0x01, 0x46, 0x46, 0x04, 0x0c, 0x11, 0x0e, 0x11, ++ 0x1e, 0x44, 0x2b, 0x40, 0x48, 0x40, 0x03, 0x07, 0x03, 0x0e, 0x0e, 0x1b, 0x07, 0x14, 0x01, 0x44, ++ 0x1b, 0x07, 0x40, 0x14, 0x01, 0x44, 0x1b, 0x07, 0x40, 0x14, 0x01, 0x44, 0x1b, 0x07, 0x40, 0x4b, ++ 0x07, 0x0e, 0x0e, 0x19, 0x1e, 0x19, 0x1e, 0x0c, 0x17, 0x01, 0x44, 0x17, 0x01, 0x44, 0x40, 0x40, ++ 0x40, 0x0e, 0x0e, 0x0c, 0x40, 0x0f, 0x0c, 0x09, 0x09, 0x2b, 0x27, 0x1b, 0x07, 0x1e, 0x1b, 0x13, ++ 0x43, 0x1e, 0x14, 0x0c, 0x40, 0x0c, 0x13, 0x09, 0x19, 0x0c, 0x24, 0x16, 0x19, 0x0c, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x4f, 0x1a, 0x03, 0x48, 0x40, 0x05, 0x4f, 0x5a, 0x27, 0x40, 0x03, 0x40, 0x40, 0x40, 0x0f, ++ 0x03, 0x11, 0x02, 0x17, 0x06, 0x11, 0x1d, 0x34, 0x34, 0x07, 0x07, 0x04, 0x07, 0x0b, 0x0e, 0x07, ++ 0x45, 0x27, 0x1a, 0x0c, 0x40, 0x44, 0x42, 0x40, 0x40, 0x40, 0x03, 0x03, 0x40, 0x02, 0x0e, 0x02, ++ 0x06, 0x11, 0x40, 0x45, 0x02, 0x19, 0x02, 0x45, 0x45, 0x06, 0x0e, 0x12, 0x0f, 0x12, 0x40, 0x02, ++ 0x0e, 0x02, 0x06, 0x11, 0x40, 0x45, 0x02, 0x19, 0x02, 0x45, 0x45, 0x06, 0x0e, 0x12, 0x0f, 0x12, ++ 0x1f, 0x44, 0x2d, 0x40, 0x48, 0x40, 0x03, 0x07, 0x03, 0x0f, 0x0f, 0x1d, 0x07, 0x14, 0x00, 0x44, ++ 0x1b, 0x07, 0x40, 0x14, 0x00, 0x44, 0x1b, 0x07, 0x40, 0x14, 0x00, 0x44, 0x1b, 0x07, 0x40, 0x4b, ++ 0x07, 0x0f, 0x0f, 0x1a, 0x1f, 0x1a, 0x1f, 0x0c, 0x17, 0x00, 0x44, 0x17, 0x00, 0x44, 0x40, 0x40, ++ 0x40, 0x0d, 0x0d, 0x0c, 0x40, 0x0f, 0x0c, 0x08, 0x08, 0x2b, 0x27, 0x1b, 0x07, 0x1f, 0x1b, 0x13, ++ 0x43, 0x1d, 0x14, 0x0c, 0x40, 0x0c, 0x13, 0x08, 0x1a, 0x0c, 0x26, 0x17, 0x1a, 0x0c, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x4f, 0x1b, 0x03, 0x48, 0x40, 0x04, 0x4f, 0x5b, 0x27, 0x40, 0x03, 0x40, 0x40, 0x40, 0x0f, ++ 0x03, 0x13, 0x03, 0x17, 0x07, 0x13, 0x1f, 0x36, 0x36, 0x07, 0x07, 0x04, 0x07, 0x0b, 0x0f, 0x07, ++ 0x44, 0x27, 0x1b, 0x0c, 0x40, 0x44, 0x43, 0x40, 0x40, 0x40, 0x03, 0x03, 0x40, 0x03, 0x0f, 0x03, ++ 0x07, 0x13, 0x40, 0x44, 0x03, 0x1b, 0x03, 0x44, 0x44, 0x07, 0x0f, 0x13, 0x0f, 0x13, 0x40, 0x03, ++ 0x0f, 0x03, 0x07, 0x13, 0x40, 0x44, 0x03, 0x1b, 0x03, 0x44, 0x44, 0x07, 0x0f, 0x13, 0x0f, 0x13, ++ 0x1f, 0x44, 0x2f, 0x40, 0x48, 0x40, 0x03, 0x07, 0x03, 0x0f, 0x0f, 0x1f, 0x07, 0x14, 0x00, 0x44, ++ 0x1b, 0x07, 0x40, 0x14, 0x00, 0x44, 0x1b, 0x07, 0x40, 0x14, 0x00, 0x44, 0x1b, 0x07, 0x40, 0x4b, ++ 0x07, 0x0f, 0x0f, 0x1b, 0x1f, 0x1b, 0x1f, 0x0c, 0x17, 0x00, 0x44, 0x17, 0x00, 0x44, 0x40, 0x40, ++ 0x40, 0x0c, 0x0c, 0x0c, 0x40, 0x0f, 0x0c, 0x08, 0x08, 0x2b, 0x27, 0x1b, 0x07, 0x1f, 0x1b, 0x13, ++ 0x43, 0x1c, 0x14, 0x0c, 0x40, 0x0c, 0x13, 0x08, 0x1b, 0x0c, 0x27, 0x17, 0x1b, 0x0c, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x50, 0x1c, 0x04, 0x47, 0x40, 0x03, 0x50, 0x5c, 0x27, 0x40, 0x04, 0x40, 0x40, 0x40, 0x0f, ++ 0x04, 0x14, 0x04, 0x18, 0x08, 0x14, 0x21, 0x39, 0x39, 0x07, 0x07, 0x03, 0x08, 0x0c, 0x10, 0x07, ++ 0x43, 0x27, 0x1c, 0x0b, 0x40, 0x43, 0x44, 0x40, 0x40, 0x40, 0x04, 0x04, 0x00, 0x04, 0x10, 0x04, ++ 0x08, 0x14, 0x00, 0x43, 0x04, 0x1c, 0x04, 0x43, 0x43, 0x08, 0x10, 0x14, 0x10, 0x14, 0x00, 0x04, ++ 0x10, 0x04, 0x08, 0x14, 0x00, 0x43, 0x04, 0x1c, 0x04, 0x43, 0x43, 0x08, 0x10, 0x14, 0x10, 0x14, ++ 0x20, 0x43, 0x31, 0x40, 0x48, 0x40, 0x04, 0x07, 0x04, 0x10, 0x10, 0x21, 0x07, 0x13, 0x40, 0x43, ++ 0x1c, 0x07, 0x40, 0x13, 0x40, 0x43, 0x1c, 0x07, 0x40, 0x13, 0x40, 0x43, 0x1c, 0x07, 0x40, 0x4c, ++ 0x07, 0x10, 0x10, 0x1c, 0x20, 0x1c, 0x20, 0x0b, 0x17, 0x40, 0x43, 0x17, 0x40, 0x43, 0x40, 0x40, ++ 0x40, 0x0b, 0x0b, 0x0b, 0x40, 0x0f, 0x0b, 0x07, 0x07, 0x2c, 0x27, 0x1c, 0x07, 0x20, 0x1c, 0x14, ++ 0x44, 0x1b, 0x13, 0x0b, 0x40, 0x0b, 0x14, 0x07, 0x1c, 0x0b, 0x28, 0x18, 0x1c, 0x0b, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x51, 0x1d, 0x04, 0x47, 0x40, 0x02, 0x51, 0x5d, 0x27, 0x40, 0x04, 0x40, 0x40, 0x40, 0x0f, ++ 0x04, 0x16, 0x05, 0x18, 0x09, 0x16, 0x22, 0x3b, 0x3b, 0x07, 0x07, 0x03, 0x08, 0x0c, 0x11, 0x07, ++ 0x42, 0x27, 0x1d, 0x0b, 0x40, 0x43, 0x45, 0x40, 0x40, 0x40, 0x04, 0x04, 0x00, 0x05, 0x11, 0x05, ++ 0x09, 0x16, 0x00, 0x42, 0x05, 0x1e, 0x05, 0x42, 0x42, 0x09, 0x11, 0x15, 0x10, 0x15, 0x00, 0x05, ++ 0x11, 0x05, 0x09, 0x16, 0x00, 0x42, 0x05, 0x1e, 0x05, 0x42, 0x42, 0x09, 0x11, 0x15, 0x10, 0x15, ++ 0x20, 0x43, 0x32, 0x40, 0x48, 0x40, 0x04, 0x07, 0x04, 0x10, 0x10, 0x22, 0x07, 0x13, 0x41, 0x43, ++ 0x1c, 0x07, 0x40, 0x13, 0x41, 0x43, 0x1c, 0x07, 0x40, 0x13, 0x41, 0x43, 0x1c, 0x07, 0x40, 0x4c, ++ 0x07, 0x10, 0x10, 0x1d, 0x20, 0x1d, 0x20, 0x0b, 0x17, 0x41, 0x43, 0x17, 0x41, 0x43, 0x40, 0x40, ++ 0x40, 0x0a, 0x0a, 0x0b, 0x40, 0x0f, 0x0b, 0x06, 0x06, 0x2c, 0x27, 0x1c, 0x07, 0x20, 0x1c, 0x14, ++ 0x44, 0x1a, 0x13, 0x0b, 0x40, 0x0b, 0x14, 0x06, 0x1d, 0x0b, 0x29, 0x18, 0x1d, 0x0b, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x51, 0x1e, 0x04, 0x46, 0x40, 0x01, 0x51, 0x5e, 0x27, 0x40, 0x04, 0x40, 0x40, 0x40, 0x0f, ++ 0x04, 0x18, 0x06, 0x19, 0x0b, 0x18, 0x24, 0x3e, 0x3e, 0x07, 0x07, 0x03, 0x09, 0x0c, 0x13, 0x07, ++ 0x41, 0x27, 0x1e, 0x0b, 0x40, 0x43, 0x46, 0x40, 0x40, 0x40, 0x04, 0x04, 0x01, 0x06, 0x13, 0x06, ++ 0x0b, 0x18, 0x01, 0x41, 0x06, 0x20, 0x06, 0x41, 0x41, 0x0b, 0x13, 0x16, 0x11, 0x16, 0x01, 0x06, ++ 0x13, 0x06, 0x0b, 0x18, 0x01, 0x41, 0x06, 0x20, 0x06, 0x41, 0x41, 0x0b, 0x13, 0x16, 0x11, 0x16, ++ 0x21, 0x43, 0x34, 0x40, 0x48, 0x40, 0x04, 0x07, 0x04, 0x11, 0x11, 0x24, 0x07, 0x13, 0x41, 0x43, ++ 0x1c, 0x07, 0x40, 0x13, 0x41, 0x43, 0x1c, 0x07, 0x40, 0x13, 0x41, 0x43, 0x1c, 0x07, 0x40, 0x4c, ++ 0x07, 0x11, 0x11, 0x1e, 0x21, 0x1e, 0x21, 0x0b, 0x17, 0x41, 0x43, 0x17, 0x41, 0x43, 0x40, 0x40, ++ 0x40, 0x09, 0x09, 0x0b, 0x40, 0x0f, 0x0b, 0x06, 0x06, 0x2c, 0x27, 0x1c, 0x07, 0x21, 0x1c, 0x14, ++ 0x44, 0x19, 0x13, 0x0b, 0x40, 0x0b, 0x14, 0x06, 0x1e, 0x0b, 0x2b, 0x19, 0x1e, 0x0b, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x52, 0x1f, 0x05, 0x45, 0x40, 0x00, 0x52, 0x5f, 0x27, 0x40, 0x05, 0x40, 0x40, 0x40, 0x0f, ++ 0x05, 0x19, 0x07, 0x1a, 0x0c, 0x19, 0x26, 0x3e, 0x3e, 0x07, 0x07, 0x02, 0x0a, 0x0d, 0x14, 0x07, ++ 0x40, 0x27, 0x1f, 0x0a, 0x40, 0x42, 0x47, 0x40, 0x40, 0x40, 0x05, 0x05, 0x02, 0x07, 0x14, 0x07, ++ 0x0c, 0x19, 0x02, 0x40, 0x07, 0x21, 0x07, 0x40, 0x40, 0x0c, 0x14, 0x17, 0x12, 0x17, 0x02, 0x07, ++ 0x14, 0x07, 0x0c, 0x19, 0x02, 0x40, 0x07, 0x21, 0x07, 0x40, 0x40, 0x0c, 0x14, 0x17, 0x12, 0x17, ++ 0x22, 0x42, 0x36, 0x40, 0x48, 0x40, 0x05, 0x07, 0x05, 0x12, 0x12, 0x26, 0x07, 0x12, 0x42, 0x42, ++ 0x1d, 0x07, 0x40, 0x12, 0x42, 0x42, 0x1d, 0x07, 0x40, 0x12, 0x42, 0x42, 0x1d, 0x07, 0x40, 0x4d, ++ 0x07, 0x12, 0x12, 0x1f, 0x22, 0x1f, 0x22, 0x0a, 0x17, 0x42, 0x42, 0x17, 0x42, 0x42, 0x40, 0x40, ++ 0x40, 0x08, 0x08, 0x0a, 0x40, 0x0f, 0x0a, 0x05, 0x05, 0x2d, 0x27, 0x1d, 0x07, 0x22, 0x1d, 0x15, ++ 0x45, 0x18, 0x12, 0x0a, 0x40, 0x0a, 0x15, 0x05, 0x1f, 0x0a, 0x2c, 0x1a, 0x1f, 0x0a, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x52, 0x20, 0x05, 0x45, 0x40, 0x40, 0x52, 0x60, 0x27, 0x40, 0x05, 0x40, 0x40, 0x40, 0x0f, ++ 0x05, 0x1b, 0x08, 0x1a, 0x0d, 0x1b, 0x28, 0x3e, 0x3e, 0x07, 0x07, 0x02, 0x0a, 0x0d, 0x15, 0x07, ++ 0x00, 0x27, 0x20, 0x0a, 0x40, 0x42, 0x48, 0x40, 0x40, 0x40, 0x05, 0x05, 0x02, 0x08, 0x15, 0x08, ++ 0x0d, 0x1b, 0x02, 0x00, 0x08, 0x23, 0x08, 0x00, 0x00, 0x0d, 0x15, 0x18, 0x12, 0x18, 0x02, 0x08, ++ 0x15, 0x08, 0x0d, 0x1b, 0x02, 0x00, 0x08, 0x23, 0x08, 0x00, 0x00, 0x0d, 0x15, 0x18, 0x12, 0x18, ++ 0x22, 0x42, 0x38, 0x40, 0x48, 0x40, 0x05, 0x07, 0x05, 0x12, 0x12, 0x28, 0x07, 0x12, 0x42, 0x42, ++ 0x1d, 0x07, 0x40, 0x12, 0x42, 0x42, 0x1d, 0x07, 0x40, 0x12, 0x42, 0x42, 0x1d, 0x07, 0x40, 0x4d, ++ 0x07, 0x12, 0x12, 0x20, 0x22, 0x20, 0x22, 0x0a, 0x17, 0x42, 0x42, 0x17, 0x42, 0x42, 0x40, 0x40, ++ 0x40, 0x07, 0x07, 0x0a, 0x40, 0x0f, 0x0a, 0x05, 0x05, 0x2d, 0x27, 0x1d, 0x07, 0x22, 0x1d, 0x15, ++ 0x45, 0x17, 0x12, 0x0a, 0x40, 0x0a, 0x15, 0x05, 0x20, 0x0a, 0x2d, 0x1a, 0x20, 0x0a, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x53, 0x21, 0x05, 0x44, 0x40, 0x41, 0x53, 0x61, 0x27, 0x40, 0x05, 0x40, 0x40, 0x40, 0x0f, ++ 0x05, 0x1c, 0x09, 0x1b, 0x0e, 0x1c, 0x2a, 0x3e, 0x3e, 0x07, 0x07, 0x02, 0x0b, 0x0d, 0x16, 0x07, ++ 0x01, 0x27, 0x21, 0x0a, 0x40, 0x42, 0x49, 0x40, 0x40, 0x40, 0x05, 0x05, 0x03, 0x09, 0x16, 0x09, ++ 0x0e, 0x1c, 0x03, 0x01, 0x09, 0x24, 0x09, 0x01, 0x01, 0x0e, 0x16, 0x19, 0x13, 0x19, 0x03, 0x09, ++ 0x16, 0x09, 0x0e, 0x1c, 0x03, 0x01, 0x09, 0x24, 0x09, 0x01, 0x01, 0x0e, 0x16, 0x19, 0x13, 0x19, ++ 0x23, 0x42, 0x3a, 0x40, 0x48, 0x40, 0x05, 0x07, 0x05, 0x13, 0x13, 0x2a, 0x07, 0x12, 0x43, 0x42, ++ 0x1d, 0x07, 0x40, 0x12, 0x43, 0x42, 0x1d, 0x07, 0x40, 0x12, 0x43, 0x42, 0x1d, 0x07, 0x40, 0x4d, ++ 0x07, 0x13, 0x13, 0x21, 0x23, 0x21, 0x23, 0x0a, 0x17, 0x43, 0x42, 0x17, 0x43, 0x42, 0x40, 0x40, ++ 0x40, 0x06, 0x06, 0x0a, 0x40, 0x0f, 0x0a, 0x04, 0x04, 0x2d, 0x27, 0x1d, 0x07, 0x23, 0x1d, 0x15, ++ 0x45, 0x16, 0x12, 0x0a, 0x40, 0x0a, 0x15, 0x04, 0x21, 0x0a, 0x2e, 0x1b, 0x21, 0x0a, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x54, 0x22, 0x06, 0x43, 0x40, 0x42, 0x54, 0x62, 0x27, 0x40, 0x06, 0x40, 0x40, 0x40, 0x0f, ++ 0x06, 0x1e, 0x0a, 0x1c, 0x10, 0x1e, 0x2c, 0x3e, 0x3e, 0x07, 0x07, 0x01, 0x0c, 0x0e, 0x18, 0x07, ++ 0x02, 0x27, 0x22, 0x09, 0x40, 0x41, 0x4a, 0x40, 0x40, 0x40, 0x06, 0x06, 0x04, 0x0a, 0x18, 0x0a, ++ 0x10, 0x1e, 0x04, 0x02, 0x0a, 0x26, 0x0a, 0x02, 0x02, 0x10, 0x18, 0x1a, 0x14, 0x1a, 0x04, 0x0a, ++ 0x18, 0x0a, 0x10, 0x1e, 0x04, 0x02, 0x0a, 0x26, 0x0a, 0x02, 0x02, 0x10, 0x18, 0x1a, 0x14, 0x1a, ++ 0x24, 0x41, 0x3c, 0x40, 0x48, 0x40, 0x06, 0x07, 0x06, 0x14, 0x14, 0x2c, 0x07, 0x11, 0x44, 0x41, ++ 0x1e, 0x07, 0x40, 0x11, 0x44, 0x41, 0x1e, 0x07, 0x40, 0x11, 0x44, 0x41, 0x1e, 0x07, 0x40, 0x4e, ++ 0x07, 0x14, 0x14, 0x22, 0x24, 0x22, 0x24, 0x09, 0x17, 0x44, 0x41, 0x17, 0x44, 0x41, 0x40, 0x40, ++ 0x40, 0x05, 0x05, 0x09, 0x40, 0x0f, 0x09, 0x03, 0x03, 0x2e, 0x27, 0x1e, 0x07, 0x24, 0x1e, 0x16, ++ 0x46, 0x15, 0x11, 0x09, 0x40, 0x09, 0x16, 0x03, 0x22, 0x09, 0x30, 0x1c, 0x22, 0x09, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x54, 0x23, 0x06, 0x43, 0x40, 0x43, 0x54, 0x63, 0x27, 0x40, 0x06, 0x40, 0x40, 0x40, 0x0f, ++ 0x06, 0x1f, 0x0b, 0x1c, 0x11, 0x1f, 0x2e, 0x3e, 0x3e, 0x07, 0x07, 0x01, 0x0c, 0x0e, 0x19, 0x07, ++ 0x03, 0x27, 0x23, 0x09, 0x40, 0x41, 0x4b, 0x40, 0x40, 0x40, 0x06, 0x06, 0x04, 0x0b, 0x19, 0x0b, ++ 0x11, 0x1f, 0x04, 0x03, 0x0b, 0x27, 0x0b, 0x03, 0x03, 0x11, 0x19, 0x1b, 0x14, 0x1b, 0x04, 0x0b, ++ 0x19, 0x0b, 0x11, 0x1f, 0x04, 0x03, 0x0b, 0x27, 0x0b, 0x03, 0x03, 0x11, 0x19, 0x1b, 0x14, 0x1b, ++ 0x24, 0x41, 0x3e, 0x40, 0x48, 0x40, 0x06, 0x07, 0x06, 0x14, 0x14, 0x2e, 0x07, 0x11, 0x44, 0x41, ++ 0x1e, 0x07, 0x40, 0x11, 0x44, 0x41, 0x1e, 0x07, 0x40, 0x11, 0x44, 0x41, 0x1e, 0x07, 0x40, 0x4e, ++ 0x07, 0x14, 0x14, 0x23, 0x24, 0x23, 0x24, 0x09, 0x17, 0x44, 0x41, 0x17, 0x44, 0x41, 0x40, 0x40, ++ 0x40, 0x04, 0x04, 0x09, 0x40, 0x0f, 0x09, 0x03, 0x03, 0x2e, 0x27, 0x1e, 0x07, 0x24, 0x1e, 0x16, ++ 0x46, 0x14, 0x11, 0x09, 0x40, 0x09, 0x16, 0x03, 0x23, 0x09, 0x31, 0x1c, 0x23, 0x09, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x55, 0x24, 0x06, 0x42, 0x40, 0x44, 0x55, 0x64, 0x27, 0x40, 0x06, 0x40, 0x40, 0x40, 0x0f, ++ 0x06, 0x21, 0x0c, 0x1d, 0x12, 0x21, 0x30, 0x3e, 0x3e, 0x07, 0x07, 0x01, 0x0d, 0x0e, 0x1a, 0x07, ++ 0x04, 0x27, 0x24, 0x09, 0x40, 0x41, 0x4c, 0x40, 0x40, 0x40, 0x06, 0x06, 0x05, 0x0c, 0x1a, 0x0c, ++ 0x12, 0x21, 0x05, 0x04, 0x0c, 0x29, 0x0c, 0x04, 0x04, 0x12, 0x1a, 0x1c, 0x15, 0x1c, 0x05, 0x0c, ++ 0x1a, 0x0c, 0x12, 0x21, 0x05, 0x04, 0x0c, 0x29, 0x0c, 0x04, 0x04, 0x12, 0x1a, 0x1c, 0x15, 0x1c, ++ 0x25, 0x41, 0x3e, 0x40, 0x48, 0x40, 0x06, 0x07, 0x06, 0x15, 0x15, 0x30, 0x07, 0x11, 0x45, 0x41, ++ 0x1e, 0x07, 0x40, 0x11, 0x45, 0x41, 0x1e, 0x07, 0x40, 0x11, 0x45, 0x41, 0x1e, 0x07, 0x40, 0x4e, ++ 0x07, 0x15, 0x15, 0x24, 0x25, 0x24, 0x25, 0x09, 0x17, 0x45, 0x41, 0x17, 0x45, 0x41, 0x40, 0x40, ++ 0x40, 0x03, 0x03, 0x09, 0x40, 0x0f, 0x09, 0x02, 0x02, 0x2e, 0x27, 0x1e, 0x07, 0x25, 0x1e, 0x16, ++ 0x46, 0x13, 0x11, 0x09, 0x40, 0x09, 0x16, 0x02, 0x24, 0x09, 0x32, 0x1d, 0x24, 0x09, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x56, 0x24, 0x06, 0x42, 0x40, 0x45, 0x56, 0x65, 0x27, 0x40, 0x06, 0x40, 0x40, 0x40, 0x0f, ++ 0x06, 0x22, 0x0c, 0x1d, 0x13, 0x22, 0x31, 0x3e, 0x3e, 0x07, 0x07, 0x00, 0x0d, 0x0e, 0x1b, 0x07, ++ 0x04, 0x27, 0x24, 0x08, 0x40, 0x41, 0x4d, 0x40, 0x40, 0x40, 0x06, 0x06, 0x05, 0x0c, 0x1b, 0x0c, ++ 0x13, 0x22, 0x05, 0x04, 0x0c, 0x2a, 0x0c, 0x04, 0x04, 0x13, 0x1b, 0x1c, 0x15, 0x1c, 0x05, 0x0c, ++ 0x1b, 0x0c, 0x13, 0x22, 0x05, 0x04, 0x0c, 0x2a, 0x0c, 0x04, 0x04, 0x13, 0x1b, 0x1c, 0x15, 0x1c, ++ 0x25, 0x41, 0x3e, 0x40, 0x48, 0x40, 0x06, 0x07, 0x06, 0x15, 0x15, 0x31, 0x07, 0x10, 0x46, 0x41, ++ 0x1e, 0x07, 0x40, 0x10, 0x46, 0x41, 0x1e, 0x07, 0x40, 0x10, 0x46, 0x41, 0x1e, 0x07, 0x40, 0x4f, ++ 0x07, 0x15, 0x15, 0x24, 0x25, 0x24, 0x25, 0x08, 0x17, 0x46, 0x41, 0x17, 0x46, 0x41, 0x40, 0x40, ++ 0x40, 0x02, 0x02, 0x08, 0x40, 0x0f, 0x08, 0x01, 0x01, 0x2e, 0x27, 0x1e, 0x07, 0x25, 0x1e, 0x16, ++ 0x47, 0x12, 0x10, 0x08, 0x40, 0x08, 0x16, 0x01, 0x24, 0x08, 0x33, 0x1d, 0x24, 0x08, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x56, 0x25, 0x07, 0x41, 0x40, 0x45, 0x56, 0x65, 0x27, 0x40, 0x07, 0x40, 0x40, 0x40, 0x0f, ++ 0x07, 0x24, 0x0d, 0x1e, 0x15, 0x24, 0x33, 0x3e, 0x3e, 0x07, 0x07, 0x00, 0x0e, 0x0f, 0x1d, 0x07, ++ 0x05, 0x27, 0x25, 0x08, 0x40, 0x40, 0x4d, 0x40, 0x40, 0x40, 0x07, 0x07, 0x06, 0x0d, 0x1d, 0x0d, ++ 0x15, 0x24, 0x06, 0x05, 0x0d, 0x2c, 0x0d, 0x05, 0x05, 0x15, 0x1d, 0x1d, 0x16, 0x1d, 0x06, 0x0d, ++ 0x1d, 0x0d, 0x15, 0x24, 0x06, 0x05, 0x0d, 0x2c, 0x0d, 0x05, 0x05, 0x15, 0x1d, 0x1d, 0x16, 0x1d, ++ 0x26, 0x40, 0x3e, 0x40, 0x48, 0x40, 0x07, 0x07, 0x07, 0x16, 0x16, 0x33, 0x07, 0x10, 0x46, 0x40, ++ 0x1f, 0x07, 0x40, 0x10, 0x46, 0x40, 0x1f, 0x07, 0x40, 0x10, 0x46, 0x40, 0x1f, 0x07, 0x40, 0x4f, ++ 0x07, 0x16, 0x16, 0x25, 0x26, 0x25, 0x26, 0x08, 0x17, 0x46, 0x40, 0x17, 0x46, 0x40, 0x40, 0x40, ++ 0x40, 0x02, 0x02, 0x08, 0x40, 0x0f, 0x08, 0x01, 0x01, 0x2f, 0x27, 0x1f, 0x07, 0x26, 0x1f, 0x17, ++ 0x47, 0x12, 0x10, 0x08, 0x40, 0x08, 0x17, 0x01, 0x25, 0x08, 0x35, 0x1e, 0x25, 0x08, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x57, 0x26, 0x07, 0x40, 0x40, 0x46, 0x57, 0x66, 0x27, 0x40, 0x07, 0x40, 0x40, 0x40, 0x0f, ++ 0x07, 0x26, 0x0e, 0x1f, 0x16, 0x26, 0x35, 0x3e, 0x3e, 0x07, 0x07, 0x00, 0x0f, 0x0f, 0x1e, 0x07, ++ 0x06, 0x27, 0x26, 0x08, 0x40, 0x40, 0x4e, 0x40, 0x40, 0x40, 0x07, 0x07, 0x07, 0x0e, 0x1e, 0x0e, ++ 0x16, 0x26, 0x07, 0x06, 0x0e, 0x2e, 0x0e, 0x06, 0x06, 0x16, 0x1e, 0x1e, 0x17, 0x1e, 0x07, 0x0e, ++ 0x1e, 0x0e, 0x16, 0x26, 0x07, 0x06, 0x0e, 0x2e, 0x0e, 0x06, 0x06, 0x16, 0x1e, 0x1e, 0x17, 0x1e, ++ 0x27, 0x40, 0x3e, 0x40, 0x48, 0x40, 0x07, 0x07, 0x07, 0x17, 0x17, 0x35, 0x07, 0x10, 0x47, 0x40, ++ 0x1f, 0x07, 0x40, 0x10, 0x47, 0x40, 0x1f, 0x07, 0x40, 0x10, 0x47, 0x40, 0x1f, 0x07, 0x40, 0x4f, ++ 0x07, 0x17, 0x17, 0x26, 0x27, 0x26, 0x27, 0x08, 0x17, 0x47, 0x40, 0x17, 0x47, 0x40, 0x40, 0x40, ++ 0x40, 0x01, 0x01, 0x08, 0x40, 0x0f, 0x08, 0x00, 0x00, 0x2f, 0x27, 0x1f, 0x07, 0x27, 0x1f, 0x17, ++ 0x47, 0x11, 0x10, 0x08, 0x40, 0x08, 0x17, 0x00, 0x26, 0x08, 0x36, 0x1f, 0x26, 0x08, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x57, 0x27, 0x07, 0x40, 0x40, 0x47, 0x57, 0x67, 0x27, 0x40, 0x07, 0x40, 0x40, 0x40, 0x0f, ++ 0x07, 0x27, 0x0f, 0x1f, 0x17, 0x27, 0x37, 0x3e, 0x3e, 0x07, 0x07, 0x00, 0x0f, 0x0f, 0x1f, 0x07, ++ 0x07, 0x27, 0x27, 0x08, 0x40, 0x40, 0x4f, 0x40, 0x40, 0x40, 0x07, 0x07, 0x07, 0x0f, 0x1f, 0x0f, ++ 0x17, 0x27, 0x07, 0x07, 0x0f, 0x2f, 0x0f, 0x07, 0x07, 0x17, 0x1f, 0x1f, 0x17, 0x1f, 0x07, 0x0f, ++ 0x1f, 0x0f, 0x17, 0x27, 0x07, 0x07, 0x0f, 0x2f, 0x0f, 0x07, 0x07, 0x17, 0x1f, 0x1f, 0x17, 0x1f, ++ 0x27, 0x40, 0x3e, 0x40, 0x48, 0x40, 0x07, 0x07, 0x07, 0x17, 0x17, 0x37, 0x07, 0x10, 0x47, 0x40, ++ 0x1f, 0x07, 0x40, 0x10, 0x47, 0x40, 0x1f, 0x07, 0x40, 0x10, 0x47, 0x40, 0x1f, 0x07, 0x40, 0x4f, ++ 0x07, 0x17, 0x17, 0x27, 0x27, 0x27, 0x27, 0x08, 0x17, 0x47, 0x40, 0x17, 0x47, 0x40, 0x40, 0x40, ++ 0x40, 0x00, 0x00, 0x08, 0x40, 0x0f, 0x08, 0x00, 0x00, 0x2f, 0x27, 0x1f, 0x07, 0x27, 0x1f, 0x17, ++ 0x47, 0x10, 0x10, 0x08, 0x40, 0x08, 0x17, 0x00, 0x27, 0x08, 0x37, 0x1f, 0x27, 0x08, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x3e, 0x48, 0x48, 0x60, 0x40, 0x27, 0x07, 0x07, 0x1f, 0x40, 0x48, 0x40, 0x40, 0x17, 0x0f, ++ 0x48, 0x68, 0x40, 0x07, 0x68, 0x68, 0x68, 0x68, 0x68, 0x07, 0x07, 0x0f, 0x3e, 0x17, 0x40, 0x07, ++ 0x68, 0x27, 0x50, 0x17, 0x40, 0x07, 0x1f, 0x40, 0x40, 0x40, 0x48, 0x48, 0x58, 0x60, 0x50, 0x60, ++ 0x68, 0x60, 0x58, 0x68, 0x68, 0x68, 0x58, 0x60, 0x68, 0x68, 0x68, 0x50, 0x48, 0x58, 0x58, 0x60, ++ 0x50, 0x60, 0x68, 0x60, 0x58, 0x68, 0x68, 0x68, 0x58, 0x60, 0x68, 0x68, 0x68, 0x50, 0x48, 0x58, ++ 0x07, 0x50, 0x58, 0x40, 0x40, 0x40, 0x48, 0x07, 0x48, 0x48, 0x48, 0x68, 0x50, 0x1f, 0x17, 0x50, ++ 0x0f, 0x07, 0x40, 0x1f, 0x17, 0x50, 0x0f, 0x07, 0x40, 0x1f, 0x17, 0x50, 0x0f, 0x07, 0x40, 0x40, ++ 0x07, 0x40, 0x40, 0x40, 0x07, 0x40, 0x07, 0x17, 0x17, 0x17, 0x50, 0x17, 0x17, 0x50, 0x40, 0x40, ++ 0x40, 0x2f, 0x17, 0x17, 0x40, 0x0f, 0x17, 0x1f, 0x1f, 0x1f, 0x27, 0x0f, 0x07, 0x07, 0x0f, 0x40, ++ 0x07, 0x3e, 0x1f, 0x17, 0x40, 0x0f, 0x17, 0x1f, 0x48, 0x17, 0x48, 0x48, 0x48, 0x17, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x3e, 0x47, 0x47, 0x5f, 0x40, 0x27, 0x07, 0x07, 0x20, 0x40, 0x47, 0x40, 0x40, 0x17, 0x0f, ++ 0x47, 0x66, 0x40, 0x08, 0x66, 0x66, 0x66, 0x65, 0x65, 0x07, 0x07, 0x0f, 0x3e, 0x17, 0x00, 0x07, ++ 0x67, 0x27, 0x4e, 0x17, 0x40, 0x07, 0x1f, 0x40, 0x40, 0x40, 0x47, 0x47, 0x57, 0x5f, 0x4f, 0x5f, ++ 0x66, 0x5e, 0x57, 0x67, 0x67, 0x66, 0x57, 0x5f, 0x67, 0x67, 0x66, 0x4f, 0x47, 0x56, 0x57, 0x5f, ++ 0x4f, 0x5f, 0x66, 0x5e, 0x57, 0x67, 0x67, 0x66, 0x57, 0x5f, 0x67, 0x67, 0x66, 0x4f, 0x47, 0x56, ++ 0x08, 0x4f, 0x56, 0x40, 0x40, 0x40, 0x47, 0x07, 0x47, 0x47, 0x47, 0x66, 0x4f, 0x1f, 0x17, 0x4f, ++ 0x10, 0x07, 0x40, 0x1f, 0x17, 0x4f, 0x10, 0x07, 0x40, 0x1f, 0x17, 0x4f, 0x10, 0x07, 0x40, 0x40, ++ 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x08, 0x17, 0x17, 0x17, 0x4f, 0x17, 0x17, 0x4f, 0x40, 0x40, ++ 0x40, 0x2f, 0x17, 0x17, 0x40, 0x0f, 0x17, 0x1f, 0x1f, 0x20, 0x27, 0x10, 0x07, 0x08, 0x10, 0x00, ++ 0x07, 0x3e, 0x1f, 0x17, 0x40, 0x0f, 0x17, 0x1f, 0x47, 0x17, 0x46, 0x47, 0x47, 0x17, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x3e, 0x46, 0x47, 0x5e, 0x40, 0x26, 0x06, 0x06, 0x20, 0x40, 0x47, 0x40, 0x40, 0x16, 0x0f, ++ 0x47, 0x64, 0x40, 0x08, 0x65, 0x64, 0x64, 0x63, 0x63, 0x07, 0x07, 0x0f, 0x3e, 0x17, 0x01, 0x07, ++ 0x66, 0x27, 0x4d, 0x17, 0x40, 0x07, 0x1e, 0x40, 0x40, 0x40, 0x47, 0x47, 0x56, 0x5e, 0x4e, 0x5e, ++ 0x65, 0x5d, 0x56, 0x66, 0x66, 0x64, 0x56, 0x5e, 0x66, 0x66, 0x64, 0x4e, 0x46, 0x55, 0x56, 0x5e, ++ 0x4e, 0x5e, 0x65, 0x5d, 0x56, 0x66, 0x66, 0x64, 0x56, 0x5e, 0x66, 0x66, 0x64, 0x4e, 0x46, 0x55, ++ 0x09, 0x4f, 0x54, 0x40, 0x40, 0x40, 0x47, 0x07, 0x47, 0x46, 0x46, 0x64, 0x4e, 0x1f, 0x16, 0x4f, ++ 0x10, 0x07, 0x40, 0x1f, 0x16, 0x4f, 0x10, 0x07, 0x40, 0x1f, 0x16, 0x4f, 0x10, 0x07, 0x40, 0x40, ++ 0x07, 0x00, 0x00, 0x01, 0x09, 0x01, 0x09, 0x17, 0x17, 0x16, 0x4f, 0x17, 0x16, 0x4f, 0x40, 0x40, ++ 0x40, 0x2e, 0x17, 0x17, 0x40, 0x0f, 0x17, 0x1e, 0x1e, 0x20, 0x27, 0x10, 0x07, 0x09, 0x10, 0x01, ++ 0x07, 0x3e, 0x1f, 0x17, 0x40, 0x0f, 0x17, 0x1e, 0x46, 0x17, 0x45, 0x46, 0x46, 0x17, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x3e, 0x45, 0x47, 0x5e, 0x40, 0x25, 0x06, 0x05, 0x20, 0x40, 0x47, 0x40, 0x40, 0x16, 0x0f, ++ 0x47, 0x63, 0x40, 0x08, 0x64, 0x63, 0x62, 0x60, 0x60, 0x07, 0x07, 0x0f, 0x3e, 0x17, 0x01, 0x07, ++ 0x65, 0x27, 0x4c, 0x17, 0x40, 0x07, 0x1d, 0x40, 0x40, 0x40, 0x47, 0x47, 0x56, 0x5d, 0x4e, 0x5d, ++ 0x64, 0x5c, 0x56, 0x65, 0x65, 0x63, 0x56, 0x5e, 0x65, 0x65, 0x63, 0x4d, 0x46, 0x54, 0x56, 0x5d, ++ 0x4e, 0x5d, 0x64, 0x5c, 0x56, 0x65, 0x65, 0x63, 0x56, 0x5e, 0x65, 0x65, 0x63, 0x4d, 0x46, 0x54, ++ 0x09, 0x4f, 0x52, 0x40, 0x40, 0x40, 0x47, 0x07, 0x47, 0x46, 0x46, 0x62, 0x4e, 0x1f, 0x16, 0x4f, ++ 0x10, 0x07, 0x40, 0x1f, 0x16, 0x4f, 0x10, 0x07, 0x40, 0x1f, 0x16, 0x4f, 0x10, 0x07, 0x40, 0x40, ++ 0x07, 0x00, 0x00, 0x01, 0x09, 0x01, 0x09, 0x17, 0x17, 0x16, 0x4f, 0x17, 0x16, 0x4f, 0x40, 0x40, ++ 0x40, 0x2d, 0x17, 0x17, 0x40, 0x0f, 0x17, 0x1e, 0x1e, 0x20, 0x27, 0x10, 0x07, 0x09, 0x10, 0x01, ++ 0x07, 0x3e, 0x1f, 0x17, 0x40, 0x0f, 0x17, 0x1e, 0x45, 0x17, 0x44, 0x45, 0x45, 0x17, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x3e, 0x44, 0x46, 0x5d, 0x40, 0x24, 0x05, 0x04, 0x21, 0x40, 0x46, 0x40, 0x40, 0x15, 0x0f, ++ 0x46, 0x61, 0x40, 0x09, 0x63, 0x61, 0x60, 0x5e, 0x5e, 0x07, 0x07, 0x0e, 0x3e, 0x16, 0x02, 0x07, ++ 0x64, 0x27, 0x4b, 0x16, 0x40, 0x06, 0x1c, 0x40, 0x40, 0x40, 0x46, 0x46, 0x55, 0x5c, 0x4d, 0x5c, ++ 0x63, 0x5b, 0x55, 0x64, 0x64, 0x61, 0x55, 0x5d, 0x64, 0x64, 0x61, 0x4c, 0x45, 0x53, 0x55, 0x5c, ++ 0x4d, 0x5c, 0x63, 0x5b, 0x55, 0x64, 0x64, 0x61, 0x55, 0x5d, 0x64, 0x64, 0x61, 0x4c, 0x45, 0x53, ++ 0x0a, 0x4e, 0x50, 0x40, 0x41, 0x40, 0x46, 0x07, 0x46, 0x45, 0x45, 0x60, 0x4d, 0x1e, 0x15, 0x4e, ++ 0x11, 0x07, 0x40, 0x1e, 0x15, 0x4e, 0x11, 0x07, 0x40, 0x1e, 0x15, 0x4e, 0x11, 0x07, 0x40, 0x41, ++ 0x07, 0x01, 0x01, 0x02, 0x0a, 0x02, 0x0a, 0x16, 0x17, 0x15, 0x4e, 0x17, 0x15, 0x4e, 0x40, 0x40, ++ 0x40, 0x2c, 0x16, 0x16, 0x40, 0x0f, 0x16, 0x1d, 0x1d, 0x21, 0x27, 0x11, 0x07, 0x0a, 0x11, 0x02, ++ 0x06, 0x3e, 0x1e, 0x16, 0x40, 0x0f, 0x16, 0x1d, 0x44, 0x16, 0x43, 0x44, 0x44, 0x16, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x3e, 0x43, 0x46, 0x5c, 0x40, 0x23, 0x04, 0x03, 0x21, 0x40, 0x46, 0x40, 0x40, 0x14, 0x0f, ++ 0x46, 0x60, 0x40, 0x09, 0x61, 0x60, 0x5e, 0x5b, 0x5b, 0x07, 0x07, 0x0e, 0x3e, 0x16, 0x03, 0x07, ++ 0x63, 0x27, 0x49, 0x16, 0x40, 0x06, 0x1b, 0x40, 0x40, 0x40, 0x46, 0x46, 0x54, 0x5b, 0x4c, 0x5b, ++ 0x61, 0x59, 0x54, 0x63, 0x63, 0x60, 0x54, 0x5c, 0x63, 0x63, 0x60, 0x4b, 0x44, 0x51, 0x54, 0x5b, ++ 0x4c, 0x5b, 0x61, 0x59, 0x54, 0x63, 0x63, 0x60, 0x54, 0x5c, 0x63, 0x63, 0x60, 0x4b, 0x44, 0x51, ++ 0x0b, 0x4e, 0x4e, 0x40, 0x41, 0x40, 0x46, 0x07, 0x46, 0x44, 0x44, 0x5e, 0x4c, 0x1e, 0x14, 0x4e, ++ 0x11, 0x07, 0x40, 0x1e, 0x14, 0x4e, 0x11, 0x07, 0x40, 0x1e, 0x14, 0x4e, 0x11, 0x07, 0x40, 0x41, ++ 0x07, 0x01, 0x01, 0x03, 0x0b, 0x03, 0x0b, 0x16, 0x17, 0x14, 0x4e, 0x17, 0x14, 0x4e, 0x40, 0x40, ++ 0x40, 0x2b, 0x16, 0x16, 0x40, 0x0f, 0x16, 0x1c, 0x1c, 0x21, 0x27, 0x11, 0x07, 0x0b, 0x11, 0x03, ++ 0x06, 0x3e, 0x1e, 0x16, 0x40, 0x0f, 0x16, 0x1c, 0x43, 0x16, 0x41, 0x43, 0x43, 0x16, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x3e, 0x42, 0x46, 0x5c, 0x40, 0x22, 0x04, 0x02, 0x21, 0x40, 0x46, 0x40, 0x40, 0x14, 0x0f, ++ 0x46, 0x5e, 0x40, 0x09, 0x60, 0x5e, 0x5c, 0x59, 0x59, 0x07, 0x07, 0x0e, 0x3e, 0x16, 0x03, 0x07, ++ 0x62, 0x27, 0x48, 0x16, 0x40, 0x06, 0x1a, 0x40, 0x40, 0x40, 0x46, 0x46, 0x54, 0x5a, 0x4c, 0x5a, ++ 0x60, 0x58, 0x54, 0x62, 0x62, 0x5e, 0x54, 0x5c, 0x62, 0x62, 0x5e, 0x4a, 0x44, 0x50, 0x54, 0x5a, ++ 0x4c, 0x5a, 0x60, 0x58, 0x54, 0x62, 0x62, 0x5e, 0x54, 0x5c, 0x62, 0x62, 0x5e, 0x4a, 0x44, 0x50, ++ 0x0b, 0x4e, 0x4c, 0x40, 0x41, 0x40, 0x46, 0x07, 0x46, 0x44, 0x44, 0x5c, 0x4c, 0x1e, 0x14, 0x4e, ++ 0x11, 0x07, 0x40, 0x1e, 0x14, 0x4e, 0x11, 0x07, 0x40, 0x1e, 0x14, 0x4e, 0x11, 0x07, 0x40, 0x41, ++ 0x07, 0x01, 0x01, 0x03, 0x0b, 0x03, 0x0b, 0x16, 0x17, 0x14, 0x4e, 0x17, 0x14, 0x4e, 0x40, 0x40, ++ 0x40, 0x2a, 0x16, 0x16, 0x40, 0x0f, 0x16, 0x1c, 0x1c, 0x21, 0x27, 0x11, 0x07, 0x0b, 0x11, 0x03, ++ 0x06, 0x3e, 0x1e, 0x16, 0x40, 0x0f, 0x16, 0x1c, 0x42, 0x16, 0x40, 0x42, 0x42, 0x16, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x3e, 0x41, 0x45, 0x5b, 0x40, 0x21, 0x03, 0x01, 0x22, 0x40, 0x45, 0x40, 0x40, 0x13, 0x0f, ++ 0x45, 0x5d, 0x40, 0x0a, 0x5f, 0x5d, 0x5a, 0x56, 0x56, 0x07, 0x07, 0x0d, 0x3e, 0x15, 0x04, 0x07, ++ 0x61, 0x27, 0x47, 0x15, 0x40, 0x05, 0x19, 0x40, 0x40, 0x40, 0x45, 0x45, 0x53, 0x59, 0x4b, 0x59, ++ 0x5f, 0x57, 0x53, 0x61, 0x61, 0x5d, 0x53, 0x5b, 0x61, 0x61, 0x5d, 0x49, 0x43, 0x4f, 0x53, 0x59, ++ 0x4b, 0x59, 0x5f, 0x57, 0x53, 0x61, 0x61, 0x5d, 0x53, 0x5b, 0x61, 0x61, 0x5d, 0x49, 0x43, 0x4f, ++ 0x0c, 0x4d, 0x4a, 0x40, 0x42, 0x40, 0x45, 0x07, 0x45, 0x43, 0x43, 0x5a, 0x4b, 0x1d, 0x13, 0x4d, ++ 0x12, 0x07, 0x40, 0x1d, 0x13, 0x4d, 0x12, 0x07, 0x40, 0x1d, 0x13, 0x4d, 0x12, 0x07, 0x40, 0x42, ++ 0x07, 0x02, 0x02, 0x04, 0x0c, 0x04, 0x0c, 0x15, 0x17, 0x13, 0x4d, 0x17, 0x13, 0x4d, 0x40, 0x40, ++ 0x40, 0x29, 0x15, 0x15, 0x40, 0x0f, 0x15, 0x1b, 0x1b, 0x22, 0x27, 0x12, 0x07, 0x0c, 0x12, 0x04, ++ 0x05, 0x3e, 0x1d, 0x15, 0x40, 0x0f, 0x15, 0x1b, 0x41, 0x15, 0x00, 0x41, 0x41, 0x15, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x3e, 0x40, 0x45, 0x5b, 0x40, 0x20, 0x02, 0x00, 0x22, 0x40, 0x45, 0x40, 0x40, 0x12, 0x0f, ++ 0x45, 0x5b, 0x40, 0x0a, 0x5e, 0x5b, 0x59, 0x54, 0x54, 0x07, 0x07, 0x0d, 0x3e, 0x15, 0x04, 0x07, ++ 0x60, 0x27, 0x46, 0x15, 0x40, 0x05, 0x18, 0x40, 0x40, 0x40, 0x45, 0x45, 0x53, 0x58, 0x4b, 0x58, ++ 0x5e, 0x56, 0x53, 0x60, 0x60, 0x5b, 0x53, 0x5b, 0x60, 0x60, 0x5b, 0x48, 0x43, 0x4e, 0x53, 0x58, ++ 0x4b, 0x58, 0x5e, 0x56, 0x53, 0x60, 0x60, 0x5b, 0x53, 0x5b, 0x60, 0x60, 0x5b, 0x48, 0x43, 0x4e, ++ 0x0c, 0x4d, 0x49, 0x40, 0x42, 0x40, 0x45, 0x07, 0x45, 0x43, 0x43, 0x59, 0x4b, 0x1d, 0x12, 0x4d, ++ 0x12, 0x07, 0x40, 0x1d, 0x12, 0x4d, 0x12, 0x07, 0x40, 0x1d, 0x12, 0x4d, 0x12, 0x07, 0x40, 0x42, ++ 0x07, 0x02, 0x02, 0x04, 0x0c, 0x04, 0x0c, 0x15, 0x17, 0x12, 0x4d, 0x17, 0x12, 0x4d, 0x40, 0x40, ++ 0x40, 0x28, 0x15, 0x15, 0x40, 0x0f, 0x15, 0x1a, 0x1a, 0x22, 0x27, 0x12, 0x07, 0x0c, 0x12, 0x04, ++ 0x05, 0x3e, 0x1d, 0x15, 0x40, 0x0f, 0x15, 0x1a, 0x40, 0x15, 0x01, 0x40, 0x40, 0x15, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x3e, 0x00, 0x45, 0x5a, 0x40, 0x1f, 0x02, 0x40, 0x22, 0x40, 0x45, 0x40, 0x40, 0x12, 0x0f, ++ 0x45, 0x59, 0x40, 0x0a, 0x5c, 0x59, 0x57, 0x51, 0x51, 0x07, 0x07, 0x0d, 0x3e, 0x15, 0x05, 0x07, ++ 0x5f, 0x27, 0x44, 0x15, 0x40, 0x05, 0x17, 0x40, 0x40, 0x40, 0x45, 0x45, 0x52, 0x57, 0x4a, 0x57, ++ 0x5c, 0x54, 0x52, 0x5f, 0x5f, 0x59, 0x52, 0x5a, 0x5f, 0x5f, 0x59, 0x47, 0x42, 0x4c, 0x52, 0x57, ++ 0x4a, 0x57, 0x5c, 0x54, 0x52, 0x5f, 0x5f, 0x59, 0x52, 0x5a, 0x5f, 0x5f, 0x59, 0x47, 0x42, 0x4c, ++ 0x0d, 0x4d, 0x47, 0x40, 0x42, 0x40, 0x45, 0x07, 0x45, 0x42, 0x42, 0x57, 0x4a, 0x1d, 0x12, 0x4d, ++ 0x12, 0x07, 0x40, 0x1d, 0x12, 0x4d, 0x12, 0x07, 0x40, 0x1d, 0x12, 0x4d, 0x12, 0x07, 0x40, 0x42, ++ 0x07, 0x02, 0x02, 0x05, 0x0d, 0x05, 0x0d, 0x15, 0x17, 0x12, 0x4d, 0x17, 0x12, 0x4d, 0x40, 0x40, ++ 0x40, 0x27, 0x15, 0x15, 0x40, 0x0f, 0x15, 0x1a, 0x1a, 0x22, 0x27, 0x12, 0x07, 0x0d, 0x12, 0x05, ++ 0x05, 0x3e, 0x1d, 0x15, 0x40, 0x0f, 0x15, 0x1a, 0x00, 0x15, 0x03, 0x00, 0x00, 0x15, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x3e, 0x01, 0x44, 0x59, 0x40, 0x1e, 0x01, 0x41, 0x23, 0x40, 0x44, 0x40, 0x40, 0x11, 0x0f, ++ 0x44, 0x58, 0x40, 0x0b, 0x5b, 0x58, 0x55, 0x4f, 0x4f, 0x07, 0x07, 0x0c, 0x3e, 0x14, 0x06, 0x07, ++ 0x5e, 0x27, 0x43, 0x14, 0x40, 0x04, 0x16, 0x40, 0x40, 0x40, 0x44, 0x44, 0x51, 0x56, 0x49, 0x56, ++ 0x5b, 0x53, 0x51, 0x5e, 0x5e, 0x58, 0x51, 0x59, 0x5e, 0x5e, 0x58, 0x46, 0x41, 0x4b, 0x51, 0x56, ++ 0x49, 0x56, 0x5b, 0x53, 0x51, 0x5e, 0x5e, 0x58, 0x51, 0x59, 0x5e, 0x5e, 0x58, 0x46, 0x41, 0x4b, ++ 0x0e, 0x4c, 0x45, 0x40, 0x43, 0x40, 0x44, 0x07, 0x44, 0x41, 0x41, 0x55, 0x49, 0x1c, 0x11, 0x4c, ++ 0x13, 0x07, 0x40, 0x1c, 0x11, 0x4c, 0x13, 0x07, 0x40, 0x1c, 0x11, 0x4c, 0x13, 0x07, 0x40, 0x43, ++ 0x07, 0x03, 0x03, 0x06, 0x0e, 0x06, 0x0e, 0x14, 0x17, 0x11, 0x4c, 0x17, 0x11, 0x4c, 0x40, 0x40, ++ 0x40, 0x26, 0x14, 0x14, 0x40, 0x0f, 0x14, 0x19, 0x19, 0x23, 0x27, 0x13, 0x07, 0x0e, 0x13, 0x06, ++ 0x04, 0x3e, 0x1c, 0x14, 0x40, 0x0f, 0x14, 0x19, 0x01, 0x14, 0x04, 0x01, 0x01, 0x14, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x3e, 0x02, 0x44, 0x59, 0x40, 0x1d, 0x01, 0x42, 0x23, 0x40, 0x44, 0x40, 0x40, 0x11, 0x0f, ++ 0x44, 0x56, 0x40, 0x0b, 0x5a, 0x56, 0x53, 0x4c, 0x4c, 0x07, 0x07, 0x0c, 0x3e, 0x14, 0x06, 0x07, ++ 0x5d, 0x27, 0x42, 0x14, 0x40, 0x04, 0x15, 0x40, 0x40, 0x40, 0x44, 0x44, 0x51, 0x55, 0x49, 0x55, ++ 0x5a, 0x52, 0x51, 0x5d, 0x5d, 0x56, 0x51, 0x59, 0x5d, 0x5d, 0x56, 0x45, 0x41, 0x4a, 0x51, 0x55, ++ 0x49, 0x55, 0x5a, 0x52, 0x51, 0x5d, 0x5d, 0x56, 0x51, 0x59, 0x5d, 0x5d, 0x56, 0x45, 0x41, 0x4a, ++ 0x0e, 0x4c, 0x43, 0x40, 0x43, 0x40, 0x44, 0x07, 0x44, 0x41, 0x41, 0x53, 0x49, 0x1c, 0x11, 0x4c, ++ 0x13, 0x07, 0x40, 0x1c, 0x11, 0x4c, 0x13, 0x07, 0x40, 0x1c, 0x11, 0x4c, 0x13, 0x07, 0x40, 0x43, ++ 0x07, 0x03, 0x03, 0x06, 0x0e, 0x06, 0x0e, 0x14, 0x17, 0x11, 0x4c, 0x17, 0x11, 0x4c, 0x40, 0x40, ++ 0x40, 0x25, 0x14, 0x14, 0x40, 0x0f, 0x14, 0x19, 0x19, 0x23, 0x27, 0x13, 0x07, 0x0e, 0x13, 0x06, ++ 0x04, 0x3e, 0x1c, 0x14, 0x40, 0x0f, 0x14, 0x19, 0x02, 0x14, 0x05, 0x02, 0x02, 0x14, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x3e, 0x03, 0x44, 0x58, 0x40, 0x1c, 0x00, 0x43, 0x23, 0x40, 0x44, 0x40, 0x40, 0x10, 0x0f, ++ 0x44, 0x55, 0x40, 0x0b, 0x59, 0x55, 0x51, 0x4a, 0x4a, 0x07, 0x07, 0x0c, 0x3d, 0x14, 0x07, 0x07, ++ 0x5c, 0x27, 0x41, 0x14, 0x40, 0x04, 0x14, 0x40, 0x40, 0x40, 0x44, 0x44, 0x50, 0x54, 0x48, 0x54, ++ 0x59, 0x51, 0x50, 0x5c, 0x5c, 0x55, 0x50, 0x58, 0x5c, 0x5c, 0x55, 0x44, 0x40, 0x49, 0x50, 0x54, ++ 0x48, 0x54, 0x59, 0x51, 0x50, 0x5c, 0x5c, 0x55, 0x50, 0x58, 0x5c, 0x5c, 0x55, 0x44, 0x40, 0x49, ++ 0x0f, 0x4c, 0x41, 0x40, 0x43, 0x40, 0x44, 0x07, 0x44, 0x40, 0x40, 0x51, 0x48, 0x1c, 0x10, 0x4c, ++ 0x13, 0x07, 0x40, 0x1c, 0x10, 0x4c, 0x13, 0x07, 0x40, 0x1c, 0x10, 0x4c, 0x13, 0x07, 0x40, 0x43, ++ 0x07, 0x03, 0x03, 0x07, 0x0f, 0x07, 0x0f, 0x14, 0x17, 0x10, 0x4c, 0x17, 0x10, 0x4c, 0x40, 0x40, ++ 0x40, 0x24, 0x14, 0x14, 0x40, 0x0f, 0x14, 0x18, 0x18, 0x23, 0x27, 0x13, 0x07, 0x0f, 0x13, 0x07, ++ 0x04, 0x3e, 0x1c, 0x14, 0x40, 0x0f, 0x14, 0x18, 0x03, 0x14, 0x06, 0x03, 0x03, 0x14, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x3e, 0x04, 0x43, 0x57, 0x40, 0x1b, 0x40, 0x44, 0x24, 0x40, 0x43, 0x40, 0x40, 0x0f, 0x0f, ++ 0x43, 0x53, 0x40, 0x0c, 0x57, 0x53, 0x4f, 0x47, 0x47, 0x07, 0x07, 0x0b, 0x3b, 0x13, 0x08, 0x07, ++ 0x5b, 0x27, 0x00, 0x13, 0x40, 0x03, 0x13, 0x40, 0x40, 0x40, 0x43, 0x43, 0x4f, 0x53, 0x47, 0x53, ++ 0x57, 0x4f, 0x4f, 0x5b, 0x5b, 0x53, 0x4f, 0x57, 0x5b, 0x5b, 0x53, 0x43, 0x00, 0x47, 0x4f, 0x53, ++ 0x47, 0x53, 0x57, 0x4f, 0x4f, 0x5b, 0x5b, 0x53, 0x4f, 0x57, 0x5b, 0x5b, 0x53, 0x43, 0x00, 0x47, ++ 0x10, 0x4b, 0x00, 0x40, 0x44, 0x40, 0x43, 0x07, 0x43, 0x00, 0x00, 0x4f, 0x47, 0x1b, 0x0f, 0x4b, ++ 0x14, 0x07, 0x40, 0x1b, 0x0f, 0x4b, 0x14, 0x07, 0x40, 0x1b, 0x0f, 0x4b, 0x14, 0x07, 0x40, 0x44, ++ 0x07, 0x04, 0x04, 0x08, 0x10, 0x08, 0x10, 0x13, 0x17, 0x0f, 0x4b, 0x17, 0x0f, 0x4b, 0x40, 0x40, ++ 0x40, 0x23, 0x13, 0x13, 0x40, 0x0f, 0x13, 0x17, 0x17, 0x24, 0x27, 0x14, 0x07, 0x10, 0x14, 0x08, ++ 0x03, 0x3e, 0x1b, 0x13, 0x40, 0x0f, 0x13, 0x17, 0x04, 0x13, 0x08, 0x04, 0x04, 0x13, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x3e, 0x05, 0x43, 0x57, 0x40, 0x1a, 0x40, 0x45, 0x24, 0x40, 0x43, 0x40, 0x40, 0x0f, 0x0f, ++ 0x43, 0x52, 0x40, 0x0c, 0x56, 0x52, 0x4d, 0x45, 0x45, 0x07, 0x07, 0x0b, 0x3a, 0x13, 0x08, 0x07, ++ 0x5a, 0x27, 0x01, 0x13, 0x40, 0x03, 0x12, 0x40, 0x40, 0x40, 0x43, 0x43, 0x4f, 0x52, 0x47, 0x52, ++ 0x56, 0x4e, 0x4f, 0x5a, 0x5a, 0x52, 0x4f, 0x57, 0x5a, 0x5a, 0x52, 0x42, 0x00, 0x46, 0x4f, 0x52, ++ 0x47, 0x52, 0x56, 0x4e, 0x4f, 0x5a, 0x5a, 0x52, 0x4f, 0x57, 0x5a, 0x5a, 0x52, 0x42, 0x00, 0x46, ++ 0x10, 0x4b, 0x02, 0x40, 0x44, 0x40, 0x43, 0x07, 0x43, 0x00, 0x00, 0x4d, 0x47, 0x1b, 0x0f, 0x4b, ++ 0x14, 0x07, 0x40, 0x1b, 0x0f, 0x4b, 0x14, 0x07, 0x40, 0x1b, 0x0f, 0x4b, 0x14, 0x07, 0x40, 0x44, ++ 0x07, 0x04, 0x04, 0x08, 0x10, 0x08, 0x10, 0x13, 0x17, 0x0f, 0x4b, 0x17, 0x0f, 0x4b, 0x40, 0x40, ++ 0x40, 0x22, 0x13, 0x13, 0x40, 0x0f, 0x13, 0x17, 0x17, 0x24, 0x27, 0x14, 0x07, 0x10, 0x14, 0x08, ++ 0x03, 0x3e, 0x1b, 0x13, 0x40, 0x0f, 0x13, 0x17, 0x05, 0x13, 0x09, 0x05, 0x05, 0x13, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x3e, 0x06, 0x43, 0x56, 0x40, 0x19, 0x41, 0x46, 0x24, 0x40, 0x43, 0x40, 0x40, 0x0e, 0x0f, ++ 0x43, 0x50, 0x40, 0x0c, 0x55, 0x50, 0x4b, 0x42, 0x42, 0x07, 0x07, 0x0b, 0x38, 0x13, 0x09, 0x07, ++ 0x59, 0x27, 0x02, 0x13, 0x40, 0x03, 0x11, 0x40, 0x40, 0x40, 0x43, 0x43, 0x4e, 0x51, 0x46, 0x51, ++ 0x55, 0x4d, 0x4e, 0x59, 0x59, 0x50, 0x4e, 0x56, 0x59, 0x59, 0x50, 0x41, 0x01, 0x45, 0x4e, 0x51, ++ 0x46, 0x51, 0x55, 0x4d, 0x4e, 0x59, 0x59, 0x50, 0x4e, 0x56, 0x59, 0x59, 0x50, 0x41, 0x01, 0x45, ++ 0x11, 0x4b, 0x04, 0x40, 0x44, 0x40, 0x43, 0x07, 0x43, 0x01, 0x01, 0x4b, 0x46, 0x1b, 0x0e, 0x4b, ++ 0x14, 0x07, 0x40, 0x1b, 0x0e, 0x4b, 0x14, 0x07, 0x40, 0x1b, 0x0e, 0x4b, 0x14, 0x07, 0x40, 0x44, ++ 0x07, 0x04, 0x04, 0x09, 0x11, 0x09, 0x11, 0x13, 0x17, 0x0e, 0x4b, 0x17, 0x0e, 0x4b, 0x40, 0x40, ++ 0x40, 0x21, 0x13, 0x13, 0x40, 0x0f, 0x13, 0x16, 0x16, 0x24, 0x27, 0x14, 0x07, 0x11, 0x14, 0x09, ++ 0x03, 0x3d, 0x1b, 0x13, 0x40, 0x0f, 0x13, 0x16, 0x06, 0x13, 0x0a, 0x06, 0x06, 0x13, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x3e, 0x06, 0x43, 0x56, 0x40, 0x18, 0x42, 0x47, 0x24, 0x40, 0x43, 0x40, 0x40, 0x0d, 0x0f, ++ 0x43, 0x4f, 0x40, 0x0c, 0x54, 0x4f, 0x4a, 0x40, 0x40, 0x07, 0x07, 0x0a, 0x36, 0x12, 0x09, 0x07, ++ 0x59, 0x27, 0x03, 0x12, 0x40, 0x02, 0x10, 0x40, 0x40, 0x40, 0x43, 0x43, 0x4e, 0x51, 0x46, 0x51, ++ 0x54, 0x4c, 0x4e, 0x59, 0x59, 0x4f, 0x4e, 0x56, 0x59, 0x59, 0x4f, 0x41, 0x01, 0x44, 0x4e, 0x51, ++ 0x46, 0x51, 0x54, 0x4c, 0x4e, 0x59, 0x59, 0x4f, 0x4e, 0x56, 0x59, 0x59, 0x4f, 0x41, 0x01, 0x44, ++ 0x11, 0x4b, 0x05, 0x40, 0x45, 0x40, 0x43, 0x07, 0x43, 0x01, 0x01, 0x4a, 0x46, 0x1a, 0x0d, 0x4b, ++ 0x14, 0x07, 0x40, 0x1a, 0x0d, 0x4b, 0x14, 0x07, 0x40, 0x1a, 0x0d, 0x4b, 0x14, 0x07, 0x40, 0x45, ++ 0x07, 0x04, 0x04, 0x09, 0x11, 0x09, 0x11, 0x12, 0x17, 0x0d, 0x4b, 0x17, 0x0d, 0x4b, 0x40, 0x40, ++ 0x40, 0x20, 0x12, 0x12, 0x40, 0x0f, 0x12, 0x15, 0x15, 0x24, 0x27, 0x14, 0x07, 0x11, 0x14, 0x09, ++ 0x02, 0x3b, 0x1a, 0x12, 0x40, 0x0f, 0x12, 0x15, 0x06, 0x12, 0x0b, 0x06, 0x06, 0x12, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x3e, 0x07, 0x42, 0x55, 0x40, 0x18, 0x42, 0x47, 0x25, 0x40, 0x42, 0x40, 0x40, 0x0d, 0x0f, ++ 0x42, 0x4d, 0x40, 0x0d, 0x52, 0x4d, 0x48, 0x02, 0x02, 0x07, 0x07, 0x0a, 0x35, 0x12, 0x0a, 0x07, ++ 0x58, 0x27, 0x05, 0x12, 0x40, 0x02, 0x10, 0x40, 0x40, 0x40, 0x42, 0x42, 0x4d, 0x50, 0x45, 0x50, ++ 0x52, 0x4a, 0x4d, 0x58, 0x58, 0x4d, 0x4d, 0x55, 0x58, 0x58, 0x4d, 0x40, 0x02, 0x42, 0x4d, 0x50, ++ 0x45, 0x50, 0x52, 0x4a, 0x4d, 0x58, 0x58, 0x4d, 0x4d, 0x55, 0x58, 0x58, 0x4d, 0x40, 0x02, 0x42, ++ 0x12, 0x4a, 0x07, 0x40, 0x45, 0x40, 0x42, 0x07, 0x42, 0x02, 0x02, 0x48, 0x45, 0x1a, 0x0d, 0x4a, ++ 0x15, 0x07, 0x40, 0x1a, 0x0d, 0x4a, 0x15, 0x07, 0x40, 0x1a, 0x0d, 0x4a, 0x15, 0x07, 0x40, 0x45, ++ 0x07, 0x05, 0x05, 0x0a, 0x12, 0x0a, 0x12, 0x12, 0x17, 0x0d, 0x4a, 0x17, 0x0d, 0x4a, 0x40, 0x40, ++ 0x40, 0x20, 0x12, 0x12, 0x40, 0x0f, 0x12, 0x15, 0x15, 0x25, 0x27, 0x15, 0x07, 0x12, 0x15, 0x0a, ++ 0x02, 0x3a, 0x1a, 0x12, 0x40, 0x0f, 0x12, 0x15, 0x07, 0x12, 0x0d, 0x07, 0x07, 0x12, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x3e, 0x08, 0x42, 0x54, 0x40, 0x17, 0x43, 0x48, 0x25, 0x40, 0x42, 0x40, 0x40, 0x0c, 0x0f, ++ 0x42, 0x4b, 0x40, 0x0d, 0x51, 0x4b, 0x46, 0x04, 0x04, 0x07, 0x07, 0x0a, 0x33, 0x12, 0x0b, 0x07, ++ 0x57, 0x27, 0x06, 0x12, 0x40, 0x02, 0x0f, 0x40, 0x40, 0x40, 0x42, 0x42, 0x4c, 0x4f, 0x44, 0x4f, ++ 0x51, 0x49, 0x4c, 0x57, 0x57, 0x4b, 0x4c, 0x54, 0x57, 0x57, 0x4b, 0x00, 0x03, 0x41, 0x4c, 0x4f, ++ 0x44, 0x4f, 0x51, 0x49, 0x4c, 0x57, 0x57, 0x4b, 0x4c, 0x54, 0x57, 0x57, 0x4b, 0x00, 0x03, 0x41, ++ 0x13, 0x4a, 0x09, 0x40, 0x45, 0x40, 0x42, 0x07, 0x42, 0x03, 0x03, 0x46, 0x44, 0x1a, 0x0c, 0x4a, ++ 0x15, 0x07, 0x40, 0x1a, 0x0c, 0x4a, 0x15, 0x07, 0x40, 0x1a, 0x0c, 0x4a, 0x15, 0x07, 0x40, 0x45, ++ 0x07, 0x05, 0x05, 0x0b, 0x13, 0x0b, 0x13, 0x12, 0x17, 0x0c, 0x4a, 0x17, 0x0c, 0x4a, 0x40, 0x40, ++ 0x40, 0x1f, 0x12, 0x12, 0x40, 0x0f, 0x12, 0x14, 0x14, 0x25, 0x27, 0x15, 0x07, 0x13, 0x15, 0x0b, ++ 0x02, 0x39, 0x1a, 0x12, 0x40, 0x0f, 0x12, 0x14, 0x08, 0x12, 0x0e, 0x08, 0x08, 0x12, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x3e, 0x09, 0x42, 0x54, 0x40, 0x16, 0x43, 0x49, 0x25, 0x40, 0x42, 0x40, 0x40, 0x0c, 0x0f, ++ 0x42, 0x4a, 0x40, 0x0d, 0x50, 0x4a, 0x44, 0x07, 0x07, 0x07, 0x07, 0x0a, 0x32, 0x12, 0x0b, 0x07, ++ 0x56, 0x27, 0x07, 0x12, 0x40, 0x02, 0x0e, 0x40, 0x40, 0x40, 0x42, 0x42, 0x4c, 0x4e, 0x44, 0x4e, ++ 0x50, 0x48, 0x4c, 0x56, 0x56, 0x4a, 0x4c, 0x54, 0x56, 0x56, 0x4a, 0x01, 0x03, 0x40, 0x4c, 0x4e, ++ 0x44, 0x4e, 0x50, 0x48, 0x4c, 0x56, 0x56, 0x4a, 0x4c, 0x54, 0x56, 0x56, 0x4a, 0x01, 0x03, 0x40, ++ 0x13, 0x4a, 0x0b, 0x40, 0x45, 0x40, 0x42, 0x07, 0x42, 0x03, 0x03, 0x44, 0x44, 0x1a, 0x0c, 0x4a, ++ 0x15, 0x07, 0x40, 0x1a, 0x0c, 0x4a, 0x15, 0x07, 0x40, 0x1a, 0x0c, 0x4a, 0x15, 0x07, 0x40, 0x45, ++ 0x07, 0x05, 0x05, 0x0b, 0x13, 0x0b, 0x13, 0x12, 0x17, 0x0c, 0x4a, 0x17, 0x0c, 0x4a, 0x40, 0x40, ++ 0x40, 0x1e, 0x12, 0x12, 0x40, 0x0f, 0x12, 0x14, 0x14, 0x25, 0x27, 0x15, 0x07, 0x13, 0x15, 0x0b, ++ 0x02, 0x38, 0x1a, 0x12, 0x40, 0x0f, 0x12, 0x14, 0x09, 0x12, 0x0f, 0x09, 0x09, 0x12, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x3e, 0x0a, 0x41, 0x53, 0x40, 0x15, 0x44, 0x4a, 0x26, 0x40, 0x41, 0x40, 0x40, 0x0b, 0x0f, ++ 0x41, 0x48, 0x40, 0x0e, 0x4f, 0x48, 0x42, 0x09, 0x09, 0x07, 0x07, 0x09, 0x30, 0x11, 0x0c, 0x07, ++ 0x55, 0x27, 0x08, 0x11, 0x40, 0x01, 0x0d, 0x40, 0x40, 0x40, 0x41, 0x41, 0x4b, 0x4d, 0x43, 0x4d, ++ 0x4f, 0x47, 0x4b, 0x55, 0x55, 0x48, 0x4b, 0x53, 0x55, 0x55, 0x48, 0x02, 0x04, 0x00, 0x4b, 0x4d, ++ 0x43, 0x4d, 0x4f, 0x47, 0x4b, 0x55, 0x55, 0x48, 0x4b, 0x53, 0x55, 0x55, 0x48, 0x02, 0x04, 0x00, ++ 0x14, 0x49, 0x0d, 0x40, 0x46, 0x40, 0x41, 0x07, 0x41, 0x04, 0x04, 0x42, 0x43, 0x19, 0x0b, 0x49, ++ 0x16, 0x07, 0x40, 0x19, 0x0b, 0x49, 0x16, 0x07, 0x40, 0x19, 0x0b, 0x49, 0x16, 0x07, 0x40, 0x46, ++ 0x07, 0x06, 0x06, 0x0c, 0x14, 0x0c, 0x14, 0x11, 0x17, 0x0b, 0x49, 0x17, 0x0b, 0x49, 0x40, 0x40, ++ 0x40, 0x1d, 0x11, 0x11, 0x40, 0x0f, 0x11, 0x13, 0x13, 0x26, 0x27, 0x16, 0x07, 0x14, 0x16, 0x0c, ++ 0x01, 0x36, 0x19, 0x11, 0x40, 0x0f, 0x11, 0x13, 0x0a, 0x11, 0x10, 0x0a, 0x0a, 0x11, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x3e, 0x0b, 0x41, 0x52, 0x40, 0x14, 0x45, 0x4b, 0x26, 0x40, 0x41, 0x40, 0x40, 0x0a, 0x0f, ++ 0x41, 0x47, 0x40, 0x0e, 0x4d, 0x47, 0x40, 0x0c, 0x0c, 0x07, 0x07, 0x09, 0x2f, 0x11, 0x0d, 0x07, ++ 0x54, 0x27, 0x0a, 0x11, 0x40, 0x01, 0x0c, 0x40, 0x40, 0x40, 0x41, 0x41, 0x4a, 0x4c, 0x42, 0x4c, ++ 0x4d, 0x45, 0x4a, 0x54, 0x54, 0x47, 0x4a, 0x52, 0x54, 0x54, 0x47, 0x03, 0x05, 0x02, 0x4a, 0x4c, ++ 0x42, 0x4c, 0x4d, 0x45, 0x4a, 0x54, 0x54, 0x47, 0x4a, 0x52, 0x54, 0x54, 0x47, 0x03, 0x05, 0x02, ++ 0x15, 0x49, 0x0f, 0x40, 0x46, 0x40, 0x41, 0x07, 0x41, 0x05, 0x05, 0x40, 0x42, 0x19, 0x0a, 0x49, ++ 0x16, 0x07, 0x40, 0x19, 0x0a, 0x49, 0x16, 0x07, 0x40, 0x19, 0x0a, 0x49, 0x16, 0x07, 0x40, 0x46, ++ 0x07, 0x06, 0x06, 0x0d, 0x15, 0x0d, 0x15, 0x11, 0x17, 0x0a, 0x49, 0x17, 0x0a, 0x49, 0x40, 0x40, ++ 0x40, 0x1c, 0x11, 0x11, 0x40, 0x0f, 0x11, 0x12, 0x12, 0x26, 0x27, 0x16, 0x07, 0x15, 0x16, 0x0d, ++ 0x01, 0x35, 0x19, 0x11, 0x40, 0x0f, 0x11, 0x12, 0x0b, 0x11, 0x12, 0x0b, 0x0b, 0x11, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x3e, 0x0c, 0x41, 0x52, 0x40, 0x13, 0x45, 0x4c, 0x26, 0x40, 0x41, 0x40, 0x40, 0x0a, 0x0f, ++ 0x41, 0x45, 0x40, 0x0e, 0x4c, 0x45, 0x01, 0x0e, 0x0e, 0x07, 0x07, 0x09, 0x2d, 0x11, 0x0d, 0x07, ++ 0x53, 0x27, 0x0b, 0x11, 0x40, 0x01, 0x0b, 0x40, 0x40, 0x40, 0x41, 0x41, 0x4a, 0x4b, 0x42, 0x4b, ++ 0x4c, 0x44, 0x4a, 0x53, 0x53, 0x45, 0x4a, 0x52, 0x53, 0x53, 0x45, 0x04, 0x05, 0x03, 0x4a, 0x4b, ++ 0x42, 0x4b, 0x4c, 0x44, 0x4a, 0x53, 0x53, 0x45, 0x4a, 0x52, 0x53, 0x53, 0x45, 0x04, 0x05, 0x03, ++ 0x15, 0x49, 0x11, 0x40, 0x46, 0x40, 0x41, 0x07, 0x41, 0x05, 0x05, 0x01, 0x42, 0x19, 0x0a, 0x49, ++ 0x16, 0x07, 0x40, 0x19, 0x0a, 0x49, 0x16, 0x07, 0x40, 0x19, 0x0a, 0x49, 0x16, 0x07, 0x40, 0x46, ++ 0x07, 0x06, 0x06, 0x0d, 0x15, 0x0d, 0x15, 0x11, 0x17, 0x0a, 0x49, 0x17, 0x0a, 0x49, 0x40, 0x40, ++ 0x40, 0x1b, 0x11, 0x11, 0x40, 0x0f, 0x11, 0x12, 0x12, 0x26, 0x27, 0x16, 0x07, 0x15, 0x16, 0x0d, ++ 0x01, 0x34, 0x19, 0x11, 0x40, 0x0f, 0x11, 0x12, 0x0c, 0x11, 0x13, 0x0c, 0x0c, 0x11, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x3e, 0x0d, 0x40, 0x51, 0x40, 0x12, 0x46, 0x4d, 0x27, 0x40, 0x40, 0x40, 0x40, 0x09, 0x0f, ++ 0x40, 0x44, 0x40, 0x0f, 0x4b, 0x44, 0x03, 0x11, 0x11, 0x07, 0x07, 0x08, 0x2c, 0x10, 0x0e, 0x07, ++ 0x52, 0x27, 0x0c, 0x10, 0x40, 0x00, 0x0a, 0x40, 0x40, 0x40, 0x40, 0x40, 0x49, 0x4a, 0x41, 0x4a, ++ 0x4b, 0x43, 0x49, 0x52, 0x52, 0x44, 0x49, 0x51, 0x52, 0x52, 0x44, 0x05, 0x06, 0x04, 0x49, 0x4a, ++ 0x41, 0x4a, 0x4b, 0x43, 0x49, 0x52, 0x52, 0x44, 0x49, 0x51, 0x52, 0x52, 0x44, 0x05, 0x06, 0x04, ++ 0x16, 0x48, 0x13, 0x40, 0x47, 0x40, 0x40, 0x07, 0x40, 0x06, 0x06, 0x03, 0x41, 0x18, 0x09, 0x48, ++ 0x17, 0x07, 0x40, 0x18, 0x09, 0x48, 0x17, 0x07, 0x40, 0x18, 0x09, 0x48, 0x17, 0x07, 0x40, 0x47, ++ 0x07, 0x07, 0x07, 0x0e, 0x16, 0x0e, 0x16, 0x10, 0x17, 0x09, 0x48, 0x17, 0x09, 0x48, 0x40, 0x40, ++ 0x40, 0x1a, 0x10, 0x10, 0x40, 0x0f, 0x10, 0x11, 0x11, 0x27, 0x27, 0x17, 0x07, 0x16, 0x17, 0x0e, ++ 0x00, 0x33, 0x18, 0x10, 0x40, 0x0f, 0x10, 0x11, 0x0d, 0x10, 0x14, 0x0d, 0x0d, 0x10, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x3e, 0x0e, 0x40, 0x51, 0x40, 0x11, 0x47, 0x4e, 0x27, 0x40, 0x40, 0x40, 0x40, 0x08, 0x0f, ++ 0x40, 0x42, 0x40, 0x0f, 0x4a, 0x42, 0x04, 0x13, 0x13, 0x07, 0x07, 0x08, 0x2a, 0x10, 0x0e, 0x07, ++ 0x51, 0x27, 0x0d, 0x10, 0x40, 0x00, 0x09, 0x40, 0x40, 0x40, 0x40, 0x40, 0x49, 0x49, 0x41, 0x49, ++ 0x4a, 0x42, 0x49, 0x51, 0x51, 0x42, 0x49, 0x51, 0x51, 0x51, 0x42, 0x06, 0x06, 0x05, 0x49, 0x49, ++ 0x41, 0x49, 0x4a, 0x42, 0x49, 0x51, 0x51, 0x42, 0x49, 0x51, 0x51, 0x51, 0x42, 0x06, 0x06, 0x05, ++ 0x16, 0x48, 0x14, 0x40, 0x47, 0x40, 0x40, 0x07, 0x40, 0x06, 0x06, 0x04, 0x41, 0x18, 0x08, 0x48, ++ 0x17, 0x07, 0x40, 0x18, 0x08, 0x48, 0x17, 0x07, 0x40, 0x18, 0x08, 0x48, 0x17, 0x07, 0x40, 0x47, ++ 0x07, 0x07, 0x07, 0x0e, 0x16, 0x0e, 0x16, 0x10, 0x17, 0x08, 0x48, 0x17, 0x08, 0x48, 0x40, 0x40, ++ 0x40, 0x19, 0x10, 0x10, 0x40, 0x0f, 0x10, 0x10, 0x10, 0x27, 0x27, 0x17, 0x07, 0x16, 0x17, 0x0e, ++ 0x00, 0x31, 0x18, 0x10, 0x40, 0x0f, 0x10, 0x10, 0x0e, 0x10, 0x15, 0x0e, 0x0e, 0x10, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x3e, 0x0f, 0x40, 0x50, 0x40, 0x10, 0x47, 0x4f, 0x27, 0x40, 0x40, 0x40, 0x40, 0x08, 0x0f, ++ 0x40, 0x40, 0x40, 0x0f, 0x48, 0x40, 0x06, 0x16, 0x16, 0x07, 0x07, 0x08, 0x28, 0x10, 0x0f, 0x07, ++ 0x50, 0x27, 0x0f, 0x10, 0x40, 0x00, 0x08, 0x40, 0x40, 0x40, 0x40, 0x40, 0x48, 0x48, 0x40, 0x48, ++ 0x48, 0x40, 0x48, 0x50, 0x50, 0x40, 0x48, 0x50, 0x50, 0x50, 0x40, 0x07, 0x07, 0x07, 0x48, 0x48, ++ 0x40, 0x48, 0x48, 0x40, 0x48, 0x50, 0x50, 0x40, 0x48, 0x50, 0x50, 0x50, 0x40, 0x07, 0x07, 0x07, ++ 0x17, 0x48, 0x16, 0x40, 0x47, 0x40, 0x40, 0x07, 0x40, 0x07, 0x07, 0x06, 0x40, 0x18, 0x08, 0x48, ++ 0x17, 0x07, 0x40, 0x18, 0x08, 0x48, 0x17, 0x07, 0x40, 0x18, 0x08, 0x48, 0x17, 0x07, 0x40, 0x47, ++ 0x07, 0x07, 0x07, 0x0f, 0x17, 0x0f, 0x17, 0x10, 0x17, 0x08, 0x48, 0x17, 0x08, 0x48, 0x40, 0x40, ++ 0x40, 0x18, 0x10, 0x10, 0x40, 0x0f, 0x10, 0x10, 0x10, 0x27, 0x27, 0x17, 0x07, 0x17, 0x17, 0x0f, ++ 0x00, 0x30, 0x18, 0x10, 0x40, 0x0f, 0x10, 0x10, 0x0f, 0x10, 0x17, 0x0f, 0x0f, 0x10, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x3e, 0x10, 0x00, 0x4f, 0x40, 0x0f, 0x48, 0x50, 0x28, 0x40, 0x00, 0x40, 0x40, 0x07, 0x0f, ++ 0x00, 0x00, 0x40, 0x10, 0x47, 0x00, 0x08, 0x18, 0x18, 0x07, 0x07, 0x07, 0x27, 0x0f, 0x10, 0x07, ++ 0x4f, 0x27, 0x10, 0x0f, 0x40, 0x40, 0x07, 0x40, 0x40, 0x40, 0x00, 0x00, 0x47, 0x47, 0x00, 0x47, ++ 0x47, 0x00, 0x47, 0x4f, 0x4f, 0x00, 0x47, 0x4f, 0x4f, 0x4f, 0x00, 0x08, 0x08, 0x08, 0x47, 0x47, ++ 0x00, 0x47, 0x47, 0x00, 0x47, 0x4f, 0x4f, 0x00, 0x47, 0x4f, 0x4f, 0x4f, 0x00, 0x08, 0x08, 0x08, ++ 0x18, 0x47, 0x18, 0x40, 0x48, 0x40, 0x00, 0x07, 0x00, 0x08, 0x08, 0x08, 0x00, 0x17, 0x07, 0x47, ++ 0x18, 0x07, 0x40, 0x17, 0x07, 0x47, 0x18, 0x07, 0x40, 0x17, 0x07, 0x47, 0x18, 0x07, 0x40, 0x48, ++ 0x07, 0x08, 0x08, 0x10, 0x18, 0x10, 0x18, 0x0f, 0x17, 0x07, 0x47, 0x17, 0x07, 0x47, 0x40, 0x40, ++ 0x40, 0x17, 0x0f, 0x0f, 0x40, 0x0f, 0x0f, 0x0f, 0x0f, 0x28, 0x27, 0x18, 0x07, 0x18, 0x18, 0x10, ++ 0x40, 0x2f, 0x17, 0x0f, 0x40, 0x0f, 0x0f, 0x0f, 0x10, 0x0f, 0x18, 0x10, 0x10, 0x0f, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x3e, 0x11, 0x00, 0x4f, 0x40, 0x0e, 0x48, 0x51, 0x28, 0x40, 0x00, 0x40, 0x40, 0x07, 0x0f, ++ 0x00, 0x02, 0x40, 0x10, 0x46, 0x02, 0x0a, 0x1b, 0x1b, 0x07, 0x07, 0x07, 0x25, 0x0f, 0x10, 0x07, ++ 0x4e, 0x27, 0x11, 0x0f, 0x40, 0x40, 0x06, 0x40, 0x40, 0x40, 0x00, 0x00, 0x47, 0x46, 0x00, 0x46, ++ 0x46, 0x01, 0x47, 0x4e, 0x4e, 0x02, 0x47, 0x4f, 0x4e, 0x4e, 0x02, 0x09, 0x08, 0x09, 0x47, 0x46, ++ 0x00, 0x46, 0x46, 0x01, 0x47, 0x4e, 0x4e, 0x02, 0x47, 0x4f, 0x4e, 0x4e, 0x02, 0x09, 0x08, 0x09, ++ 0x18, 0x47, 0x1a, 0x40, 0x48, 0x40, 0x00, 0x07, 0x00, 0x08, 0x08, 0x0a, 0x00, 0x17, 0x07, 0x47, ++ 0x18, 0x07, 0x40, 0x17, 0x07, 0x47, 0x18, 0x07, 0x40, 0x17, 0x07, 0x47, 0x18, 0x07, 0x40, 0x48, ++ 0x07, 0x08, 0x08, 0x10, 0x18, 0x10, 0x18, 0x0f, 0x17, 0x07, 0x47, 0x17, 0x07, 0x47, 0x40, 0x40, ++ 0x40, 0x16, 0x0f, 0x0f, 0x40, 0x0f, 0x0f, 0x0f, 0x0f, 0x28, 0x27, 0x18, 0x07, 0x18, 0x18, 0x10, ++ 0x40, 0x2e, 0x17, 0x0f, 0x40, 0x0f, 0x0f, 0x0f, 0x11, 0x0f, 0x19, 0x11, 0x11, 0x0f, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x3e, 0x12, 0x00, 0x4e, 0x40, 0x0d, 0x49, 0x52, 0x28, 0x40, 0x00, 0x40, 0x40, 0x06, 0x0f, ++ 0x00, 0x03, 0x40, 0x10, 0x45, 0x03, 0x0c, 0x1d, 0x1d, 0x07, 0x07, 0x07, 0x24, 0x0f, 0x11, 0x07, ++ 0x4d, 0x27, 0x12, 0x0f, 0x40, 0x40, 0x05, 0x40, 0x40, 0x40, 0x00, 0x00, 0x46, 0x45, 0x01, 0x45, ++ 0x45, 0x02, 0x46, 0x4d, 0x4d, 0x03, 0x46, 0x4e, 0x4d, 0x4d, 0x03, 0x0a, 0x09, 0x0a, 0x46, 0x45, ++ 0x01, 0x45, 0x45, 0x02, 0x46, 0x4d, 0x4d, 0x03, 0x46, 0x4e, 0x4d, 0x4d, 0x03, 0x0a, 0x09, 0x0a, ++ 0x19, 0x47, 0x1c, 0x40, 0x48, 0x40, 0x00, 0x07, 0x00, 0x09, 0x09, 0x0c, 0x01, 0x17, 0x06, 0x47, ++ 0x18, 0x07, 0x40, 0x17, 0x06, 0x47, 0x18, 0x07, 0x40, 0x17, 0x06, 0x47, 0x18, 0x07, 0x40, 0x48, ++ 0x07, 0x08, 0x08, 0x11, 0x19, 0x11, 0x19, 0x0f, 0x17, 0x06, 0x47, 0x17, 0x06, 0x47, 0x40, 0x40, ++ 0x40, 0x15, 0x0f, 0x0f, 0x40, 0x0f, 0x0f, 0x0e, 0x0e, 0x28, 0x27, 0x18, 0x07, 0x19, 0x18, 0x11, ++ 0x40, 0x2c, 0x17, 0x0f, 0x40, 0x0f, 0x0f, 0x0e, 0x12, 0x0f, 0x1a, 0x12, 0x12, 0x0f, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x3e, 0x13, 0x01, 0x4d, 0x40, 0x0c, 0x4a, 0x53, 0x29, 0x40, 0x01, 0x40, 0x40, 0x05, 0x0f, ++ 0x01, 0x05, 0x40, 0x11, 0x43, 0x05, 0x0e, 0x20, 0x20, 0x07, 0x07, 0x06, 0x22, 0x0e, 0x12, 0x07, ++ 0x4c, 0x27, 0x14, 0x0e, 0x40, 0x41, 0x04, 0x40, 0x40, 0x40, 0x01, 0x01, 0x45, 0x44, 0x02, 0x44, ++ 0x43, 0x04, 0x45, 0x4c, 0x4c, 0x05, 0x45, 0x4d, 0x4c, 0x4c, 0x05, 0x0b, 0x0a, 0x0c, 0x45, 0x44, ++ 0x02, 0x44, 0x43, 0x04, 0x45, 0x4c, 0x4c, 0x05, 0x45, 0x4d, 0x4c, 0x4c, 0x05, 0x0b, 0x0a, 0x0c, ++ 0x1a, 0x46, 0x1e, 0x40, 0x49, 0x40, 0x01, 0x07, 0x01, 0x0a, 0x0a, 0x0e, 0x02, 0x16, 0x05, 0x46, ++ 0x19, 0x07, 0x40, 0x16, 0x05, 0x46, 0x19, 0x07, 0x40, 0x16, 0x05, 0x46, 0x19, 0x07, 0x40, 0x49, ++ 0x07, 0x09, 0x09, 0x12, 0x1a, 0x12, 0x1a, 0x0e, 0x17, 0x05, 0x46, 0x17, 0x05, 0x46, 0x40, 0x40, ++ 0x40, 0x14, 0x0e, 0x0e, 0x40, 0x0f, 0x0e, 0x0d, 0x0d, 0x29, 0x27, 0x19, 0x07, 0x1a, 0x19, 0x12, ++ 0x41, 0x2b, 0x16, 0x0e, 0x40, 0x0f, 0x0e, 0x0d, 0x13, 0x0e, 0x1c, 0x13, 0x13, 0x0e, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x3e, 0x14, 0x01, 0x4d, 0x40, 0x0b, 0x4a, 0x54, 0x29, 0x40, 0x01, 0x40, 0x40, 0x05, 0x0f, ++ 0x01, 0x06, 0x40, 0x11, 0x42, 0x06, 0x10, 0x22, 0x22, 0x07, 0x07, 0x06, 0x21, 0x0e, 0x12, 0x07, ++ 0x4b, 0x27, 0x15, 0x0e, 0x40, 0x41, 0x03, 0x40, 0x40, 0x40, 0x01, 0x01, 0x45, 0x43, 0x02, 0x43, ++ 0x42, 0x05, 0x45, 0x4b, 0x4b, 0x06, 0x45, 0x4d, 0x4b, 0x4b, 0x06, 0x0c, 0x0a, 0x0d, 0x45, 0x43, ++ 0x02, 0x43, 0x42, 0x05, 0x45, 0x4b, 0x4b, 0x06, 0x45, 0x4d, 0x4b, 0x4b, 0x06, 0x0c, 0x0a, 0x0d, ++ 0x1a, 0x46, 0x20, 0x40, 0x49, 0x40, 0x01, 0x07, 0x01, 0x0a, 0x0a, 0x10, 0x02, 0x16, 0x05, 0x46, ++ 0x19, 0x07, 0x40, 0x16, 0x05, 0x46, 0x19, 0x07, 0x40, 0x16, 0x05, 0x46, 0x19, 0x07, 0x40, 0x49, ++ 0x07, 0x09, 0x09, 0x12, 0x1a, 0x12, 0x1a, 0x0e, 0x17, 0x05, 0x46, 0x17, 0x05, 0x46, 0x40, 0x40, ++ 0x40, 0x13, 0x0e, 0x0e, 0x40, 0x0f, 0x0e, 0x0d, 0x0d, 0x29, 0x27, 0x19, 0x07, 0x1a, 0x19, 0x12, ++ 0x41, 0x2a, 0x16, 0x0e, 0x40, 0x0f, 0x0e, 0x0d, 0x14, 0x0e, 0x1d, 0x14, 0x14, 0x0e, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x3e, 0x15, 0x01, 0x4c, 0x40, 0x0a, 0x4b, 0x55, 0x29, 0x40, 0x01, 0x40, 0x40, 0x04, 0x0f, ++ 0x01, 0x08, 0x40, 0x11, 0x41, 0x08, 0x12, 0x25, 0x25, 0x07, 0x07, 0x06, 0x1f, 0x0e, 0x13, 0x07, ++ 0x4a, 0x27, 0x16, 0x0e, 0x40, 0x41, 0x02, 0x40, 0x40, 0x40, 0x01, 0x01, 0x44, 0x42, 0x03, 0x42, ++ 0x41, 0x06, 0x44, 0x4a, 0x4a, 0x08, 0x44, 0x4c, 0x4a, 0x4a, 0x08, 0x0d, 0x0b, 0x0e, 0x44, 0x42, ++ 0x03, 0x42, 0x41, 0x06, 0x44, 0x4a, 0x4a, 0x08, 0x44, 0x4c, 0x4a, 0x4a, 0x08, 0x0d, 0x0b, 0x0e, ++ 0x1b, 0x46, 0x22, 0x40, 0x49, 0x40, 0x01, 0x07, 0x01, 0x0b, 0x0b, 0x12, 0x03, 0x16, 0x04, 0x46, ++ 0x19, 0x07, 0x40, 0x16, 0x04, 0x46, 0x19, 0x07, 0x40, 0x16, 0x04, 0x46, 0x19, 0x07, 0x40, 0x49, ++ 0x07, 0x09, 0x09, 0x13, 0x1b, 0x13, 0x1b, 0x0e, 0x17, 0x04, 0x46, 0x17, 0x04, 0x46, 0x40, 0x40, ++ 0x40, 0x12, 0x0e, 0x0e, 0x40, 0x0f, 0x0e, 0x0c, 0x0c, 0x29, 0x27, 0x19, 0x07, 0x1b, 0x19, 0x13, ++ 0x41, 0x29, 0x16, 0x0e, 0x40, 0x0f, 0x0e, 0x0c, 0x15, 0x0e, 0x1e, 0x15, 0x15, 0x0e, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x3e, 0x15, 0x01, 0x4c, 0x40, 0x09, 0x4c, 0x56, 0x29, 0x40, 0x01, 0x40, 0x40, 0x03, 0x0f, ++ 0x01, 0x09, 0x40, 0x11, 0x40, 0x09, 0x13, 0x27, 0x27, 0x07, 0x07, 0x05, 0x1d, 0x0d, 0x13, 0x07, ++ 0x4a, 0x27, 0x17, 0x0d, 0x40, 0x42, 0x01, 0x40, 0x40, 0x40, 0x01, 0x01, 0x44, 0x42, 0x03, 0x42, ++ 0x40, 0x07, 0x44, 0x4a, 0x4a, 0x09, 0x44, 0x4c, 0x4a, 0x4a, 0x09, 0x0d, 0x0b, 0x0f, 0x44, 0x42, ++ 0x03, 0x42, 0x40, 0x07, 0x44, 0x4a, 0x4a, 0x09, 0x44, 0x4c, 0x4a, 0x4a, 0x09, 0x0d, 0x0b, 0x0f, ++ 0x1b, 0x46, 0x23, 0x40, 0x4a, 0x40, 0x01, 0x07, 0x01, 0x0b, 0x0b, 0x13, 0x03, 0x15, 0x03, 0x46, ++ 0x19, 0x07, 0x40, 0x15, 0x03, 0x46, 0x19, 0x07, 0x40, 0x15, 0x03, 0x46, 0x19, 0x07, 0x40, 0x4a, ++ 0x07, 0x09, 0x09, 0x13, 0x1b, 0x13, 0x1b, 0x0d, 0x17, 0x03, 0x46, 0x17, 0x03, 0x46, 0x40, 0x40, ++ 0x40, 0x11, 0x0d, 0x0d, 0x40, 0x0f, 0x0d, 0x0b, 0x0b, 0x29, 0x27, 0x19, 0x07, 0x1b, 0x19, 0x13, ++ 0x42, 0x27, 0x15, 0x0d, 0x40, 0x0f, 0x0d, 0x0b, 0x15, 0x0d, 0x1f, 0x15, 0x15, 0x0d, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x3e, 0x16, 0x02, 0x4b, 0x40, 0x09, 0x4c, 0x56, 0x2a, 0x40, 0x02, 0x40, 0x40, 0x03, 0x0f, ++ 0x02, 0x0b, 0x40, 0x12, 0x01, 0x0b, 0x15, 0x2a, 0x2a, 0x07, 0x07, 0x05, 0x1c, 0x0d, 0x14, 0x07, ++ 0x49, 0x27, 0x19, 0x0d, 0x40, 0x42, 0x01, 0x40, 0x40, 0x40, 0x02, 0x02, 0x43, 0x41, 0x04, 0x41, ++ 0x01, 0x09, 0x43, 0x49, 0x49, 0x0b, 0x43, 0x4b, 0x49, 0x49, 0x0b, 0x0e, 0x0c, 0x11, 0x43, 0x41, ++ 0x04, 0x41, 0x01, 0x09, 0x43, 0x49, 0x49, 0x0b, 0x43, 0x4b, 0x49, 0x49, 0x0b, 0x0e, 0x0c, 0x11, ++ 0x1c, 0x45, 0x25, 0x40, 0x4a, 0x40, 0x02, 0x07, 0x02, 0x0c, 0x0c, 0x15, 0x04, 0x15, 0x03, 0x45, ++ 0x1a, 0x07, 0x40, 0x15, 0x03, 0x45, 0x1a, 0x07, 0x40, 0x15, 0x03, 0x45, 0x1a, 0x07, 0x40, 0x4a, ++ 0x07, 0x0a, 0x0a, 0x14, 0x1c, 0x14, 0x1c, 0x0d, 0x17, 0x03, 0x45, 0x17, 0x03, 0x45, 0x40, 0x40, ++ 0x40, 0x11, 0x0d, 0x0d, 0x40, 0x0f, 0x0d, 0x0b, 0x0b, 0x2a, 0x27, 0x1a, 0x07, 0x1c, 0x1a, 0x14, ++ 0x42, 0x26, 0x15, 0x0d, 0x40, 0x0f, 0x0d, 0x0b, 0x16, 0x0d, 0x21, 0x16, 0x16, 0x0d, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x3e, 0x17, 0x02, 0x4a, 0x40, 0x08, 0x4d, 0x57, 0x2a, 0x40, 0x02, 0x40, 0x40, 0x02, 0x0f, ++ 0x02, 0x0d, 0x40, 0x12, 0x02, 0x0d, 0x17, 0x2c, 0x2c, 0x07, 0x07, 0x05, 0x1a, 0x0d, 0x15, 0x07, ++ 0x48, 0x27, 0x1a, 0x0d, 0x40, 0x42, 0x00, 0x40, 0x40, 0x40, 0x02, 0x02, 0x42, 0x40, 0x05, 0x40, ++ 0x02, 0x0a, 0x42, 0x48, 0x48, 0x0d, 0x42, 0x4a, 0x48, 0x48, 0x0d, 0x0f, 0x0d, 0x12, 0x42, 0x40, ++ 0x05, 0x40, 0x02, 0x0a, 0x42, 0x48, 0x48, 0x0d, 0x42, 0x4a, 0x48, 0x48, 0x0d, 0x0f, 0x0d, 0x12, ++ 0x1d, 0x45, 0x27, 0x40, 0x4a, 0x40, 0x02, 0x07, 0x02, 0x0d, 0x0d, 0x17, 0x05, 0x15, 0x02, 0x45, ++ 0x1a, 0x07, 0x40, 0x15, 0x02, 0x45, 0x1a, 0x07, 0x40, 0x15, 0x02, 0x45, 0x1a, 0x07, 0x40, 0x4a, ++ 0x07, 0x0a, 0x0a, 0x15, 0x1d, 0x15, 0x1d, 0x0d, 0x17, 0x02, 0x45, 0x17, 0x02, 0x45, 0x40, 0x40, ++ 0x40, 0x10, 0x0d, 0x0d, 0x40, 0x0f, 0x0d, 0x0a, 0x0a, 0x2a, 0x27, 0x1a, 0x07, 0x1d, 0x1a, 0x15, ++ 0x42, 0x25, 0x15, 0x0d, 0x40, 0x0f, 0x0d, 0x0a, 0x17, 0x0d, 0x22, 0x17, 0x17, 0x0d, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x3e, 0x18, 0x02, 0x4a, 0x40, 0x07, 0x4d, 0x58, 0x2a, 0x40, 0x02, 0x40, 0x40, 0x02, 0x0f, ++ 0x02, 0x0e, 0x40, 0x12, 0x03, 0x0e, 0x19, 0x2f, 0x2f, 0x07, 0x07, 0x05, 0x19, 0x0d, 0x15, 0x07, ++ 0x47, 0x27, 0x1b, 0x0d, 0x40, 0x42, 0x40, 0x40, 0x40, 0x40, 0x02, 0x02, 0x42, 0x00, 0x05, 0x00, ++ 0x03, 0x0b, 0x42, 0x47, 0x47, 0x0e, 0x42, 0x4a, 0x47, 0x47, 0x0e, 0x10, 0x0d, 0x13, 0x42, 0x00, ++ 0x05, 0x00, 0x03, 0x0b, 0x42, 0x47, 0x47, 0x0e, 0x42, 0x4a, 0x47, 0x47, 0x0e, 0x10, 0x0d, 0x13, ++ 0x1d, 0x45, 0x29, 0x40, 0x4a, 0x40, 0x02, 0x07, 0x02, 0x0d, 0x0d, 0x19, 0x05, 0x15, 0x02, 0x45, ++ 0x1a, 0x07, 0x40, 0x15, 0x02, 0x45, 0x1a, 0x07, 0x40, 0x15, 0x02, 0x45, 0x1a, 0x07, 0x40, 0x4a, ++ 0x07, 0x0a, 0x0a, 0x15, 0x1d, 0x15, 0x1d, 0x0d, 0x17, 0x02, 0x45, 0x17, 0x02, 0x45, 0x40, 0x40, ++ 0x40, 0x0f, 0x0d, 0x0d, 0x40, 0x0f, 0x0d, 0x0a, 0x0a, 0x2a, 0x27, 0x1a, 0x07, 0x1d, 0x1a, 0x15, ++ 0x42, 0x24, 0x15, 0x0d, 0x40, 0x0f, 0x0d, 0x0a, 0x18, 0x0d, 0x23, 0x18, 0x18, 0x0d, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x3e, 0x19, 0x03, 0x49, 0x40, 0x06, 0x4e, 0x59, 0x2b, 0x40, 0x03, 0x40, 0x40, 0x01, 0x0f, ++ 0x03, 0x10, 0x40, 0x13, 0x04, 0x10, 0x1b, 0x31, 0x31, 0x07, 0x07, 0x04, 0x17, 0x0c, 0x16, 0x07, ++ 0x46, 0x27, 0x1c, 0x0c, 0x40, 0x43, 0x41, 0x40, 0x40, 0x40, 0x03, 0x03, 0x41, 0x01, 0x06, 0x01, ++ 0x04, 0x0c, 0x41, 0x46, 0x46, 0x10, 0x41, 0x49, 0x46, 0x46, 0x10, 0x11, 0x0e, 0x14, 0x41, 0x01, ++ 0x06, 0x01, 0x04, 0x0c, 0x41, 0x46, 0x46, 0x10, 0x41, 0x49, 0x46, 0x46, 0x10, 0x11, 0x0e, 0x14, ++ 0x1e, 0x44, 0x2b, 0x40, 0x4b, 0x40, 0x03, 0x07, 0x03, 0x0e, 0x0e, 0x1b, 0x06, 0x14, 0x01, 0x44, ++ 0x1b, 0x07, 0x40, 0x14, 0x01, 0x44, 0x1b, 0x07, 0x40, 0x14, 0x01, 0x44, 0x1b, 0x07, 0x40, 0x4b, ++ 0x07, 0x0b, 0x0b, 0x16, 0x1e, 0x16, 0x1e, 0x0c, 0x17, 0x01, 0x44, 0x17, 0x01, 0x44, 0x40, 0x40, ++ 0x40, 0x0e, 0x0c, 0x0c, 0x40, 0x0f, 0x0c, 0x09, 0x09, 0x2b, 0x27, 0x1b, 0x07, 0x1e, 0x1b, 0x16, ++ 0x43, 0x22, 0x14, 0x0c, 0x40, 0x0f, 0x0c, 0x09, 0x19, 0x0c, 0x24, 0x19, 0x19, 0x0c, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x3e, 0x1a, 0x03, 0x48, 0x40, 0x05, 0x4f, 0x5a, 0x2b, 0x40, 0x03, 0x40, 0x40, 0x00, 0x0f, ++ 0x03, 0x11, 0x40, 0x13, 0x06, 0x11, 0x1d, 0x34, 0x34, 0x07, 0x07, 0x04, 0x16, 0x0c, 0x17, 0x07, ++ 0x45, 0x27, 0x1e, 0x0c, 0x40, 0x43, 0x42, 0x40, 0x40, 0x40, 0x03, 0x03, 0x40, 0x02, 0x07, 0x02, ++ 0x06, 0x0e, 0x40, 0x45, 0x45, 0x11, 0x40, 0x48, 0x45, 0x45, 0x11, 0x12, 0x0f, 0x16, 0x40, 0x02, ++ 0x07, 0x02, 0x06, 0x0e, 0x40, 0x45, 0x45, 0x11, 0x40, 0x48, 0x45, 0x45, 0x11, 0x12, 0x0f, 0x16, ++ 0x1f, 0x44, 0x2d, 0x40, 0x4b, 0x40, 0x03, 0x07, 0x03, 0x0f, 0x0f, 0x1d, 0x07, 0x14, 0x00, 0x44, ++ 0x1b, 0x07, 0x40, 0x14, 0x00, 0x44, 0x1b, 0x07, 0x40, 0x14, 0x00, 0x44, 0x1b, 0x07, 0x40, 0x4b, ++ 0x07, 0x0b, 0x0b, 0x17, 0x1f, 0x17, 0x1f, 0x0c, 0x17, 0x00, 0x44, 0x17, 0x00, 0x44, 0x40, 0x40, ++ 0x40, 0x0d, 0x0c, 0x0c, 0x40, 0x0f, 0x0c, 0x08, 0x08, 0x2b, 0x27, 0x1b, 0x07, 0x1f, 0x1b, 0x17, ++ 0x43, 0x21, 0x14, 0x0c, 0x40, 0x0f, 0x0c, 0x08, 0x1a, 0x0c, 0x26, 0x1a, 0x1a, 0x0c, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x3e, 0x1b, 0x03, 0x48, 0x40, 0x04, 0x4f, 0x5b, 0x2b, 0x40, 0x03, 0x40, 0x40, 0x00, 0x0f, ++ 0x03, 0x13, 0x40, 0x13, 0x07, 0x13, 0x1f, 0x36, 0x36, 0x07, 0x07, 0x04, 0x14, 0x0c, 0x17, 0x07, ++ 0x44, 0x27, 0x1f, 0x0c, 0x40, 0x43, 0x43, 0x40, 0x40, 0x40, 0x03, 0x03, 0x40, 0x03, 0x07, 0x03, ++ 0x07, 0x0f, 0x40, 0x44, 0x44, 0x13, 0x40, 0x48, 0x44, 0x44, 0x13, 0x13, 0x0f, 0x17, 0x40, 0x03, ++ 0x07, 0x03, 0x07, 0x0f, 0x40, 0x44, 0x44, 0x13, 0x40, 0x48, 0x44, 0x44, 0x13, 0x13, 0x0f, 0x17, ++ 0x1f, 0x44, 0x2f, 0x40, 0x4b, 0x40, 0x03, 0x07, 0x03, 0x0f, 0x0f, 0x1f, 0x07, 0x14, 0x00, 0x44, ++ 0x1b, 0x07, 0x40, 0x14, 0x00, 0x44, 0x1b, 0x07, 0x40, 0x14, 0x00, 0x44, 0x1b, 0x07, 0x40, 0x4b, ++ 0x07, 0x0b, 0x0b, 0x17, 0x1f, 0x17, 0x1f, 0x0c, 0x17, 0x00, 0x44, 0x17, 0x00, 0x44, 0x40, 0x40, ++ 0x40, 0x0c, 0x0c, 0x0c, 0x40, 0x0f, 0x0c, 0x08, 0x08, 0x2b, 0x27, 0x1b, 0x07, 0x1f, 0x1b, 0x17, ++ 0x43, 0x20, 0x14, 0x0c, 0x40, 0x0f, 0x0c, 0x08, 0x1b, 0x0c, 0x27, 0x1b, 0x1b, 0x0c, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x3e, 0x1c, 0x04, 0x47, 0x40, 0x03, 0x50, 0x5c, 0x2c, 0x40, 0x04, 0x40, 0x40, 0x40, 0x0f, ++ 0x04, 0x14, 0x40, 0x14, 0x08, 0x14, 0x21, 0x39, 0x39, 0x07, 0x07, 0x03, 0x13, 0x0b, 0x18, 0x07, ++ 0x43, 0x27, 0x20, 0x0b, 0x40, 0x44, 0x44, 0x40, 0x40, 0x40, 0x04, 0x04, 0x00, 0x04, 0x08, 0x04, ++ 0x08, 0x10, 0x00, 0x43, 0x43, 0x14, 0x00, 0x47, 0x43, 0x43, 0x14, 0x14, 0x10, 0x18, 0x00, 0x04, ++ 0x08, 0x04, 0x08, 0x10, 0x00, 0x43, 0x43, 0x14, 0x00, 0x47, 0x43, 0x43, 0x14, 0x14, 0x10, 0x18, ++ 0x20, 0x43, 0x31, 0x40, 0x4c, 0x40, 0x04, 0x07, 0x04, 0x10, 0x10, 0x21, 0x08, 0x13, 0x40, 0x43, ++ 0x1c, 0x07, 0x40, 0x13, 0x40, 0x43, 0x1c, 0x07, 0x40, 0x13, 0x40, 0x43, 0x1c, 0x07, 0x40, 0x4c, ++ 0x07, 0x0c, 0x0c, 0x18, 0x20, 0x18, 0x20, 0x0b, 0x17, 0x40, 0x43, 0x17, 0x40, 0x43, 0x40, 0x40, ++ 0x40, 0x0b, 0x0b, 0x0b, 0x40, 0x0f, 0x0b, 0x07, 0x07, 0x2c, 0x27, 0x1c, 0x07, 0x20, 0x1c, 0x18, ++ 0x44, 0x1f, 0x13, 0x0b, 0x40, 0x0f, 0x0b, 0x07, 0x1c, 0x0b, 0x28, 0x1c, 0x1c, 0x0b, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x3e, 0x1d, 0x04, 0x47, 0x40, 0x02, 0x51, 0x5d, 0x2c, 0x40, 0x04, 0x40, 0x40, 0x41, 0x0f, ++ 0x04, 0x16, 0x40, 0x14, 0x09, 0x16, 0x22, 0x3b, 0x3b, 0x07, 0x07, 0x03, 0x11, 0x0b, 0x18, 0x07, ++ 0x42, 0x27, 0x21, 0x0b, 0x40, 0x44, 0x45, 0x40, 0x40, 0x40, 0x04, 0x04, 0x00, 0x05, 0x08, 0x05, ++ 0x09, 0x11, 0x00, 0x42, 0x42, 0x16, 0x00, 0x47, 0x42, 0x42, 0x16, 0x15, 0x10, 0x19, 0x00, 0x05, ++ 0x08, 0x05, 0x09, 0x11, 0x00, 0x42, 0x42, 0x16, 0x00, 0x47, 0x42, 0x42, 0x16, 0x15, 0x10, 0x19, ++ 0x20, 0x43, 0x32, 0x40, 0x4c, 0x40, 0x04, 0x07, 0x04, 0x10, 0x10, 0x22, 0x08, 0x13, 0x41, 0x43, ++ 0x1c, 0x07, 0x40, 0x13, 0x41, 0x43, 0x1c, 0x07, 0x40, 0x13, 0x41, 0x43, 0x1c, 0x07, 0x40, 0x4c, ++ 0x07, 0x0c, 0x0c, 0x18, 0x20, 0x18, 0x20, 0x0b, 0x17, 0x41, 0x43, 0x17, 0x41, 0x43, 0x40, 0x40, ++ 0x40, 0x0a, 0x0b, 0x0b, 0x40, 0x0f, 0x0b, 0x06, 0x06, 0x2c, 0x27, 0x1c, 0x07, 0x20, 0x1c, 0x18, ++ 0x44, 0x1d, 0x13, 0x0b, 0x40, 0x0f, 0x0b, 0x06, 0x1d, 0x0b, 0x29, 0x1d, 0x1d, 0x0b, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x3e, 0x1e, 0x04, 0x46, 0x40, 0x01, 0x51, 0x5e, 0x2c, 0x40, 0x04, 0x40, 0x40, 0x41, 0x0f, ++ 0x04, 0x18, 0x40, 0x14, 0x0b, 0x18, 0x24, 0x3e, 0x3e, 0x07, 0x07, 0x03, 0x0f, 0x0b, 0x19, 0x07, ++ 0x41, 0x27, 0x23, 0x0b, 0x40, 0x44, 0x46, 0x40, 0x40, 0x40, 0x04, 0x04, 0x01, 0x06, 0x09, 0x06, ++ 0x0b, 0x13, 0x01, 0x41, 0x41, 0x18, 0x01, 0x46, 0x41, 0x41, 0x18, 0x16, 0x11, 0x1b, 0x01, 0x06, ++ 0x09, 0x06, 0x0b, 0x13, 0x01, 0x41, 0x41, 0x18, 0x01, 0x46, 0x41, 0x41, 0x18, 0x16, 0x11, 0x1b, ++ 0x21, 0x43, 0x34, 0x40, 0x4c, 0x40, 0x04, 0x07, 0x04, 0x11, 0x11, 0x24, 0x09, 0x13, 0x41, 0x43, ++ 0x1c, 0x07, 0x40, 0x13, 0x41, 0x43, 0x1c, 0x07, 0x40, 0x13, 0x41, 0x43, 0x1c, 0x07, 0x40, 0x4c, ++ 0x07, 0x0c, 0x0c, 0x19, 0x21, 0x19, 0x21, 0x0b, 0x17, 0x41, 0x43, 0x17, 0x41, 0x43, 0x40, 0x40, ++ 0x40, 0x09, 0x0b, 0x0b, 0x40, 0x0f, 0x0b, 0x06, 0x06, 0x2c, 0x27, 0x1c, 0x07, 0x21, 0x1c, 0x19, ++ 0x44, 0x1c, 0x13, 0x0b, 0x40, 0x0f, 0x0b, 0x06, 0x1e, 0x0b, 0x2b, 0x1e, 0x1e, 0x0b, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x3e, 0x1f, 0x05, 0x45, 0x40, 0x00, 0x52, 0x5f, 0x2d, 0x40, 0x05, 0x40, 0x40, 0x42, 0x0f, ++ 0x05, 0x19, 0x40, 0x15, 0x0c, 0x19, 0x26, 0x3e, 0x3e, 0x07, 0x07, 0x02, 0x0e, 0x0a, 0x1a, 0x07, ++ 0x40, 0x27, 0x24, 0x0a, 0x40, 0x45, 0x47, 0x40, 0x40, 0x40, 0x05, 0x05, 0x02, 0x07, 0x0a, 0x07, ++ 0x0c, 0x14, 0x02, 0x40, 0x40, 0x19, 0x02, 0x45, 0x40, 0x40, 0x19, 0x17, 0x12, 0x1c, 0x02, 0x07, ++ 0x0a, 0x07, 0x0c, 0x14, 0x02, 0x40, 0x40, 0x19, 0x02, 0x45, 0x40, 0x40, 0x19, 0x17, 0x12, 0x1c, ++ 0x22, 0x42, 0x36, 0x40, 0x4d, 0x40, 0x05, 0x07, 0x05, 0x12, 0x12, 0x26, 0x0a, 0x12, 0x42, 0x42, ++ 0x1d, 0x07, 0x40, 0x12, 0x42, 0x42, 0x1d, 0x07, 0x40, 0x12, 0x42, 0x42, 0x1d, 0x07, 0x40, 0x4d, ++ 0x07, 0x0d, 0x0d, 0x1a, 0x22, 0x1a, 0x22, 0x0a, 0x17, 0x42, 0x42, 0x17, 0x42, 0x42, 0x40, 0x40, ++ 0x40, 0x08, 0x0a, 0x0a, 0x40, 0x0f, 0x0a, 0x05, 0x05, 0x2d, 0x27, 0x1d, 0x07, 0x22, 0x1d, 0x1a, ++ 0x45, 0x1b, 0x12, 0x0a, 0x40, 0x0f, 0x0a, 0x05, 0x1f, 0x0a, 0x2c, 0x1f, 0x1f, 0x0a, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x3e, 0x20, 0x05, 0x45, 0x40, 0x40, 0x52, 0x60, 0x2d, 0x40, 0x05, 0x40, 0x40, 0x42, 0x0f, ++ 0x05, 0x1b, 0x40, 0x15, 0x0d, 0x1b, 0x28, 0x3e, 0x3e, 0x07, 0x07, 0x02, 0x0c, 0x0a, 0x1a, 0x07, ++ 0x00, 0x27, 0x25, 0x0a, 0x40, 0x45, 0x48, 0x40, 0x40, 0x40, 0x05, 0x05, 0x02, 0x08, 0x0a, 0x08, ++ 0x0d, 0x15, 0x02, 0x00, 0x00, 0x1b, 0x02, 0x45, 0x00, 0x00, 0x1b, 0x18, 0x12, 0x1d, 0x02, 0x08, ++ 0x0a, 0x08, 0x0d, 0x15, 0x02, 0x00, 0x00, 0x1b, 0x02, 0x45, 0x00, 0x00, 0x1b, 0x18, 0x12, 0x1d, ++ 0x22, 0x42, 0x38, 0x40, 0x4d, 0x40, 0x05, 0x07, 0x05, 0x12, 0x12, 0x28, 0x0a, 0x12, 0x42, 0x42, ++ 0x1d, 0x07, 0x40, 0x12, 0x42, 0x42, 0x1d, 0x07, 0x40, 0x12, 0x42, 0x42, 0x1d, 0x07, 0x40, 0x4d, ++ 0x07, 0x0d, 0x0d, 0x1a, 0x22, 0x1a, 0x22, 0x0a, 0x17, 0x42, 0x42, 0x17, 0x42, 0x42, 0x40, 0x40, ++ 0x40, 0x07, 0x0a, 0x0a, 0x40, 0x0f, 0x0a, 0x05, 0x05, 0x2d, 0x27, 0x1d, 0x07, 0x22, 0x1d, 0x1a, ++ 0x45, 0x1a, 0x12, 0x0a, 0x40, 0x0f, 0x0a, 0x05, 0x20, 0x0a, 0x2d, 0x20, 0x20, 0x0a, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x3e, 0x21, 0x05, 0x44, 0x40, 0x41, 0x53, 0x61, 0x2d, 0x40, 0x05, 0x40, 0x40, 0x43, 0x0f, ++ 0x05, 0x1c, 0x40, 0x15, 0x0e, 0x1c, 0x2a, 0x3e, 0x3e, 0x07, 0x07, 0x02, 0x0b, 0x0a, 0x1b, 0x07, ++ 0x01, 0x27, 0x26, 0x0a, 0x40, 0x45, 0x49, 0x40, 0x40, 0x40, 0x05, 0x05, 0x03, 0x09, 0x0b, 0x09, ++ 0x0e, 0x16, 0x03, 0x01, 0x01, 0x1c, 0x03, 0x44, 0x01, 0x01, 0x1c, 0x19, 0x13, 0x1e, 0x03, 0x09, ++ 0x0b, 0x09, 0x0e, 0x16, 0x03, 0x01, 0x01, 0x1c, 0x03, 0x44, 0x01, 0x01, 0x1c, 0x19, 0x13, 0x1e, ++ 0x23, 0x42, 0x3a, 0x40, 0x4d, 0x40, 0x05, 0x07, 0x05, 0x13, 0x13, 0x2a, 0x0b, 0x12, 0x43, 0x42, ++ 0x1d, 0x07, 0x40, 0x12, 0x43, 0x42, 0x1d, 0x07, 0x40, 0x12, 0x43, 0x42, 0x1d, 0x07, 0x40, 0x4d, ++ 0x07, 0x0d, 0x0d, 0x1b, 0x23, 0x1b, 0x23, 0x0a, 0x17, 0x43, 0x42, 0x17, 0x43, 0x42, 0x40, 0x40, ++ 0x40, 0x06, 0x0a, 0x0a, 0x40, 0x0f, 0x0a, 0x04, 0x04, 0x2d, 0x27, 0x1d, 0x07, 0x23, 0x1d, 0x1b, ++ 0x45, 0x18, 0x12, 0x0a, 0x40, 0x0f, 0x0a, 0x04, 0x21, 0x0a, 0x2e, 0x21, 0x21, 0x0a, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x3e, 0x22, 0x06, 0x43, 0x40, 0x42, 0x54, 0x62, 0x2e, 0x40, 0x06, 0x40, 0x40, 0x44, 0x0f, ++ 0x06, 0x1e, 0x40, 0x16, 0x10, 0x1e, 0x2c, 0x3e, 0x3e, 0x07, 0x07, 0x01, 0x09, 0x09, 0x1c, 0x07, ++ 0x02, 0x27, 0x28, 0x09, 0x40, 0x46, 0x4a, 0x40, 0x40, 0x40, 0x06, 0x06, 0x04, 0x0a, 0x0c, 0x0a, ++ 0x10, 0x18, 0x04, 0x02, 0x02, 0x1e, 0x04, 0x43, 0x02, 0x02, 0x1e, 0x1a, 0x14, 0x20, 0x04, 0x0a, ++ 0x0c, 0x0a, 0x10, 0x18, 0x04, 0x02, 0x02, 0x1e, 0x04, 0x43, 0x02, 0x02, 0x1e, 0x1a, 0x14, 0x20, ++ 0x24, 0x41, 0x3c, 0x40, 0x4e, 0x40, 0x06, 0x07, 0x06, 0x14, 0x14, 0x2c, 0x0c, 0x11, 0x44, 0x41, ++ 0x1e, 0x07, 0x40, 0x11, 0x44, 0x41, 0x1e, 0x07, 0x40, 0x11, 0x44, 0x41, 0x1e, 0x07, 0x40, 0x4e, ++ 0x07, 0x0e, 0x0e, 0x1c, 0x24, 0x1c, 0x24, 0x09, 0x17, 0x44, 0x41, 0x17, 0x44, 0x41, 0x40, 0x40, ++ 0x40, 0x05, 0x09, 0x09, 0x40, 0x0f, 0x09, 0x03, 0x03, 0x2e, 0x27, 0x1e, 0x07, 0x24, 0x1e, 0x1c, ++ 0x46, 0x17, 0x11, 0x09, 0x40, 0x0f, 0x09, 0x03, 0x22, 0x09, 0x30, 0x22, 0x22, 0x09, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x3e, 0x23, 0x06, 0x43, 0x40, 0x43, 0x54, 0x63, 0x2e, 0x40, 0x06, 0x40, 0x40, 0x44, 0x0f, ++ 0x06, 0x1f, 0x40, 0x16, 0x11, 0x1f, 0x2e, 0x3e, 0x3e, 0x07, 0x07, 0x01, 0x08, 0x09, 0x1c, 0x07, ++ 0x03, 0x27, 0x29, 0x09, 0x40, 0x46, 0x4b, 0x40, 0x40, 0x40, 0x06, 0x06, 0x04, 0x0b, 0x0c, 0x0b, ++ 0x11, 0x19, 0x04, 0x03, 0x03, 0x1f, 0x04, 0x43, 0x03, 0x03, 0x1f, 0x1b, 0x14, 0x21, 0x04, 0x0b, ++ 0x0c, 0x0b, 0x11, 0x19, 0x04, 0x03, 0x03, 0x1f, 0x04, 0x43, 0x03, 0x03, 0x1f, 0x1b, 0x14, 0x21, ++ 0x24, 0x41, 0x3e, 0x40, 0x4e, 0x40, 0x06, 0x07, 0x06, 0x14, 0x14, 0x2e, 0x0c, 0x11, 0x44, 0x41, ++ 0x1e, 0x07, 0x40, 0x11, 0x44, 0x41, 0x1e, 0x07, 0x40, 0x11, 0x44, 0x41, 0x1e, 0x07, 0x40, 0x4e, ++ 0x07, 0x0e, 0x0e, 0x1c, 0x24, 0x1c, 0x24, 0x09, 0x17, 0x44, 0x41, 0x17, 0x44, 0x41, 0x40, 0x40, ++ 0x40, 0x04, 0x09, 0x09, 0x40, 0x0f, 0x09, 0x03, 0x03, 0x2e, 0x27, 0x1e, 0x07, 0x24, 0x1e, 0x1c, ++ 0x46, 0x16, 0x11, 0x09, 0x40, 0x0f, 0x09, 0x03, 0x23, 0x09, 0x31, 0x23, 0x23, 0x09, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x3e, 0x24, 0x06, 0x42, 0x40, 0x44, 0x55, 0x64, 0x2e, 0x40, 0x06, 0x40, 0x40, 0x45, 0x0f, ++ 0x06, 0x21, 0x40, 0x16, 0x12, 0x21, 0x30, 0x3e, 0x3e, 0x07, 0x07, 0x01, 0x06, 0x09, 0x1d, 0x07, ++ 0x04, 0x27, 0x2a, 0x09, 0x40, 0x46, 0x4c, 0x40, 0x40, 0x40, 0x06, 0x06, 0x05, 0x0c, 0x0d, 0x0c, ++ 0x12, 0x1a, 0x05, 0x04, 0x04, 0x21, 0x05, 0x42, 0x04, 0x04, 0x21, 0x1c, 0x15, 0x22, 0x05, 0x0c, ++ 0x0d, 0x0c, 0x12, 0x1a, 0x05, 0x04, 0x04, 0x21, 0x05, 0x42, 0x04, 0x04, 0x21, 0x1c, 0x15, 0x22, ++ 0x25, 0x41, 0x3e, 0x40, 0x4e, 0x40, 0x06, 0x07, 0x06, 0x15, 0x15, 0x30, 0x0d, 0x11, 0x45, 0x41, ++ 0x1e, 0x07, 0x40, 0x11, 0x45, 0x41, 0x1e, 0x07, 0x40, 0x11, 0x45, 0x41, 0x1e, 0x07, 0x40, 0x4e, ++ 0x07, 0x0e, 0x0e, 0x1d, 0x25, 0x1d, 0x25, 0x09, 0x17, 0x45, 0x41, 0x17, 0x45, 0x41, 0x40, 0x40, ++ 0x40, 0x03, 0x09, 0x09, 0x40, 0x0f, 0x09, 0x02, 0x02, 0x2e, 0x27, 0x1e, 0x07, 0x25, 0x1e, 0x1d, ++ 0x46, 0x15, 0x11, 0x09, 0x40, 0x0f, 0x09, 0x02, 0x24, 0x09, 0x32, 0x24, 0x24, 0x09, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x3e, 0x24, 0x06, 0x42, 0x40, 0x45, 0x56, 0x65, 0x2e, 0x40, 0x06, 0x40, 0x40, 0x46, 0x0f, ++ 0x06, 0x22, 0x40, 0x16, 0x13, 0x22, 0x31, 0x3e, 0x3e, 0x07, 0x07, 0x00, 0x04, 0x08, 0x1d, 0x07, ++ 0x04, 0x27, 0x2b, 0x08, 0x40, 0x47, 0x4d, 0x40, 0x40, 0x40, 0x06, 0x06, 0x05, 0x0c, 0x0d, 0x0c, ++ 0x13, 0x1b, 0x05, 0x04, 0x04, 0x22, 0x05, 0x42, 0x04, 0x04, 0x22, 0x1c, 0x15, 0x23, 0x05, 0x0c, ++ 0x0d, 0x0c, 0x13, 0x1b, 0x05, 0x04, 0x04, 0x22, 0x05, 0x42, 0x04, 0x04, 0x22, 0x1c, 0x15, 0x23, ++ 0x25, 0x41, 0x3e, 0x40, 0x4f, 0x40, 0x06, 0x07, 0x06, 0x15, 0x15, 0x31, 0x0d, 0x10, 0x46, 0x41, ++ 0x1e, 0x07, 0x40, 0x10, 0x46, 0x41, 0x1e, 0x07, 0x40, 0x10, 0x46, 0x41, 0x1e, 0x07, 0x40, 0x4f, ++ 0x07, 0x0e, 0x0e, 0x1d, 0x25, 0x1d, 0x25, 0x08, 0x17, 0x46, 0x41, 0x17, 0x46, 0x41, 0x40, 0x40, ++ 0x40, 0x02, 0x08, 0x08, 0x40, 0x0f, 0x08, 0x01, 0x01, 0x2e, 0x27, 0x1e, 0x07, 0x25, 0x1e, 0x1d, ++ 0x47, 0x13, 0x10, 0x08, 0x40, 0x0f, 0x08, 0x01, 0x24, 0x08, 0x33, 0x24, 0x24, 0x08, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x3e, 0x25, 0x07, 0x41, 0x40, 0x45, 0x56, 0x65, 0x2f, 0x40, 0x07, 0x40, 0x40, 0x46, 0x0f, ++ 0x07, 0x24, 0x40, 0x17, 0x15, 0x24, 0x33, 0x3e, 0x3e, 0x07, 0x07, 0x00, 0x03, 0x08, 0x1e, 0x07, ++ 0x05, 0x27, 0x2d, 0x08, 0x40, 0x47, 0x4d, 0x40, 0x40, 0x40, 0x07, 0x07, 0x06, 0x0d, 0x0e, 0x0d, ++ 0x15, 0x1d, 0x06, 0x05, 0x05, 0x24, 0x06, 0x41, 0x05, 0x05, 0x24, 0x1d, 0x16, 0x25, 0x06, 0x0d, ++ 0x0e, 0x0d, 0x15, 0x1d, 0x06, 0x05, 0x05, 0x24, 0x06, 0x41, 0x05, 0x05, 0x24, 0x1d, 0x16, 0x25, ++ 0x26, 0x40, 0x3e, 0x40, 0x4f, 0x40, 0x07, 0x07, 0x07, 0x16, 0x16, 0x33, 0x0e, 0x10, 0x46, 0x40, ++ 0x1f, 0x07, 0x40, 0x10, 0x46, 0x40, 0x1f, 0x07, 0x40, 0x10, 0x46, 0x40, 0x1f, 0x07, 0x40, 0x4f, ++ 0x07, 0x0f, 0x0f, 0x1e, 0x26, 0x1e, 0x26, 0x08, 0x17, 0x46, 0x40, 0x17, 0x46, 0x40, 0x40, 0x40, ++ 0x40, 0x02, 0x08, 0x08, 0x40, 0x0f, 0x08, 0x01, 0x01, 0x2f, 0x27, 0x1f, 0x07, 0x26, 0x1f, 0x1e, ++ 0x47, 0x12, 0x10, 0x08, 0x40, 0x0f, 0x08, 0x01, 0x25, 0x08, 0x35, 0x25, 0x25, 0x08, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x3e, 0x26, 0x07, 0x40, 0x40, 0x46, 0x57, 0x66, 0x2f, 0x40, 0x07, 0x40, 0x40, 0x47, 0x0f, ++ 0x07, 0x26, 0x40, 0x17, 0x16, 0x26, 0x35, 0x3e, 0x3e, 0x07, 0x07, 0x00, 0x01, 0x08, 0x1f, 0x07, ++ 0x06, 0x27, 0x2e, 0x08, 0x40, 0x47, 0x4e, 0x40, 0x40, 0x40, 0x07, 0x07, 0x07, 0x0e, 0x0f, 0x0e, ++ 0x16, 0x1e, 0x07, 0x06, 0x06, 0x26, 0x07, 0x40, 0x06, 0x06, 0x26, 0x1e, 0x17, 0x26, 0x07, 0x0e, ++ 0x0f, 0x0e, 0x16, 0x1e, 0x07, 0x06, 0x06, 0x26, 0x07, 0x40, 0x06, 0x06, 0x26, 0x1e, 0x17, 0x26, ++ 0x27, 0x40, 0x3e, 0x40, 0x4f, 0x40, 0x07, 0x07, 0x07, 0x17, 0x17, 0x35, 0x0f, 0x10, 0x47, 0x40, ++ 0x1f, 0x07, 0x40, 0x10, 0x47, 0x40, 0x1f, 0x07, 0x40, 0x10, 0x47, 0x40, 0x1f, 0x07, 0x40, 0x4f, ++ 0x07, 0x0f, 0x0f, 0x1f, 0x27, 0x1f, 0x27, 0x08, 0x17, 0x47, 0x40, 0x17, 0x47, 0x40, 0x40, 0x40, ++ 0x40, 0x01, 0x08, 0x08, 0x40, 0x0f, 0x08, 0x00, 0x00, 0x2f, 0x27, 0x1f, 0x07, 0x27, 0x1f, 0x1f, ++ 0x47, 0x11, 0x10, 0x08, 0x40, 0x0f, 0x08, 0x00, 0x26, 0x08, 0x36, 0x26, 0x26, 0x08, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x3e, 0x27, 0x07, 0x40, 0x40, 0x47, 0x57, 0x67, 0x2f, 0x40, 0x07, 0x40, 0x40, 0x47, 0x0f, ++ 0x07, 0x27, 0x40, 0x17, 0x17, 0x27, 0x37, 0x3e, 0x3e, 0x07, 0x07, 0x00, 0x00, 0x08, 0x1f, 0x07, ++ 0x07, 0x27, 0x2f, 0x08, 0x40, 0x47, 0x4f, 0x40, 0x40, 0x40, 0x07, 0x07, 0x07, 0x0f, 0x0f, 0x0f, ++ 0x17, 0x1f, 0x07, 0x07, 0x07, 0x27, 0x07, 0x40, 0x07, 0x07, 0x27, 0x1f, 0x17, 0x27, 0x07, 0x0f, ++ 0x0f, 0x0f, 0x17, 0x1f, 0x07, 0x07, 0x07, 0x27, 0x07, 0x40, 0x07, 0x07, 0x27, 0x1f, 0x17, 0x27, ++ 0x27, 0x40, 0x3e, 0x40, 0x4f, 0x40, 0x07, 0x07, 0x07, 0x17, 0x17, 0x37, 0x0f, 0x10, 0x47, 0x40, ++ 0x1f, 0x07, 0x40, 0x10, 0x47, 0x40, 0x1f, 0x07, 0x40, 0x10, 0x47, 0x40, 0x1f, 0x07, 0x40, 0x4f, ++ 0x07, 0x0f, 0x0f, 0x1f, 0x27, 0x1f, 0x27, 0x08, 0x17, 0x47, 0x40, 0x17, 0x47, 0x40, 0x40, 0x40, ++ 0x40, 0x00, 0x08, 0x08, 0x40, 0x0f, 0x08, 0x00, 0x00, 0x2f, 0x27, 0x1f, 0x07, 0x27, 0x1f, 0x1f, ++ 0x47, 0x10, 0x10, 0x08, 0x40, 0x0f, 0x08, 0x00, 0x27, 0x08, 0x37, 0x27, 0x27, 0x08, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++}; ++ ++static void set_ps_field(u32 *buf, struct rkvdec_ps_field field, u32 value) ++{ ++ u8 bit = field.offset % 32, word = field.offset / 32; ++ u64 mask = GENMASK_ULL(bit + field.len - 1, bit); ++ u64 val = ((u64)value << bit) & mask; ++ ++ buf[word] &= ~mask; ++ buf[word] |= val; ++ if (bit + field.len > 32) { ++ buf[word + 1] &= ~(mask >> 32); ++ buf[word + 1] |= val >> 32; ++ } ++} ++ ++static void assemble_hw_pps(struct rkvdec_ctx *ctx, ++ struct rkvdec_hevc_run *run) ++{ ++ struct rkvdec_hevc_ctx *hevc_ctx = ctx->priv; ++ const struct v4l2_ctrl_hevc_sps *sps = run->sps; ++ const struct v4l2_ctrl_hevc_pps *pps = run->pps; ++ struct rkvdec_hevc_priv_tbl *priv_tbl = hevc_ctx->priv_tbl.cpu; ++ struct rkvdec_sps_pps_packet *hw_ps; ++ u32 min_cb_log2_size_y, ctb_log2_size_y, ctb_size_y; ++ u32 log2_min_cu_qp_delta_size; ++ dma_addr_t scaling_list_address; ++ u32 scaling_distance; ++ int i; ++ ++ /* ++ * HW read the SPS/PPS information from PPS packet index by PPS id. ++ * offset from the base can be calculated by PPS_id * 80 (size per PPS ++ * packet unit). so the driver copy SPS/PPS information to the exact PPS ++ * packet unit for HW accessing. ++ */ ++ hw_ps = &priv_tbl->param_set[pps->pic_parameter_set_id]; ++ memset(hw_ps, 0, sizeof(*hw_ps)); ++ ++ min_cb_log2_size_y = sps->log2_min_luma_coding_block_size_minus3 + 3; ++ ctb_log2_size_y = min_cb_log2_size_y + ++ sps->log2_diff_max_min_luma_coding_block_size; ++ ctb_size_y = 1 << ctb_log2_size_y; ++ ++#define WRITE_PPS(value, field) set_ps_field(hw_ps->info, field, value) ++ /* write sps */ ++ WRITE_PPS(sps->video_parameter_set_id, VIDEO_PARAMETER_SET_ID); ++ WRITE_PPS(sps->seq_parameter_set_id, SEQ_PARAMETER_SET_ID); ++ WRITE_PPS(1, CHROMA_FORMAT_IDC); ++ WRITE_PPS(sps->pic_width_in_luma_samples, PIC_WIDTH_IN_LUMA_SAMPLES); ++ WRITE_PPS(sps->pic_height_in_luma_samples, PIC_HEIGHT_IN_LUMA_SAMPLES); ++ WRITE_PPS(sps->bit_depth_luma_minus8 + 8, BIT_DEPTH_LUMA); ++ WRITE_PPS(sps->bit_depth_chroma_minus8 + 8, BIT_DEPTH_CHROMA); ++ WRITE_PPS(sps->log2_max_pic_order_cnt_lsb_minus4 + 4, ++ LOG2_MAX_PIC_ORDER_CNT_LSB); ++ WRITE_PPS(sps->log2_diff_max_min_luma_coding_block_size, ++ LOG2_DIFF_MAX_MIN_LUMA_CODING_BLOCK_SIZE); ++ WRITE_PPS(sps->log2_min_luma_coding_block_size_minus3 + 3, ++ LOG2_MIN_LUMA_CODING_BLOCK_SIZE); ++ WRITE_PPS(sps->log2_min_luma_transform_block_size_minus2 + 2, ++ LOG2_MIN_TRANSFORM_BLOCK_SIZE); ++ WRITE_PPS(sps->log2_diff_max_min_luma_transform_block_size, ++ LOG2_DIFF_MAX_MIN_LUMA_TRANSFORM_BLOCK_SIZE); ++ WRITE_PPS(sps->max_transform_hierarchy_depth_inter, ++ MAX_TRANSFORM_HIERARCHY_DEPTH_INTER); ++ WRITE_PPS(sps->max_transform_hierarchy_depth_intra, ++ MAX_TRANSFORM_HIERARCHY_DEPTH_INTRA); ++ WRITE_PPS(!!(sps->flags & V4L2_HEVC_SPS_FLAG_SCALING_LIST_ENABLED), ++ SCALING_LIST_ENABLED_FLAG); ++ WRITE_PPS(!!(sps->flags & V4L2_HEVC_SPS_FLAG_AMP_ENABLED), ++ AMP_ENABLED_FLAG); ++ WRITE_PPS(!!(sps->flags & V4L2_HEVC_SPS_FLAG_SAMPLE_ADAPTIVE_OFFSET), ++ SAMPLE_ADAPTIVE_OFFSET_ENABLED_FLAG); ++ if (sps->flags & V4L2_HEVC_SPS_FLAG_PCM_ENABLED) { ++ WRITE_PPS(1, PCM_ENABLED_FLAG); ++ WRITE_PPS(sps->pcm_sample_bit_depth_luma_minus1 + 1, ++ PCM_SAMPLE_BIT_DEPTH_LUMA); ++ WRITE_PPS(sps->pcm_sample_bit_depth_chroma_minus1 + 1, ++ PCM_SAMPLE_BIT_DEPTH_CHROMA); ++ WRITE_PPS(!!(sps->flags & V4L2_HEVC_SPS_FLAG_PCM_LOOP_FILTER_DISABLED), ++ PCM_LOOP_FILTER_DISABLED_FLAG); ++ WRITE_PPS(sps->log2_diff_max_min_pcm_luma_coding_block_size, ++ LOG2_DIFF_MAX_MIN_PCM_LUMA_CODING_BLOCK_SIZE); ++ WRITE_PPS(sps->log2_min_pcm_luma_coding_block_size_minus3 + 3, ++ LOG2_MIN_PCM_LUMA_CODING_BLOCK_SIZE); ++ } ++ WRITE_PPS(sps->num_short_term_ref_pic_sets, NUM_SHORT_TERM_REF_PIC_SETS); ++ WRITE_PPS(!!(sps->flags & V4L2_HEVC_SPS_FLAG_LONG_TERM_REF_PICS_PRESENT), ++ LONG_TERM_REF_PICS_PRESENT_FLAG); ++ WRITE_PPS(sps->num_long_term_ref_pics_sps, NUM_LONG_TERM_REF_PICS_SPS); ++ WRITE_PPS(!!(sps->flags & V4L2_HEVC_SPS_FLAG_SPS_TEMPORAL_MVP_ENABLED), ++ SPS_TEMPORAL_MVP_ENABLED_FLAG); ++ WRITE_PPS(!!(sps->flags & V4L2_HEVC_SPS_FLAG_STRONG_INTRA_SMOOTHING_ENABLED), ++ STRONG_INTRA_SMOOTHING_ENABLED_FLAG); ++ //WRITE_PPS(0, PS_FIELD(100, 7)); ++ //WRITE_PPS(0x1fffff, PS_FIELD(107, 21)); ++ ++ /* write pps */ ++ WRITE_PPS(pps->pic_parameter_set_id, PIC_PARAMETER_SET_ID); ++ WRITE_PPS(sps->seq_parameter_set_id, PPS_SEQ_PARAMETER_SET_ID); ++ WRITE_PPS(!!(pps->flags & V4L2_HEVC_PPS_FLAG_DEPENDENT_SLICE_SEGMENT), ++ DEPENDENT_SLICE_SEGMENTS_ENABLED_FLAG); ++ WRITE_PPS(!!(pps->flags & V4L2_HEVC_PPS_FLAG_OUTPUT_FLAG_PRESENT), ++ OUTPUT_FLAG_PRESENT_FLAG); ++ WRITE_PPS(pps->num_extra_slice_header_bits, NUM_EXTRA_SLICE_HEADER_BITS); ++ WRITE_PPS(!!(pps->flags & V4L2_HEVC_PPS_FLAG_SIGN_DATA_HIDING_ENABLED), ++ SIGN_DATA_HIDING_ENABLED_FLAG); ++ WRITE_PPS(!!(pps->flags & V4L2_HEVC_PPS_FLAG_CABAC_INIT_PRESENT), ++ CABAC_INIT_PRESENT_FLAG); ++ WRITE_PPS(pps->num_ref_idx_l0_default_active_minus1 + 1, ++ NUM_REF_IDX_L0_DEFAULT_ACTIVE); ++ WRITE_PPS(pps->num_ref_idx_l1_default_active_minus1 + 1, ++ NUM_REF_IDX_L1_DEFAULT_ACTIVE); ++ WRITE_PPS(pps->init_qp_minus26, INIT_QP_MINUS26); ++ WRITE_PPS(!!(pps->flags & V4L2_HEVC_PPS_FLAG_CONSTRAINED_INTRA_PRED), ++ CONSTRAINED_INTRA_PRED_FLAG); ++ WRITE_PPS(!!(pps->flags & V4L2_HEVC_PPS_FLAG_TRANSFORM_SKIP_ENABLED), ++ TRANSFORM_SKIP_ENABLED_FLAG); ++ WRITE_PPS(!!(pps->flags & V4L2_HEVC_PPS_FLAG_CU_QP_DELTA_ENABLED), ++ CU_QP_DELTA_ENABLED_FLAG); ++ ++ log2_min_cu_qp_delta_size = ctb_log2_size_y - pps->diff_cu_qp_delta_depth; ++ WRITE_PPS(log2_min_cu_qp_delta_size, LOG2_MIN_CU_QP_DELTA_SIZE); ++ ++ WRITE_PPS(pps->pps_cb_qp_offset, PPS_CB_QP_OFFSET); ++ WRITE_PPS(pps->pps_cr_qp_offset, PPS_CR_QP_OFFSET); ++ WRITE_PPS(!!(pps->flags & V4L2_HEVC_PPS_FLAG_PPS_SLICE_CHROMA_QP_OFFSETS_PRESENT), ++ PPS_SLICE_CHROMA_QP_OFFSETS_PRESENT_FLAG); ++ WRITE_PPS(!!(pps->flags & V4L2_HEVC_PPS_FLAG_WEIGHTED_PRED), ++ WEIGHTED_PRED_FLAG); ++ WRITE_PPS(!!(pps->flags & V4L2_HEVC_PPS_FLAG_WEIGHTED_BIPRED), ++ WEIGHTED_BIPRED_FLAG); ++ WRITE_PPS(!!(pps->flags & V4L2_HEVC_PPS_FLAG_TRANSQUANT_BYPASS_ENABLED), ++ TRANSQUANT_BYPASS_ENABLED_FLAG); ++ WRITE_PPS(!!(pps->flags & V4L2_HEVC_PPS_FLAG_TILES_ENABLED), ++ TILES_ENABLED_FLAG); ++ WRITE_PPS(!!(pps->flags & V4L2_HEVC_PPS_FLAG_ENTROPY_CODING_SYNC_ENABLED), ++ ENTROPY_CODING_SYNC_ENABLED_FLAG); ++ WRITE_PPS(!!(pps->flags & V4L2_HEVC_PPS_FLAG_PPS_LOOP_FILTER_ACROSS_SLICES_ENABLED), ++ PPS_LOOP_FILTER_ACROSS_SLICES_ENABLED_FLAG); ++ WRITE_PPS(!!(pps->flags & V4L2_HEVC_PPS_FLAG_LOOP_FILTER_ACROSS_TILES_ENABLED), ++ LOOP_FILTER_ACROSS_TILES_ENABLED_FLAG); ++ WRITE_PPS(!!(pps->flags & V4L2_HEVC_PPS_FLAG_DEBLOCKING_FILTER_OVERRIDE_ENABLED), ++ DEBLOCKING_FILTER_OVERRIDE_ENABLED_FLAG); ++ WRITE_PPS(!!(pps->flags & V4L2_HEVC_PPS_FLAG_PPS_DISABLE_DEBLOCKING_FILTER), ++ PPS_DEBLOCKING_FILTER_DISABLED_FLAG); ++ WRITE_PPS(pps->pps_beta_offset_div2, PPS_BETA_OFFSET_DIV2); ++ WRITE_PPS(pps->pps_tc_offset_div2, PPS_TC_OFFSET_DIV2); ++ WRITE_PPS(!!(pps->flags & V4L2_HEVC_PPS_FLAG_LISTS_MODIFICATION_PRESENT), ++ LISTS_MODIFICATION_PRESENT_FLAG); ++ WRITE_PPS(pps->log2_parallel_merge_level_minus2 + 2, LOG2_PARALLEL_MERGE_LEVEL); ++ WRITE_PPS(!!(pps->flags & V4L2_HEVC_PPS_FLAG_SLICE_SEGMENT_HEADER_EXTENSION_PRESENT), ++ SLICE_SEGMENT_HEADER_EXTENSION_PRESENT_FLAG); ++ //WRITE_PPS(0, PS_FIELD(209, 3)); ++ WRITE_PPS(pps->num_tile_columns_minus1 + 1, NUM_TILE_COLUMNS); ++ WRITE_PPS(pps->num_tile_rows_minus1 + 1, NUM_TILE_ROWS); ++ //WRITE_PPS(0x2, PS_FIELD(222, 2)); ++ //WRITE_PPS(0xffffffff, PS_FIELD(224, 32)); ++ ++ if (pps->flags & V4L2_HEVC_PPS_FLAG_TILES_ENABLED) { ++ for (i = 0; i <= pps->num_tile_columns_minus1; i++) ++ WRITE_PPS(pps->column_width_minus1[i], COLUMN_WIDTH(i)); ++ for (i = 0; i <= pps->num_tile_rows_minus1; i++) ++ WRITE_PPS(pps->row_height_minus1[i], ROW_HEIGHT(i)); ++ } else { ++ WRITE_PPS(round_up(sps->pic_width_in_luma_samples, ctb_size_y) - 1, ++ COLUMN_WIDTH(0)); ++ WRITE_PPS(round_up(sps->pic_height_in_luma_samples, ctb_size_y) - 1, ++ ROW_HEIGHT(0)); ++ } ++ ++ scaling_distance = offsetof(struct rkvdec_hevc_priv_tbl, scaling_list); ++ scaling_list_address = hevc_ctx->priv_tbl.dma + scaling_distance; ++ WRITE_PPS(scaling_list_address, SCALING_LIST_ADDRESS); ++ //WRITE_PPS(0xffff, PS_FIELD(624, 16)); ++} ++ ++static void assemble_hw_rps(struct rkvdec_ctx *ctx, ++ struct rkvdec_hevc_run *run) ++{ ++ const struct v4l2_ctrl_hevc_slice_params *sl_params; ++ const struct v4l2_hevc_dpb_entry *dpb; ++ struct rkvdec_hevc_ctx *hevc_ctx = ctx->priv; ++ struct rkvdec_hevc_priv_tbl *priv_tbl = hevc_ctx->priv_tbl.cpu; ++ struct rkvdec_rps_packet *hw_ps; ++ int i, j; ++ ++#define WRITE_RPS(value, field) set_ps_field(hw_ps->info, field, value) ++ ++#define REF_PIC_LONG_TERM_L0(i) PS_FIELD(i * 5, 1) ++#define REF_PIC_IDX_L0(i) PS_FIELD(1 + (i * 5), 4) ++#define REF_PIC_LONG_TERM_L1(i) PS_FIELD((i < 5 ? 75 : 132) + (i * 5), 1) ++#define REF_PIC_IDX_L1(i) PS_FIELD((i < 4 ? 76 : 128) + (i * 5), 4) ++ ++#define LOWDELAY PS_FIELD(182, 1) ++#define SHORT_TERM_REF_PIC_SET_SIZE PS_FIELD(183, 10) ++#define LONG_TERM_REF_PIC_SET_SIZE PS_FIELD(193, 9) ++#define NUM_RPS_POC PS_FIELD(202, 4) ++ ++ for (j = 0; j < run->num_slices; j++) { ++ sl_params = &run->slices_params[j]; ++ dpb = sl_params->dpb; ++ ++ hw_ps = &priv_tbl->rps[j]; ++ memset(hw_ps, 0, sizeof(*hw_ps)); ++ ++ for (i = 0; i <= sl_params->num_ref_idx_l0_active_minus1; i++) { ++ WRITE_RPS(!!(dpb[sl_params->ref_idx_l0[i]].rps == V4L2_HEVC_DPB_ENTRY_RPS_LT_CURR), ++ REF_PIC_LONG_TERM_L0(i)); ++ WRITE_RPS(sl_params->ref_idx_l0[i], REF_PIC_IDX_L0(i)); ++ } ++ ++ for (i = 0; i <= sl_params->num_ref_idx_l1_active_minus1; i++) { ++ WRITE_RPS(!!(dpb[sl_params->ref_idx_l1[i]].rps == V4L2_HEVC_DPB_ENTRY_RPS_LT_CURR), ++ REF_PIC_LONG_TERM_L1(i)); ++ WRITE_RPS(sl_params->ref_idx_l1[i], REF_PIC_IDX_L1(i)); ++ } ++ ++ //WRITE_RPS(0xffffffff, PS_FIELD(96, 32)); ++ ++ // TODO: lowdelay ++ WRITE_RPS(0, LOWDELAY); ++ ++ // NOTE: these two differs from mpp ++ WRITE_RPS(sl_params->short_term_ref_pic_set_size, ++ SHORT_TERM_REF_PIC_SET_SIZE); ++ WRITE_RPS(sl_params->long_term_ref_pic_set_size, ++ LONG_TERM_REF_PIC_SET_SIZE); ++ ++ WRITE_RPS(sl_params->num_rps_poc_st_curr_before + ++ sl_params->num_rps_poc_st_curr_after + ++ sl_params->num_rps_poc_lt_curr, ++ NUM_RPS_POC); ++ ++ //WRITE_RPS(0x3ffff, PS_FIELD(206, 18)); ++ //WRITE_RPS(0xffffffff, PS_FIELD(224, 32)); ++ } ++} ++ ++static void assemble_hw_scaling_list(struct rkvdec_ctx *ctx, ++ struct rkvdec_hevc_run *run) ++{ ++ const struct v4l2_ctrl_hevc_scaling_matrix *scaling = run->scaling_matrix; ++ struct rkvdec_hevc_ctx *hevc_ctx = ctx->priv; ++ struct rkvdec_hevc_priv_tbl *tbl = hevc_ctx->priv_tbl.cpu; ++ u8 *dst; ++ scalingList_t sl; ++ int i, j; ++ ++ if (!memcmp((void*)&hevc_ctx->scaling_matrix_cache, scaling, ++ sizeof(struct v4l2_ctrl_hevc_scaling_matrix))) ++ return; ++ ++ memset(&sl, 0, sizeof(scalingList_t)); ++ ++ for (i = 0; i < 6; i++) { ++ for (j = 0; j < 16; j++) ++ sl.sl[0][i][j] = scaling->scaling_list_4x4[i][j]; ++ for (j = 0; j < 64; j++) { ++ sl.sl[1][i][j] = scaling->scaling_list_8x8[i][j]; ++ sl.sl[2][i][j] = scaling->scaling_list_16x16[i][j]; ++ if (i < 2) ++ sl.sl[3][i][j] = scaling->scaling_list_32x32[i][j]; ++ } ++ sl.sl_dc[0][i] = scaling->scaling_list_dc_coef_16x16[i]; ++ if (i < 2) ++ sl.sl_dc[1][i] = scaling->scaling_list_dc_coef_32x32[i]; ++ } ++ ++ dst = tbl->scaling_list; ++ hal_record_scaling_list((scalingFactor_t *)dst, &sl); ++ ++ memcpy((void*)&hevc_ctx->scaling_matrix_cache, scaling, ++ sizeof(struct v4l2_ctrl_hevc_scaling_matrix)); ++} ++ ++static struct vb2_buffer * ++get_ref_buf(struct rkvdec_ctx *ctx, struct rkvdec_hevc_run *run, ++ unsigned int dpb_idx) ++{ ++ struct v4l2_m2m_ctx *m2m_ctx = ctx->fh.m2m_ctx; ++ const struct v4l2_ctrl_hevc_slice_params *sl_params = &run->slices_params[0]; ++ const struct v4l2_hevc_dpb_entry *dpb = sl_params->dpb; ++ struct vb2_queue *cap_q = &m2m_ctx->cap_q_ctx.q; ++ int buf_idx = -1; ++ ++ if (dpb_idx < sl_params->num_active_dpb_entries) ++ buf_idx = vb2_find_timestamp(cap_q, ++ dpb[dpb_idx].timestamp, 0); ++ ++ /* ++ * If a DPB entry is unused or invalid, address of current destination ++ * buffer is returned. ++ */ ++ if (buf_idx < 0) ++ return &run->base.bufs.dst->vb2_buf; ++ ++ return vb2_get_buffer(cap_q, buf_idx); ++} ++ ++static void config_registers(struct rkvdec_ctx *ctx, ++ struct rkvdec_hevc_run *run) ++{ ++ struct rkvdec_dev *rkvdec = ctx->dev; ++ const struct v4l2_ctrl_hevc_slice_params *sl_params = &run->slices_params[0]; ++ const struct v4l2_hevc_dpb_entry *dpb = sl_params->dpb; ++ struct rkvdec_hevc_ctx *hevc_ctx = ctx->priv; ++ dma_addr_t priv_start_addr = hevc_ctx->priv_tbl.dma; ++ const struct v4l2_pix_format_mplane *dst_fmt; ++ struct vb2_v4l2_buffer *src_buf = run->base.bufs.src; ++ struct vb2_v4l2_buffer *dst_buf = run->base.bufs.dst; ++ const struct v4l2_format *f; ++ dma_addr_t rlc_addr; ++ dma_addr_t refer_addr; ++ u32 rlc_len; ++ u32 hor_virstride; ++ u32 ver_virstride; ++ u32 y_virstride; ++ u32 uv_virstride; ++ u32 yuv_virstride; ++ u32 offset; ++ dma_addr_t dst_addr; ++ u32 reg, i; ++ ++ reg = RKVDEC_MODE(RKVDEC_MODE_HEVC); ++ writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_SYSCTRL); ++ ++ f = &ctx->decoded_fmt; ++ dst_fmt = &f->fmt.pix_mp; ++ hor_virstride = dst_fmt->plane_fmt[0].bytesperline; ++ ver_virstride = dst_fmt->height; ++ y_virstride = hor_virstride * ver_virstride; ++ uv_virstride = y_virstride / 2; ++ yuv_virstride = y_virstride + uv_virstride; ++ ++ reg = RKVDEC_Y_HOR_VIRSTRIDE(hor_virstride / 16) | ++ RKVDEC_UV_HOR_VIRSTRIDE(hor_virstride / 16) | ++ RKVDEC_SLICE_NUM_LOWBITS(run->num_slices); ++ writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_PICPAR); ++ ++ /* config rlc base address */ ++ rlc_addr = vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, 0); ++ writel_relaxed(rlc_addr, rkvdec->regs + RKVDEC_REG_STRM_RLC_BASE); ++ ++ rlc_len = vb2_get_plane_payload(&src_buf->vb2_buf, 0); ++ reg = RKVDEC_STRM_LEN(round_up(rlc_len, 16) + 64); ++ writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_STRM_LEN); ++ ++ /* config cabac table */ ++ offset = offsetof(struct rkvdec_hevc_priv_tbl, cabac_table); ++ writel_relaxed(priv_start_addr + offset, ++ rkvdec->regs + RKVDEC_REG_CABACTBL_PROB_BASE); ++ ++ /* config output base address */ ++ dst_addr = vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 0); ++ writel_relaxed(dst_addr, rkvdec->regs + RKVDEC_REG_DECOUT_BASE); ++ ++ reg = RKVDEC_Y_VIRSTRIDE(y_virstride / 16); ++ writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_Y_VIRSTRIDE); ++ ++ reg = RKVDEC_YUV_VIRSTRIDE(yuv_virstride / 16); ++ writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_YUV_VIRSTRIDE); ++ ++ /* config ref pic address */ ++ for (i = 0; i < 15; i++) { ++ struct vb2_buffer *vb_buf = get_ref_buf(ctx, run, i); ++ ++ if (i < 4 && sl_params->num_active_dpb_entries) { ++ reg = GENMASK(sl_params->num_active_dpb_entries - 1, 0); ++ reg = (reg >> (i * 4)) & 0xf; ++ } else ++ reg = 0; ++ ++ refer_addr = vb2_dma_contig_plane_dma_addr(vb_buf, 0); ++ writel_relaxed(refer_addr | reg, ++ rkvdec->regs + RKVDEC_REG_H264_BASE_REFER(i)); ++ ++ reg = RKVDEC_POC_REFER(i < sl_params->num_active_dpb_entries ? dpb[i].pic_order_cnt[0] : 0); ++ writel_relaxed(reg, ++ rkvdec->regs + RKVDEC_REG_H264_POC_REFER0(i)); ++ } ++ ++ reg = RKVDEC_CUR_POC(sl_params->slice_pic_order_cnt); ++ writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_CUR_POC0); ++ ++ /* config hw pps address */ ++ offset = offsetof(struct rkvdec_hevc_priv_tbl, param_set); ++ writel_relaxed(priv_start_addr + offset, ++ rkvdec->regs + RKVDEC_REG_PPS_BASE); ++ ++ /* config hw rps address */ ++ offset = offsetof(struct rkvdec_hevc_priv_tbl, rps); ++ writel_relaxed(priv_start_addr + offset, ++ rkvdec->regs + RKVDEC_REG_RPS_BASE); ++ ++ reg = RKVDEC_AXI_DDR_RDATA(0); ++ writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_AXI_DDR_RDATA); ++ ++ reg = RKVDEC_AXI_DDR_WDATA(0); ++ writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_AXI_DDR_WDATA); ++} ++ ++#define RKVDEC_HEVC_MAX_DEPTH_IN_BYTES 2 ++ ++static int rkvdec_hevc_adjust_fmt(struct rkvdec_ctx *ctx, ++ struct v4l2_format *f) ++{ ++ struct v4l2_pix_format_mplane *fmt = &f->fmt.pix_mp; ++ ++ fmt->num_planes = 1; ++ if (!fmt->plane_fmt[0].sizeimage) ++ fmt->plane_fmt[0].sizeimage = fmt->width * fmt->height * ++ RKVDEC_HEVC_MAX_DEPTH_IN_BYTES; ++ return 0; ++} ++ ++static int rkvdec_hevc_start(struct rkvdec_ctx *ctx) ++{ ++ struct rkvdec_dev *rkvdec = ctx->dev; ++ struct rkvdec_hevc_priv_tbl *priv_tbl; ++ struct rkvdec_hevc_ctx *hevc_ctx; ++ int ret; ++ ++ hevc_ctx = kzalloc(sizeof(*hevc_ctx), GFP_KERNEL); ++ if (!hevc_ctx) ++ return -ENOMEM; ++ ++ priv_tbl = dma_alloc_coherent(rkvdec->dev, sizeof(*priv_tbl), ++ &hevc_ctx->priv_tbl.dma, GFP_KERNEL); ++ if (!priv_tbl) { ++ ret = -ENOMEM; ++ goto err_free_ctx; ++ } ++ ++ hevc_ctx->priv_tbl.size = sizeof(*priv_tbl); ++ hevc_ctx->priv_tbl.cpu = priv_tbl; ++ memset(priv_tbl, 0, sizeof(*priv_tbl)); ++ memcpy(priv_tbl->cabac_table, rkvdec_hevc_cabac_table, ++ sizeof(rkvdec_hevc_cabac_table)); ++ ++ ctx->priv = hevc_ctx; ++ return 0; ++ ++err_free_ctx: ++ kfree(hevc_ctx); ++ return ret; ++} ++ ++static void rkvdec_hevc_stop(struct rkvdec_ctx *ctx) ++{ ++ struct rkvdec_hevc_ctx *hevc_ctx = ctx->priv; ++ struct rkvdec_dev *rkvdec = ctx->dev; ++ ++ dma_free_coherent(rkvdec->dev, hevc_ctx->priv_tbl.size, ++ hevc_ctx->priv_tbl.cpu, hevc_ctx->priv_tbl.dma); ++ kfree(hevc_ctx); ++} ++ ++static void rkvdec_hevc_run_preamble(struct rkvdec_ctx *ctx, ++ struct rkvdec_hevc_run *run) ++{ ++ struct v4l2_ctrl *ctrl; ++ ++ ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl, ++ V4L2_CID_MPEG_VIDEO_HEVC_SLICE_PARAMS); ++ run->slices_params = ctrl ? ctrl->p_cur.p : NULL; ++ ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl, ++ V4L2_CID_MPEG_VIDEO_HEVC_SPS); ++ run->sps = ctrl ? ctrl->p_cur.p : NULL; ++ ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl, ++ V4L2_CID_MPEG_VIDEO_HEVC_PPS); ++ run->pps = ctrl ? ctrl->p_cur.p : NULL; ++ ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl, ++ V4L2_CID_MPEG_VIDEO_HEVC_SCALING_MATRIX); ++ run->scaling_matrix = ctrl ? ctrl->p_cur.p : NULL; ++ ++ rkvdec_run_preamble(ctx, &run->base); ++ ++ // HACK: we need num slices from somewhere ++ run->num_slices = run->sps->num_slices; ++} ++ ++static int rkvdec_hevc_run(struct rkvdec_ctx *ctx) ++{ ++ struct rkvdec_dev *rkvdec = ctx->dev; ++ struct rkvdec_hevc_run run; ++ ++ rkvdec_hevc_run_preamble(ctx, &run); ++ ++ assemble_hw_scaling_list(ctx, &run); ++ assemble_hw_pps(ctx, &run); ++ assemble_hw_rps(ctx, &run); ++ config_registers(ctx, &run); ++ ++ rkvdec_run_postamble(ctx, &run.base); ++ ++ // sw_cabac_error_e - cabac error enable ++ writel_relaxed(0xfdfffffd, rkvdec->regs + RKVDEC_REG_STRMD_ERR_EN); ++ // slice end error enable = BIT(28) ++ // frame end error enable = BIT(29) ++ writel_relaxed(0x30000000, rkvdec->regs + RKVDEC_REG_H264_ERR_E); ++ ++ schedule_delayed_work(&rkvdec->watchdog_work, msecs_to_jiffies(2000)); ++ ++ writel(1, rkvdec->regs + RKVDEC_REG_PREF_LUMA_CACHE_COMMAND); ++ writel(1, rkvdec->regs + RKVDEC_REG_PREF_CHR_CACHE_COMMAND); ++ ++ /* Start decoding! */ ++ writel(RKVDEC_INTERRUPT_DEC_E | RKVDEC_CONFIG_DEC_CLK_GATE_E | ++ RKVDEC_TIMEOUT_E | RKVDEC_BUF_EMPTY_E, ++ rkvdec->regs + RKVDEC_REG_INTERRUPT); ++ ++ return 0; ++} ++ ++const struct rkvdec_coded_fmt_ops rkvdec_hevc_fmt_ops = { ++ .adjust_fmt = rkvdec_hevc_adjust_fmt, ++ .start = rkvdec_hevc_start, ++ .stop = rkvdec_hevc_stop, ++ .run = rkvdec_hevc_run, ++}; +diff --git a/drivers/staging/media/rkvdec/rkvdec-regs.h b/drivers/staging/media/rkvdec/rkvdec-regs.h +index 15b9bee92016..83bf790ed9b7 100644 +--- a/drivers/staging/media/rkvdec/rkvdec-regs.h ++++ b/drivers/staging/media/rkvdec/rkvdec-regs.h +@@ -43,6 +43,7 @@ + #define RKVDEC_RLC_MODE BIT(11) + #define RKVDEC_STRM_START_BIT(x) (((x) & 0x7f) << 12) + #define RKVDEC_MODE(x) (((x) & 0x03) << 20) ++#define RKVDEC_MODE_HEVC 0 + #define RKVDEC_MODE_H264 1 + #define RKVDEC_MODE_VP9 2 + #define RKVDEC_RPS_MODE BIT(24) +diff --git a/drivers/staging/media/rkvdec/rkvdec.c b/drivers/staging/media/rkvdec/rkvdec.c +index 658fb6028e72..2141633c7437 100644 +--- a/drivers/staging/media/rkvdec/rkvdec.c ++++ b/drivers/staging/media/rkvdec/rkvdec.c +@@ -159,6 +159,61 @@ static const u32 rkvdec_h264_decoded_fmts[] = { + V4L2_PIX_FMT_NV20, + }; + ++static const struct rkvdec_ctrl_desc rkvdec_hevc_ctrl_descs[] = { ++ { ++ .mandatory = true, ++ .cfg.id = V4L2_CID_MPEG_VIDEO_HEVC_SLICE_PARAMS, ++ // HACK: match ffmpeg v4l2 request api hwaccel size, ++ // we should support variable length up to 600 slices ++ .cfg.dims = { 16 }, ++ }, ++ { ++ .mandatory = true, ++ .cfg.id = V4L2_CID_MPEG_VIDEO_HEVC_SPS, ++ }, ++ { ++ .mandatory = true, ++ .cfg.id = V4L2_CID_MPEG_VIDEO_HEVC_PPS, ++ }, ++ { ++ .mandatory = true, ++ .cfg.id = V4L2_CID_MPEG_VIDEO_HEVC_SCALING_MATRIX, ++ }, ++ { ++ .cfg.id = V4L2_CID_MPEG_VIDEO_HEVC_DECODE_MODE, ++ .cfg.min = V4L2_MPEG_VIDEO_HEVC_DECODE_MODE_FRAME_BASED, ++ .cfg.max = V4L2_MPEG_VIDEO_HEVC_DECODE_MODE_FRAME_BASED, ++ .cfg.def = V4L2_MPEG_VIDEO_HEVC_DECODE_MODE_FRAME_BASED, ++ }, ++ { ++ .cfg.id = V4L2_CID_MPEG_VIDEO_HEVC_START_CODE, ++ .cfg.min = V4L2_MPEG_VIDEO_HEVC_START_CODE_ANNEX_B, ++ .cfg.def = V4L2_MPEG_VIDEO_HEVC_START_CODE_ANNEX_B, ++ .cfg.max = V4L2_MPEG_VIDEO_HEVC_START_CODE_ANNEX_B, ++ }, ++ { ++ .cfg.id = V4L2_CID_MPEG_VIDEO_HEVC_PROFILE, ++ .cfg.min = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN, ++ .cfg.max = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10, ++ .cfg.def = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN, ++ }, ++ { ++ .cfg.id = V4L2_CID_MPEG_VIDEO_HEVC_LEVEL, ++ .cfg.min = V4L2_MPEG_VIDEO_HEVC_LEVEL_1, ++ .cfg.max = V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1, ++ }, ++}; ++ ++static const struct rkvdec_ctrls rkvdec_hevc_ctrls = { ++ .ctrls = rkvdec_hevc_ctrl_descs, ++ .num_ctrls = ARRAY_SIZE(rkvdec_hevc_ctrl_descs), ++}; ++ ++static const u32 rkvdec_hevc_decoded_fmts[] = { ++ V4L2_PIX_FMT_NV12, ++ V4L2_PIX_FMT_NV15, ++}; ++ + static const struct rkvdec_ctrl_desc rkvdec_vp9_ctrl_descs[] = { + { + .mandatory = true, +@@ -209,6 +264,21 @@ static const struct rkvdec_coded_fmt_desc rkvdec_coded_fmts[] = { + .num_decoded_fmts = ARRAY_SIZE(rkvdec_h264_decoded_fmts), + .decoded_fmts = rkvdec_h264_decoded_fmts, + }, ++ { ++ .fourcc = V4L2_PIX_FMT_HEVC_SLICE, ++ .frmsize = { ++ .min_width = 64, ++ .max_width = 4096, ++ .step_width = 64, ++ .min_height = 64, ++ .max_height = 2304, ++ .step_height = 16, ++ }, ++ .ctrls = &rkvdec_hevc_ctrls, ++ .ops = &rkvdec_hevc_fmt_ops, ++ .num_decoded_fmts = ARRAY_SIZE(rkvdec_hevc_decoded_fmts), ++ .decoded_fmts = rkvdec_hevc_decoded_fmts, ++ }, + { + .fourcc = V4L2_PIX_FMT_VP9_FRAME, + .frmsize = { +diff --git a/drivers/staging/media/rkvdec/rkvdec.h b/drivers/staging/media/rkvdec/rkvdec.h +index 5f66f07acac5..d5600c6a4c17 100644 +--- a/drivers/staging/media/rkvdec/rkvdec.h ++++ b/drivers/staging/media/rkvdec/rkvdec.h +@@ -123,6 +123,7 @@ void rkvdec_run_preamble(struct rkvdec_ctx *ctx, struct rkvdec_run *run); + void rkvdec_run_postamble(struct rkvdec_ctx *ctx, struct rkvdec_run *run); + + extern const struct rkvdec_coded_fmt_ops rkvdec_h264_fmt_ops; ++extern const struct rkvdec_coded_fmt_ops rkvdec_hevc_fmt_ops; + extern const struct rkvdec_coded_fmt_ops rkvdec_vp9_fmt_ops; + + #endif /* RKVDEC_H_ */ + +From 42bf64d9be3b320b3ff6617a63b177f6dae206fb Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Sat, 1 Aug 2020 12:24:58 +0000 +Subject: [PATCH] WIP: media: rkvdec: add HEVC format validation + +--- + drivers/staging/media/rkvdec/rkvdec-hevc.c | 11 +++++++++++ + drivers/staging/media/rkvdec/rkvdec.c | 23 +++++++++++++++++++++- + 2 files changed, 33 insertions(+), 1 deletion(-) + +diff --git a/drivers/staging/media/rkvdec/rkvdec-hevc.c b/drivers/staging/media/rkvdec/rkvdec-hevc.c +index 03ba848411c6..b8ad7fc2271c 100644 +--- a/drivers/staging/media/rkvdec/rkvdec-hevc.c ++++ b/drivers/staging/media/rkvdec/rkvdec-hevc.c +@@ -2415,6 +2415,16 @@ static int rkvdec_hevc_adjust_fmt(struct rkvdec_ctx *ctx, + return 0; + } + ++static u32 rkvdec_hevc_valid_fmt(struct rkvdec_ctx *ctx, struct v4l2_ctrl *ctrl) ++{ ++ const struct v4l2_ctrl_hevc_sps *sps = ctrl->p_new.p_hevc_sps; ++ ++ if (sps->bit_depth_luma_minus8 == 2) ++ return V4L2_PIX_FMT_NV15; ++ else ++ return V4L2_PIX_FMT_NV12; ++} ++ + static int rkvdec_hevc_start(struct rkvdec_ctx *ctx) + { + struct rkvdec_dev *rkvdec = ctx->dev; +@@ -2516,6 +2526,7 @@ static int rkvdec_hevc_run(struct rkvdec_ctx *ctx) + + const struct rkvdec_coded_fmt_ops rkvdec_hevc_fmt_ops = { + .adjust_fmt = rkvdec_hevc_adjust_fmt, ++ .valid_fmt = rkvdec_hevc_valid_fmt, + .start = rkvdec_hevc_start, + .stop = rkvdec_hevc_stop, + .run = rkvdec_hevc_run, +diff --git a/drivers/staging/media/rkvdec/rkvdec.c b/drivers/staging/media/rkvdec/rkvdec.c +index 2141633c7437..869275a411c8 100644 +--- a/drivers/staging/media/rkvdec/rkvdec.c ++++ b/drivers/staging/media/rkvdec/rkvdec.c +@@ -76,6 +76,26 @@ static int rkvdec_try_ctrl(struct v4l2_ctrl *ctrl) + if (width > ctx->coded_fmt.fmt.pix_mp.width || + height > ctx->coded_fmt.fmt.pix_mp.height) + return -EINVAL; ++ } else if (ctrl->id == V4L2_CID_MPEG_VIDEO_HEVC_SPS) { ++ const struct v4l2_ctrl_hevc_sps *sps = ctrl->p_new.p_hevc_sps; ++ ++ if (sps->chroma_format_idc > 1) ++ /* Only 4:0:0 and 4:2:0 are supported */ ++ return -EINVAL; ++ if (sps->bit_depth_luma_minus8 != sps->bit_depth_chroma_minus8) ++ /* Luma and chroma bit depth mismatch */ ++ return -EINVAL; ++ if (sps->bit_depth_luma_minus8 != 0 && sps->bit_depth_luma_minus8 != 2) ++ /* Only 8-bit and 10-bit is supported */ ++ return -EINVAL; ++ ++ if (ctx->valid_fmt && ctx->valid_fmt != rkvdec_valid_fmt(ctx, ctrl)) ++ /* Only current valid format */ ++ return -EINVAL; ++ ++ if (sps->pic_width_in_luma_samples > ctx->coded_fmt.fmt.pix_mp.width || ++ sps->pic_height_in_luma_samples > ctx->coded_fmt.fmt.pix_mp.height) ++ return -EINVAL; + } + return 0; + } +@@ -84,7 +104,7 @@ static int rkvdec_s_ctrl(struct v4l2_ctrl *ctrl) + { + struct rkvdec_ctx *ctx = container_of(ctrl->handler, struct rkvdec_ctx, ctrl_hdl); + +- if (ctrl->id == V4L2_CID_MPEG_VIDEO_H264_SPS && !ctx->valid_fmt) { ++ if (!ctx->valid_fmt) { + ctx->valid_fmt = rkvdec_valid_fmt(ctx, ctrl); + if (ctx->valid_fmt) { + struct v4l2_pix_format_mplane *pix_mp; +@@ -170,6 +190,7 @@ static const struct rkvdec_ctrl_desc rkvdec_hevc_ctrl_descs[] = { + { + .mandatory = true, + .cfg.id = V4L2_CID_MPEG_VIDEO_HEVC_SPS, ++ .cfg.ops = &rkvdec_ctrl_ops, + }, + { + .mandatory = true, + +From d37481b9f7f915f93efaee842548a4b42b2da4ce Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Tue, 29 Oct 2019 01:26:02 +0000 +Subject: [PATCH] RFC: media: hantro: Fix H264 decoding of field encoded + content + +This still need code cleanup and formatting + +Signed-off-by: Jonas Karlman +--- + .../staging/media/hantro/hantro_g1_h264_dec.c | 17 +--- + drivers/staging/media/hantro/hantro_h264.c | 81 ++++++++++++++++--- + drivers/staging/media/hantro/hantro_hw.h | 2 + + 3 files changed, 74 insertions(+), 26 deletions(-) + +diff --git a/drivers/staging/media/hantro/hantro_g1_h264_dec.c b/drivers/staging/media/hantro/hantro_g1_h264_dec.c +index 845bef73d218..869ee261a5db 100644 +--- a/drivers/staging/media/hantro/hantro_g1_h264_dec.c ++++ b/drivers/staging/media/hantro/hantro_g1_h264_dec.c +@@ -130,25 +130,12 @@ static void set_ref(struct hantro_ctx *ctx) + struct v4l2_h264_dpb_entry *dpb = ctx->h264_dec.dpb; + const u8 *b0_reflist, *b1_reflist, *p_reflist; + struct hantro_dev *vpu = ctx->dev; +- u32 dpb_longterm = 0; +- u32 dpb_valid = 0; + int reg_num; + u32 reg; + int i; + +- /* +- * Set up bit maps of valid and long term DPBs. +- * NOTE: The bits are reversed, i.e. MSb is DPB 0. +- */ +- for (i = 0; i < HANTRO_H264_DPB_SIZE; ++i) { +- if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE) +- dpb_valid |= BIT(HANTRO_H264_DPB_SIZE - 1 - i); +- +- if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM) +- dpb_longterm |= BIT(HANTRO_H264_DPB_SIZE - 1 - i); +- } +- vdpu_write_relaxed(vpu, dpb_valid << 16, G1_REG_VALID_REF); +- vdpu_write_relaxed(vpu, dpb_longterm << 16, G1_REG_LT_REF); ++ vdpu_write_relaxed(vpu, ctx->h264_dec.dpb_valid, G1_REG_VALID_REF); ++ vdpu_write_relaxed(vpu, ctx->h264_dec.dpb_longterm, G1_REG_LT_REF); + + /* + * Set up reference frame picture numbers. +diff --git a/drivers/staging/media/hantro/hantro_h264.c b/drivers/staging/media/hantro/hantro_h264.c +index b1bdc00ac262..bc2af450a94c 100644 +--- a/drivers/staging/media/hantro/hantro_h264.c ++++ b/drivers/staging/media/hantro/hantro_h264.c +@@ -227,17 +227,67 @@ static void prepare_table(struct hantro_ctx *ctx) + { + const struct hantro_h264_dec_ctrls *ctrls = &ctx->h264_dec.ctrls; + const struct v4l2_ctrl_h264_decode_params *dec_param = ctrls->decode; ++ const struct v4l2_ctrl_h264_sps *sps = ctrls->sps; + struct hantro_h264_dec_priv_tbl *tbl = ctx->h264_dec.priv.cpu; + const struct v4l2_h264_dpb_entry *dpb = ctx->h264_dec.dpb; ++ u32 dpb_longterm = 0; ++ u32 dpb_valid = 0; + int i; + ++ /* ++ * Set up bit maps of valid and long term DPBs. ++ * NOTE: The bits are reversed, i.e. MSb is DPB 0. ++ */ ++ if ((dec_param->flags & V4L2_H264_DECODE_PARAM_FLAG_FIELD_PIC) || (sps->flags & V4L2_H264_SPS_FLAG_MB_ADAPTIVE_FRAME_FIELD)) { ++ for (i = 0; i < HANTRO_H264_DPB_SIZE * 2; ++i) { ++ // check for correct reference use ++ enum v4l2_h264_field_reference parity = (i & 0x1) ? ++ V4L2_H264_BOTTOM_FIELD_REF : V4L2_H264_TOP_FIELD_REF; ++ if (dpb[i / 2].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE && ++ dpb[i / 2].reference & parity) ++ dpb_valid |= BIT(HANTRO_H264_DPB_SIZE * 2 - 1 - i); ++ ++ if (dpb[i / 2].flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM) ++ dpb_longterm |= BIT(HANTRO_H264_DPB_SIZE * 2 - 1 - i); ++ } ++ ++ ctx->h264_dec.dpb_valid = dpb_valid; ++ ctx->h264_dec.dpb_longterm = dpb_longterm; ++ } else { ++ for (i = 0; i < HANTRO_H264_DPB_SIZE; ++i) { ++ if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE) ++ dpb_valid |= BIT(HANTRO_H264_DPB_SIZE - 1 - i); ++ ++ if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM) ++ dpb_longterm |= BIT(HANTRO_H264_DPB_SIZE - 1 - i); ++ } ++ ++ ctx->h264_dec.dpb_valid = dpb_valid << 16; ++ ctx->h264_dec.dpb_longterm = dpb_longterm << 16; ++ } ++ + for (i = 0; i < HANTRO_H264_DPB_SIZE; ++i) { +- tbl->poc[i * 2] = dpb[i].top_field_order_cnt; +- tbl->poc[i * 2 + 1] = dpb[i].bottom_field_order_cnt; ++ if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE) { ++ tbl->poc[i * 2] = dpb[i].top_field_order_cnt; ++ tbl->poc[i * 2 + 1] = dpb[i].bottom_field_order_cnt; ++ } else { ++ tbl->poc[i * 2] = 0; ++ tbl->poc[i * 2 + 1] = 0; ++ } + } + +- tbl->poc[32] = dec_param->top_field_order_cnt; +- tbl->poc[33] = dec_param->bottom_field_order_cnt; ++ if ((dec_param->flags & V4L2_H264_DECODE_PARAM_FLAG_FIELD_PIC) || !(sps->flags & V4L2_H264_SPS_FLAG_MB_ADAPTIVE_FRAME_FIELD)) { ++ if ((dec_param->flags & V4L2_H264_DECODE_PARAM_FLAG_FIELD_PIC)) ++ tbl->poc[32] = (dec_param->flags & V4L2_H264_DECODE_PARAM_FLAG_BOTTOM_FIELD) ? ++ dec_param->bottom_field_order_cnt : ++ dec_param->top_field_order_cnt; ++ else ++ tbl->poc[32] = min(dec_param->top_field_order_cnt, dec_param->bottom_field_order_cnt); ++ tbl->poc[33] = 0; ++ } else { ++ tbl->poc[32] = dec_param->top_field_order_cnt; ++ tbl->poc[33] = dec_param->bottom_field_order_cnt; ++ } + + assemble_scaling_list(ctx); + } +@@ -245,8 +295,7 @@ static void prepare_table(struct hantro_ctx *ctx) + static bool dpb_entry_match(const struct v4l2_h264_dpb_entry *a, + const struct v4l2_h264_dpb_entry *b) + { +- return a->top_field_order_cnt == b->top_field_order_cnt && +- a->bottom_field_order_cnt == b->bottom_field_order_cnt; ++ return a->reference_ts == b->reference_ts; + } + + static void update_dpb(struct hantro_ctx *ctx) +@@ -260,13 +309,13 @@ static void update_dpb(struct hantro_ctx *ctx) + + /* Disable all entries by default. */ + for (i = 0; i < ARRAY_SIZE(ctx->h264_dec.dpb); i++) +- ctx->h264_dec.dpb[i].flags &= ~V4L2_H264_DPB_ENTRY_FLAG_ACTIVE; ++ ctx->h264_dec.dpb[i].flags = 0; + + /* Try to match new DPB entries with existing ones by their POCs. */ + for (i = 0; i < ARRAY_SIZE(dec_param->dpb); i++) { + const struct v4l2_h264_dpb_entry *ndpb = &dec_param->dpb[i]; + +- if (!(ndpb->flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE)) ++ if (!(ndpb->flags & V4L2_H264_DPB_ENTRY_FLAG_VALID)) + continue; + + /* +@@ -277,8 +326,7 @@ static void update_dpb(struct hantro_ctx *ctx) + struct v4l2_h264_dpb_entry *cdpb; + + cdpb = &ctx->h264_dec.dpb[j]; +- if (cdpb->flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE || +- !dpb_entry_match(cdpb, ndpb)) ++ if (!dpb_entry_match(cdpb, ndpb)) + continue; + + *cdpb = *ndpb; +@@ -314,7 +362,10 @@ dma_addr_t hantro_h264_get_ref_buf(struct hantro_ctx *ctx, + unsigned int dpb_idx) + { + struct v4l2_h264_dpb_entry *dpb = ctx->h264_dec.dpb; ++ const struct v4l2_ctrl_h264_decode_params *dec_param = ctx->h264_dec.ctrls.decode; + dma_addr_t dma_addr = 0; ++ s32 cur_poc; ++ u32 flags; + + if (dpb[dpb_idx].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE) + dma_addr = hantro_get_ref(ctx, dpb[dpb_idx].reference_ts); +@@ -332,7 +383,15 @@ dma_addr_t hantro_h264_get_ref_buf(struct hantro_ctx *ctx, + dma_addr = hantro_get_dec_buf_addr(ctx, buf); + } + +- return dma_addr; ++ cur_poc = dec_param->flags & V4L2_H264_DECODE_PARAM_FLAG_BOTTOM_FIELD ? ++ dec_param->bottom_field_order_cnt : ++ dec_param->top_field_order_cnt; ++ flags = dpb[dpb_idx].flags & V4L2_H264_DPB_ENTRY_FLAG_FIELD ? 0x2 : 0; ++ flags |= abs(dpb[dpb_idx].top_field_order_cnt - cur_poc) < ++ abs(dpb[dpb_idx].bottom_field_order_cnt - cur_poc) ? ++ 0x1 : 0; ++ ++ return dma_addr | flags; + } + + int hantro_h264_dec_prepare_run(struct hantro_ctx *ctx) +diff --git a/drivers/staging/media/hantro/hantro_hw.h b/drivers/staging/media/hantro/hantro_hw.h +index 219283a06f52..7e35140a4f22 100644 +--- a/drivers/staging/media/hantro/hantro_hw.h ++++ b/drivers/staging/media/hantro/hantro_hw.h +@@ -90,6 +90,8 @@ struct hantro_h264_dec_hw_ctx { + struct v4l2_h264_dpb_entry dpb[HANTRO_H264_DPB_SIZE]; + struct hantro_h264_dec_reflists reflists; + struct hantro_h264_dec_ctrls ctrls; ++ u32 dpb_longterm; ++ u32 dpb_valid; + }; + + /** + +From badc3bfbfabd4fd01837498a4dd6bc84420bea79 Mon Sep 17 00:00:00 2001 +From: Randy Li +Date: Sun, 6 Jan 2019 01:48:37 +0800 +Subject: [PATCH] soc: rockchip: power-domain: export idle request + +We need to put the power status of HEVC IP into IDLE unless +we can't reset that IP or the SoC would crash down. +rockchip_pmu_idle_request(dev, true)---> enter idle +rockchip_pmu_idle_request(dev, false)---> exit idle + +Signed-off-by: Caesar Wang +Signed-off-by: Jeffy Chen +Signed-off-by: Randy Li +--- + drivers/soc/rockchip/pm_domains.c | 23 +++++++++++++++++++++++ + include/linux/rockchip_pmu.h | 15 +++++++++++++++ + include/soc/rockchip/pm_domains.h | 18 ++++++++++++++++++ + 3 files changed, 56 insertions(+) + create mode 100644 include/linux/rockchip_pmu.h + create mode 100644 include/soc/rockchip/pm_domains.h + +diff --git a/drivers/soc/rockchip/pm_domains.c b/drivers/soc/rockchip/pm_domains.c +index 54eb6cfc5d5b..727af107e6d3 100644 +--- a/drivers/soc/rockchip/pm_domains.c ++++ b/drivers/soc/rockchip/pm_domains.c +@@ -196,6 +196,29 @@ static int rockchip_pmu_set_idle_request(struct rockchip_pm_domain *pd, + return 0; + } + ++int rockchip_pmu_idle_request(struct device *dev, bool idle) ++{ ++ struct generic_pm_domain *genpd; ++ struct rockchip_pm_domain *pd; ++ int ret; ++ ++ if (IS_ERR_OR_NULL(dev)) ++ return -EINVAL; ++ ++ if (IS_ERR_OR_NULL(dev->pm_domain)) ++ return -EINVAL; ++ ++ genpd = pd_to_genpd(dev->pm_domain); ++ pd = to_rockchip_pd(genpd); ++ ++ mutex_lock(&pd->pmu->mutex); ++ ret = rockchip_pmu_set_idle_request(pd, idle); ++ mutex_unlock(&pd->pmu->mutex); ++ ++ return ret; ++} ++EXPORT_SYMBOL(rockchip_pmu_idle_request); ++ + static int rockchip_pmu_save_qos(struct rockchip_pm_domain *pd) + { + int i; +diff --git a/include/linux/rockchip_pmu.h b/include/linux/rockchip_pmu.h +new file mode 100644 +index 000000000000..720b3314e71a +--- /dev/null ++++ b/include/linux/rockchip_pmu.h +@@ -0,0 +1,15 @@ ++/* ++ * pm_domain.h - Definitions and headers related to device power domains. ++ * ++ * Copyright (C) 2017 Randy Li . ++ * ++ * This file is released under the GPLv2. ++ */ ++ ++#ifndef _LINUX_ROCKCHIP_PM_H ++#define _LINUX_ROCKCHIP_PM_H ++#include ++ ++int rockchip_pmu_idle_request(struct device *dev, bool idle); ++ ++#endif /* _LINUX_ROCKCHIP_PM_H */ +diff --git a/include/soc/rockchip/pm_domains.h b/include/soc/rockchip/pm_domains.h +new file mode 100644 +index 000000000000..690db6118636 +--- /dev/null ++++ b/include/soc/rockchip/pm_domains.h +@@ -0,0 +1,18 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++#ifndef __SOC_ROCKCHIP_PM_DOMAINS_H ++#define __SOC_ROCKCHIP_PM_DOMAINS_H ++ ++#include ++ ++struct device; ++ ++#ifdef CONFIG_ROCKCHIP_PM_DOMAINS ++int rockchip_pmu_idle_request(struct device *dev, bool idle); ++#else ++static inline int rockchip_pmu_idle_request(struct device *dev, bool idle) ++{ ++ return -ENOTSUPP; ++} ++#endif ++ ++#endif + +From 495e11bbb264dfb5f1d8b319ed647901fc91dc11 Mon Sep 17 00:00:00 2001 +From: Alex Bee +Date: Wed, 20 May 2020 17:04:47 +0200 +Subject: [PATCH] media: rkvdec: implement reset controls + +--- + .../bindings/media/rockchip,vdec.yaml | 19 ++++++ + drivers/staging/media/rkvdec/rkvdec-regs.h | 5 ++ + drivers/staging/media/rkvdec/rkvdec.c | 60 +++++++++++++++++++ + drivers/staging/media/rkvdec/rkvdec.h | 11 +++- + 4 files changed, 94 insertions(+), 1 deletion(-) + +diff --git a/Documentation/devicetree/bindings/media/rockchip,vdec.yaml b/Documentation/devicetree/bindings/media/rockchip,vdec.yaml +index 8d35c327018b..1e8cfd8e032b 100644 +--- a/Documentation/devicetree/bindings/media/rockchip,vdec.yaml ++++ b/Documentation/devicetree/bindings/media/rockchip,vdec.yaml +@@ -43,6 +43,18 @@ properties: + iommus: + maxItems: 1 + ++ resets: ++ maxItems: 6 ++ ++ reset-names: ++ items: ++ - const: video_h ++ - const: video_a ++ - const: video_core ++ - const: video_cabac ++ - const: niu_a ++ - const: niu_h ++ + required: + - compatible + - reg +@@ -50,6 +62,8 @@ required: + - clocks + - clock-names + - power-domains ++ - resets ++ - reset-names + + additionalProperties: false + +@@ -68,6 +82,11 @@ examples: + clock-names = "axi", "ahb", "cabac", "core"; + power-domains = <&power RK3399_PD_VDU>; + iommus = <&vdec_mmu>; ++ resets = <&cru SRST_H_VDU>, <&cru SRST_A_VDU>, ++ <&cru SRST_VDU_CORE>, <&cru SRST_VDU_CA>, ++ <&cru SRST_A_VDU_NOC>, <&cru SRST_H_VDU_NOC>; ++ reset-names = "video_h", "video_a", "video_core", "video_cabac", ++ "niu_a", "niu_h" + }; + + ... +diff --git a/drivers/staging/media/rkvdec/rkvdec-regs.h b/drivers/staging/media/rkvdec/rkvdec-regs.h +index 83bf790ed9b7..4addfaefdfb4 100644 +--- a/drivers/staging/media/rkvdec/rkvdec-regs.h ++++ b/drivers/staging/media/rkvdec/rkvdec-regs.h +@@ -28,6 +28,11 @@ + #define RKVDEC_SOFTRST_EN_P BIT(20) + #define RKVDEC_FORCE_SOFTRESET_VALID BIT(21) + #define RKVDEC_SOFTRESET_RDY BIT(22) ++#define RKVDEC_ERR_MASK (RKVDEC_BUS_STA \ ++ | RKVDEC_ERR_STA \ ++ | RKVDEC_TIMEOUT_STA \ ++ | RKVDEC_BUF_EMPTY_STA \ ++ | RKVDEC_COLMV_REF_ERR_STA ) + + #define RKVDEC_REG_SYSCTRL 0x008 + #define RKVDEC_IN_ENDIAN BIT(0) +diff --git a/drivers/staging/media/rkvdec/rkvdec.c b/drivers/staging/media/rkvdec/rkvdec.c +index 869275a411c8..74f566e65413 100644 +--- a/drivers/staging/media/rkvdec/rkvdec.c ++++ b/drivers/staging/media/rkvdec/rkvdec.c +@@ -10,12 +10,15 @@ + */ + + #include ++#include + #include + #include + #include + #include + #include + #include ++#include ++#include + #include + #include + #include +@@ -871,6 +874,11 @@ static void rkvdec_job_finish(struct rkvdec_ctx *ctx, + + pm_runtime_mark_last_busy(rkvdec->dev); + pm_runtime_put_autosuspend(rkvdec->dev); ++ ++ if (result == VB2_BUF_STATE_ERROR && ++ rkvdec->reset_mask == RESET_NONE) ++ rkvdec->reset_mask |= RESET_SOFT; ++ + rkvdec_job_finish_no_pm(ctx, result); + } + +@@ -908,6 +916,40 @@ static void rkvdec_device_run(void *priv) + + if (WARN_ON(!desc)) + return; ++ if (rkvdec->reset_mask != RESET_NONE) { ++ ++ if (rkvdec->reset_mask & RESET_SOFT) { ++ writel(RKVDEC_SOFTRST_EN_P, ++ rkvdec->regs + RKVDEC_REG_INTERRUPT); ++ udelay(RKVDEC_RESET_DELAY); ++ if (readl(rkvdec->regs + RKVDEC_REG_INTERRUPT) ++ & RKVDEC_SOFTRESET_RDY) ++ dev_info_ratelimited(rkvdec->dev, ++ "softreset failed\n"); ++ else ++ dev_notice_ratelimited(rkvdec->dev, ++ "softreset done\n"); ++ } ++ ++ if (rkvdec->reset_mask & RESET_HARD) { ++ pm_runtime_suspend(rkvdec->dev); ++ rockchip_pmu_idle_request(rkvdec->dev, true); ++ ret = reset_control_assert(rkvdec->rstc); ++ if (!ret) { ++ udelay(RKVDEC_RESET_DELAY); ++ ret = reset_control_deassert(rkvdec->rstc); ++ } ++ rockchip_pmu_idle_request(rkvdec->dev, false); ++ if (ret) ++ dev_notice_ratelimited(rkvdec->dev, ++ "hardreset failed\n"); ++ else ++ dev_notice_ratelimited(rkvdec->dev, ++ "hardreset done\n"); ++ } ++ ++ rkvdec->reset_mask = RESET_NONE; ++ } + + ret = pm_runtime_get_sync(rkvdec->dev); + if (ret < 0) { +@@ -1175,6 +1217,11 @@ static irqreturn_t rkvdec_irq_handler(int irq, void *priv) + if (cancel_delayed_work(&rkvdec->watchdog_work)) { + struct rkvdec_ctx *ctx; + ++ if (state == VB2_BUF_STATE_ERROR) { ++ rkvdec->reset_mask |= (status & RKVDEC_ERR_MASK) ? ++ RESET_HARD : RESET_SOFT; ++ } ++ + ctx = v4l2_m2m_get_curr_priv(rkvdec->m2m_dev); + rkvdec_job_finish(ctx, state); + } +@@ -1192,6 +1239,7 @@ static void rkvdec_watchdog_func(struct work_struct *work) + ctx = v4l2_m2m_get_curr_priv(rkvdec->m2m_dev); + if (ctx) { + dev_err(rkvdec->dev, "Frame processing timed out!\n"); ++ rkvdec->reset_mask |= RESET_HARD; + writel(RKVDEC_CONFIG_DEC_CLK_GATE_E | RKVDEC_IRQ_DIS, + rkvdec->regs + RKVDEC_REG_INTERRUPT); + writel(0, rkvdec->regs + RKVDEC_REG_SYSCTRL); +@@ -1271,6 +1319,18 @@ static int rkvdec_probe(struct platform_device *pdev) + return ret; + } + ++ ++ rkvdec->rstc = devm_reset_control_array_get(&pdev->dev, false, true); ++ if (IS_ERR(rkvdec->rstc)) { ++ dev_err(&pdev->dev, ++ "get resets failed %ld\n", PTR_ERR(rkvdec->rstc)); ++ return PTR_ERR(rkvdec->rstc); ++ } else { ++ dev_dbg(&pdev->dev, ++ "requested %d resets\n", ++ reset_control_get_count(&pdev->dev)); ++ } ++ + pm_runtime_set_autosuspend_delay(&pdev->dev, 100); + pm_runtime_use_autosuspend(&pdev->dev); + pm_runtime_enable(&pdev->dev); +diff --git a/drivers/staging/media/rkvdec/rkvdec.h b/drivers/staging/media/rkvdec/rkvdec.h +index d5600c6a4c17..975fe4b5dd68 100644 +--- a/drivers/staging/media/rkvdec/rkvdec.h ++++ b/drivers/staging/media/rkvdec/rkvdec.h +@@ -11,10 +11,11 @@ + #ifndef RKVDEC_H_ + #define RKVDEC_H_ + ++#include + #include ++#include + #include + #include +-#include + + #include + #include +@@ -22,6 +23,12 @@ + #include + #include + ++#define RESET_NONE 0 ++#define RESET_SOFT BIT(0) ++#define RESET_HARD BIT(1) ++ ++#define RKVDEC_RESET_DELAY 5 ++ + struct rkvdec_ctx; + + struct rkvdec_ctrl_desc { +@@ -95,6 +102,8 @@ struct rkvdec_dev { + void __iomem *regs; + struct mutex vdev_lock; /* serializes ioctls */ + struct delayed_work watchdog_work; ++ struct reset_control *rstc; ++ u8 reset_mask; + }; + + struct rkvdec_ctx { + +From 0f3ef2d452750f5688292c232b6c7d28ce2b0095 Mon Sep 17 00:00:00 2001 +From: Alex Bee +Date: Tue, 18 Aug 2020 11:38:04 +0200 +Subject: [PATCH] WIP: arm64: dts: add resets to vdec for RK3399 + +--- + arch/arm64/boot/dts/rockchip/rk3399.dtsi | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/arch/arm64/boot/dts/rockchip/rk3399.dtsi b/arch/arm64/boot/dts/rockchip/rk3399.dtsi +index 8973bf68d652..1efe2c916508 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3399.dtsi ++++ b/arch/arm64/boot/dts/rockchip/rk3399.dtsi +@@ -1281,6 +1281,11 @@ vdec: video-codec@ff660000 { + clock-names = "axi", "ahb", "cabac", "core"; + iommus = <&vdec_mmu>; + power-domains = <&power RK3399_PD_VDU>; ++ resets = <&cru SRST_H_VDU>, <&cru SRST_A_VDU>, ++ <&cru SRST_VDU_CORE>, <&cru SRST_VDU_CA>, ++ <&cru SRST_A_VDU_NOC>, <&cru SRST_H_VDU_NOC>; ++ reset-names = "video_h", "video_a", "video_core", "video_cabac", ++ "niu_a", "niu_h" + }; + + vdec_mmu: iommu@ff660480 { + +From 98eac32dca51c74be1d223854976b834ac2d9587 Mon Sep 17 00:00:00 2001 +From: Alex Bee +Date: Fri, 24 Apr 2020 12:36:13 +0200 +Subject: [PATCH] media: hantro: add Rockchip RK3228 + +RK3228 has the same VPU IP-Block as RK3399 has and at the current state +the driver can be taken as is. +This adds just a new compatible string to bindings file if any future +ajustment for this SoC is necessary. +--- + Documentation/devicetree/bindings/media/rockchip-vpu.yaml | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/Documentation/devicetree/bindings/media/rockchip-vpu.yaml b/Documentation/devicetree/bindings/media/rockchip-vpu.yaml +index 2b629456d75f..4509891a0f0f 100644 +--- a/Documentation/devicetree/bindings/media/rockchip-vpu.yaml ++++ b/Documentation/devicetree/bindings/media/rockchip-vpu.yaml +@@ -16,6 +16,7 @@ description: + properties: + compatible: + enum: ++ - rockchip,rk3228-vpu + - rockchip,rk3288-vpu + - rockchip,rk3328-vpu + - rockchip,rk3399-vpu + +From e47b8ed20a45dcb324b997e5fa74586f71fc71cc Mon Sep 17 00:00:00 2001 +From: Alex Bee +Date: Fri, 24 Apr 2020 12:38:24 +0200 +Subject: [PATCH] ARM: dts: rockchip: add vpu node for RK322x + +This adds VPU node to RK3228. While at it also add the required power-domain +controller and qos node to make the VPU work on this SoC. +--- + arch/arm/boot/dts/rk322x.dtsi | 35 +++++++++++++++++++++++++++++++++-- + 1 file changed, 33 insertions(+), 2 deletions(-) + +diff --git a/arch/arm/boot/dts/rk322x.dtsi b/arch/arm/boot/dts/rk322x.dtsi +index b69b5be110c3..0586a89d24d3 100644 +--- a/arch/arm/boot/dts/rk322x.dtsi ++++ b/arch/arm/boot/dts/rk322x.dtsi +@@ -6,6 +6,7 @@ + #include + #include + #include ++#include + + / { + #address-cells = <1>; +@@ -208,6 +209,19 @@ io_domains: io-domains { + status = "disabled"; + }; + ++ power: power-controller { ++ compatible = "rockchip,rk3228-power-controller"; ++ #power-domain-cells = <1>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ pd_vpu@RK3228_PD_VPU { ++ reg = ; ++ clocks = <&cru ACLK_VPU>, <&cru HCLK_VPU>; ++ pm_qos = <&qos_vpu>; ++ }; ++ }; ++ + u2phy0: usb2-phy@760 { + compatible = "rockchip,rk3228-usb2phy"; + reg = <0x0760 0x0c>; +@@ -561,6 +575,18 @@ gpu: gpu@20000000 { + status = "disabled"; + }; + ++ vpu: video-codec@20020000 { ++ compatible = "rockchip,rk3228-vpu", "rockchip,rk3399-vpu"; ++ reg = <0x20020000 0x800>; ++ interrupts = , ++ ; ++ interrupt-names = "vepu", "vdpu"; ++ clocks = <&cru ACLK_VPU>, <&cru HCLK_VPU>; ++ clock-names = "aclk", "hclk"; ++ iommus = <&vpu_mmu>; ++ power-domains = <&power RK3228_PD_VPU>; ++ }; ++ + vpu_mmu: iommu@20020800 { + compatible = "rockchip,iommu"; + reg = <0x20020800 0x100>; +@@ -568,8 +594,8 @@ vpu_mmu: iommu@20020800 { + interrupt-names = "vpu_mmu"; + clocks = <&cru ACLK_VPU>, <&cru HCLK_VPU>; + clock-names = "aclk", "iface"; +- iommu-cells = <0>; +- status = "disabled"; ++ power-domains = <&power RK3228_PD_VPU>; ++ #iommu-cells = <0>; + }; + + vdec_mmu: iommu@20030480 { +@@ -807,6 +833,11 @@ gmac: ethernet@30200000 { + status = "disabled"; + }; + ++ qos_vpu: qos@31040000 { ++ compatible = "syscon"; ++ reg = <0x31040000 0x20>; ++ }; ++ + gic: interrupt-controller@32010000 { + compatible = "arm,gic-400"; + interrupt-controller; + +From 70feb241848426de731a1f8bc5ad0d9c45bf5bfa Mon Sep 17 00:00:00 2001 +From: Alex Bee +Date: Tue, 26 May 2020 14:11:57 +0200 +Subject: [PATCH] media: hantro: add support for RK3188 + +RK3188s VPU IP-Block is the predecessor from what RK3288 has. + +While most of the registers match in the current state of the driver +there are some HW differences: + - supports resultion up to 1920x1088 only + - has one aclk and one hclk per vdpu/vepu + - doesn't have the 'G1_REG_SOFT_RESET' register + - ACLKs can be clocked up to 300 MHz only + - no MMU for VPU +These make it necessary to add another variant to the driver. + +This should be also reuseable for RK3066 but has not been tested, +so I'm not adding it here. +--- + .../bindings/media/rockchip-vpu.yaml | 7 +- + drivers/staging/media/hantro/hantro_drv.c | 1 + + drivers/staging/media/hantro/hantro_hw.h | 1 + + drivers/staging/media/hantro/rk3288_vpu_hw.c | 116 ++++++++++++++++++ + 4 files changed, 124 insertions(+), 1 deletion(-) + +diff --git a/Documentation/devicetree/bindings/media/rockchip-vpu.yaml b/Documentation/devicetree/bindings/media/rockchip-vpu.yaml +index 4509891a0f0f..d95274bf3b0f 100644 +--- a/Documentation/devicetree/bindings/media/rockchip-vpu.yaml ++++ b/Documentation/devicetree/bindings/media/rockchip-vpu.yaml +@@ -16,6 +16,7 @@ description: + properties: + compatible: + enum: ++ - rockchip,rk3188-vpu + - rockchip,rk3228-vpu + - rockchip,rk3288-vpu + - rockchip,rk3328-vpu +@@ -36,12 +37,16 @@ properties: + - const: vdpu + + clocks: +- maxItems: 2 ++ maxItems: 4 + + clock-names: + items: + - const: aclk ++ - const: aclk_vdpu ++ - const: aclk_vepu + - const: hclk ++ - const: hclk_vdpu ++ - const: hclk_vepu + + power-domains: + maxItems: 1 +diff --git a/drivers/staging/media/hantro/hantro_drv.c b/drivers/staging/media/hantro/hantro_drv.c +index 3cd00cc0a364..ecc0938b7f35 100644 +--- a/drivers/staging/media/hantro/hantro_drv.c ++++ b/drivers/staging/media/hantro/hantro_drv.c +@@ -475,6 +475,7 @@ static const struct of_device_id of_hantro_match[] = { + { .compatible = "rockchip,rk3399-vpu", .data = &rk3399_vpu_variant, }, + { .compatible = "rockchip,rk3328-vpu", .data = &rk3328_vpu_variant, }, + { .compatible = "rockchip,rk3288-vpu", .data = &rk3288_vpu_variant, }, ++ { .compatible = "rockchip,rk3188-vpu", .data = &rk3188_vpu_variant, }, + #endif + #ifdef CONFIG_VIDEO_HANTRO_IMX8M + { .compatible = "nxp,imx8mq-vpu", .data = &imx8mq_vpu_variant, }, +diff --git a/drivers/staging/media/hantro/hantro_hw.h b/drivers/staging/media/hantro/hantro_hw.h +index 7e35140a4f22..22b0ed01f673 100644 +--- a/drivers/staging/media/hantro/hantro_hw.h ++++ b/drivers/staging/media/hantro/hantro_hw.h +@@ -152,6 +152,7 @@ enum hantro_enc_fmt { + RK3288_VPU_ENC_FMT_UYVY422 = 3, + }; + ++extern const struct hantro_variant rk3188_vpu_variant; + extern const struct hantro_variant rk3399_vpu_variant; + extern const struct hantro_variant rk3328_vpu_variant; + extern const struct hantro_variant rk3288_vpu_variant; +diff --git a/drivers/staging/media/hantro/rk3288_vpu_hw.c b/drivers/staging/media/hantro/rk3288_vpu_hw.c +index 7b299ee3e93d..1ac00695a864 100644 +--- a/drivers/staging/media/hantro/rk3288_vpu_hw.c ++++ b/drivers/staging/media/hantro/rk3288_vpu_hw.c +@@ -13,6 +13,7 @@ + #include "hantro_g1_regs.h" + #include "hantro_h1_regs.h" + ++#define RK3188_ACLK_MAX_FREQ (300 * 1000 * 1000) + #define RK3288_ACLK_MAX_FREQ (400 * 1000 * 1000) + + /* +@@ -63,6 +64,52 @@ static const struct hantro_fmt rk3288_vpu_postproc_fmts[] = { + }, + }; + ++static const struct hantro_fmt rk3188_vpu_dec_fmts[] = { ++ { ++ .fourcc = V4L2_PIX_FMT_NV12, ++ .codec_mode = HANTRO_MODE_NONE, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_H264_SLICE, ++ .codec_mode = HANTRO_MODE_H264_DEC, ++ .max_depth = 2, ++ .frmsize = { ++ .min_width = 48, ++ .max_width = 1920, ++ .step_width = MB_DIM, ++ .min_height = 48, ++ .max_height = 1088, ++ .step_height = MB_DIM, ++ }, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_MPEG2_SLICE, ++ .codec_mode = HANTRO_MODE_MPEG2_DEC, ++ .max_depth = 2, ++ .frmsize = { ++ .min_width = 48, ++ .max_width = 1920, ++ .step_width = MB_DIM, ++ .min_height = 48, ++ .max_height = 1088, ++ .step_height = MB_DIM, ++ }, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_VP8_FRAME, ++ .codec_mode = HANTRO_MODE_VP8_DEC, ++ .max_depth = 2, ++ .frmsize = { ++ .min_width = 48, ++ .max_width = 1920, ++ .step_width = MB_DIM, ++ .min_height = 48, ++ .max_height = 1088, ++ .step_height = MB_DIM, ++ }, ++ }, ++}; ++ + static const struct hantro_fmt rk3288_vpu_dec_fmts[] = { + { + .fourcc = V4L2_PIX_FMT_NV12, +@@ -145,6 +192,14 @@ static irqreturn_t rk3288_vdpu_irq(int irq, void *dev_id) + return IRQ_HANDLED; + } + ++static int rk3188_vpu_hw_init(struct hantro_dev *vpu) ++{ ++ /* Bump ACLKs to max. possible freq. to improve performance. */ ++ clk_set_rate(vpu->clocks[0].clk, RK3188_ACLK_MAX_FREQ); ++ clk_set_rate(vpu->clocks[2].clk, RK3188_ACLK_MAX_FREQ); ++ return 0; ++} ++ + static int rk3288_vpu_hw_init(struct hantro_dev *vpu) + { + /* Bump ACLK to max. possible freq. to improve performance. */ +@@ -161,6 +216,15 @@ static void rk3288_vpu_enc_reset(struct hantro_ctx *ctx) + vepu_write(vpu, 0, H1_REG_AXI_CTRL); + } + ++ ++static void rk3188_vpu_dec_reset(struct hantro_ctx *ctx) ++{ ++ struct hantro_dev *vpu = ctx->dev; ++ ++ vdpu_write(vpu, G1_REG_INTERRUPT_DEC_IRQ_DIS, G1_REG_INTERRUPT); ++ vdpu_write(vpu, G1_REG_CONFIG_DEC_CLK_GATE_E, G1_REG_CONFIG); ++} ++ + static void rk3288_vpu_dec_reset(struct hantro_ctx *ctx) + { + struct hantro_dev *vpu = ctx->dev; +@@ -174,6 +238,33 @@ static void rk3288_vpu_dec_reset(struct hantro_ctx *ctx) + * Supported codec ops. + */ + ++static const struct hantro_codec_ops rk3188_vpu_codec_ops[] = { ++ [HANTRO_MODE_JPEG_ENC] = { ++ .run = hantro_h1_jpeg_enc_run, ++ .reset = rk3288_vpu_enc_reset, ++ .init = hantro_jpeg_enc_init, ++ .exit = hantro_jpeg_enc_exit, ++ }, ++ [HANTRO_MODE_H264_DEC] = { ++ .run = hantro_g1_h264_dec_run, ++ .reset = rk3188_vpu_dec_reset, ++ .init = hantro_h264_dec_init, ++ .exit = hantro_h264_dec_exit, ++ }, ++ [HANTRO_MODE_MPEG2_DEC] = { ++ .run = hantro_g1_mpeg2_dec_run, ++ .reset = rk3188_vpu_dec_reset, ++ .init = hantro_mpeg2_dec_init, ++ .exit = hantro_mpeg2_dec_exit, ++ }, ++ [HANTRO_MODE_VP8_DEC] = { ++ .run = hantro_g1_vp8_dec_run, ++ .reset = rk3188_vpu_dec_reset, ++ .init = hantro_vp8_dec_init, ++ .exit = hantro_vp8_dec_exit, ++ }, ++}; ++ + static const struct hantro_codec_ops rk3288_vpu_codec_ops[] = { + [HANTRO_MODE_JPEG_ENC] = { + .run = hantro_h1_jpeg_enc_run, +@@ -211,10 +302,35 @@ static const struct hantro_irq rk3288_irqs[] = { + { "vdpu", rk3288_vdpu_irq }, + }; + ++static const char * const rk3188_clk_names[] = { ++ "aclk_vdpu", "hclk_vdpu", ++ "aclk_vepu", "hclk_vepu", ++}; ++ + static const char * const rk3288_clk_names[] = { + "aclk", "hclk" + }; + ++const struct hantro_variant rk3188_vpu_variant = { ++ .enc_offset = 0x0, ++ .enc_fmts = rk3288_vpu_enc_fmts, ++ .num_enc_fmts = ARRAY_SIZE(rk3288_vpu_enc_fmts), ++ .dec_offset = 0x400, ++ .dec_fmts = rk3188_vpu_dec_fmts, ++ .num_dec_fmts = ARRAY_SIZE(rk3188_vpu_dec_fmts), ++ .postproc_fmts = rk3288_vpu_postproc_fmts, ++ .num_postproc_fmts = ARRAY_SIZE(rk3288_vpu_postproc_fmts), ++ .postproc_regs = &hantro_g1_postproc_regs, ++ .codec = HANTRO_JPEG_ENCODER | HANTRO_MPEG2_DECODER | ++ HANTRO_VP8_DECODER | HANTRO_H264_DECODER, ++ .codec_ops = rk3188_vpu_codec_ops, ++ .irqs = rk3288_irqs, ++ .num_irqs = ARRAY_SIZE(rk3288_irqs), ++ .init = rk3188_vpu_hw_init, ++ .clk_names = rk3188_clk_names, ++ .num_clocks = ARRAY_SIZE(rk3188_clk_names) ++}; ++ + const struct hantro_variant rk3288_vpu_variant = { + .enc_offset = 0x0, + .enc_fmts = rk3288_vpu_enc_fmts, + +From 134592088d9c703169c9daff5793e0321ecc245d Mon Sep 17 00:00:00 2001 +From: Alex Bee +Date: Tue, 26 May 2020 14:12:35 +0200 +Subject: [PATCH] ARM: dts: rockchip: add vpu node for RK3188 + +Add VPU node to RK3188s dtsi. +--- + arch/arm/boot/dts/rk3188.dtsi | 13 +++++++++++++ + 1 file changed, 13 insertions(+) + +diff --git a/arch/arm/boot/dts/rk3188.dtsi b/arch/arm/boot/dts/rk3188.dtsi +index 2298a8d840ba..b6c1699345d0 100644 +--- a/arch/arm/boot/dts/rk3188.dtsi ++++ b/arch/arm/boot/dts/rk3188.dtsi +@@ -112,6 +112,19 @@ smp-sram@0 { + }; + }; + ++ vpu: video-codec@10104000 { ++ compatible = "rockchip,rk3188-vpu"; ++ reg = <0x10104000 0x800>; ++ interrupts = , ++ ; ++ interrupt-names = "vepu", "vdpu"; ++ clocks = <&cru ACLK_VDPU>, <&cru HCLK_VDPU>, ++ <&cru ACLK_VEPU>, <&cru HCLK_VEPU>; ++ clock-names = "aclk_vdpu", "hclk_vdpu", ++ "aclk_vepu", "hclk_vepu"; ++ power-domains = <&power RK3188_PD_VIDEO>; ++ }; ++ + vop0: vop@1010c000 { + compatible = "rockchip,rk3188-vop"; + reg = <0x1010c000 0x1000>; + +From 573413b3e49d1ca7676c976aa3e7d6bb65e497ed Mon Sep 17 00:00:00 2001 +From: Alex Bee +Date: Tue, 26 May 2020 17:24:12 +0200 +Subject: [PATCH] media: hantro: add support for Rockchip RK3036 + +RK3036 shares the hantro VPU IP Block with RK3288. +HW differences are: +- supports decoding up to 1920x1088 only +- ACLK can be clocked at max. 300MHz +This makes adding another variant to the driver necessary here also. + +However RK3036 TRM does not mention that it has an encoder also. I verfied +this on my devices and it worked for JPEG encoding. Since the identification +register share the id with RK3288 and the fact that it has an interrupt for +video encoding, makes me think that the encoding IP is the same. + +This variant could also be used for RK312x, but has not been tested. +--- + drivers/staging/media/hantro/hantro_drv.c | 1 + + drivers/staging/media/hantro/hantro_hw.h | 1 + + drivers/staging/media/hantro/rk3288_vpu_hw.c | 27 ++++++++++++++++++++ + 3 files changed, 29 insertions(+) + +diff --git a/drivers/staging/media/hantro/hantro_drv.c b/drivers/staging/media/hantro/hantro_drv.c +index ecc0938b7f35..ee59fad9a2f3 100644 +--- a/drivers/staging/media/hantro/hantro_drv.c ++++ b/drivers/staging/media/hantro/hantro_drv.c +@@ -476,6 +476,7 @@ static const struct of_device_id of_hantro_match[] = { + { .compatible = "rockchip,rk3328-vpu", .data = &rk3328_vpu_variant, }, + { .compatible = "rockchip,rk3288-vpu", .data = &rk3288_vpu_variant, }, + { .compatible = "rockchip,rk3188-vpu", .data = &rk3188_vpu_variant, }, ++ { .compatible = "rockchip,rk3036-vpu", .data = &rk3036_vpu_variant, }, + #endif + #ifdef CONFIG_VIDEO_HANTRO_IMX8M + { .compatible = "nxp,imx8mq-vpu", .data = &imx8mq_vpu_variant, }, +diff --git a/drivers/staging/media/hantro/hantro_hw.h b/drivers/staging/media/hantro/hantro_hw.h +index 22b0ed01f673..ede7acec5e9f 100644 +--- a/drivers/staging/media/hantro/hantro_hw.h ++++ b/drivers/staging/media/hantro/hantro_hw.h +@@ -152,6 +152,7 @@ enum hantro_enc_fmt { + RK3288_VPU_ENC_FMT_UYVY422 = 3, + }; + ++extern const struct hantro_variant rk3036_vpu_variant; + extern const struct hantro_variant rk3188_vpu_variant; + extern const struct hantro_variant rk3399_vpu_variant; + extern const struct hantro_variant rk3328_vpu_variant; +diff --git a/drivers/staging/media/hantro/rk3288_vpu_hw.c b/drivers/staging/media/hantro/rk3288_vpu_hw.c +index 1ac00695a864..b5887fdae250 100644 +--- a/drivers/staging/media/hantro/rk3288_vpu_hw.c ++++ b/drivers/staging/media/hantro/rk3288_vpu_hw.c +@@ -192,6 +192,13 @@ static irqreturn_t rk3288_vdpu_irq(int irq, void *dev_id) + return IRQ_HANDLED; + } + ++static int rk3036_vpu_hw_init(struct hantro_dev *vpu) ++{ ++ /* Bump ACLK to max. possible freq. to improve performance. */ ++ clk_set_rate(vpu->clocks[0].clk, RK3188_ACLK_MAX_FREQ); ++ return 0; ++} ++ + static int rk3188_vpu_hw_init(struct hantro_dev *vpu) + { + /* Bump ACLKs to max. possible freq. to improve performance. */ +@@ -311,6 +318,26 @@ static const char * const rk3288_clk_names[] = { + "aclk", "hclk" + }; + ++const struct hantro_variant rk3036_vpu_variant = { ++ .enc_offset = 0x0, ++ .enc_fmts = rk3288_vpu_enc_fmts, ++ .num_enc_fmts = ARRAY_SIZE(rk3288_vpu_enc_fmts), ++ .dec_offset = 0x400, ++ .dec_fmts = rk3188_vpu_dec_fmts, ++ .num_dec_fmts = ARRAY_SIZE(rk3188_vpu_dec_fmts), ++ .postproc_fmts = rk3288_vpu_postproc_fmts, ++ .num_postproc_fmts = ARRAY_SIZE(rk3288_vpu_postproc_fmts), ++ .postproc_regs = &hantro_g1_postproc_regs, ++ .codec = HANTRO_JPEG_ENCODER | HANTRO_MPEG2_DECODER | ++ HANTRO_VP8_DECODER | HANTRO_H264_DECODER, ++ .codec_ops = rk3288_vpu_codec_ops, ++ .irqs = rk3288_irqs, ++ .num_irqs = ARRAY_SIZE(rk3288_irqs), ++ .init = rk3036_vpu_hw_init, ++ .clk_names = rk3288_clk_names, ++ .num_clocks = ARRAY_SIZE(rk3288_clk_names) ++}; ++ + const struct hantro_variant rk3188_vpu_variant = { + .enc_offset = 0x0, + .enc_fmts = rk3288_vpu_enc_fmts, + +From 387d5e35e99f03bb0caed01163ef393e15b30362 Mon Sep 17 00:00:00 2001 +From: Alex Bee +Date: Tue, 26 May 2020 17:42:55 +0200 +Subject: [PATCH] ARM: dts: rockchip: add vpu node for RK3036 + +This adds VPU node to RK3036. While at it also add the required mmu, +power-domain controller and qos node to make the VPU work on this SoC. +--- + .../bindings/media/rockchip-vpu.yaml | 1 + + arch/arm/boot/dts/rk3036.dtsi | 44 +++++++++++++++++++ + 2 files changed, 45 insertions(+) + +diff --git a/Documentation/devicetree/bindings/media/rockchip-vpu.yaml b/Documentation/devicetree/bindings/media/rockchip-vpu.yaml +index d95274bf3b0f..15aeae3d1daf 100644 +--- a/Documentation/devicetree/bindings/media/rockchip-vpu.yaml ++++ b/Documentation/devicetree/bindings/media/rockchip-vpu.yaml +@@ -16,6 +16,7 @@ description: + properties: + compatible: + enum: ++ - rockchip,rk3036-vpu + - rockchip,rk3188-vpu + - rockchip,rk3228-vpu + - rockchip,rk3288-vpu +diff --git a/arch/arm/boot/dts/rk3036.dtsi b/arch/arm/boot/dts/rk3036.dtsi +index 6be6d9d134fe..10f15cdb932c 100644 +--- a/arch/arm/boot/dts/rk3036.dtsi ++++ b/arch/arm/boot/dts/rk3036.dtsi +@@ -6,6 +6,7 @@ + #include + #include + #include ++#include + + / { + #address-cells = <1>; +@@ -134,6 +135,29 @@ gpu: gpu@10090000 { + status = "disabled"; + }; + ++ vpu: video-codec@10108000 { ++ compatible = "rockchip,rk3036-vpu"; ++ reg = <0x10108000 0x800>; ++ interrupts = , ++ ; ++ interrupt-names = "vepu", "vdpu"; ++ clocks = <&cru ACLK_VCODEC>, <&cru HCLK_VCODEC>; ++ clock-names = "aclk", "hclk"; ++ iommus = <&vpu_mmu>; ++ power-domains = <&power RK3036_PD_VPU>; ++ }; ++ ++ vpu_mmu: iommu@10108800 { ++ compatible = "rockchip,iommu"; ++ reg = <0x10108800 0x100>; ++ interrupts = ; ++ interrupt-names = "vpu_mmu"; ++ clocks = <&cru ACLK_VCODEC>, <&cru HCLK_VCODEC>; ++ clock-names = "aclk", "iface"; ++ power-domains = <&power RK3036_PD_VPU>; ++ #iommu-cells = <0>; ++ }; ++ + vop: vop@10118000 { + compatible = "rockchip,rk3036-vop"; + reg = <0x10118000 0x19c>; +@@ -166,6 +190,11 @@ vop_mmu: iommu@10118300 { + status = "disabled"; + }; + ++ qos_vpu: qos@1012e000 { ++ compatible = "syscon"; ++ reg = <0x1012e000 0x20>; ++ }; ++ + gic: interrupt-controller@10139000 { + compatible = "arm,gic-400"; + interrupt-controller; +@@ -329,6 +358,21 @@ reboot-mode { + mode-bootloader = ; + mode-loader = ; + }; ++ ++ power: power-controller { ++ compatible = "rockchip,rk3036-power-controller"; ++ #power-domain-cells = <1>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ pd_vpu@RK3036_PD_VPU { ++ reg = ; ++ clocks = <&cru ACLK_VCODEC>, ++ <&cru HCLK_VCODEC>; ++ pm_qos = <&qos_vpu>; ++ }; ++ ++ }; + }; + + acodec: acodec-ana@20030000 { + +From 871a3ef06a4100a3d7ecc75d2751acf67269a07c Mon Sep 17 00:00:00 2001 +From: Alex Bee +Date: Tue, 26 May 2020 17:54:22 +0200 +Subject: [PATCH] media: hantro: adapt Kconfig help text + +Since help text line would get very long if all supported SoCs are mentioned +I shortend it to "Rockchip SoCs" +--- + drivers/staging/media/hantro/Kconfig | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/staging/media/hantro/Kconfig b/drivers/staging/media/hantro/Kconfig +index 5b6cf9f62b1a..d33f1ddbc9c9 100644 +--- a/drivers/staging/media/hantro/Kconfig ++++ b/drivers/staging/media/hantro/Kconfig +@@ -30,4 +30,4 @@ config VIDEO_HANTRO_ROCKCHIP + depends on ARCH_ROCKCHIP || COMPILE_TEST + default y + help +- Enable support for RK3288, RK3328, and RK3399 SoCs. ++ Enable support for Rockchip SoCs. + +From 83c9c3f037c52e8c4ada8b5b5f1269ccfa6f6f14 Mon Sep 17 00:00:00 2001 +From: Alex Bee +Date: Sat, 23 May 2020 14:22:54 +0200 +Subject: [PATCH] ARM: dts: rockchip: add vdec node for RK322x + +RK322x has the same VDEC IP block as RK3399 has and the driver in its +current state can be used as is. +Other than RK3399 its SCLKs have also to set to a fixed value to make it +work correctly. Rather than doing this in the driver it is done via +"assigned-clocks" in the vdec node. +--- + arch/arm/boot/dts/rk322x.dtsi | 42 +++++++++++++++++++++++++++++++++-- + 1 file changed, 40 insertions(+), 2 deletions(-) + +diff --git a/arch/arm/boot/dts/rk322x.dtsi b/arch/arm/boot/dts/rk322x.dtsi +index 0586a89d24d3..eec601fb4cd0 100644 +--- a/arch/arm/boot/dts/rk322x.dtsi ++++ b/arch/arm/boot/dts/rk322x.dtsi +@@ -220,6 +220,15 @@ pd_vpu@RK3228_PD_VPU { + clocks = <&cru ACLK_VPU>, <&cru HCLK_VPU>; + pm_qos = <&qos_vpu>; + }; ++ ++ pd_rkvdec@RK3228_PD_RKVDEC { ++ reg = ; ++ clocks = <&cru ACLK_RKVDEC>, ++ <&cru HCLK_RKVDEC>, ++ <&cru SCLK_VDEC_CABAC>, ++ <&cru SCLK_VDEC_CORE>; ++ pm_qos = <&qos_rkvdec_r>, <&qos_rkvdec_w>; ++ }; + }; + + u2phy0: usb2-phy@760 { +@@ -598,6 +607,25 @@ vpu_mmu: iommu@20020800 { + #iommu-cells = <0>; + }; + ++ vdec: video-codec@20030000 { ++ compatible = "rockchip,rk322x-vdec", "rockchip,rk3399-vdec"; ++ reg = <0x20030000 0x400>; ++ interrupts = ; ++ clocks = <&cru ACLK_RKVDEC>, <&cru HCLK_RKVDEC>, ++ <&cru SCLK_VDEC_CABAC>, <&cru SCLK_VDEC_CORE>; ++ clock-names = "axi", "ahb", "cabac", "core"; ++ assigned-clocks = <&cru ACLK_RKVDEC>, <&cru SCLK_VDEC_CABAC>, ++ <&cru SCLK_VDEC_CORE>; ++ assigned-clock-rates = <500000000>, <300000000>, <300000000>; ++ power-domains = <&power RK3228_PD_RKVDEC>; ++ resets = <&cru SRST_RKVDEC_H>, <&cru SRST_RKVDEC_A>, ++ <&cru SRST_RKVDEC_CORE>, <&cru SRST_RKVDEC_CABAC>, ++ <&cru SRST_RKVDEC_NOC_A>, <&cru SRST_RKVDEC_NOC_H>; ++ reset-names = "video_h", "video_a", "video_core", "video_cabac", ++ "niu_a", "niu_h"; ++ iommus = <&vdec_mmu>; ++ }; ++ + vdec_mmu: iommu@20030480 { + compatible = "rockchip,iommu"; + reg = <0x20030480 0x40>, <0x200304c0 0x40>; +@@ -605,8 +633,8 @@ vdec_mmu: iommu@20030480 { + interrupt-names = "vdec_mmu"; + clocks = <&cru ACLK_RKVDEC>, <&cru HCLK_RKVDEC>; + clock-names = "aclk", "iface"; +- iommu-cells = <0>; +- status = "disabled"; ++ power-domains = <&power RK3228_PD_RKVDEC>; ++ #iommu-cells = <0>; + }; + + vop: vop@20050000 { +@@ -838,6 +866,16 @@ qos_vpu: qos@31040000 { + reg = <0x31040000 0x20>; + }; + ++ qos_rkvdec_r: qos@31070000 { ++ compatible = "syscon"; ++ reg = <0x31070000 0x20>; ++ }; ++ ++ qos_rkvdec_w: qos@31070080 { ++ compatible = "syscon"; ++ reg = <0x31070080 0x20>; ++ }; ++ + gic: interrupt-controller@32010000 { + compatible = "arm,gic-400"; + interrupt-controller; diff --git a/patch/kernel/rk322x-current/01-linux-4000-rockchip-linux-wip.patch b/patch/kernel/rk322x-current/01-linux-4000-rockchip-linux-wip.patch new file mode 100644 index 000000000..2c2489b47 --- /dev/null +++ b/patch/kernel/rk322x-current/01-linux-4000-rockchip-linux-wip.patch @@ -0,0 +1,1692 @@ +From a49884fc5063fb0eb3db69568b45e3b8ef5ea094 Mon Sep 17 00:00:00 2001 +From: Finley Xiao +Date: Thu, 22 Jun 2017 20:22:25 +0800 +Subject: [PATCH] clk: rockchip: rk3228: fix some PLL_NUX_CLKs' gates + +Some PLL_NUX_CLKs' gates is actually behind muxs according to latest TRM, +so move the gates to composite clocks and amend their parent clocks. + +Change-Id: Ib6043caa61e9df0473f2d0bdc756850968bb2a55 +Signed-off-by: Finley Xiao +--- + drivers/clk/rockchip/clk-rk3228.c | 53 ++++++++----------------------- + 1 file changed, 14 insertions(+), 39 deletions(-) + +diff --git a/drivers/clk/rockchip/clk-rk3228.c b/drivers/clk/rockchip/clk-rk3228.c +index dd414c8255e3..734126a2ad7e 100644 +--- a/drivers/clk/rockchip/clk-rk3228.c ++++ b/drivers/clk/rockchip/clk-rk3228.c +@@ -130,24 +130,22 @@ static const struct rockchip_cpuclk_reg_data rk3228_cpuclk_data = { + + PNAME(mux_pll_p) = { "clk_24m", "xin24m" }; + +-PNAME(mux_ddrphy_p) = { "dpll_ddr", "gpll_ddr", "apll_ddr" }; +-PNAME(mux_armclk_p) = { "apll_core", "gpll_core", "dpll_core" }; ++PNAME(mux_ddrphy_p) = { "dpll", "gpll", "apll" }; ++PNAME(mux_armclk_p) = { "apll", "gpll", "dpll" }; + PNAME(mux_usb480m_phy_p) = { "usb480m_phy0", "usb480m_phy1" }; + PNAME(mux_usb480m_p) = { "usb480m_phy", "xin24m" }; + PNAME(mux_hdmiphy_p) = { "hdmiphy_phy", "xin24m" }; +-PNAME(mux_aclk_cpu_src_p) = { "cpll_aclk_cpu", "gpll_aclk_cpu", "hdmiphy_aclk_cpu" }; + + PNAME(mux_pll_src_4plls_p) = { "cpll", "gpll", "hdmiphy" "usb480m" }; + PNAME(mux_pll_src_3plls_p) = { "cpll", "gpll", "hdmiphy" }; + PNAME(mux_pll_src_2plls_p) = { "cpll", "gpll" }; + PNAME(mux_sclk_hdmi_cec_p) = { "cpll", "gpll", "xin24m" }; +-PNAME(mux_aclk_peri_src_p) = { "cpll_peri", "gpll_peri", "hdmiphy_peri" }; + PNAME(mux_mmc_src_p) = { "cpll", "gpll", "xin24m", "usb480m" }; + PNAME(mux_pll_src_cpll_gpll_usb480m_p) = { "cpll", "gpll", "usb480m" }; + + PNAME(mux_sclk_rga_p) = { "gpll", "cpll", "sclk_rga_src" }; + +-PNAME(mux_sclk_vop_src_p) = { "gpll_vop", "cpll_vop" }; ++PNAME(mux_sclk_vop_src_p) = { "gpll", "cpll" }; + PNAME(mux_dclk_vop_p) = { "hdmiphy", "sclk_vop_pre" }; + + PNAME(mux_i2s0_p) = { "i2s0_src", "i2s0_frac", "ext_i2s", "xin12m" }; +@@ -216,27 +214,17 @@ static struct rockchip_clk_branch rk3228_clk_branches[] __initdata = { + RK2928_CLKSEL_CON(4), 8, 5, DFLAGS), + + /* PD_DDR */ +- GATE(0, "apll_ddr", "apll", CLK_IGNORE_UNUSED, ++ COMPOSITE(0, "clk_ddrphy_src", mux_ddrphy_p, CLK_IGNORE_UNUSED, ++ RK2928_CLKSEL_CON(26), 8, 2, MFLAGS, 0, 2, DFLAGS | CLK_DIVIDER_POWER_OF_TWO, + RK2928_CLKGATE_CON(0), 2, GFLAGS), +- GATE(0, "dpll_ddr", "dpll", CLK_IGNORE_UNUSED, +- RK2928_CLKGATE_CON(0), 2, GFLAGS), +- GATE(0, "gpll_ddr", "gpll", CLK_IGNORE_UNUSED, +- RK2928_CLKGATE_CON(0), 2, GFLAGS), +- COMPOSITE(0, "ddrphy4x", mux_ddrphy_p, CLK_IGNORE_UNUSED, +- RK2928_CLKSEL_CON(26), 8, 2, MFLAGS, 0, 3, DFLAGS | CLK_DIVIDER_POWER_OF_TWO, ++ GATE(0, "ddrphy4x", "clk_ddrphy_src", CLK_IGNORE_UNUSED, + RK2928_CLKGATE_CON(7), 1, GFLAGS), +- GATE(0, "ddrc", "ddrphy_pre", CLK_IGNORE_UNUSED, ++ FACTOR_GATE(0, "ddrc", "clk_ddrphy_src", CLK_IGNORE_UNUSED, 1, 4, + RK2928_CLKGATE_CON(8), 5, GFLAGS), +- FACTOR_GATE(0, "ddrphy", "ddrphy4x", CLK_IGNORE_UNUSED, 1, 4, ++ FACTOR_GATE(0, "ddrphy", "clk_ddrphy_src", CLK_IGNORE_UNUSED, 1, 4, + RK2928_CLKGATE_CON(7), 0, GFLAGS), + + /* PD_CORE */ +- GATE(0, "dpll_core", "dpll", CLK_IGNORE_UNUSED, +- RK2928_CLKGATE_CON(0), 6, GFLAGS), +- GATE(0, "apll_core", "apll", CLK_IGNORE_UNUSED, +- RK2928_CLKGATE_CON(0), 6, GFLAGS), +- GATE(0, "gpll_core", "gpll", CLK_IGNORE_UNUSED, +- RK2928_CLKGATE_CON(0), 6, GFLAGS), + COMPOSITE_NOMUX(0, "pclk_dbg", "armclk", CLK_IGNORE_UNUSED, + RK2928_CLKSEL_CON(1), 0, 4, DFLAGS | CLK_DIVIDER_READ_ONLY, + RK2928_CLKGATE_CON(4), 1, GFLAGS), +@@ -253,14 +241,9 @@ static struct rockchip_clk_branch rk3228_clk_branches[] __initdata = { + RK2928_MISC_CON, 15, 1, MFLAGS), + + /* PD_BUS */ +- GATE(0, "hdmiphy_aclk_cpu", "hdmiphy", CLK_IGNORE_UNUSED, +- RK2928_CLKGATE_CON(0), 1, GFLAGS), +- GATE(0, "gpll_aclk_cpu", "gpll", CLK_IGNORE_UNUSED, +- RK2928_CLKGATE_CON(0), 1, GFLAGS), +- GATE(0, "cpll_aclk_cpu", "cpll", CLK_IGNORE_UNUSED, ++ COMPOSITE(0, "aclk_cpu_src", mux_pll_src_3plls_p, 0, ++ RK2928_CLKSEL_CON(0), 13, 2, MFLAGS, 8, 5, DFLAGS, + RK2928_CLKGATE_CON(0), 1, GFLAGS), +- COMPOSITE_NOGATE(0, "aclk_cpu_src", mux_aclk_cpu_src_p, 0, +- RK2928_CLKSEL_CON(0), 13, 2, MFLAGS, 8, 5, DFLAGS), + GATE(ACLK_CPU, "aclk_cpu", "aclk_cpu_src", 0, + RK2928_CLKGATE_CON(6), 0, GFLAGS), + COMPOSITE_NOMUX(HCLK_CPU, "hclk_cpu", "aclk_cpu_src", 0, +@@ -333,14 +316,9 @@ static struct rockchip_clk_branch rk3228_clk_branches[] __initdata = { + RK2928_CLKGATE_CON(3), 8, GFLAGS), + + /* PD_PERI */ +- GATE(0, "cpll_peri", "cpll", CLK_IGNORE_UNUSED, ++ COMPOSITE(0, "aclk_peri_src", mux_pll_src_3plls_p, 0, ++ RK2928_CLKSEL_CON(10), 10, 2, MFLAGS, 0, 5, DFLAGS, + RK2928_CLKGATE_CON(2), 0, GFLAGS), +- GATE(0, "gpll_peri", "gpll", CLK_IGNORE_UNUSED, +- RK2928_CLKGATE_CON(2), 0, GFLAGS), +- GATE(0, "hdmiphy_peri", "hdmiphy", CLK_IGNORE_UNUSED, +- RK2928_CLKGATE_CON(2), 0, GFLAGS), +- COMPOSITE_NOGATE(0, "aclk_peri_src", mux_aclk_peri_src_p, 0, +- RK2928_CLKSEL_CON(10), 10, 2, MFLAGS, 0, 5, DFLAGS), + COMPOSITE_NOMUX(PCLK_PERI, "pclk_peri", "aclk_peri_src", 0, + RK2928_CLKSEL_CON(10), 12, 3, DFLAGS, + RK2928_CLKGATE_CON(5), 2, GFLAGS), +@@ -398,12 +376,9 @@ static struct rockchip_clk_branch rk3228_clk_branches[] __initdata = { + * Clock-Architecture Diagram 2 + */ + +- GATE(0, "gpll_vop", "gpll", 0, +- RK2928_CLKGATE_CON(3), 1, GFLAGS), +- GATE(0, "cpll_vop", "cpll", 0, ++ COMPOSITE_NODIV(0, "sclk_vop_src", mux_sclk_vop_src_p, 0, ++ RK2928_CLKSEL_CON(27), 0, 1, MFLAGS, + RK2928_CLKGATE_CON(3), 1, GFLAGS), +- MUX(0, "sclk_vop_src", mux_sclk_vop_src_p, 0, +- RK2928_CLKSEL_CON(27), 0, 1, MFLAGS), + DIV(DCLK_HDMI_PHY, "dclk_hdmiphy", "sclk_vop_src", 0, + RK2928_CLKSEL_CON(29), 0, 3, DFLAGS), + DIV(0, "sclk_vop_pre", "sclk_vop_src", 0, + +From 368824e53d6be0914927df4281bbce6da58a03ff Mon Sep 17 00:00:00 2001 +From: Finley Xiao +Date: Sun, 18 Mar 2018 21:41:43 +0800 +Subject: [PATCH] clk: rockchip: rk3228: Fix sclk_wifi div_width + +Change-Id: I8e216249fbd588ce55660eba9911fc59aedc920d +Signed-off-by: Finley Xiao +--- + drivers/clk/rockchip/clk-rk3228.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/clk/rockchip/clk-rk3228.c b/drivers/clk/rockchip/clk-rk3228.c +index 734126a2ad7e..90e5638d4e7e 100644 +--- a/drivers/clk/rockchip/clk-rk3228.c ++++ b/drivers/clk/rockchip/clk-rk3228.c +@@ -353,7 +353,7 @@ static struct rockchip_clk_branch rk3228_clk_branches[] __initdata = { + RK2928_CLKGATE_CON(10), 12, GFLAGS), + + COMPOSITE(SCLK_WIFI, "sclk_wifi", mux_pll_src_cpll_gpll_usb480m_p, 0, +- RK2928_CLKSEL_CON(23), 5, 2, MFLAGS, 0, 6, DFLAGS, ++ RK2928_CLKSEL_CON(23), 5, 2, MFLAGS, 0, 5, DFLAGS, + RK2928_CLKGATE_CON(2), 15, GFLAGS), + + COMPOSITE(SCLK_SDMMC, "sclk_sdmmc", mux_mmc_src_p, 0, + +From 06685aabce5c6147ca099bd1b1399f6a170f78e1 Mon Sep 17 00:00:00 2001 +From: Chen Lei +Date: Tue, 25 Dec 2018 18:29:04 +0800 +Subject: [PATCH] clk: rockchip: rk322x: fix wrong mmc phase shift for rk3228 + +mmc sample shift should be 1 for rk3228, or it will fail +if we enable mmc tuning for rk3228. + +Change-Id: I301c2a7d33de8d519d7c288aef03a82531016373 +Signed-off-by: Chen Lei +--- + drivers/clk/rockchip/clk-rk3228.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/clk/rockchip/clk-rk3228.c b/drivers/clk/rockchip/clk-rk3228.c +index 90e5638d4e7e..7fff74043766 100644 +--- a/drivers/clk/rockchip/clk-rk3228.c ++++ b/drivers/clk/rockchip/clk-rk3228.c +@@ -610,13 +610,13 @@ static struct rockchip_clk_branch rk3228_clk_branches[] __initdata = { + + /* PD_MMC */ + MMC(SCLK_SDMMC_DRV, "sdmmc_drv", "sclk_sdmmc", RK3228_SDMMC_CON0, 1), +- MMC(SCLK_SDMMC_SAMPLE, "sdmmc_sample", "sclk_sdmmc", RK3228_SDMMC_CON1, 0), ++ MMC(SCLK_SDMMC_SAMPLE, "sdmmc_sample", "sclk_sdmmc", RK3228_SDMMC_CON1, 1), + + MMC(SCLK_SDIO_DRV, "sdio_drv", "sclk_sdio", RK3228_SDIO_CON0, 1), +- MMC(SCLK_SDIO_SAMPLE, "sdio_sample", "sclk_sdio", RK3228_SDIO_CON1, 0), ++ MMC(SCLK_SDIO_SAMPLE, "sdio_sample", "sclk_sdio", RK3228_SDIO_CON1, 1), + + MMC(SCLK_EMMC_DRV, "emmc_drv", "sclk_emmc", RK3228_EMMC_CON0, 1), +- MMC(SCLK_EMMC_SAMPLE, "emmc_sample", "sclk_emmc", RK3228_EMMC_CON1, 0), ++ MMC(SCLK_EMMC_SAMPLE, "emmc_sample", "sclk_emmc", RK3228_EMMC_CON1, 1), + }; + + static const char *const rk3228_critical_clocks[] __initconst = { + +From a74448d0259e2fe4ad3d791d779ba7a85d31a08b Mon Sep 17 00:00:00 2001 +From: Finley Xiao +Date: Mon, 5 Feb 2018 10:04:15 +0800 +Subject: [PATCH] clk: rockchip: rk3228: Fix armclk parent + +Change-Id: I09830d96b37cca600f1782b9013b25e043467f97 +Signed-off-by: Finley Xiao +--- + drivers/clk/rockchip/clk-rk3228.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/drivers/clk/rockchip/clk-rk3228.c b/drivers/clk/rockchip/clk-rk3228.c +index 7fff74043766..00c5b8a1e295 100644 +--- a/drivers/clk/rockchip/clk-rk3228.c ++++ b/drivers/clk/rockchip/clk-rk3228.c +@@ -131,7 +131,7 @@ static const struct rockchip_cpuclk_reg_data rk3228_cpuclk_data = { + PNAME(mux_pll_p) = { "clk_24m", "xin24m" }; + + PNAME(mux_ddrphy_p) = { "dpll", "gpll", "apll" }; +-PNAME(mux_armclk_p) = { "apll", "gpll", "dpll" }; ++PNAME(mux_armclk_p) = { "apll_core", "gpll_core", "dpll_core" }; + PNAME(mux_usb480m_phy_p) = { "usb480m_phy0", "usb480m_phy1" }; + PNAME(mux_usb480m_p) = { "usb480m_phy", "xin24m" }; + PNAME(mux_hdmiphy_p) = { "hdmiphy_phy", "xin24m" }; +@@ -225,6 +225,12 @@ static struct rockchip_clk_branch rk3228_clk_branches[] __initdata = { + RK2928_CLKGATE_CON(7), 0, GFLAGS), + + /* PD_CORE */ ++ GATE(0, "apll_core", "apll", CLK_IGNORE_UNUSED, ++ PX30_CLKGATE_CON(0), 6, GFLAGS), ++ GATE(0, "gpll_core", "gpll", CLK_IGNORE_UNUSED, ++ PX30_CLKGATE_CON(0), 6, GFLAGS), ++ GATE(0, "dpll_core", "dpll", CLK_IGNORE_UNUSED, ++ PX30_CLKGATE_CON(0), 6, GFLAGS), + COMPOSITE_NOMUX(0, "pclk_dbg", "armclk", CLK_IGNORE_UNUSED, + RK2928_CLKSEL_CON(1), 0, 4, DFLAGS | CLK_DIVIDER_READ_ONLY, + RK2928_CLKGATE_CON(4), 1, GFLAGS), + +From bdbce1840c0b73a5e5c01576fb394d1719736ee8 Mon Sep 17 00:00:00 2001 +From: Finley Xiao +Date: Sun, 18 Mar 2018 21:42:22 +0800 +Subject: [PATCH] clk: rockchip: rk3228: remove the flag ROCKCHIP_PLL_SYNC_RATE + for GPLL + +To slove the display shaking, when uboot logo display to kernel show. + +Change-Id: Ifc97f72df27b4e8dbcd34ab8ed65ac027fd424d1 +Signed-off-by: Finley Xiao +--- + drivers/clk/rockchip/clk-rk3228.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/clk/rockchip/clk-rk3228.c b/drivers/clk/rockchip/clk-rk3228.c +index 00c5b8a1e295..5e9c6986e541 100644 +--- a/drivers/clk/rockchip/clk-rk3228.c ++++ b/drivers/clk/rockchip/clk-rk3228.c +@@ -170,7 +170,7 @@ static struct rockchip_pll_clock rk3228_pll_clks[] __initdata = { + [cpll] = PLL(pll_rk3036, PLL_CPLL, "cpll", mux_pll_p, 0, RK2928_PLL_CON(6), + RK2928_MODE_CON, 8, 8, 0, NULL), + [gpll] = PLL(pll_rk3036, PLL_GPLL, "gpll", mux_pll_p, 0, RK2928_PLL_CON(9), +- RK2928_MODE_CON, 12, 9, ROCKCHIP_PLL_SYNC_RATE, rk3228_pll_rates), ++ RK2928_MODE_CON, 12, 9, 0, rk3228_pll_rates), + }; + + #define MFLAGS CLK_MUX_HIWORD_MASK + +From 0b7003eb4fe6803d6f6071758f069fd7a63f096a Mon Sep 17 00:00:00 2001 +From: Elaine Zhang +Date: Tue, 25 Dec 2018 14:58:30 +0800 +Subject: [PATCH] clk: rockchip: rk322x: fix up the gate con description error + +Change-Id: I439314c590a7144fab6e33d1fb4f325530669842 +Signed-off-by: Elaine Zhang +--- + drivers/clk/rockchip/clk-rk3228.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/clk/rockchip/clk-rk3228.c b/drivers/clk/rockchip/clk-rk3228.c +index 5e9c6986e541..448b202bf4f3 100644 +--- a/drivers/clk/rockchip/clk-rk3228.c ++++ b/drivers/clk/rockchip/clk-rk3228.c +@@ -226,11 +226,11 @@ static struct rockchip_clk_branch rk3228_clk_branches[] __initdata = { + + /* PD_CORE */ + GATE(0, "apll_core", "apll", CLK_IGNORE_UNUSED, +- PX30_CLKGATE_CON(0), 6, GFLAGS), ++ RK2928_CLKGATE_CON(0), 6, GFLAGS), + GATE(0, "gpll_core", "gpll", CLK_IGNORE_UNUSED, +- PX30_CLKGATE_CON(0), 6, GFLAGS), ++ RK2928_CLKGATE_CON(0), 6, GFLAGS), + GATE(0, "dpll_core", "dpll", CLK_IGNORE_UNUSED, +- PX30_CLKGATE_CON(0), 6, GFLAGS), ++ RK2928_CLKGATE_CON(0), 6, GFLAGS), + COMPOSITE_NOMUX(0, "pclk_dbg", "armclk", CLK_IGNORE_UNUSED, + RK2928_CLKSEL_CON(1), 0, 4, DFLAGS | CLK_DIVIDER_READ_ONLY, + RK2928_CLKGATE_CON(4), 1, GFLAGS), + +From 8c78a060509051d135fceaaddd45aa8f3991298f Mon Sep 17 00:00:00 2001 +From: Alex Bee +Date: Sun, 16 Aug 2020 16:52:03 +0200 +Subject: [PATCH] clk: rockchip: add CLOCK_IGNORE_UNUSED to serval RK3228 clks + +Some clocks need the CLOCK_IGNORE_UNUSED flag in order to be prevented from being +disabled at boot time and to get respective devices working. +Has been taken from vendor kernel. +--- + drivers/clk/rockchip/clk-rk3228.c | 58 +++++++++++++++---------------- + 1 file changed, 29 insertions(+), 29 deletions(-) + +diff --git a/drivers/clk/rockchip/clk-rk3228.c b/drivers/clk/rockchip/clk-rk3228.c +index 448b202bf4f3..e6654938d6bd 100644 +--- a/drivers/clk/rockchip/clk-rk3228.c ++++ b/drivers/clk/rockchip/clk-rk3228.c +@@ -510,12 +510,12 @@ static struct rockchip_clk_branch rk3228_clk_branches[] __initdata = { + + /* PD_VOP */ + GATE(ACLK_RGA, "aclk_rga", "aclk_rga_pre", 0, RK2928_CLKGATE_CON(13), 0, GFLAGS), +- GATE(0, "aclk_rga_noc", "aclk_rga_pre", 0, RK2928_CLKGATE_CON(13), 11, GFLAGS), ++ GATE(0, "aclk_rga_noc", "aclk_rga_pre", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(13), 11, GFLAGS), + GATE(ACLK_IEP, "aclk_iep", "aclk_iep_pre", 0, RK2928_CLKGATE_CON(13), 2, GFLAGS), +- GATE(0, "aclk_iep_noc", "aclk_iep_pre", 0, RK2928_CLKGATE_CON(13), 9, GFLAGS), ++ GATE(0, "aclk_iep_noc", "aclk_iep_pre", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(13), 9, GFLAGS), + + GATE(ACLK_VOP, "aclk_vop", "aclk_vop_pre", 0, RK2928_CLKGATE_CON(13), 5, GFLAGS), +- GATE(0, "aclk_vop_noc", "aclk_vop_pre", 0, RK2928_CLKGATE_CON(13), 12, GFLAGS), ++ GATE(0, "aclk_vop_noc", "aclk_vop_pre", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(13), 12, GFLAGS), + + GATE(ACLK_HDCP, "aclk_hdcp", "aclk_hdcp_pre", 0, RK2928_CLKGATE_CON(14), 10, GFLAGS), + GATE(0, "aclk_hdcp_noc", "aclk_hdcp_pre", 0, RK2928_CLKGATE_CON(13), 10, GFLAGS), +@@ -523,13 +523,13 @@ static struct rockchip_clk_branch rk3228_clk_branches[] __initdata = { + GATE(HCLK_RGA, "hclk_rga", "hclk_vio_pre", 0, RK2928_CLKGATE_CON(13), 1, GFLAGS), + GATE(HCLK_IEP, "hclk_iep", "hclk_vio_pre", 0, RK2928_CLKGATE_CON(13), 3, GFLAGS), + GATE(HCLK_VOP, "hclk_vop", "hclk_vio_pre", 0, RK2928_CLKGATE_CON(13), 6, GFLAGS), +- GATE(0, "hclk_vio_ahb_arbi", "hclk_vio_pre", 0, RK2928_CLKGATE_CON(13), 7, GFLAGS), +- GATE(0, "hclk_vio_noc", "hclk_vio_pre", 0, RK2928_CLKGATE_CON(13), 8, GFLAGS), +- GATE(0, "hclk_vop_noc", "hclk_vio_pre", 0, RK2928_CLKGATE_CON(13), 13, GFLAGS), +- GATE(HCLK_VIO_H2P, "hclk_vio_h2p", "hclk_vio_pre", 0, RK2928_CLKGATE_CON(14), 7, GFLAGS), ++ GATE(0, "hclk_vio_ahb_arbi", "hclk_vio_pre", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(13), 7, GFLAGS), ++ GATE(0, "hclk_vio_noc", "hclk_vio_pre", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(13), 8, GFLAGS), ++ GATE(0, "hclk_vop_noc", "hclk_vio_pre", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(13), 13, GFLAGS), ++ GATE(HCLK_VIO_H2P, "hclk_vio_h2p", "hclk_vio_pre", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(14), 7, GFLAGS), + GATE(HCLK_HDCP_MMU, "hclk_hdcp_mmu", "hclk_vio_pre", 0, RK2928_CLKGATE_CON(14), 12, GFLAGS), + GATE(PCLK_HDMI_CTRL, "pclk_hdmi_ctrl", "hclk_vio_pre", 0, RK2928_CLKGATE_CON(14), 6, GFLAGS), +- GATE(PCLK_VIO_H2P, "pclk_vio_h2p", "hclk_vio_pre", 0, RK2928_CLKGATE_CON(14), 8, GFLAGS), ++ GATE(PCLK_VIO_H2P, "pclk_vio_h2p", "hclk_vio_pre", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(14), 8, GFLAGS), + GATE(PCLK_HDCP, "pclk_hdcp", "hclk_vio_pre", 0, RK2928_CLKGATE_CON(14), 11, GFLAGS), + + /* PD_PERI */ +@@ -541,13 +541,13 @@ static struct rockchip_clk_branch rk3228_clk_branches[] __initdata = { + GATE(HCLK_EMMC, "hclk_emmc", "hclk_peri", 0, RK2928_CLKGATE_CON(11), 2, GFLAGS), + GATE(HCLK_NANDC, "hclk_nandc", "hclk_peri", 0, RK2928_CLKGATE_CON(11), 3, GFLAGS), + GATE(HCLK_HOST0, "hclk_host0", "hclk_peri", 0, RK2928_CLKGATE_CON(11), 6, GFLAGS), +- GATE(0, "hclk_host0_arb", "hclk_peri", 0, RK2928_CLKGATE_CON(11), 7, GFLAGS), ++ GATE(0, "hclk_host0_arb", "hclk_peri", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(11), 7, GFLAGS), + GATE(HCLK_HOST1, "hclk_host1", "hclk_peri", 0, RK2928_CLKGATE_CON(11), 8, GFLAGS), +- GATE(0, "hclk_host1_arb", "hclk_peri", 0, RK2928_CLKGATE_CON(11), 9, GFLAGS), ++ GATE(0, "hclk_host1_arb", "hclk_peri", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(11), 9, GFLAGS), + GATE(HCLK_HOST2, "hclk_host2", "hclk_peri", 0, RK2928_CLKGATE_CON(11), 10, GFLAGS), + GATE(HCLK_OTG, "hclk_otg", "hclk_peri", 0, RK2928_CLKGATE_CON(11), 12, GFLAGS), +- GATE(0, "hclk_otg_pmu", "hclk_peri", 0, RK2928_CLKGATE_CON(11), 13, GFLAGS), +- GATE(0, "hclk_host2_arb", "hclk_peri", 0, RK2928_CLKGATE_CON(11), 14, GFLAGS), ++ GATE(0, "hclk_otg_pmu", "hclk_peri", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(11), 13, GFLAGS), ++ GATE(0, "hclk_host2_arb", "hclk_peri", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(11), 14, GFLAGS), + GATE(0, "hclk_peri_noc", "hclk_peri", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(12), 1, GFLAGS), + + GATE(PCLK_GMAC, "pclk_gmac", "pclk_peri", 0, RK2928_CLKGATE_CON(11), 5, GFLAGS), +@@ -555,15 +555,15 @@ static struct rockchip_clk_branch rk3228_clk_branches[] __initdata = { + + /* PD_GPU */ + GATE(ACLK_GPU, "aclk_gpu", "aclk_gpu_pre", 0, RK2928_CLKGATE_CON(7), 14, GFLAGS), +- GATE(0, "aclk_gpu_noc", "aclk_gpu_pre", 0, RK2928_CLKGATE_CON(7), 15, GFLAGS), ++ GATE(0, "aclk_gpu_noc", "aclk_gpu_pre", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(7), 15, GFLAGS), + + /* PD_BUS */ +- GATE(0, "sclk_initmem_mbist", "aclk_cpu", 0, RK2928_CLKGATE_CON(8), 1, GFLAGS), +- GATE(0, "aclk_initmem", "aclk_cpu", 0, RK2928_CLKGATE_CON(8), 0, GFLAGS), ++ GATE(0, "sclk_initmem_mbist", "aclk_cpu", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(8), 1, GFLAGS), ++ GATE(0, "aclk_initmem", "aclk_cpu", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(8), 0, GFLAGS), + GATE(ACLK_DMAC, "aclk_dmac_bus", "aclk_cpu", 0, RK2928_CLKGATE_CON(8), 2, GFLAGS), + GATE(0, "aclk_bus_noc", "aclk_cpu", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(10), 1, GFLAGS), + +- GATE(0, "hclk_rom", "hclk_cpu", 0, RK2928_CLKGATE_CON(8), 3, GFLAGS), ++ GATE(0, "hclk_rom", "hclk_cpu", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(8), 3, GFLAGS), + GATE(HCLK_I2S0_8CH, "hclk_i2s0_8ch", "hclk_cpu", 0, RK2928_CLKGATE_CON(8), 7, GFLAGS), + GATE(HCLK_I2S1_8CH, "hclk_i2s1_8ch", "hclk_cpu", 0, RK2928_CLKGATE_CON(8), 8, GFLAGS), + GATE(HCLK_I2S2_2CH, "hclk_i2s2_2ch", "hclk_cpu", 0, RK2928_CLKGATE_CON(8), 9, GFLAGS), +@@ -572,9 +572,9 @@ static struct rockchip_clk_branch rk3228_clk_branches[] __initdata = { + GATE(HCLK_M_CRYPTO, "hclk_crypto_mst", "hclk_cpu", 0, RK2928_CLKGATE_CON(8), 11, GFLAGS), + GATE(HCLK_S_CRYPTO, "hclk_crypto_slv", "hclk_cpu", 0, RK2928_CLKGATE_CON(8), 12, GFLAGS), + +- GATE(0, "pclk_ddrupctl", "pclk_ddr_pre", 0, RK2928_CLKGATE_CON(8), 4, GFLAGS), +- GATE(0, "pclk_ddrmon", "pclk_ddr_pre", 0, RK2928_CLKGATE_CON(8), 6, GFLAGS), +- GATE(0, "pclk_msch_noc", "pclk_ddr_pre", 0, RK2928_CLKGATE_CON(10), 2, GFLAGS), ++ GATE(0, "pclk_ddrupctl", "pclk_ddr_pre", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(8), 4, GFLAGS), ++ GATE(0, "pclk_ddrmon", "pclk_ddr_pre", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(8), 6, GFLAGS), ++ GATE(0, "pclk_msch_noc", "pclk_ddr_pre", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(10), 2, GFLAGS), + + GATE(PCLK_EFUSE_1024, "pclk_efuse_1024", "pclk_cpu", 0, RK2928_CLKGATE_CON(8), 13, GFLAGS), + GATE(PCLK_EFUSE_256, "pclk_efuse_256", "pclk_cpu", 0, RK2928_CLKGATE_CON(8), 14, GFLAGS), +@@ -583,7 +583,7 @@ static struct rockchip_clk_branch rk3228_clk_branches[] __initdata = { + GATE(PCLK_I2C2, "pclk_i2c2", "pclk_cpu", 0, RK2928_CLKGATE_CON(9), 1, GFLAGS), + GATE(PCLK_I2C3, "pclk_i2c3", "pclk_cpu", 0, RK2928_CLKGATE_CON(9), 2, GFLAGS), + GATE(PCLK_TIMER, "pclk_timer0", "pclk_cpu", 0, RK2928_CLKGATE_CON(9), 4, GFLAGS), +- GATE(0, "pclk_stimer", "pclk_cpu", 0, RK2928_CLKGATE_CON(9), 5, GFLAGS), ++ GATE(0, "pclk_stimer", "pclk_cpu", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(9), 5, GFLAGS), + GATE(PCLK_SPI0, "pclk_spi0", "pclk_cpu", 0, RK2928_CLKGATE_CON(9), 6, GFLAGS), + GATE(PCLK_PWM, "pclk_rk_pwm", "pclk_cpu", 0, RK2928_CLKGATE_CON(9), 7, GFLAGS), + GATE(PCLK_GPIO0, "pclk_gpio0", "pclk_cpu", 0, RK2928_CLKGATE_CON(9), 8, GFLAGS), +@@ -597,22 +597,22 @@ static struct rockchip_clk_branch rk3228_clk_branches[] __initdata = { + GATE(PCLK_GRF, "pclk_grf", "pclk_cpu", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(10), 0, GFLAGS), + GATE(0, "pclk_cru", "pclk_cpu", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(10), 1, GFLAGS), + GATE(0, "pclk_sgrf", "pclk_cpu", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(10), 2, GFLAGS), +- GATE(0, "pclk_sim", "pclk_cpu", 0, RK2928_CLKGATE_CON(10), 3, GFLAGS), ++ GATE(0, "pclk_sim", "pclk_cpu", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(10), 3, GFLAGS), + +- GATE(0, "pclk_ddrphy", "pclk_phy_pre", 0, RK2928_CLKGATE_CON(10), 3, GFLAGS), +- GATE(0, "pclk_acodecphy", "pclk_phy_pre", 0, RK2928_CLKGATE_CON(10), 5, GFLAGS), ++ GATE(0, "pclk_ddrphy", "pclk_phy_pre", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(10), 3, GFLAGS), ++ GATE(0, "pclk_acodecphy", "pclk_phy_pre", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(10), 5, GFLAGS), + GATE(PCLK_HDMI_PHY, "pclk_hdmiphy", "pclk_phy_pre", 0, RK2928_CLKGATE_CON(10), 7, GFLAGS), +- GATE(0, "pclk_vdacphy", "pclk_phy_pre", 0, RK2928_CLKGATE_CON(10), 8, GFLAGS), +- GATE(0, "pclk_phy_noc", "pclk_phy_pre", 0, RK2928_CLKGATE_CON(10), 9, GFLAGS), ++ GATE(0, "pclk_vdacphy", "pclk_phy_pre", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(10), 8, GFLAGS), ++ GATE(0, "pclk_phy_noc", "pclk_phy_pre", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(10), 9, GFLAGS), + + GATE(ACLK_VPU, "aclk_vpu", "aclk_vpu_pre", 0, RK2928_CLKGATE_CON(15), 0, GFLAGS), +- GATE(0, "aclk_vpu_noc", "aclk_vpu_pre", 0, RK2928_CLKGATE_CON(15), 4, GFLAGS), ++ GATE(0, "aclk_vpu_noc", "aclk_vpu_pre", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(15), 4, GFLAGS), + GATE(ACLK_RKVDEC, "aclk_rkvdec", "aclk_rkvdec_pre", 0, RK2928_CLKGATE_CON(15), 2, GFLAGS), +- GATE(0, "aclk_rkvdec_noc", "aclk_rkvdec_pre", 0, RK2928_CLKGATE_CON(15), 6, GFLAGS), ++ GATE(0, "aclk_rkvdec_noc", "aclk_rkvdec_pre", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(15), 6, GFLAGS), + GATE(HCLK_VPU, "hclk_vpu", "hclk_vpu_pre", 0, RK2928_CLKGATE_CON(15), 1, GFLAGS), +- GATE(0, "hclk_vpu_noc", "hclk_vpu_pre", 0, RK2928_CLKGATE_CON(15), 5, GFLAGS), ++ GATE(0, "hclk_vpu_noc", "hclk_vpu_pre", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(15), 5, GFLAGS), + GATE(HCLK_RKVDEC, "hclk_rkvdec", "hclk_rkvdec_pre", 0, RK2928_CLKGATE_CON(15), 3, GFLAGS), +- GATE(0, "hclk_rkvdec_noc", "hclk_rkvdec_pre", 0, RK2928_CLKGATE_CON(15), 7, GFLAGS), ++ GATE(0, "hclk_rkvdec_noc", "hclk_rkvdec_pre", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(15), 7, GFLAGS), + + /* PD_MMC */ + MMC(SCLK_SDMMC_DRV, "sdmmc_drv", "sclk_sdmmc", RK3228_SDMMC_CON0, 1), + +From facbc2eed0bab25a67e65387c9ac05d504fb886e Mon Sep 17 00:00:00 2001 +From: Alex Bee +Date: Sun, 16 Aug 2020 17:07:35 +0200 +Subject: [PATCH] clk: rockchip add aclk_rkvdec and hclk_rkvdec to RK3228 + critical clocks + +To be prevented from being disabled at any time add aclk_rkvdec and hclk_rkvdec +to RK3228 critical clocks +--- + drivers/clk/rockchip/clk-rk3228.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/clk/rockchip/clk-rk3228.c b/drivers/clk/rockchip/clk-rk3228.c +index e6654938d6bd..595ad0301ca6 100644 +--- a/drivers/clk/rockchip/clk-rk3228.c ++++ b/drivers/clk/rockchip/clk-rk3228.c +@@ -656,8 +656,10 @@ static const char *const rk3228_critical_clocks[] __initconst = { + "pclk_phy_noc", + "aclk_vpu_noc", + "aclk_rkvdec_noc", ++ "aclk_rkvdec", + "hclk_vpu_noc", + "hclk_rkvdec_noc", ++ "hclk_rkvdec", + }; + + static void __init rk3228_clk_init(struct device_node *np) + +From 4a3f15e1bc2fb7cb7c093e2814dbc9f447e82bbc Mon Sep 17 00:00:00 2001 +From: Alex Bee +Date: Fri, 24 Apr 2020 11:42:58 +0200 +Subject: [PATCH] soc: rockchip: Support powerdomains which don't need / + support to be switched on / off + +Taken from https://github.com/rockchip-linux/kernel/commit/5be2cb19cf8e678655b59ec70c6a5f66f08d9418 +--- + drivers/soc/rockchip/pm_domains.c | 23 +++++++++++++++++++++++ + 1 file changed, 23 insertions(+) + +diff --git a/drivers/soc/rockchip/pm_domains.c b/drivers/soc/rockchip/pm_domains.c +index 727af107e6d3..3688e9e67872 100644 +--- a/drivers/soc/rockchip/pm_domains.c ++++ b/drivers/soc/rockchip/pm_domains.c +@@ -71,6 +71,7 @@ struct rockchip_pm_domain { + struct regmap **qos_regmap; + u32 *qos_save_regs[MAX_QOS_REGS_NUM]; + int num_clks; ++ bool is_ignore_pwr; + struct clk_bulk_data *clks; + }; + +@@ -353,6 +354,9 @@ static int rockchip_pd_power_on(struct generic_pm_domain *domain) + { + struct rockchip_pm_domain *pd = to_rockchip_pd(domain); + ++ if (pd->is_ignore_pwr) ++ return 0; ++ + return rockchip_pd_power(pd, true); + } + +@@ -360,6 +364,9 @@ static int rockchip_pd_power_off(struct generic_pm_domain *domain) + { + struct rockchip_pm_domain *pd = to_rockchip_pd(domain); + ++ if (pd->is_ignore_pwr) ++ return 0; ++ + return rockchip_pd_power(pd, false); + } + +@@ -439,6 +446,9 @@ static int rockchip_pm_add_one_domain(struct rockchip_pmu *pmu, + pd->info = pd_info; + pd->pmu = pmu; + ++ if (!pd_info->pwr_mask) ++ pd->is_ignore_pwr = true; ++ + pd->num_clks = of_clk_get_parent_count(node); + if (pd->num_clks > 0) { + pd->clks = devm_kcalloc(pmu->dev, pd->num_clks, +@@ -589,6 +599,7 @@ static int rockchip_pm_add_subdomain(struct rockchip_pmu *pmu, + { + struct device_node *np; + struct generic_pm_domain *child_domain, *parent_domain; ++ struct rockchip_pm_domain *child_pd, *parent_pd; + int error; + + for_each_child_of_node(parent, np) { +@@ -629,6 +640,18 @@ static int rockchip_pm_add_subdomain(struct rockchip_pmu *pmu, + parent_domain->name, child_domain->name); + } + ++ /* ++ * If child_pd doesn't do idle request or power on/off, ++ * parent_pd may fail to do power on/off, so if parent_pd ++ * need to power on/off, child_pd can't ignore to do idle ++ * request and power on/off. ++ */ ++ child_pd = to_rockchip_pd(child_domain); ++ parent_pd = to_rockchip_pd(parent_domain); ++ if (!parent_pd->is_ignore_pwr) ++ child_pd->is_ignore_pwr = false; ++ ++ + rockchip_pm_add_subdomain(pmu, np); + } + + +From 02a2d327ebfce5e3b4ddd839c2cf3b9631c38b91 Mon Sep 17 00:00:00 2001 +From: Alex Bee +Date: Fri, 24 Apr 2020 13:01:07 +0200 +Subject: [PATCH] sound: soc: rockchip: use rouned rate for i2s + +--- + sound/soc/rockchip/rockchip_i2s.c | 9 +++++++-- + 1 file changed, 7 insertions(+), 2 deletions(-) + +diff --git a/sound/soc/rockchip/rockchip_i2s.c b/sound/soc/rockchip/rockchip_i2s.c +index 61c984f10d8e..efca853eba6b 100644 +--- a/sound/soc/rockchip/rockchip_i2s.c ++++ b/sound/soc/rockchip/rockchip_i2s.c +@@ -279,10 +279,13 @@ static int rockchip_i2s_hw_params(struct snd_pcm_substream *substream, + if (i2s->is_master_mode) { + mclk_rate = clk_get_rate(i2s->mclk); + bclk_rate = 2 * 32 * params_rate(params); +- if (bclk_rate && mclk_rate % bclk_rate) ++ if (!bclk_rate) { ++ dev_err(i2s->dev, "invalid bclk_rate: %d\n", ++ bclk_rate); + return -EINVAL; ++ } + +- div_bclk = mclk_rate / bclk_rate; ++ div_bclk = DIV_ROUND_CLOSEST(mclk_rate, bclk_rate); + div_lrck = bclk_rate / params_rate(params); + regmap_update_bits(i2s->regmap, I2S_CKR, + I2S_CKR_MDIV_MASK, +@@ -312,6 +315,8 @@ static int rockchip_i2s_hw_params(struct snd_pcm_substream *substream, + val |= I2S_TXCR_VDW(32); + break; + default: ++ dev_err(i2s->dev, "invalid format: %d\n", ++ params_format(params)); + return -EINVAL; + } + + +From 824bce392cfdaaf0037f33637078e722a9f757b9 Mon Sep 17 00:00:00 2001 +From: Alex Bee +Date: Fri, 24 Apr 2020 09:08:44 +0200 +Subject: [PATCH] phy: rockchip: hdmi: readout hdmi phy flag for RK3228 HDMI + phys + +Some RK3228 HDMI phys only get a stable pll on frequencies higher 33,75 MHz. +This is defined in a flag in efuse of those devices. +--- + arch/arm/boot/dts/rk322x.dtsi | 6 +++ + drivers/phy/rockchip/phy-rockchip-inno-hdmi.c | 38 ++++++++++++++++++- + 2 files changed, 42 insertions(+), 2 deletions(-) + +diff --git a/arch/arm/boot/dts/rk322x.dtsi b/arch/arm/boot/dts/rk322x.dtsi +index eec601fb4cd0..81dfdc8c864a 100644 +--- a/arch/arm/boot/dts/rk322x.dtsi ++++ b/arch/arm/boot/dts/rk322x.dtsi +@@ -340,6 +340,10 @@ efuse_id: id@7 { + cpu_leakage: cpu_leakage@17 { + reg = <0x17 0x1>; + }; ++ hdmi_phy_flag: hdmi-phy-flag@1d { ++ reg = <0x1d 0x1>; ++ bits = <1 1>; ++ }; + }; + + i2c0: i2c@11050000 { +@@ -559,6 +563,8 @@ hdmi_phy: hdmi-phy@12030000 { + clock-names = "sysclk", "refoclk", "refpclk"; + #clock-cells = <0>; + clock-output-names = "hdmiphy_phy"; ++ nvmem-cells = <&hdmi_phy_flag>; ++ nvmem-cell-names = "hdmi-phy-flag"; + #phy-cells = <0>; + status = "disabled"; + }; +diff --git a/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c b/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c +index bb8bdf5e3301..0c7a97352714 100644 +--- a/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c ++++ b/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c +@@ -237,6 +237,9 @@ struct inno_hdmi_phy { + struct clk *refoclk; + struct clk *refpclk; + ++ /* phy_flag flag */ ++ bool phy_flag; ++ + /* platform data */ + const struct inno_hdmi_phy_drv_data *plat_data; + int chip_version; +@@ -347,6 +350,7 @@ static const struct pre_pll_config pre_pll_cfg_table[] = { + static const struct post_pll_config post_pll_cfg_table[] = { + {33750000, 1, 40, 8, 1}, + {33750000, 1, 80, 8, 2}, ++ {33750000, 1, 10, 2, 4}, + {74250000, 1, 40, 8, 1}, + {74250000, 18, 80, 8, 2}, + {148500000, 2, 40, 4, 3}, +@@ -497,8 +501,11 @@ static int inno_hdmi_phy_power_on(struct phy *phy) + return -EINVAL; + + for (; cfg->tmdsclock != 0; cfg++) +- if (tmdsclock <= cfg->tmdsclock && +- cfg->version & inno->chip_version) ++ if (((!inno->phy_flag || tmdsclock > 33750000) ++ && tmdsclock <= cfg->tmdsclock ++ && cfg->version & inno->chip_version) || ++ (inno->phy_flag && tmdsclock <= 33750000 ++ && cfg->version & 4)) + break; + + for (; phy_cfg->tmdsclock != 0; phy_cfg++) +@@ -909,6 +916,10 @@ static int inno_hdmi_phy_clk_register(struct inno_hdmi_phy *inno) + + static int inno_hdmi_phy_rk3228_init(struct inno_hdmi_phy *inno) + { ++ struct nvmem_cell *cell; ++ unsigned char *efuse_buf; ++ size_t len; ++ + /* + * Use phy internal register control + * rxsense/poweron/pllpd/pdataen signal. +@@ -923,7 +934,28 @@ static int inno_hdmi_phy_rk3228_init(struct inno_hdmi_phy *inno) + inno_update_bits(inno, 0xaa, RK3228_POST_PLL_CTRL_MANUAL, + RK3228_POST_PLL_CTRL_MANUAL); + ++ + inno->chip_version = 1; ++ inno->phy_flag = false; ++ ++ cell = nvmem_cell_get(inno->dev, "hdmi-phy-flag"); ++ if (IS_ERR(cell)) { ++ if (PTR_ERR(cell) == -EPROBE_DEFER) ++ return -EPROBE_DEFER; ++ ++ return 0; ++ } ++ ++ efuse_buf = nvmem_cell_read(cell, &len); ++ nvmem_cell_put(cell); ++ ++ if (IS_ERR(efuse_buf)) ++ return 0; ++ if (len == 1) ++ inno->phy_flag = (efuse_buf[0] & BIT(1)) ? true : false; ++ kfree(efuse_buf); ++ ++ dev_info(inno->dev, "phy_flag is: %d\n", inno->phy_flag); + + return 0; + } +@@ -1023,6 +1055,8 @@ static int inno_hdmi_phy_rk3328_init(struct inno_hdmi_phy *inno) + + /* try to read the chip-version */ + inno->chip_version = 1; ++ inno->phy_flag = false; ++ + cell = nvmem_cell_get(inno->dev, "cpu-version"); + if (IS_ERR(cell)) { + if (PTR_ERR(cell) == -EPROBE_DEFER) + +From ac8834648e1e35703f6a0533b7c90b24d0d537da Mon Sep 17 00:00:00 2001 +From: Alex Bee +Date: Tue, 26 May 2020 14:41:39 +0200 +Subject: [PATCH] usb: dwc2: QUIRKS: rockchip host only controller needs longer + msleep to initialize + +--- + drivers/usb/dwc2/core.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/usb/dwc2/core.c b/drivers/usb/dwc2/core.c +index fec17a2d2447..eb55c64f63be 100644 +--- a/drivers/usb/dwc2/core.c ++++ b/drivers/usb/dwc2/core.c +@@ -663,7 +663,7 @@ void dwc2_force_dr_mode(struct dwc2_hsotg *hsotg) + * platforms on their host-only dwc2. + */ + if (!dwc2_hw_is_otg(hsotg)) +- msleep(50); ++ msleep(200); + + break; + case USB_DR_MODE_PERIPHERAL: + +From 98c3cfe4ee409e64edcb9dff8341637588c9e166 Mon Sep 17 00:00:00 2001 +From: Alex Bee +Date: Sun, 16 Aug 2020 17:35:43 +0200 +Subject: [PATCH] nvmem: rockchip-efuse: fix RK3188 efuse read + +In order to read from RK3188s efuse, the logic is slightly different from whats +done currently for RK3288 and also used for this SoC. +Logic, register mask and udelays have been taken from vendor kernel. +--- + drivers/nvmem/rockchip-efuse.c | 49 +++++++++++++++++++++++++++++++++- + 1 file changed, 48 insertions(+), 1 deletion(-) + +diff --git a/drivers/nvmem/rockchip-efuse.c b/drivers/nvmem/rockchip-efuse.c +index e4579de5d014..9afd71edf503 100644 +--- a/drivers/nvmem/rockchip-efuse.c ++++ b/drivers/nvmem/rockchip-efuse.c +@@ -17,6 +17,8 @@ + #include + #include + ++#define RK3188_A_MASK 0xff ++ + #define RK3288_A_SHIFT 6 + #define RK3288_A_MASK 0x3ff + #define RK3288_PGENB BIT(3) +@@ -52,6 +54,51 @@ struct rockchip_efuse_chip { + struct clk *clk; + }; + ++static int rockchip_rk3188_efuse_read(void *context, unsigned int offset, ++ void *val, size_t bytes) ++{ ++ struct rockchip_efuse_chip *efuse = context; ++ u8 *buf = val; ++ int ret; ++ ++ ret = clk_prepare_enable(efuse->clk); ++ if (ret < 0) { ++ dev_err(efuse->dev, "failed to prepare/enable efuse clk\n"); ++ return ret; ++ } ++ ++ writel(RK3288_CSB, efuse->base + REG_EFUSE_CTRL); ++ writel(RK3288_LOAD | RK3288_PGENB, efuse->base + REG_EFUSE_CTRL); ++ udelay(2); ++ ++ while (bytes--) { ++ writel(readl(efuse->base + REG_EFUSE_CTRL) & ++ (~(RK3188_A_MASK << RK3288_A_SHIFT)), ++ efuse->base + REG_EFUSE_CTRL); ++ writel(readl(efuse->base + REG_EFUSE_CTRL) | ++ ((offset++ & RK3188_A_MASK) << RK3288_A_SHIFT), ++ efuse->base + REG_EFUSE_CTRL); ++ udelay(2); ++ writel(readl(efuse->base + REG_EFUSE_CTRL) | ++ RK3288_STROBE, efuse->base + REG_EFUSE_CTRL); ++ udelay(2); ++ ++ *buf++ = readl(efuse->base + REG_EFUSE_DOUT); ++ writel(readl(efuse->base + REG_EFUSE_CTRL) & ++ (~RK3288_STROBE), efuse->base + REG_EFUSE_CTRL); ++ udelay(2); ++ } ++ ++ udelay(2); ++ /* Switch to standby mode */ ++ writel(RK3288_PGENB | RK3288_CSB, efuse->base + REG_EFUSE_CTRL); ++ udelay(1); ++ ++ clk_disable_unprepare(efuse->clk); ++ ++ return 0; ++} ++ + static int rockchip_rk3288_efuse_read(void *context, unsigned int offset, + void *val, size_t bytes) + { +@@ -222,7 +269,7 @@ static const struct of_device_id rockchip_efuse_match[] = { + }, + { + .compatible = "rockchip,rk3188-efuse", +- .data = (void *)&rockchip_rk3288_efuse_read, ++ .data = (void *)&rockchip_rk3188_efuse_read, + }, + { + .compatible = "rockchip,rk3228-efuse", + +From e95330563d2dfd9086ac3cadee0129b045c7a25d Mon Sep 17 00:00:00 2001 +From: Alex Bee +Date: Sun, 16 Aug 2020 17:43:08 +0200 +Subject: [PATCH] ARM: dts: rockchip: fix RK3188 efuse register width + +As with most Rockchip SoCs the RK3188s non-secure efuse contains 32 bytes of data. +This adapts the register width, so that we don't get repeated data when reading +out the values from it. +--- + arch/arm/boot/dts/rk3188.dtsi | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm/boot/dts/rk3188.dtsi b/arch/arm/boot/dts/rk3188.dtsi +index b6c1699345d0..9fab375231ec 100644 +--- a/arch/arm/boot/dts/rk3188.dtsi ++++ b/arch/arm/boot/dts/rk3188.dtsi +@@ -216,7 +216,7 @@ cru: clock-controller@20000000 { + + efuse: efuse@20010000 { + compatible = "rockchip,rk3188-efuse"; +- reg = <0x20010000 0x4000>; ++ reg = <0x20010000 0x20>; + #address-cells = <1>; + #size-cells = <1>; + clocks = <&cru PCLK_EFUSE>; + +From e12fc84e0782e332a2d309cc89f52119eee55de3 Mon Sep 17 00:00:00 2001 +From: Alex Bee +Date: Sun, 16 Aug 2020 18:51:38 +0200 +Subject: [PATCH] ARM: dts: rockchip add operating-points, power-domain for + RK322Xs GPU + +This adds the operating-points table and the power-domain and the respective +qos registers for RK322xs GPU. +While at this it also adds the GPU to be a cooling cell. +--- + arch/arm/boot/dts/rk322x.dtsi | 39 ++++++++++++++++++++++++++++++++++- + 1 file changed, 38 insertions(+), 1 deletion(-) + +diff --git a/arch/arm/boot/dts/rk322x.dtsi b/arch/arm/boot/dts/rk322x.dtsi +index 81dfdc8c864a..9e531d229ae1 100644 +--- a/arch/arm/boot/dts/rk322x.dtsi ++++ b/arch/arm/boot/dts/rk322x.dtsi +@@ -215,6 +215,12 @@ power: power-controller { + #address-cells = <1>; + #size-cells = <0>; + ++ pd_gpu@RK3228_PD_GPU { ++ reg = ; ++ clocks = <&cru ACLK_GPU>; ++ pm_qos = <&qos_gpu>; ++ }; ++ + pd_vpu@RK3228_PD_VPU { + reg = ; + clocks = <&cru ACLK_VPU>, <&cru HCLK_VPU>; +@@ -533,6 +539,11 @@ map1 { + <&cpu2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + }; ++ map2 { ++ trip = <&cpu_alert1>; ++ cooling-device = ++ <&gpu THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; ++ }; + }; + }; + }; +@@ -587,7 +598,28 @@ gpu: gpu@20000000 { + clocks = <&cru ACLK_GPU>, <&cru ACLK_GPU>; + clock-names = "bus", "core"; + resets = <&cru SRST_GPU_A>; +- status = "disabled"; ++ operating-points-v2 = <&gpu_opp_table>; ++ power-domains = <&power RK3228_PD_GPU>; ++ #cooling-cells = <2>; /* min followed by max */ ++ }; ++ ++ gpu_opp_table: opp-table2 { ++ compatible = "operating-points-v2"; ++ ++ opp-200000000 { ++ opp-hz = /bits/ 64 <200000000>; ++ opp-microvolt = <1050000>; ++ }; ++ ++ opp-300000000 { ++ opp-hz = /bits/ 64 <300000000>; ++ opp-microvolt = <1050000>; ++ }; ++ ++ opp-500000000 { ++ opp-hz = /bits/ 64 <500000000>; ++ opp-microvolt = <1150000>; ++ }; + }; + + vpu: video-codec@20020000 { +@@ -872,6 +904,11 @@ qos_vpu: qos@31040000 { + reg = <0x31040000 0x20>; + }; + ++ qos_gpu: qos@31050000 { ++ compatible = "syscon"; ++ reg = <0x31050000 0x20>; ++ }; ++ + qos_rkvdec_r: qos@31070000 { + compatible = "syscon"; + reg = <0x31070000 0x20>; + +From 19b4b92aa56381148255f8d962649869f734b5f9 Mon Sep 17 00:00:00 2001 +From: Alex Bee +Date: Sun, 16 Aug 2020 19:44:42 +0200 +Subject: [PATCH] ARM: dts: rockchip: add ethernet0 alias + +Add ethernet0 alias for gmac. This will, for example, be used +by u-boot to inject a "local-mac-address" in the devicetree. +--- + arch/arm/boot/dts/rk322x.dtsi | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/arch/arm/boot/dts/rk322x.dtsi b/arch/arm/boot/dts/rk322x.dtsi +index 9e531d229ae1..14eedffea4a3 100644 +--- a/arch/arm/boot/dts/rk322x.dtsi ++++ b/arch/arm/boot/dts/rk322x.dtsi +@@ -15,6 +15,7 @@ / { + interrupt-parent = <&gic>; + + aliases { ++ ethernet0 = &gmac; + serial0 = &uart0; + serial1 = &uart1; + serial2 = &uart2; + +From 7c1f6ab6b0c97b7aacaa39f842a9e8ef7bbea83e Mon Sep 17 00:00:00 2001 +From: Alex Bee +Date: Sun, 16 Aug 2020 20:00:01 +0200 +Subject: [PATCH] ARM: dts: rockchip: add hdmi simple-audio-card for RK322x + +Add "simple-audio-card" definition for hdmi-sound. While at +that also add the missing #sound-dai-cells for i2s, spdif and hdmi +nodes. +--- + arch/arm/boot/dts/rk322x.dtsi | 20 ++++++++++++++++++++ + 1 file changed, 20 insertions(+) + +diff --git a/arch/arm/boot/dts/rk322x.dtsi b/arch/arm/boot/dts/rk322x.dtsi +index 14eedffea4a3..7f15fc838c36 100644 +--- a/arch/arm/boot/dts/rk322x.dtsi ++++ b/arch/arm/boot/dts/rk322x.dtsi +@@ -124,6 +124,22 @@ arm-pmu { + interrupt-affinity = <&cpu0>, <&cpu1>, <&cpu2>, <&cpu3>; + }; + ++ hdmi_sound: hdmi-sound { ++ compatible = "simple-audio-card"; ++ simple-audio-card,name = "hdmi-sound"; ++ simple-audio-card,format = "i2s"; ++ simple-audio-card,mclk-fs = <256>; ++ status = "disabled"; ++ ++ simple-audio-card,cpu { ++ sound-dai = <&i2s0>; ++ }; ++ ++ simple-audio-card,codec { ++ sound-dai = <&hdmi>; ++ }; ++ }; ++ + psci { + compatible = "arm,psci-1.0", "arm,psci-0.2"; + method = "smc"; +@@ -161,6 +177,7 @@ i2s1: i2s1@100b0000 { + dma-names = "tx", "rx"; + pinctrl-names = "default"; + pinctrl-0 = <&i2s1_bus>; ++ #sound-dai-cells = <0>; + status = "disabled"; + }; + +@@ -172,6 +189,7 @@ i2s0: i2s0@100c0000 { + clocks = <&cru SCLK_I2S0>, <&cru HCLK_I2S0_8CH>; + dmas = <&pdma 11>, <&pdma 12>; + dma-names = "tx", "rx"; ++ #sound-dai-cells = <0>; + status = "disabled"; + }; + +@@ -185,6 +203,7 @@ spdif: spdif@100d0000 { + dma-names = "tx"; + pinctrl-names = "default"; + pinctrl-0 = <&spdif_tx>; ++ #sound-dai-cells = <0>; + status = "disabled"; + }; + +@@ -746,6 +765,7 @@ hdmi: hdmi@200a0000 { + phys = <&hdmi_phy>; + phy-names = "hdmi"; + rockchip,grf = <&grf>; ++ #sound-dai-cells = <0>; + status = "disabled"; + + ports { + +From 6fa1bf91b123f703a2fde726ad52af1539f365d0 Mon Sep 17 00:00:00 2001 +From: Alex Bee +Date: Sun, 16 Aug 2020 21:16:11 +0200 +Subject: [PATCH] ARM: dts: rockchip: add uart1-1 pins for RK322x + +Add uart uart1-1 pins. +While at this also correct the uart2 default pinctrl, which is uart21_xfer. +--- + arch/arm/boot/dts/rk322x.dtsi | 19 ++++++++++++++++++- + 1 file changed, 18 insertions(+), 1 deletion(-) + +diff --git a/arch/arm/boot/dts/rk322x.dtsi b/arch/arm/boot/dts/rk322x.dtsi +index 7f15fc838c36..693c6f18a889 100644 +--- a/arch/arm/boot/dts/rk322x.dtsi ++++ b/arch/arm/boot/dts/rk322x.dtsi +@@ -345,7 +345,7 @@ uart2: serial@11030000 { + clocks = <&cru SCLK_UART2>, <&cru PCLK_UART2>; + clock-names = "baudclk", "apb_pclk"; + pinctrl-names = "default"; +- pinctrl-0 = <&uart2_xfer>; ++ pinctrl-0 = <&uart21_xfer>; + reg-shift = <2>; + reg-io-width = <4>; + status = "disabled"; +@@ -1275,13 +1275,30 @@ uart1_xfer: uart1-xfer { + <1 RK_PB2 1 &pcfg_pull_none>; + }; + ++ uart11_xfer: uart11-xfer { ++ rockchip,pins = <3 RK_PB6 1 &pcfg_pull_up>, ++ <3 RK_PB5 1 &pcfg_pull_none>; ++ }; ++ + uart1_cts: uart1-cts { + rockchip,pins = <1 RK_PB0 1 &pcfg_pull_none>; + }; + ++ uart11_cts: uart11-cts { ++ rockchip,pins = <3 RK_PA7 1 &pcfg_pull_none>; ++ }; ++ + uart1_rts: uart1-rts { + rockchip,pins = <1 RK_PB3 1 &pcfg_pull_none>; + }; ++ ++ uart11_rts: uart11-rts { ++ rockchip,pins = <3 RK_PA6 1 &pcfg_pull_none>; ++ }; ++ ++ uart11_rts_gpio: uart11-rts-gpio { ++ rockchip,pins = <3 RK_PA6 RK_FUNC_GPIO &pcfg_pull_none>; ++ }; + }; + + uart2 { + +From 1c37c9a10362d2e049be1386bb1da7d4f488b1d8 Mon Sep 17 00:00:00 2001 +From: Alex Bee +Date: Sun, 16 Aug 2020 21:58:56 +0200 +Subject: [PATCH] ARM: dts: rockchip: align mmc* node properties with driver + +Add resets, max-frequency and bus-width properties where required to emmc +,sdmmc and sdio nodes. While at that also add the sdmmc_pwr pinctrl which +is required to get the sd-card controller to work, if it was not/wrong +initialized by the bootloader (i.e. u-boot) +--- + arch/arm/boot/dts/rk322x.dtsi | 17 ++++++++++++++--- + 1 file changed, 14 insertions(+), 3 deletions(-) + +diff --git a/arch/arm/boot/dts/rk322x.dtsi b/arch/arm/boot/dts/rk322x.dtsi +index 693c6f18a889..92e3eb1e7938 100644 +--- a/arch/arm/boot/dts/rk322x.dtsi ++++ b/arch/arm/boot/dts/rk322x.dtsi +@@ -787,9 +787,13 @@ sdmmc: mmc@30000000 { + clocks = <&cru HCLK_SDMMC>, <&cru SCLK_SDMMC>, + <&cru SCLK_SDMMC_DRV>, <&cru SCLK_SDMMC_SAMPLE>; + clock-names = "biu", "ciu", "ciu-drive", "ciu-sample"; ++ bus-width = <4>; + fifo-depth = <0x100>; ++ max-frequency = <150000000>; + pinctrl-names = "default"; +- pinctrl-0 = <&sdmmc_clk &sdmmc_cmd &sdmmc_bus4>; ++ pinctrl-0 = <&sdmmc_clk &sdmmc_cmd &sdmmc_bus4 &sdmmc_pwr>; ++ resets = <&cru SRST_SDMMC>; ++ reset-names = "reset"; + status = "disabled"; + }; + +@@ -799,10 +803,14 @@ sdio: mmc@30010000 { + interrupts = ; + clocks = <&cru HCLK_SDIO>, <&cru SCLK_SDIO>, + <&cru SCLK_SDIO_DRV>, <&cru SCLK_SDIO_SAMPLE>; ++ bus-width = <4>; + clock-names = "biu", "ciu", "ciu-drive", "ciu-sample"; + fifo-depth = <0x100>; ++ max-frequency = <150000000>; + pinctrl-names = "default"; + pinctrl-0 = <&sdio_clk &sdio_cmd &sdio_bus4>; ++ resets = <&cru SRST_SDIO>; ++ reset-names = "reset"; + status = "disabled"; + }; + +@@ -810,14 +818,13 @@ emmc: mmc@30020000 { + compatible = "rockchip,rk3228-dw-mshc", "rockchip,rk3288-dw-mshc"; + reg = <0x30020000 0x4000>; + interrupts = ; +- clock-frequency = <37500000>; +- max-frequency = <37500000>; + clocks = <&cru HCLK_EMMC>, <&cru SCLK_EMMC>, + <&cru SCLK_EMMC_DRV>, <&cru SCLK_EMMC_SAMPLE>; + clock-names = "biu", "ciu", "ciu-drive", "ciu-sample"; + bus-width = <8>; + rockchip,default-sample-phase = <158>; + fifo-depth = <0x100>; ++ max-frequency = <150000000>; + pinctrl-names = "default"; + pinctrl-0 = <&emmc_clk &emmc_cmd &emmc_bus8>; + resets = <&cru SRST_EMMC>; +@@ -1043,6 +1050,10 @@ sdmmc_bus4: sdmmc-bus4 { + <1 RK_PC4 1 &pcfg_pull_none_drv_12ma>, + <1 RK_PC5 1 &pcfg_pull_none_drv_12ma>; + }; ++ ++ sdmmc_pwr: sdmmc-pwr { ++ rockchip,pins = <1 RK_PB6 RK_FUNC_GPIO &pcfg_pull_none>; ++ }; + }; + + sdio { + +From 9a9db392c9d0fd23dd84c39f36290ab0bfbc2021 Mon Sep 17 00:00:00 2001 +From: Jeffy Chen +Date: Wed, 8 Jun 2016 14:05:42 +0800 +Subject: [PATCH] clk: rockchip: rk3036: add ACLK_VCODEC + +Change-Id: I36f6b23139345941656c127718cc4ff01c6d629f +Signed-off-by: Jeffy Chen +--- + drivers/clk/rockchip/clk-rk3036.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/clk/rockchip/clk-rk3036.c b/drivers/clk/rockchip/clk-rk3036.c +index 6a46f85ad837..3b285261ce39 100644 +--- a/drivers/clk/rockchip/clk-rk3036.c ++++ b/drivers/clk/rockchip/clk-rk3036.c +@@ -258,7 +258,7 @@ static struct rockchip_clk_branch rk3036_clk_branches[] __initdata = { + RK2928_CLKGATE_CON(1), 13, GFLAGS, + &rk3036_uart2_fracmux), + +- COMPOSITE(0, "aclk_vcodec", mux_pll_src_3plls_p, 0, ++ COMPOSITE(ACLK_VCODEC, "aclk_vcodec", mux_pll_src_3plls_p, 0, + RK2928_CLKSEL_CON(32), 14, 2, MFLAGS, 8, 5, DFLAGS, + RK2928_CLKGATE_CON(3), 11, GFLAGS), + FACTOR_GATE(HCLK_VCODEC, "hclk_vcodec", "aclk_vcodec", 0, 1, 4, + +From e1dd6aaa44b5ae46657f83bb066f50f5c9e0568a Mon Sep 17 00:00:00 2001 +From: Randy Li +Date: Fri, 20 Oct 2017 14:38:09 +0800 +Subject: [PATCH] clk: rockchip: rk3036: export the hevc core clock + +The clock hevc core will be used to drive the hevc decoder. + +Change-Id: Ic1298ce1edd07f86e5c243e3a2c9876481f4cba9 +Signed-off-by: Randy Li +--- + drivers/clk/rockchip/clk-rk3036.c | 2 +- + include/dt-bindings/clock/rk3036-cru.h | 1 + + 2 files changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/clk/rockchip/clk-rk3036.c b/drivers/clk/rockchip/clk-rk3036.c +index 3b285261ce39..a98ea978fc8a 100644 +--- a/drivers/clk/rockchip/clk-rk3036.c ++++ b/drivers/clk/rockchip/clk-rk3036.c +@@ -264,7 +264,7 @@ static struct rockchip_clk_branch rk3036_clk_branches[] __initdata = { + FACTOR_GATE(HCLK_VCODEC, "hclk_vcodec", "aclk_vcodec", 0, 1, 4, + RK2928_CLKGATE_CON(3), 12, GFLAGS), + +- COMPOSITE(0, "aclk_hvec", mux_pll_src_3plls_p, 0, ++ COMPOSITE(ACLK_HEVC, "aclk_hevc", mux_pll_src_3plls_p, 0, + RK2928_CLKSEL_CON(20), 0, 2, MFLAGS, 2, 5, DFLAGS, + RK2928_CLKGATE_CON(10), 6, GFLAGS), + +diff --git a/include/dt-bindings/clock/rk3036-cru.h b/include/dt-bindings/clock/rk3036-cru.h +index 35a5a01f9697..cd231f57278d 100644 +--- a/include/dt-bindings/clock/rk3036-cru.h ++++ b/include/dt-bindings/clock/rk3036-cru.h +@@ -55,6 +55,7 @@ + #define ACLK_VCODEC 208 + #define ACLK_CPU 209 + #define ACLK_PERI 210 ++#define ACLK_HEVC 211 + + /* pclk gates */ + #define PCLK_GPIO0 320 + +From e9752790e4c92f83924dc881cf1555977c512214 Mon Sep 17 00:00:00 2001 +From: Caesar Wang +Date: Mon, 13 Nov 2017 09:28:12 +0800 +Subject: [PATCH] clk: rockchip: export SCLK_I2S_PRE and SCLK_I2S_FRAC of i2s + on rk3036 + +Change-Id: I627c8c2582be2b27414e7b82e9d56dd560f68e64 +Signed-off-by: Caesar Wang +--- + drivers/clk/rockchip/clk-rk3036.c | 4 ++-- + include/dt-bindings/clock/rk3036-cru.h | 2 ++ + 2 files changed, 4 insertions(+), 2 deletions(-) + +diff --git a/drivers/clk/rockchip/clk-rk3036.c b/drivers/clk/rockchip/clk-rk3036.c +index a98ea978fc8a..c67ee61ef0cd 100644 +--- a/drivers/clk/rockchip/clk-rk3036.c ++++ b/drivers/clk/rockchip/clk-rk3036.c +@@ -157,7 +157,7 @@ static struct rockchip_clk_branch rk3036_uart2_fracmux __initdata = + RK2928_CLKSEL_CON(15), 8, 2, MFLAGS); + + static struct rockchip_clk_branch rk3036_i2s_fracmux __initdata = +- MUX(0, "i2s_pre", mux_i2s_pre_p, CLK_SET_RATE_PARENT, ++ MUX(SCLK_I2S_PRE, "i2s_pre", mux_i2s_pre_p, CLK_SET_RATE_PARENT, + RK2928_CLKSEL_CON(3), 8, 2, MFLAGS); + + static struct rockchip_clk_branch rk3036_spdif_fracmux __initdata = +@@ -306,7 +306,7 @@ static struct rockchip_clk_branch rk3036_clk_branches[] __initdata = { + COMPOSITE(0, "i2s_src", mux_pll_src_3plls_p, 0, + RK2928_CLKSEL_CON(3), 14, 2, MFLAGS, 0, 7, DFLAGS, + RK2928_CLKGATE_CON(0), 9, GFLAGS), +- COMPOSITE_FRACMUX(0, "i2s_frac", "i2s_src", CLK_SET_RATE_PARENT, ++ COMPOSITE_FRACMUX(SCLK_I2S_FRAC, "i2s_frac", "i2s_src", CLK_SET_RATE_PARENT, + RK2928_CLKSEL_CON(7), 0, + RK2928_CLKGATE_CON(0), 10, GFLAGS, + &rk3036_i2s_fracmux), +diff --git a/include/dt-bindings/clock/rk3036-cru.h b/include/dt-bindings/clock/rk3036-cru.h +index cd231f57278d..4c7ff6141a67 100644 +--- a/include/dt-bindings/clock/rk3036-cru.h ++++ b/include/dt-bindings/clock/rk3036-cru.h +@@ -43,6 +43,8 @@ + #define SCLK_PVTM_CORE 123 + #define SCLK_PVTM_GPU 124 + #define SCLK_PVTM_VIDEO 125 ++#define SCLK_I2S_FRAC 126 ++#define SCLK_I2S_PRE 127 + #define SCLK_MAC 151 + #define SCLK_MACREF 152 + #define SCLK_MACPLL 153 + +From 1cfffef46d411629c71da2dea69c41b261355d5b Mon Sep 17 00:00:00 2001 +From: Caesar Wang +Date: Fri, 17 Nov 2017 14:49:16 +0800 +Subject: [PATCH] clk: rockchip: protect the armclk for rk3036 + +Some clocks may get disabled as a side effect of another clock +being disabled, because have no consumers. Says the dclk_hdmi's parent may +change from apll to gpll, but the apll's son clocks are very less. + +Change-Id: I4fb4e5fdf83a8f73979b50dbcf4f3e4543896fcf +Signed-off-by: Caesar Wang +--- + drivers/clk/rockchip/clk-rk3036.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/drivers/clk/rockchip/clk-rk3036.c b/drivers/clk/rockchip/clk-rk3036.c +index c67ee61ef0cd..ac5c1cfb3f54 100644 +--- a/drivers/clk/rockchip/clk-rk3036.c ++++ b/drivers/clk/rockchip/clk-rk3036.c +@@ -424,6 +424,7 @@ static struct rockchip_clk_branch rk3036_clk_branches[] __initdata = { + }; + + static const char *const rk3036_critical_clocks[] __initconst = { ++ "armclk", + "aclk_cpu", + "aclk_peri", + "hclk_peri", +@@ -467,14 +468,14 @@ static void __init rk3036_clk_init(struct device_node *np) + RK3036_GRF_SOC_STATUS0); + rockchip_clk_register_branches(ctx, rk3036_clk_branches, + ARRAY_SIZE(rk3036_clk_branches)); +- rockchip_clk_protect_critical(rk3036_critical_clocks, +- ARRAY_SIZE(rk3036_critical_clocks)); +- + rockchip_clk_register_armclk(ctx, ARMCLK, "armclk", + mux_armclk_p, ARRAY_SIZE(mux_armclk_p), + &rk3036_cpuclk_data, rk3036_cpuclk_rates, + ARRAY_SIZE(rk3036_cpuclk_rates)); + ++ rockchip_clk_protect_critical(rk3036_critical_clocks, ++ ARRAY_SIZE(rk3036_critical_clocks)); ++ + rockchip_register_softrst(np, 9, reg_base + RK2928_SOFTRST_CON(0), + ROCKCHIP_SOFTRST_HIWORD_MASK); + + +From 84f5c9e7a40b0e30b087aea7a618b18e2bb87fd5 Mon Sep 17 00:00:00 2001 +From: Finley Xiao +Date: Mon, 13 Nov 2017 15:32:25 +0800 +Subject: [PATCH] clk: rockchip: rk3036: leave apll for core, mac and lcdc only + +In order not to affect other clocks, remove the apll from the +parent list of other clocks and only core, mac and lcdc can +select apll as parent. + +Change-Id: I58b995f8ccf69c6564f74b5823f618a186030d70 +Signed-off-by: Finley Xiao +--- + drivers/clk/rockchip/clk-rk3036.c | 38 ++++++++++++++++--------------- + 1 file changed, 20 insertions(+), 18 deletions(-) + +diff --git a/drivers/clk/rockchip/clk-rk3036.c b/drivers/clk/rockchip/clk-rk3036.c +index ac5c1cfb3f54..4ce2cf844123 100644 +--- a/drivers/clk/rockchip/clk-rk3036.c ++++ b/drivers/clk/rockchip/clk-rk3036.c +@@ -114,14 +114,16 @@ static const struct rockchip_cpuclk_reg_data rk3036_cpuclk_data = { + PNAME(mux_pll_p) = { "xin24m", "xin24m" }; + + PNAME(mux_armclk_p) = { "apll", "gpll_armclk" }; +-PNAME(mux_busclk_p) = { "apll", "dpll_cpu", "gpll_cpu" }; ++PNAME(mux_busclk_p) = { "dummy_apll", "dpll_cpu", "gpll_cpu" }; + PNAME(mux_ddrphy_p) = { "dpll_ddr", "gpll_ddr" }; +-PNAME(mux_pll_src_3plls_p) = { "apll", "dpll", "gpll" }; ++PNAME(mux_pll_src_apll_dpll_gpll_p) = { "apll", "dpll", "gpll" }; ++PNAME(mux_pll_src_dmyapll_dpll_gpll_p) = { "dummy_apll", "dpll", "gpll" }; ++ + PNAME(mux_timer_p) = { "xin24m", "pclk_peri_src" }; + +-PNAME(mux_pll_src_apll_dpll_gpll_usb480m_p) = { "apll", "dpll", "gpll", "usb480m" }; ++PNAME(mux_pll_src_dmyapll_dpll_gpll_usb480m_p) = { "dummy_apll", "dpll", "gpll", "usb480m" }; + +-PNAME(mux_mmc_src_p) = { "apll", "dpll", "gpll", "xin24m" }; ++PNAME(mux_mmc_src_p) = { "dummy_apll", "dpll", "gpll", "xin24m" }; + PNAME(mux_i2s_pre_p) = { "i2s_src", "i2s_frac", "ext_i2s", "xin12m" }; + PNAME(mux_i2s_clkout_p) = { "i2s_pre", "xin12m" }; + PNAME(mux_spdif_p) = { "spdif_src", "spdif_frac", "xin12m" }; +@@ -206,7 +208,7 @@ static struct rockchip_clk_branch rk3036_clk_branches[] __initdata = { + RK2928_CLKSEL_CON(1), 8, 2, DFLAGS | CLK_DIVIDER_READ_ONLY, + RK2928_CLKGATE_CON(0), 4, GFLAGS), + +- COMPOSITE(0, "aclk_peri_src", mux_pll_src_3plls_p, 0, ++ COMPOSITE(0, "aclk_peri_src", mux_pll_src_dmyapll_dpll_gpll_p, 0, + RK2928_CLKSEL_CON(10), 14, 2, MFLAGS, 0, 5, DFLAGS, + RK2928_CLKGATE_CON(2), 0, GFLAGS), + +@@ -234,7 +236,7 @@ static struct rockchip_clk_branch rk3036_clk_branches[] __initdata = { + RK2928_CLKSEL_CON(2), 7, 1, MFLAGS, + RK2928_CLKGATE_CON(2), 5, GFLAGS), + +- MUX(0, "uart_pll_clk", mux_pll_src_apll_dpll_gpll_usb480m_p, 0, ++ MUX(0, "uart_pll_clk", mux_pll_src_dmyapll_dpll_gpll_usb480m_p, 0, + RK2928_CLKSEL_CON(13), 10, 2, MFLAGS), + COMPOSITE_NOMUX(0, "uart0_src", "uart_pll_clk", 0, + RK2928_CLKSEL_CON(13), 0, 7, DFLAGS, +@@ -258,23 +260,23 @@ static struct rockchip_clk_branch rk3036_clk_branches[] __initdata = { + RK2928_CLKGATE_CON(1), 13, GFLAGS, + &rk3036_uart2_fracmux), + +- COMPOSITE(ACLK_VCODEC, "aclk_vcodec", mux_pll_src_3plls_p, 0, ++ COMPOSITE(ACLK_VCODEC, "aclk_vcodec", mux_pll_src_dmyapll_dpll_gpll_p, 0, + RK2928_CLKSEL_CON(32), 14, 2, MFLAGS, 8, 5, DFLAGS, + RK2928_CLKGATE_CON(3), 11, GFLAGS), + FACTOR_GATE(HCLK_VCODEC, "hclk_vcodec", "aclk_vcodec", 0, 1, 4, + RK2928_CLKGATE_CON(3), 12, GFLAGS), + +- COMPOSITE(ACLK_HEVC, "aclk_hevc", mux_pll_src_3plls_p, 0, ++ COMPOSITE(ACLK_HEVC, "aclk_hevc", mux_pll_src_dmyapll_dpll_gpll_p, 0, + RK2928_CLKSEL_CON(20), 0, 2, MFLAGS, 2, 5, DFLAGS, + RK2928_CLKGATE_CON(10), 6, GFLAGS), + +- COMPOSITE(0, "aclk_disp1_pre", mux_pll_src_3plls_p, 0, ++ COMPOSITE(0, "aclk_disp1_pre", mux_pll_src_dmyapll_dpll_gpll_p, 0, + RK2928_CLKSEL_CON(31), 14, 2, MFLAGS, 8, 5, DFLAGS, + RK2928_CLKGATE_CON(1), 4, GFLAGS), +- COMPOSITE(0, "hclk_disp_pre", mux_pll_src_3plls_p, 0, ++ COMPOSITE(0, "hclk_disp_pre", mux_pll_src_dmyapll_dpll_gpll_p, 0, + RK2928_CLKSEL_CON(30), 14, 2, MFLAGS, 8, 5, DFLAGS, + RK2928_CLKGATE_CON(0), 11, GFLAGS), +- COMPOSITE(SCLK_LCDC, "dclk_lcdc", mux_pll_src_3plls_p, 0, ++ COMPOSITE(SCLK_LCDC, "dclk_lcdc", mux_pll_src_apll_dpll_gpll_p, 0, + RK2928_CLKSEL_CON(28), 0, 2, MFLAGS, 8, 8, DFLAGS, + RK2928_CLKGATE_CON(3), 2, GFLAGS), + +@@ -303,7 +305,7 @@ static struct rockchip_clk_branch rk3036_clk_branches[] __initdata = { + MMC(SCLK_EMMC_DRV, "emmc_drv", "sclk_emmc", RK3036_EMMC_CON0, 1), + MMC(SCLK_EMMC_SAMPLE, "emmc_sample", "sclk_emmc", RK3036_EMMC_CON1, 0), + +- COMPOSITE(0, "i2s_src", mux_pll_src_3plls_p, 0, ++ COMPOSITE(0, "i2s_src", mux_pll_src_dmyapll_dpll_gpll_p, 0, + RK2928_CLKSEL_CON(3), 14, 2, MFLAGS, 0, 7, DFLAGS, + RK2928_CLKGATE_CON(0), 9, GFLAGS), + COMPOSITE_FRACMUX(SCLK_I2S_FRAC, "i2s_frac", "i2s_src", CLK_SET_RATE_PARENT, +@@ -316,7 +318,7 @@ static struct rockchip_clk_branch rk3036_clk_branches[] __initdata = { + GATE(SCLK_I2S, "sclk_i2s", "i2s_pre", CLK_SET_RATE_PARENT, + RK2928_CLKGATE_CON(0), 14, GFLAGS), + +- COMPOSITE(0, "spdif_src", mux_pll_src_3plls_p, 0, ++ COMPOSITE(0, "spdif_src", mux_pll_src_dmyapll_dpll_gpll_p, 0, + RK2928_CLKSEL_CON(5), 10, 2, MFLAGS, 0, 7, DFLAGS, + RK2928_CLKGATE_CON(2), 10, GFLAGS), + COMPOSITE_FRACMUX(0, "spdif_frac", "spdif_src", 0, +@@ -327,23 +329,23 @@ static struct rockchip_clk_branch rk3036_clk_branches[] __initdata = { + GATE(SCLK_OTGPHY0, "sclk_otgphy0", "xin12m", CLK_IGNORE_UNUSED, + RK2928_CLKGATE_CON(1), 5, GFLAGS), + +- COMPOSITE(SCLK_GPU, "sclk_gpu", mux_pll_src_3plls_p, 0, ++ COMPOSITE(SCLK_GPU, "sclk_gpu", mux_pll_src_dmyapll_dpll_gpll_p, 0, + RK2928_CLKSEL_CON(34), 8, 2, MFLAGS, 0, 5, DFLAGS, + RK2928_CLKGATE_CON(3), 13, GFLAGS), + +- COMPOSITE(SCLK_SPI, "sclk_spi", mux_pll_src_3plls_p, 0, ++ COMPOSITE(SCLK_SPI, "sclk_spi", mux_pll_src_dmyapll_dpll_gpll_p, 0, + RK2928_CLKSEL_CON(25), 8, 2, MFLAGS, 0, 7, DFLAGS, + RK2928_CLKGATE_CON(2), 9, GFLAGS), + +- COMPOSITE(SCLK_NANDC, "sclk_nandc", mux_pll_src_3plls_p, 0, ++ COMPOSITE(SCLK_NANDC, "sclk_nandc", mux_pll_src_dmyapll_dpll_gpll_p, 0, + RK2928_CLKSEL_CON(16), 8, 2, MFLAGS, 10, 5, DFLAGS, + RK2928_CLKGATE_CON(10), 4, GFLAGS), + +- COMPOSITE(SCLK_SFC, "sclk_sfc", mux_pll_src_apll_dpll_gpll_usb480m_p, 0, ++ COMPOSITE(SCLK_SFC, "sclk_sfc", mux_pll_src_dmyapll_dpll_gpll_usb480m_p, 0, + RK2928_CLKSEL_CON(16), 0, 2, MFLAGS, 2, 5, DFLAGS, + RK2928_CLKGATE_CON(10), 5, GFLAGS), + +- COMPOSITE_NOGATE(SCLK_MACPLL, "mac_pll_src", mux_pll_src_3plls_p, CLK_SET_RATE_NO_REPARENT, ++ COMPOSITE_NOGATE(SCLK_MACPLL, "mac_pll_src", mux_pll_src_apll_dpll_gpll_p, CLK_SET_RATE_NO_REPARENT, + RK2928_CLKSEL_CON(21), 0, 2, MFLAGS, 9, 5, DFLAGS), + MUX(SCLK_MACREF, "mac_clk_ref", mux_mac_p, CLK_SET_RATE_PARENT, + RK2928_CLKSEL_CON(21), 3, 1, MFLAGS), + +From 30337bfc416283d487d91e82397c81f1cae745a9 Mon Sep 17 00:00:00 2001 +From: Randy Li +Date: Fri, 20 Apr 2018 10:43:46 +0800 +Subject: [PATCH] clk: rockchip: rk3036: export the sfc clocks + +The serial Flash controller on the rk3036 would request +two clock nodes. + +Change-Id: Iaa50c4a25602a68241b0b9b2f186e4c7e55bc3da +Signed-off-by: Randy Li +--- + drivers/clk/rockchip/clk-rk3036.c | 2 +- + include/dt-bindings/clock/rk3036-cru.h | 1 + + 2 files changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/clk/rockchip/clk-rk3036.c b/drivers/clk/rockchip/clk-rk3036.c +index 4ce2cf844123..0d1556ac185a 100644 +--- a/drivers/clk/rockchip/clk-rk3036.c ++++ b/drivers/clk/rockchip/clk-rk3036.c +@@ -404,7 +404,7 @@ static struct rockchip_clk_branch rk3036_clk_branches[] __initdata = { + GATE(HCLK_OTG0, "hclk_otg0", "hclk_peri", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(5), 13, GFLAGS), + GATE(HCLK_OTG1, "hclk_otg1", "hclk_peri", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(7), 3, GFLAGS), + GATE(HCLK_I2S, "hclk_i2s", "hclk_peri", 0, RK2928_CLKGATE_CON(7), 2, GFLAGS), +- GATE(0, "hclk_sfc", "hclk_peri", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(3), 14, GFLAGS), ++ GATE(HCLK_SFC, "hclk_sfc", "hclk_peri", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(3), 14, GFLAGS), + GATE(HCLK_MAC, "hclk_mac", "hclk_peri", 0, RK2928_CLKGATE_CON(3), 5, GFLAGS), + + /* pclk_peri gates */ +diff --git a/include/dt-bindings/clock/rk3036-cru.h b/include/dt-bindings/clock/rk3036-cru.h +index 4c7ff6141a67..72ba1952071d 100644 +--- a/include/dt-bindings/clock/rk3036-cru.h ++++ b/include/dt-bindings/clock/rk3036-cru.h +@@ -84,6 +84,7 @@ + #define HCLK_OTG0 449 + #define HCLK_OTG1 450 + #define HCLK_NANDC 453 ++#define HCLK_SFC 454 + #define HCLK_SDMMC 456 + #define HCLK_SDIO 457 + #define HCLK_EMMC 459 + +From 62768587c0db32f4180bd4cebbd9f8d8ad865901 Mon Sep 17 00:00:00 2001 +From: Elaine Zhang +Date: Mon, 1 Jun 2020 15:36:35 +0800 +Subject: [PATCH] clk: rockchip: rk3036: fix up the sclk_sfc parent error + +Change-Id: I0903161f34de8f309392bec6926348ffe37ba2f6 +Signed-off-by: Elaine Zhang +--- + drivers/clk/rockchip/clk-rk3036.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/clk/rockchip/clk-rk3036.c b/drivers/clk/rockchip/clk-rk3036.c +index 0d1556ac185a..693bee4009db 100644 +--- a/drivers/clk/rockchip/clk-rk3036.c ++++ b/drivers/clk/rockchip/clk-rk3036.c +@@ -122,6 +122,7 @@ PNAME(mux_pll_src_dmyapll_dpll_gpll_p) = { "dummy_apll", "dpll", "gpll" }; + PNAME(mux_timer_p) = { "xin24m", "pclk_peri_src" }; + + PNAME(mux_pll_src_dmyapll_dpll_gpll_usb480m_p) = { "dummy_apll", "dpll", "gpll", "usb480m" }; ++PNAME(mux_pll_src_dmyapll_dpll_gpll_xin24_p) = { "dummy_apll", "dpll", "gpll", "xin24m" }; + + PNAME(mux_mmc_src_p) = { "dummy_apll", "dpll", "gpll", "xin24m" }; + PNAME(mux_i2s_pre_p) = { "i2s_src", "i2s_frac", "ext_i2s", "xin12m" }; +@@ -341,7 +342,7 @@ static struct rockchip_clk_branch rk3036_clk_branches[] __initdata = { + RK2928_CLKSEL_CON(16), 8, 2, MFLAGS, 10, 5, DFLAGS, + RK2928_CLKGATE_CON(10), 4, GFLAGS), + +- COMPOSITE(SCLK_SFC, "sclk_sfc", mux_pll_src_dmyapll_dpll_gpll_usb480m_p, 0, ++ COMPOSITE(SCLK_SFC, "sclk_sfc", mux_pll_src_dmyapll_dpll_gpll_xin24_p, 0, + RK2928_CLKSEL_CON(16), 0, 2, MFLAGS, 2, 5, DFLAGS, + RK2928_CLKGATE_CON(10), 5, GFLAGS), + + +From cef2d7b595360c89a57fcf38d1dcf41759ceac95 Mon Sep 17 00:00:00 2001 +From: Alex Bee +Date: Sun, 16 Aug 2020 22:41:29 +0200 +Subject: [PATCH] clk: rockchip: export PCLK_EFUSE for RK3036 + +Export PCLK_EFUSE for RK3036. +--- + drivers/clk/rockchip/clk-rk3036.c | 2 +- + include/dt-bindings/clock/rk3036-cru.h | 1 + + 2 files changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/clk/rockchip/clk-rk3036.c b/drivers/clk/rockchip/clk-rk3036.c +index 693bee4009db..06e92dd5ce25 100644 +--- a/drivers/clk/rockchip/clk-rk3036.c ++++ b/drivers/clk/rockchip/clk-rk3036.c +@@ -410,7 +410,7 @@ static struct rockchip_clk_branch rk3036_clk_branches[] __initdata = { + + /* pclk_peri gates */ + GATE(0, "pclk_peri_matrix", "pclk_peri", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(4), 1, GFLAGS), +- GATE(0, "pclk_efuse", "pclk_peri", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(5), 2, GFLAGS), ++ GATE(PCLK_EFUSE, "pclk_efuse", "pclk_peri", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(5), 2, GFLAGS), + GATE(PCLK_TIMER, "pclk_timer", "pclk_peri", 0, RK2928_CLKGATE_CON(7), 7, GFLAGS), + GATE(PCLK_PWM, "pclk_pwm", "pclk_peri", 0, RK2928_CLKGATE_CON(7), 10, GFLAGS), + GATE(PCLK_SPI, "pclk_spi", "pclk_peri", 0, RK2928_CLKGATE_CON(7), 12, GFLAGS), +diff --git a/include/dt-bindings/clock/rk3036-cru.h b/include/dt-bindings/clock/rk3036-cru.h +index 72ba1952071d..febab04521a2 100644 +--- a/include/dt-bindings/clock/rk3036-cru.h ++++ b/include/dt-bindings/clock/rk3036-cru.h +@@ -79,6 +79,7 @@ + #define PCLK_DDRUPCTL 364 + #define PCLK_WDT 368 + #define PCLK_ACODEC 369 ++#define PCLK_EFUSE 370 + + /* hclk gates */ + #define HCLK_OTG0 449 + +From bf25b1441ad681e8b56ae6ec069165dc4fb6b445 Mon Sep 17 00:00:00 2001 +From: Alex Bee +Date: Sun, 16 Aug 2020 22:43:41 +0200 +Subject: [PATCH] ARM: dts: rockchip: add RK3036 efuse node + +Add RK3036 efuse node to the devicetree and add the new compatible string +to bindings document. +--- + .../devicetree/bindings/nvmem/rockchip-efuse.yaml | 1 + + arch/arm/boot/dts/rk3036.dtsi | 7 +++++++ + 2 files changed, 8 insertions(+) + +diff --git a/Documentation/devicetree/bindings/nvmem/rockchip-efuse.yaml b/Documentation/devicetree/bindings/nvmem/rockchip-efuse.yaml +index 3ae00b0b23bc..c3fdabcb1e0a 100644 +--- a/Documentation/devicetree/bindings/nvmem/rockchip-efuse.yaml ++++ b/Documentation/devicetree/bindings/nvmem/rockchip-efuse.yaml +@@ -15,6 +15,7 @@ allOf: + properties: + compatible: + enum: ++ - rockchip,rk3036-efuse + - rockchip,rk3066a-efuse + - rockchip,rk3188-efuse + - rockchip,rk3228-efuse +diff --git a/arch/arm/boot/dts/rk3036.dtsi b/arch/arm/boot/dts/rk3036.dtsi +index 10f15cdb932c..6700a17a6446 100644 +--- a/arch/arm/boot/dts/rk3036.dtsi ++++ b/arch/arm/boot/dts/rk3036.dtsi +@@ -873,4 +873,11 @@ spi_cs1:spi-cs1 { + }; + }; + }; ++ ++ efuse: efuse@20090000 { ++ compatible = "rockchip,rk3036-efuse", "rockchip,rk3288-efuse"; ++ reg = <0x20090000 0x20>; ++ clocks = <&cru PCLK_EFUSE>; ++ clock-names = "pclk_efuse"; ++ }; + }; + +From 490be97e9fdc5e4ea8afd5b41d2a9f2942f82b02 Mon Sep 17 00:00:00 2001 +From: Alex Bee +Date: Sun, 16 Aug 2020 23:02:00 +0200 +Subject: [PATCH] ARM: dts: add opp-table for RK3188s GPU + +Add opp-table for RK3188s mali400 MP4 GPU +--- + arch/arm/boot/dts/rk3188.dtsi | 30 ++++++++++++++++++++++++++++++ + 1 file changed, 30 insertions(+) + +diff --git a/arch/arm/boot/dts/rk3188.dtsi b/arch/arm/boot/dts/rk3188.dtsi +index 9fab375231ec..894fe6259ef2 100644 +--- a/arch/arm/boot/dts/rk3188.dtsi ++++ b/arch/arm/boot/dts/rk3188.dtsi +@@ -112,6 +112,35 @@ smp-sram@0 { + }; + }; + ++ gpu_opp_table: opp-table2 { ++ compatible = "operating-points-v2"; ++ ++ opp-133000000 { ++ opp-hz = /bits/ 64 <133000000>; ++ opp-microvolt = <975000>; ++ }; ++ opp-200000000 { ++ opp-hz = /bits/ 64 <200000000>; ++ opp-microvolt = <1000000>; ++ }; ++ opp-266000000 { ++ opp-hz = /bits/ 64 <266000000>; ++ opp-microvolt = <1025000>; ++ }; ++ opp-300000000 { ++ opp-hz = /bits/ 64 <300000000>; ++ opp-microvolt = <1050000>; ++ }; ++ opp-400000000 { ++ opp-hz = /bits/ 64 <400000000>; ++ opp-microvolt = <1100000>; ++ }; ++ opp-600000000 { ++ opp-hz = /bits/ 64 <600000000>; ++ opp-microvolt = <1250000>; ++ }; ++ }; ++ + vpu: video-codec@10104000 { + compatible = "rockchip,rk3188-vpu"; + reg = <0x10104000 0x800>; +@@ -672,6 +701,7 @@ &gpu { + "ppmmu2", + "pp3", + "ppmmu3"; ++ operating-points-v2 = <&gpu_opp_table>; + power-domains = <&power RK3188_PD_GPU>; + }; + + +From 313b1d3730fc3a9076a783e9e296a13fdae599ce Mon Sep 17 00:00:00 2001 +From: Alex Bee +Date: Sun, 16 Aug 2020 23:12:25 +0200 +Subject: [PATCH] ARM: dts: rk322x: add crypto node + +In order to add support for RK322x's crypto HW, the node +has been added t its dts. + +Signed-off-by: Alex Bee +--- + arch/arm/boot/dts/rk322x.dtsi | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/arch/arm/boot/dts/rk322x.dtsi b/arch/arm/boot/dts/rk322x.dtsi +index 92e3eb1e7938..be46697e125e 100644 +--- a/arch/arm/boot/dts/rk322x.dtsi ++++ b/arch/arm/boot/dts/rk322x.dtsi +@@ -167,6 +167,17 @@ display_subsystem: display-subsystem { + ports = <&vop_out>; + }; + ++ crypto: cypto-controller@100a0000 { ++ compatible = "rockchip,rk3288-crypto"; ++ reg = <0x100a0000 0x4000>; ++ interrupts = ; ++ clocks = <&cru HCLK_M_CRYPTO>, <&cru HCLK_S_CRYPTO>, ++ <&cru SCLK_CRYPTO>, <&cru ACLK_DMAC>; ++ clock-names = "aclk", "hclk", "sclk", "apb_pclk"; ++ resets = <&cru SRST_CRYPTO>; ++ reset-names = "crypto-rst"; ++ }; ++ + i2s1: i2s1@100b0000 { + compatible = "rockchip,rk3228-i2s", "rockchip,rk3066-i2s"; + reg = <0x100b0000 0x4000>; diff --git a/patch/kernel/rk322x-current/01-linux-9000-rockchip-linux-le-wip.patch b/patch/kernel/rk322x-current/01-linux-9000-rockchip-linux-le-wip.patch new file mode 100644 index 000000000..dad10c696 --- /dev/null +++ b/patch/kernel/rk322x-current/01-linux-9000-rockchip-linux-le-wip.patch @@ -0,0 +1,912 @@ +From 71fba6c19fa57e219657226d3d20528ebec86def Mon Sep 17 00:00:00 2001 +From: Alex Bee +Date: Sun, 16 Aug 2020 23:03:12 +0200 +Subject: [PATCH] WIP: ARM: dts: add RK322x box device trees + +--- + arch/arm/boot/dts/Makefile | 4 + + arch/arm/boot/dts/rk3228a-box-h96mini.dts | 115 +++++++++ + arch/arm/boot/dts/rk3228a-box.dts | 47 ++++ + arch/arm/boot/dts/rk3228a-box.dtsi | 12 + + arch/arm/boot/dts/rk3229-box-a95xr1.dts | 57 ++++ + arch/arm/boot/dts/rk3229-box.dts | 50 ++++ + arch/arm/boot/dts/rk3229-box.dtsi | 21 ++ + arch/arm/boot/dts/rk3229-cpu-opp.dtsi | 50 ++++ + arch/arm/boot/dts/rk322x-box-dcdc.dtsi | 164 ++++++++++++ + arch/arm/boot/dts/rk322x-box.dtsi | 301 ++++++++++++++++++++++ + 10 files changed, 821 insertions(+) + create mode 100644 arch/arm/boot/dts/rk3228a-box-h96mini.dts + create mode 100644 arch/arm/boot/dts/rk3228a-box.dts + create mode 100644 arch/arm/boot/dts/rk3228a-box.dtsi + create mode 100644 arch/arm/boot/dts/rk3229-box-a95xr1.dts + create mode 100644 arch/arm/boot/dts/rk3229-box.dts + create mode 100644 arch/arm/boot/dts/rk3229-box.dtsi + create mode 100644 arch/arm/boot/dts/rk3229-cpu-opp.dtsi + create mode 100644 arch/arm/boot/dts/rk322x-box-dcdc.dtsi + create mode 100644 arch/arm/boot/dts/rk322x-box.dtsi + +diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile +index e6a1cac0bfc7..1e633e4aa5a2 100644 +--- a/arch/arm/boot/dts/Makefile ++++ b/arch/arm/boot/dts/Makefile +@@ -961,7 +961,11 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += \ + rk3188-bqedison2qc.dtb \ + rk3188-px3-evb.dtb \ + rk3188-radxarock.dtb \ ++ rk3228a-box.dtb \ ++ rk3228a-box-h96mini.dtb \ + rk3228-evb.dtb \ ++ rk3229-box.dtb \ ++ rk3229-box-a95xr1.dtb \ + rk3229-evb.dtb \ + rk3229-xms6.dtb \ + rk3288-evb-act8846.dtb \ +diff --git a/arch/arm/boot/dts/rk3228a-box-h96mini.dts b/arch/arm/boot/dts/rk3228a-box-h96mini.dts +new file mode 100644 +index 000000000000..1041b6737d40 +--- /dev/null ++++ b/arch/arm/boot/dts/rk3228a-box-h96mini.dts +@@ -0,0 +1,115 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR MIT) ++ ++/dts-v1/; ++#include ++#include ++#include "rk3228a-box.dtsi" ++ ++/ { ++ compatible = "eledvb,h96mini", "rockchip,rk3228a-box", "rockchip,rk3229"; ++ model = "Rockchip RK3228A Box H96 mini"; ++ ++ leds { ++ compatible = "gpio-leds"; ++ ++ led_green { ++ gpios = <&gpio3 RK_PC5 GPIO_ACTIVE_HIGH>; ++ default-state = "on"; ++ }; ++ ++ led_red { ++ gpios = <&gpio0 RK_PB0 GPIO_ACTIVE_HIGH>; ++ default-state = "off"; ++ }; ++ }; ++ ++ openvfd { ++ compatible = "open,vfd"; ++ dev_name = "openvfd"; ++ openvfd_gpio_clk = <&gpio0 RK_PA0 GPIO_ACTIVE_HIGH>; ++ openvfd_gpio_dat = <&gpio0 RK_PA1 GPIO_ACTIVE_HIGH>; ++ openvfd_display_type = <0x06000100>; ++ openvfd_dot_bits = [00 01 03 02 04 05 06]; ++ }; ++ ++}; ++ ++&emmc { ++ mmc-hs200-1_8v; ++ status = "okay"; ++}; ++ ++&gmac { ++ tx_delay = <0x26>; ++ rx_delay = <0x11>; ++}; ++ ++&ir_receiver { ++ status = "okay"; ++}; ++ ++&pinctrl { ++ wifi { ++ wifi_host_wake_l: wifi-host-wake-l { ++ rockchip,pins = <0 RK_PD4 RK_FUNC_GPIO &pcfg_pull_none>; ++ }; ++ }; ++ ++ bt { ++ bt_host_wake_l: bt-host-wake-l { ++ rockchip,pins = <3 RK_PD2 RK_FUNC_GPIO &pcfg_pull_none>; ++ }; ++ ++ bt_reg_on_h: bt-reg-on-h { ++ rockchip,pins = <2 RK_PD5 RK_FUNC_GPIO &pcfg_pull_none>; ++ }; ++ ++ bt_wake_l: bt-wake-l { ++ rockchip,pins = <3 RK_PD3 RK_FUNC_GPIO &pcfg_pull_none>; ++ }; ++ }; ++}; ++ ++&power_key { ++ status = "okay"; ++}; ++ ++&sdio { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "okay"; ++ ++ brcmf: wifi@1 { ++ compatible = "brcm,bcm4329-fmac"; ++ reg = <1>; ++ interrupt-parent = <&gpio0>; ++ interrupts = ; ++ interrupt-names = "host-wake"; ++ brcm,drive-strength = <5>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&wifi_host_wake_l>; ++ }; ++}; ++ ++&sdmmc { ++ disable-wp; ++ status = "okay"; ++}; ++ ++&uart1 { ++ status = "okay"; ++ ++ bluetooth { ++ compatible = "brcm,bcm4330-bt"; ++ host-wakeup-gpios = <&gpio3 RK_PD2 GPIO_ACTIVE_HIGH>; ++ device-wakeup-gpios = <&gpio3 RK_PD3 GPIO_ACTIVE_HIGH>; ++ shutdown-gpios = <&gpio2 RK_PD5 GPIO_ACTIVE_HIGH>; ++ max-speed = <4000000>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&bt_reg_on_h &bt_host_wake_l &bt_wake_l>; ++ }; ++}; ++ ++&usb_otg { ++ dr_mode = "host"; ++}; +diff --git a/arch/arm/boot/dts/rk3228a-box.dts b/arch/arm/boot/dts/rk3228a-box.dts +new file mode 100644 +index 000000000000..e68ef44b95c9 +--- /dev/null ++++ b/arch/arm/boot/dts/rk3228a-box.dts +@@ -0,0 +1,47 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR MIT) ++ ++/dts-v1/; ++#include "rk3228a-box.dtsi" ++ ++/ { ++ model = "Rockchip RK3228A Box"; ++ ++ leds { ++ compatible = "gpio-leds"; ++ ++ led_blue { ++ gpios = <&gpio3 RK_PC5 GPIO_ACTIVE_HIGH>; ++ default-state = "on"; ++ }; ++ ++ led_red { ++ gpios = <&gpio1 RK_PA7 GPIO_ACTIVE_HIGH>; ++ default-state = "off"; ++ }; ++ }; ++ ++}; ++ ++&emmc { ++ status = "okay"; ++}; ++ ++&ir_receiver { ++ status = "okay"; ++}; ++ ++&sdio { ++ status = "okay"; ++}; ++ ++&sdmmc { ++ status = "okay"; ++}; ++ ++&uart1 { ++ status = "okay"; ++}; ++ ++&usb_otg { ++ dr_mode = "host"; ++}; +diff --git a/arch/arm/boot/dts/rk3228a-box.dtsi b/arch/arm/boot/dts/rk3228a-box.dtsi +new file mode 100644 +index 000000000000..056945c6c9a7 +--- /dev/null ++++ b/arch/arm/boot/dts/rk3228a-box.dtsi +@@ -0,0 +1,12 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR MIT) ++ ++/dts-v1/; ++ ++#include "rk322x-box-dcdc.dtsi" ++ ++/ { ++ ++ model = "Rockchip RK3228A Box"; ++ compatible = "rockchip,rk3228a-box", "rockchip,rk3229"; ++ ++}; +diff --git a/arch/arm/boot/dts/rk3229-box-a95xr1.dts b/arch/arm/boot/dts/rk3229-box-a95xr1.dts +new file mode 100644 +index 000000000000..b3695fb0b255 +--- /dev/null ++++ b/arch/arm/boot/dts/rk3229-box-a95xr1.dts +@@ -0,0 +1,57 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR MIT) ++ ++/dts-v1/; ++#include ++#include ++#include "rk3229-box.dtsi" ++ ++/ { ++ model = "Rockchip RK3229 Box A95X-R1"; ++ ++ leds { ++ compatible = "gpio-leds"; ++ ++ led_blue { ++ gpios = <&gpio3 RK_PC5 GPIO_ACTIVE_HIGH>; ++ default-state = "on"; ++ }; ++ ++ led_red { ++ gpios = <&gpio1 RK_PA7 GPIO_ACTIVE_HIGH>; ++ default-state = "off"; ++ linux,default-trigger = "rc-feedback"; ++ }; ++ }; ++ ++}; ++ ++&emmc { ++ mmc-hs200-1_8v; ++ status = "okay"; ++}; ++ ++&gmac { ++ tx_delay = <0x26>; ++ rx_delay = <0x11>; ++}; ++ ++&ir_receiver { ++ status = "okay"; ++}; ++ ++&power_key { ++ status = "okay"; ++}; ++ ++&sdio { ++ status = "okay"; ++}; ++ ++&sdmmc { ++ disable-wp; ++ status = "okay"; ++}; ++ ++&usb_otg { ++ dr_mode = "host"; ++}; +diff --git a/arch/arm/boot/dts/rk3229-box.dts b/arch/arm/boot/dts/rk3229-box.dts +new file mode 100644 +index 000000000000..b63e61cda257 +--- /dev/null ++++ b/arch/arm/boot/dts/rk3229-box.dts +@@ -0,0 +1,50 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR MIT) ++ ++/dts-v1/; ++#include "rk3229-box.dtsi" ++ ++/ { ++ model = "Rockchip RK3229 Box"; ++ ++ leds { ++ compatible = "gpio-leds"; ++ ++ led_green { ++ gpios = <&gpio3 RK_PC5 GPIO_ACTIVE_HIGH>; ++ default-state = "on"; ++ }; ++ ++ led_red { ++ gpios = <&gpio0 RK_PB0 GPIO_ACTIVE_HIGH>; ++ default-state = "off"; ++ }; ++ }; ++}; ++ ++&emmc { ++ status = "okay"; ++}; ++ ++&ir_receiver { ++ status = "okay"; ++}; ++ ++&power_key { ++ status = "okay"; ++}; ++ ++&sdio { ++ status = "okay"; ++}; ++ ++&sdmmc { ++ status = "okay"; ++}; ++ ++&uart1 { ++ status = "okay"; ++}; ++ ++&usb_otg { ++ dr_mode = "host"; ++}; +diff --git a/arch/arm/boot/dts/rk3229-box.dtsi b/arch/arm/boot/dts/rk3229-box.dtsi +new file mode 100644 +index 000000000000..84f98fc53ebf +--- /dev/null ++++ b/arch/arm/boot/dts/rk3229-box.dtsi +@@ -0,0 +1,21 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR MIT) ++ ++/dts-v1/; ++ ++#include "rk322x-box-dcdc.dtsi" ++#include "rk3229-cpu-opp.dtsi" ++ ++/ { ++ ++ model = "Rockchip RK3229 Box"; ++ compatible = "rockchip,rk3229-box", "rockchip,rk3229"; ++ ++}; ++ ++&cpu0_opp_table { ++ ++ opp-1464000000 { ++ status = "disabled"; ++ }; ++ ++}; +diff --git a/arch/arm/boot/dts/rk3229-cpu-opp.dtsi b/arch/arm/boot/dts/rk3229-cpu-opp.dtsi +new file mode 100644 +index 000000000000..c1c7613bab11 +--- /dev/null ++++ b/arch/arm/boot/dts/rk3229-cpu-opp.dtsi +@@ -0,0 +1,50 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR MIT) ++/* ++ * Copyright (c) 2017 Fuzhou Rockchip Electronics Co., Ltd ++ */ ++ ++/ { ++ compatible = "rockchip,rk3229"; ++ ++ /delete-node/ opp-table0; ++ ++ cpu0_opp_table: opp_table0 { ++ compatible = "operating-points-v2"; ++ opp-shared; ++ ++ opp-408000000 { ++ opp-hz = /bits/ 64 <408000000>; ++ opp-microvolt = <950000 950000 1400000>; ++ clock-latency-ns = <40000>; ++ opp-suspend; ++ }; ++ opp-600000000 { ++ opp-hz = /bits/ 64 <600000000>; ++ opp-microvolt = <975000 975000 1400000>; ++ }; ++ opp-816000000 { ++ opp-hz = /bits/ 64 <816000000>; ++ opp-microvolt = <1000000 1000000 1400000>; ++ }; ++ opp-1008000000 { ++ opp-hz = /bits/ 64 <1008000000>; ++ opp-microvolt = <1175000 1175000 1400000>; ++ }; ++ opp-1200000000 { ++ opp-hz = /bits/ 64 <1200000000>; ++ opp-microvolt = <1275000 1275000 1400000>; ++ }; ++ opp-1296000000 { ++ opp-hz = /bits/ 64 <1296000000>; ++ opp-microvolt = <1325000 1325000 1400000>; ++ }; ++ opp-1392000000 { ++ opp-hz = /bits/ 64 <1392000000>; ++ opp-microvolt = <1350000 1350000 1400000>; ++ }; ++ opp-1464000000 { ++ opp-hz = /bits/ 64 <1464000000>; ++ opp-microvolt = <1400000 1400000 1400000>; ++ }; ++ }; ++}; +diff --git a/arch/arm/boot/dts/rk322x-box-dcdc.dtsi b/arch/arm/boot/dts/rk322x-box-dcdc.dtsi +new file mode 100644 +index 000000000000..b2e47c5b4693 +--- /dev/null ++++ b/arch/arm/boot/dts/rk322x-box-dcdc.dtsi +@@ -0,0 +1,164 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR MIT) ++ ++/dts-v1/; ++ ++#include ++#include ++#include "rk322x-box.dtsi" ++ ++/ { ++ ++ vcc_host: vcc-host-regulator { ++ compatible = "regulator-fixed"; ++ enable-active-high; ++ gpio = <&gpio3 RK_PC4 GPIO_ACTIVE_HIGH>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&host_vbus_drv>; ++ regulator-name = "vcc_host"; ++ regulator-always-on; ++ regulator-boot-on; ++ vin-supply = <&vcc_sys>; ++ }; ++ ++ vccio_1v8: vccio-1v8-regulator { ++ compatible = "regulator-fixed"; ++ regulator-name = "vccio_1v8"; ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <1800000>; ++ regulator-always-on; ++ vin-supply = <&vcc_sys>; ++ }; ++ ++ vccio_3v3: vccio-3v3-regulator { ++ compatible = "regulator-fixed"; ++ regulator-name = "vccio_3v3"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-always-on; ++ vin-supply = <&vcc_sys>; ++ }; ++ ++ ++ vcc_otg: vcc-otg-regulator { ++ compatible = "regulator-fixed"; ++ enable-active-high; ++ gpio = <&gpio3 RK_PC6 GPIO_ACTIVE_HIGH>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&otg_vbus_drv>; ++ regulator-name = "vcc_otg_vbus"; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; ++ regulator-always-on; ++ regulator-boot-on; ++ vin-supply = <&vcc_sys>; ++ }; ++ ++ vcc_phy: vcc-phy-regulator { ++ compatible = "regulator-fixed"; ++ enable-active-high; ++ regulator-name = "vcc_phy"; ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <1800000>; ++ regulator-always-on; ++ regulator-boot-on; ++ vin-supply = <&vccio_1v8>; ++ }; ++ ++ vcc_sys: vcc-sys-regulator { ++ compatible = "regulator-fixed"; ++ regulator-name = "vcc_sys"; ++ regulator-always-on; ++ regulator-boot-on; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; ++ }; ++ ++ vdd_arm: vdd-arm-regulator { ++ compatible = "pwm-regulator"; ++ pwms = <&pwm1 0 5000 1>; ++ pwm-supply = <&vcc_sys>; ++ regulator-name = "vdd_arm"; ++ regulator-min-microvolt = <950000>; ++ regulator-max-microvolt = <1400000>; ++ regulator-ramp-delay = <12500>; ++ regulator-settling-time-up-us = <250>; ++ regulator-always-on; ++ regulator-boot-on; ++ }; ++ ++ vdd_log: vdd-log-regulator { ++ compatible = "pwm-regulator"; ++ pwms = <&pwm2 0 5000 1>; ++ pwm-supply = <&vcc_sys>; ++ regulator-name = "vdd_log"; ++ regulator-min-microvolt = <1000000>; ++ regulator-max-microvolt = <1300000>; ++ regulator-ramp-delay = <12500>; ++ regulator-settling-time-up-us = <250>; ++ regulator-always-on; ++ regulator-boot-on; ++ }; ++ ++}; ++ ++ ++&cpu0 { ++ cpu-supply = <&vdd_arm>; ++}; ++ ++&cpu1 { ++ cpu-supply = <&vdd_arm>; ++}; ++ ++&cpu2 { ++ cpu-supply = <&vdd_arm>; ++}; ++ ++&cpu3 { ++ cpu-supply = <&vdd_arm>; ++}; ++ ++&io_domains { ++ vccio1-supply = <&vccio_3v3>; ++ vccio2-supply = <&vccio_1v8>; ++ vccio4-supply = <&vccio_3v3>; ++ status = "okay"; ++}; ++ ++&gmac { ++ phy-supply = <&vcc_phy>; ++}; ++ ++&gpu { ++ mali-supply = <&vdd_log>; ++}; ++ ++&pwm1 { ++ pinctrl-0 = <&pwm1_pin_pull_down>; ++ status = "okay"; ++}; ++ ++&pwm2 { ++ pinctrl-0 = <&pwm2_pin_pull_up>; ++ status = "okay"; ++}; ++ ++&u2phy0 { ++ u2phy0_host: host-port { ++ phy-supply = <&vcc_host>; ++ }; ++ ++ u2phy0_otg: otg-port { ++ phy-supply = <&vcc_otg>; ++ }; ++}; ++ ++&u2phy1 { ++ u2phy1_host: host-port { ++ phy-supply = <&vcc_host>; ++ }; ++ ++ u2phy1_otg: otg-port { ++ phy-supply = <&vcc_otg>; ++ }; ++}; +diff --git a/arch/arm/boot/dts/rk322x-box.dtsi b/arch/arm/boot/dts/rk322x-box.dtsi +new file mode 100644 +index 000000000000..02c9b3540f38 +--- /dev/null ++++ b/arch/arm/boot/dts/rk322x-box.dtsi +@@ -0,0 +1,299 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR MIT) ++ ++/dts-v1/; ++ ++#include ++#include ++#include ++#include ++#include "rk322x.dtsi" ++ ++/ { ++ model = "Rockchip RK322x Box"; ++ compatible = "rockchip,rk3229"; ++ ++ chosen { ++ bootargs = "earlyprintk=uart8250,mmio32,0x11030000"; ++ }; ++ ++ gpio_keys { ++ compatible = "gpio-keys"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ autorepeat; ++ ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pwr_key>; ++ ++ power_key: power-key { ++ label = "GPIO Key Power"; ++ gpios = <&gpio3 RK_PD1 GPIO_ACTIVE_LOW>; ++ linux,code = ; ++ debounce-interval = <100>; ++ wakeup-source; ++ status = "disabled"; ++ }; ++ }; ++ ++ ir_receiver: ir-receiver { ++ compatible = "gpio-ir-receiver"; ++ gpios = <&gpio1 RK_PB3 GPIO_ACTIVE_LOW>; ++ pinctrl-0 = <&ir_int>; ++ pinctrl-names = "default"; ++ status = "disabled"; ++ }; ++ ++ memory@60000000 { ++ device_type = "memory"; ++ reg = <0x60000000 0x40000000>; ++ }; ++ ++ reserved-memory { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ranges; ++ ++ /* Not needed since u-boot 2020.07 ++ trust_reserved: trust@68400000 { ++ reg = <0x68400000 0xe00000>; ++ no-map; ++ };*/ ++ }; ++ ++ sdio_pwrseq: sdio-pwrseq { ++ compatible = "mmc-pwrseq-simple"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&wifi_enable_h>; ++ reset-gpios = <&gpio2 RK_PD2 GPIO_ACTIVE_LOW>; ++ }; ++ ++}; ++ ++&cpu_alert1 { ++ temperature = <105000>; ++}; ++ ++&cpu_crit { ++ temperature = <115000>; ++}; ++ ++&cpu_thermal { ++ cooling-maps { ++ /delete-node/ map0; ++ }; ++}; ++ ++&cpu0_opp_table { ++ ++ opp-408000000 { ++ opp-microvolt = <950000 950000 1275000>; ++ }; ++ ++ opp-600000000 { ++ opp-microvolt = <975000 975000 1275000>; ++ }; ++ ++ opp-816000000 { ++ opp-microvolt = <1000000 1000000 1275000>; ++ }; ++ ++ opp-1008000000 { ++ opp-microvolt = <1175000 1175000 1275000>; ++ }; ++ ++ opp-1200000000 { ++ opp-microvolt = <1275000 1275000 1275000>; ++ }; ++}; ++ ++&cru { ++ assigned-clocks = ++ <&cru PLL_GPLL>, <&cru ARMCLK>, ++ <&cru PLL_CPLL>, <&cru ACLK_PERI>, ++ <&cru HCLK_PERI>, <&cru PCLK_PERI>, ++ <&cru ACLK_CPU>, <&cru HCLK_CPU>, ++ <&cru PCLK_CPU>, <&cru ACLK_VOP>; ++ assigned-clock-rates = ++ <1200000000>, <816000000>, ++ <500000000>, <150000000>, ++ <150000000>, <75000000>, ++ <150000000>, <150000000>, ++ <75000000>, <400000000>; ++}; ++ ++&emmc { ++ cap-mmc-highspeed; ++ keep-power-in-suspend; ++ non-removable; ++}; ++ ++&gmac { ++ assigned-clocks = <&cru SCLK_MAC_SRC>; ++ assigned-clock-rates = <50000000>; ++ clock_in_out = "output"; ++ phy-handle = <&phy>; ++ phy-mode = "rmii"; ++ status = "okay"; ++ ++ mdio { ++ compatible = "snps,dwmac-mdio"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ phy: phy@0 { ++ compatible = "ethernet-phy-id1234.d400", ++ "ethernet-phy-ieee802.3-c22"; ++ reg = <0>; ++ clocks = <&cru SCLK_MAC_PHY>; ++ phy-is-integrated; ++ resets = <&cru SRST_MACPHY>; ++ }; ++ }; ++}; ++ ++&gpu { ++ assigned-clocks = <&cru ACLK_GPU>; ++ assigned-clock-rates = <300000000>; ++}; ++ ++&hdmi { ++ status = "okay"; ++}; ++ ++&hdmi_sound { ++ status = "okay"; ++}; ++ ++&hdmi_phy { ++ status = "okay"; ++}; ++ ++&i2s0 { ++ status = "okay"; ++}; ++ ++&pinctrl { ++ ++ ir { ++ ir_int: ir-int { ++ rockchip,pins = <1 RK_PB3 RK_FUNC_GPIO &pcfg_pull_none>; ++ }; ++ }; ++ ++ keys { ++ pwr_key: pwr-key { ++ rockchip,pins = <3 RK_PC7 RK_FUNC_GPIO &pcfg_pull_up>; ++ }; ++ }; ++ ++ pwm1 { ++ pwm1_pin_pull_down: pwm1-pin-pull-down { ++ rockchip,pins = <0 RK_PD6 2 &pcfg_pull_down>; ++ }; ++ }; ++ ++ pwm2 { ++ pwm2_pin_pull_up: pwm2-pin-pull-up { ++ rockchip,pins = <1 RK_PB4 2 &pcfg_pull_up>; ++ }; ++ }; ++ ++ sdio-pwrseq { ++ wifi_enable_h: wifi-enable-h { ++ rockchip,pins = <2 RK_PD2 RK_FUNC_GPIO &pcfg_pull_none>; ++ }; ++ }; ++ ++ usb { ++ host_vbus_drv: host-vbus-drv { ++ rockchip,pins = <3 RK_PC4 RK_FUNC_GPIO &pcfg_pull_none>; ++ }; ++ ++ otg_vbus_drv: otg-vbus-drv { ++ rockchip,pins = <3 RK_PC6 RK_FUNC_GPIO &pcfg_pull_none>; ++ }; ++ }; ++ ++}; ++ ++&sdio { ++ mmc-pwrseq = <&sdio_pwrseq>; ++ cap-sd-highspeed; ++ cap-sdio-irq; ++ keep-power-in-suspend; ++ non-removable; ++ no-sd; ++}; ++ ++&sdmmc { ++ cap-sd-highspeed; ++ keep-power-in-suspend; ++ no-sdio; ++}; ++ ++&tsadc { ++ rockchip,grf = <&grf>; ++ rockchip,hw-tshut-mode = <0>; ++ rockchip,hw-tshut-polarity = <1>; ++ rockchip,hw-tshut-temp = <120000>; ++ status = "okay"; ++}; ++ ++&u2phy0 { ++ status = "okay"; ++}; ++ ++&u2phy1 { ++ status = "okay"; ++}; ++ ++&uart1 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&uart11_xfer &uart11_rts &uart11_cts>; ++}; ++ ++&uart2 { ++ status = "okay"; ++}; ++ ++&usb_host0_ehci { ++ status = "okay"; ++}; ++ ++&usb_host0_ohci { ++ status = "okay"; ++}; ++ ++&usb_host1_ehci { ++ status = "okay"; ++}; ++ ++&usb_host1_ohci { ++ status = "okay"; ++}; ++ ++&usb_host2_ehci { ++ status = "okay"; ++}; ++ ++&usb_host2_ohci { ++ status = "okay"; ++}; ++ ++&usb_otg { ++ status = "okay"; ++}; ++ ++&vop { ++ assigned-clocks = <&cru DCLK_VOP>; ++ assigned-clock-parents = <&cru SCLK_HDMI_PHY>; ++ status = "okay"; ++}; ++ ++&vop_mmu { ++ status = "okay"; ++}; ++ ++&wdt { ++ status = "okay"; ++}; diff --git a/patch/kernel/rk322x-current/02-linux-0004-dtsi-adjust-nand-pinctrls.patch b/patch/kernel/rk322x-current/02-linux-0004-dtsi-adjust-nand-pinctrls.patch index f342f63b7..a6ea7e3d4 100644 --- a/patch/kernel/rk322x-current/02-linux-0004-dtsi-adjust-nand-pinctrls.patch +++ b/patch/kernel/rk322x-current/02-linux-0004-dtsi-adjust-nand-pinctrls.patch @@ -1,91 +1,92 @@ diff --git a/arch/arm/boot/dts/rk322x.dtsi b/arch/arm/boot/dts/rk322x.dtsi -index b2fcf0e75..25051c03f 100644 +index be46697e1..b2a0246fb 100644 --- a/arch/arm/boot/dts/rk322x.dtsi +++ b/arch/arm/boot/dts/rk322x.dtsi -@@ -1149,51 +1149,71 @@ +@@ -843,6 +843,22 @@ + status = "disabled"; + }; - flash_cs0: flash-cs0 { - rockchip,pins = -- <2 RK_PA6 1 &pcfg_pull_none>; -+ <2 RK_PA6 RK_FUNC_1 &pcfg_pull_up>; - }; - - flash_cs1: flash-cs1 { - rockchip,pins = -- <0 RK_PC7 1 &pcfg_pull_none>; -+ <0 RK_PC7 RK_FUNC_1 &pcfg_pull_up>; -+ }; ++ nfc: nand-controller@ff4b0000 { ++ compatible = "rockchip,rk3228_nfc"; ++ reg = <0x30030000 0x4000>; ++ interrupts = ; ++ clocks = <&cru SCLK_NANDC>, <&cru HCLK_NANDC>; ++ clock-names = "nfc", "ahb"; ++ assigned-clocks = <&cru SCLK_NANDC>; ++ assigned-clock-rates = <150000000>; + -+ flash_cs2: flash-cs2 { -+ rockchip,pins = -+ <1 RK_PC6 RK_FUNC_1 &pcfg_pull_up>; -+ }; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&flash_cs0 &flash_rdy &flash_ale &flash_cle ++ &flash_wrn &flash_rdn &flash_bus8>; ++ status = "disabled"; + -+ flash_cs3: flash-cs3 { -+ rockchip,pins = -+ <1 RK_PC7 RK_FUNC_1 &pcfg_pull_up>; - }; - - flash_rdy: flash-rdy { - rockchip,pins = -- <2 RK_PA4 1 &pcfg_pull_none>; -+ <2 RK_PA4 RK_FUNC_1 &pcfg_pull_up>; - }; - - flash_ale: flash-ale { - rockchip,pins = -- <2 RK_PA0 1 &pcfg_pull_none>; -+ <2 RK_PA0 RK_FUNC_1 &pcfg_pull_down>; - }; - - flash_cle: flash-cle { - rockchip,pins = -- <2 RK_PA1 1 &pcfg_pull_none>; -+ <2 RK_PA1 RK_FUNC_1 &pcfg_pull_down>; - }; - - flash_wrn: flash-wrn { -- rockchip,pins = -- <2 RK_PA2 1 &pcfg_pull_none>; -+ rockchip,pins = -+ <2 RK_PA2 RK_FUNC_1 &pcfg_pull_up>; - }; - - flash_rdn: flash-rdn { - rockchip,pins = -- <2 RK_PA3 1 &pcfg_pull_none>; -+ <2 RK_PA3 RK_FUNC_1 &pcfg_pull_up>; - }; - - flash_bus8: flash-bus8 { -- rockchip,pins = <1 RK_PD0 1 &pcfg_pull_none>, -- <1 RK_PD1 1 &pcfg_pull_none>, -- <1 RK_PD2 1 &pcfg_pull_none>, -- <1 RK_PD3 1 &pcfg_pull_none>, -- <1 RK_PD4 1 &pcfg_pull_none>, -- <1 RK_PD5 1 &pcfg_pull_none>, -- <1 RK_PD6 1 &pcfg_pull_none>, -- <1 RK_PD7 1 &pcfg_pull_none>; -+ rockchip,pins = <1 RK_PD0 RK_FUNC_1 &pcfg_pull_up>, -+ <1 RK_PD1 RK_FUNC_1 &pcfg_pull_up>, -+ <1 RK_PD2 RK_FUNC_1 &pcfg_pull_up>, -+ <1 RK_PD3 RK_FUNC_1 &pcfg_pull_up>, -+ <1 RK_PD4 RK_FUNC_1 &pcfg_pull_up>, -+ <1 RK_PD5 RK_FUNC_1 &pcfg_pull_up>, -+ <1 RK_PD6 RK_FUNC_1 &pcfg_pull_up>, -+ <1 RK_PD7 RK_FUNC_1 &pcfg_pull_up>; - }; -+ -+ flash_dqs: flash-dqs { -+ rockchip,pins = <2 RK_PA7 RK_FUNC_1 &pcfg_pull_up>; -+ }; -+ -+ flash_wp: flash-wp { -+ rockchip,pins = <2 RK_PA5 RK_FUNC_1 &pcfg_pull_down>; -+ }; ++ }; + + usb_otg: usb@30040000 { + compatible = "rockchip,rk3228-usb", "rockchip,rk3066-usb", + "snps,dwc2"; +@@ -1105,6 +1121,65 @@ + }; }; ++ flash { ++ ++ flash_cs0: flash-cs0 { ++ rockchip,pins = <2 RK_PA6 1 &pcfg_pull_up>; ++ }; ++ ++ flash_cs1: flash-cs1 { ++ rockchip,pins = <0 RK_PC7 1 &pcfg_pull_up>; ++ }; ++ ++ flash_cs2: flash-cs2 { ++ rockchip,pins = <1 RK_PC6 1 &pcfg_pull_up>; ++ }; ++ ++ flash_cs3: flash-cs3 { ++ rockchip,pins = <1 RK_PC7 1 &pcfg_pull_up>; ++ }; ++ ++ flash_rdy: flash-rdy { ++ rockchip,pins = <2 RK_PA4 1 &pcfg_pull_up>; ++ }; ++ ++ flash_ale: flash-ale { ++ rockchip,pins = <2 RK_PA0 1 &pcfg_pull_down>; ++ }; ++ ++ flash_cle: flash-cle { ++ rockchip,pins = <2 RK_PA1 1 &pcfg_pull_down>; ++ }; ++ ++ flash_wrn: flash-wrn { ++ rockchip,pins = <2 RK_PA2 1 &pcfg_pull_up>; ++ }; ++ ++ flash_rdn: flash-rdn { ++ rockchip,pins = <2 RK_PA3 1 &pcfg_pull_up>; ++ }; ++ ++ flash_bus8: flash-bus8 { ++ rockchip,pins = <1 RK_PD0 1 &pcfg_pull_up>, ++ <1 RK_PD1 1 &pcfg_pull_up>, ++ <1 RK_PD2 1 &pcfg_pull_up>, ++ <1 RK_PD3 1 &pcfg_pull_up>, ++ <1 RK_PD4 1 &pcfg_pull_up>, ++ <1 RK_PD5 1 &pcfg_pull_up>, ++ <1 RK_PD6 1 &pcfg_pull_up>, ++ <1 RK_PD7 1 &pcfg_pull_up>; ++ }; ++ ++ flash_dqs: flash-dqs { ++ rockchip,pins = <2 RK_PA7 1 &pcfg_pull_up>; ++ }; ++ ++ flash_wp: flash-wp { ++ rockchip,pins = <2 RK_PA5 1 &pcfg_pull_down>; ++ }; ++ ++ }; + gmac { rgmii_pins: rgmii-pins { diff --git a/patch/kernel/rk322x-current/02-linux-0005-drm-plane-overlay.patch b/patch/kernel/rk322x-current/02-linux-0005-drm-plane-overlay.patch new file mode 100644 index 000000000..15319a894 --- /dev/null +++ b/patch/kernel/rk322x-current/02-linux-0005-drm-plane-overlay.patch @@ -0,0 +1,66 @@ +diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c +index 73d24c6bbf05..d4ac6e161ef2 100644 +--- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c ++++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c +@@ -614,6 +614,44 @@ static const struct vop_common rk3288_common = { + .dsp_background = VOP_REG(RK3288_DSP_BG, 0xffffffff, 0), + }; + ++static const struct vop_win_phy rk3228_win0_data = { ++ .scl = &rk3288_win_full_scl, ++ .data_formats = formats_win_full, ++ .nformats = ARRAY_SIZE(formats_win_full), ++ .enable = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 0), ++ .format = VOP_REG(RK3288_WIN0_CTRL0, 0x7, 1), ++ .rb_swap = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 12), ++ .act_info = VOP_REG(RK3288_WIN0_ACT_INFO, 0x1fff1fff, 0), ++ .dsp_info = VOP_REG(RK3288_WIN0_DSP_INFO, 0x0fff0fff, 0), ++ .dsp_st = VOP_REG(RK3288_WIN0_DSP_ST, 0x1fff1fff, 0), ++ .yrgb_mst = VOP_REG(RK3288_WIN0_YRGB_MST, 0xffffffff, 0), ++ .uv_mst = VOP_REG(RK3288_WIN0_CBR_MST, 0xffffffff, 0), ++ .yrgb_vir = VOP_REG(RK3288_WIN0_VIR, 0x3fff, 0), ++ .uv_vir = VOP_REG(RK3288_WIN0_VIR, 0x3fff, 16), ++ .src_alpha_ctl = VOP_REG(RK3288_WIN0_SRC_ALPHA_CTRL, 0xff, 0), ++ .dst_alpha_ctl = VOP_REG(RK3288_WIN0_DST_ALPHA_CTRL, 0xff, 0), ++ .channel = VOP_REG(RK3288_WIN0_CTRL2, 0xff, 0), ++}; ++ ++static const struct vop_win_phy rk3228_win1_data = { ++ .scl = &rk3288_win_full_scl, ++ .data_formats = formats_win_lite, ++ .nformats = ARRAY_SIZE(formats_win_lite), ++ .enable = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 0), ++ .format = VOP_REG(RK3288_WIN0_CTRL0, 0x7, 1), ++ .rb_swap = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 12), ++ .act_info = VOP_REG(RK3288_WIN0_ACT_INFO, 0x1fff1fff, 0), ++ .dsp_info = VOP_REG(RK3288_WIN0_DSP_INFO, 0x0fff0fff, 0), ++ .dsp_st = VOP_REG(RK3288_WIN0_DSP_ST, 0x1fff1fff, 0), ++ .yrgb_mst = VOP_REG(RK3288_WIN0_YRGB_MST, 0xffffffff, 0), ++ .uv_mst = VOP_REG(RK3288_WIN0_CBR_MST, 0xffffffff, 0), ++ .yrgb_vir = VOP_REG(RK3288_WIN0_VIR, 0x3fff, 0), ++ .uv_vir = VOP_REG(RK3288_WIN0_VIR, 0x3fff, 16), ++ .src_alpha_ctl = VOP_REG(RK3288_WIN0_SRC_ALPHA_CTRL, 0xff, 0), ++ .dst_alpha_ctl = VOP_REG(RK3288_WIN0_DST_ALPHA_CTRL, 0xff, 0), ++ .channel = VOP_REG(RK3288_WIN0_CTRL2, 0xff, 0), ++}; ++ + /* + * Note: rk3288 has a dedicated 'cursor' window, however, that window requires + * special support to get alpha blending working. For now, just use overlay +@@ -864,10 +902,10 @@ static const struct vop_data rk3399_vop_lit = { + }; + + static const struct vop_win_data rk3228_vop_win_data[] = { +- { .base = 0x00, .phy = &rk3288_win01_data, ++ { .base = 0x00, .phy = &rk3228_win0_data, + .type = DRM_PLANE_TYPE_PRIMARY }, +- { .base = 0x40, .phy = &rk3288_win01_data, +- .type = DRM_PLANE_TYPE_CURSOR }, ++ { .base = 0x40, .phy = &rk3228_win1_data, ++ .type = DRM_PLANE_TYPE_OVERLAY }, + }; + + static const struct vop_data rk3228_vop = { +-- +2.17.1 + diff --git a/patch/kernel/rk322x-current/board-rk322x-box.patch b/patch/kernel/rk322x-current/board-rk322x-box.patch index 2151c9d54..2b92f90c3 100644 --- a/patch/kernel/rk322x-current/board-rk322x-box.patch +++ b/patch/kernel/rk322x-current/board-rk322x-box.patch @@ -3,7 +3,7 @@ new file mode 100644 index 000000000..24590f864 --- /dev/null +++ b/arch/arm/boot/dts/rk322x-box.dts -@@ -0,0 +1,239 @@ +@@ -0,0 +1,235 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) + +/dts-v1/; @@ -53,10 +53,6 @@ index 000000000..24590f864 + rockchip,default-sample-phase = <180>; +}; + -+&nfc { -+ status = "okay"; -+}; -+ +&gmac { + tx_delay = <0x26>; + rx_delay = <0x11>; @@ -141,18 +137,18 @@ index 000000000..24590f864 + */ + sdmmc { + sdmmc_clk: sdmmc-clk { -+ rockchip,pins = <1 16 RK_FUNC_1 &pcfg_pull_down>; ++ rockchip,pins = <1 16 1 &pcfg_pull_down>; + }; + + sdmmc_cmd: sdmmc-cmd { -+ rockchip,pins = <1 15 RK_FUNC_1 &pcfg_pull_up>; ++ rockchip,pins = <1 15 1 &pcfg_pull_up>; + }; + + sdmmc_bus4: sdmmc-bus4 { -+ rockchip,pins = <1 18 RK_FUNC_1 &pcfg_pull_up>, -+ <1 19 RK_FUNC_1 &pcfg_pull_up>, -+ <1 20 RK_FUNC_1 &pcfg_pull_up>, -+ <1 21 RK_FUNC_1 &pcfg_pull_up>; ++ rockchip,pins = <1 18 1 &pcfg_pull_up>, ++ <1 19 1 &pcfg_pull_up>, ++ <1 20 1 &pcfg_pull_up>, ++ <1 21 1 &pcfg_pull_up>; + }; + }; + @@ -162,18 +158,18 @@ index 000000000..24590f864 + */ + sdio { + sdio_clk: sdio-clk { -+ rockchip,pins = <3 0 RK_FUNC_1 &pcfg_pull_down_2ma>; ++ rockchip,pins = <3 0 1 &pcfg_pull_down_2ma>; + }; + + sdio_cmd: sdio-cmd { -+ rockchip,pins = <3 1 RK_FUNC_1 &pcfg_pull_up_2ma>; ++ rockchip,pins = <3 1 1 &pcfg_pull_up_2ma>; + }; + + sdio_bus4: sdio-bus4 { -+ rockchip,pins = <3 2 RK_FUNC_1 &pcfg_pull_up_2ma>, -+ <3 3 RK_FUNC_1 &pcfg_pull_up_2ma>, -+ <3 4 RK_FUNC_1 &pcfg_pull_up_2ma>, -+ <3 5 RK_FUNC_1 &pcfg_pull_up_2ma>; ++ rockchip,pins = <3 2 1 &pcfg_pull_up_2ma>, ++ <3 3 1 &pcfg_pull_up_2ma>, ++ <3 4 1 &pcfg_pull_up_2ma>, ++ <3 5 1 &pcfg_pull_up_2ma>; + }; + }; + @@ -183,30 +179,30 @@ index 000000000..24590f864 + */ + emmc { + emmc_clk: emmc-clk { -+ rockchip,pins = <2 7 RK_FUNC_2 &pcfg_pull_up>; ++ rockchip,pins = <2 7 2 &pcfg_pull_up>; + }; + + emmc_cmd: emmc-cmd { -+ rockchip,pins = <1 22 RK_FUNC_2 &pcfg_pull_up>; ++ rockchip,pins = <1 22 2 &pcfg_pull_up>; + }; + + emmc_bus8: emmc-bus8 { -+ rockchip,pins = <1 24 RK_FUNC_2 &pcfg_pull_up>, -+ <1 25 RK_FUNC_2 &pcfg_pull_up>, -+ <1 26 RK_FUNC_2 &pcfg_pull_up>, -+ <1 27 RK_FUNC_2 &pcfg_pull_up>, -+ <1 28 RK_FUNC_2 &pcfg_pull_up>, -+ <1 29 RK_FUNC_2 &pcfg_pull_up>, -+ <1 30 RK_FUNC_2 &pcfg_pull_up>, -+ <1 31 RK_FUNC_2 &pcfg_pull_up>; ++ rockchip,pins = <1 24 2 &pcfg_pull_up>, ++ <1 25 2 &pcfg_pull_up>, ++ <1 26 2 &pcfg_pull_up>, ++ <1 27 2 &pcfg_pull_up>, ++ <1 28 2 &pcfg_pull_up>, ++ <1 29 2 &pcfg_pull_up>, ++ <1 30 2 &pcfg_pull_up>, ++ <1 31 2 &pcfg_pull_up>; + }; + + emmc_pwr: emmc-pwr { -+ rockchip,pins = <2 RK_PA5 RK_FUNC_2 &pcfg_pull_down>; ++ rockchip,pins = <2 RK_PA5 2 &pcfg_pull_down>; + }; + + emmc_rst: emmc-rst { -+ rockchip,pins = <1 RK_PC7 RK_FUNC_2 &pcfg_pull_up>; ++ rockchip,pins = <1 RK_PC7 2 &pcfg_pull_up>; + }; + + }; diff --git a/patch/kernel/rk322x-current/wifi-4003-fix-sha256_state-clashes.patch b/patch/kernel/rk322x-current/wifi-4003-fix-sha256_state-clashes.patch new file mode 100644 index 000000000..0dce511a1 --- /dev/null +++ b/patch/kernel/rk322x-current/wifi-4003-fix-sha256_state-clashes.patch @@ -0,0 +1,248 @@ +diff --git a/drivers/net/wireless/rtl8189es/include/rtw_security.h b/drivers/net/wireless/rtl8189es/include/rtw_security.h +index 5820a55..3e8e428 100644 +--- a/drivers/net/wireless/rtl8189es/include/rtw_security.h ++++ b/drivers/net/wireless/rtl8189es/include/rtw_security.h +@@ -238,7 +238,7 @@ struct security_priv + #endif /* DBG_SW_SEC_CNT */ + }; + +-struct sha256_state { ++struct rtl_sha256_state { + u64 length; + u32 state[8], curlen; + u8 buf[64]; +diff --git a/drivers/net/wireless/rtl8189es/core/rtw_security.c b/drivers/net/wireless/rtl8189es/core/rtw_security.c +index 8dac771..9b3a1f9 100644 +--- a/drivers/net/wireless/rtl8189es/core/rtw_security.c ++++ b/drivers/net/wireless/rtl8189es/core/rtw_security.c +@@ -2281,7 +2281,7 @@ BIP_exit: + + #ifndef PLATFORM_FREEBSD + /* compress 512-bits */ +-static int sha256_compress(struct sha256_state *md, unsigned char *buf) ++static int sha256_compress(struct rtl_sha256_state *md, unsigned char *buf) + { + u32 S[8], W[64], t0, t1; + u32 t; +@@ -2323,7 +2323,7 @@ static int sha256_compress(struct sha256_state *md, unsigned char *buf) + } + + /* Initialize the hash state */ +-static void sha256_init(struct sha256_state *md) ++static void sha256_init(struct rtl_sha256_state *md) + { + md->curlen = 0; + md->length = 0; +@@ -2344,7 +2344,7 @@ static void sha256_init(struct sha256_state *md) + @param inlen The length of the data (octets) + @return CRYPT_OK if successful + */ +-static int sha256_process(struct sha256_state *md, unsigned char *in, ++static int sha256_process(struct rtl_sha256_state *md, unsigned char *in, + unsigned long inlen) + { + unsigned long n; +@@ -2385,7 +2385,7 @@ static int sha256_process(struct sha256_state *md, unsigned char *in, + @param out [out] The destination of the hash (32 bytes) + @return CRYPT_OK if successful + */ +-static int sha256_done(struct sha256_state *md, unsigned char *out) ++static int sha256_done(struct rtl_sha256_state *md, unsigned char *out) + { + int i; + +@@ -2437,7 +2437,7 @@ static int sha256_done(struct sha256_state *md, unsigned char *out) + static int sha256_vector(size_t num_elem, u8 *addr[], size_t *len, + u8 *mac) + { +- struct sha256_state ctx; ++ struct rtl_sha256_state ctx; + size_t i; + + sha256_init(&ctx); +diff --git a/drivers/net/wireless/rtl8811cu/include/rtw_security.h b/drivers/net/wireless/rtl8811cu/include/rtw_security.h +index ac8432e..5f74fb7 100755 +--- a/drivers/net/wireless/rtl8811cu/include/rtw_security.h ++++ b/drivers/net/wireless/rtl8811cu/include/rtw_security.h +@@ -249,7 +249,7 @@ struct security_priv { + #define SEC_IS_BIP_KEY_INSTALLED(sec) _FALSE + #endif + +-struct sha256_state { ++struct rtl_sha256_state { + u64 length; + u32 state[8], curlen; + u8 buf[64]; +diff --git a/drivers/net/wireless/rtl8811cu/core/rtw_security.c b/drivers/net/wireless/rtl8811cu/core/rtw_security.c +index b537a26..f8c42f4 100755 +--- a/drivers/net/wireless/rtl8811cu/core/rtw_security.c ++++ b/drivers/net/wireless/rtl8811cu/core/rtw_security.c +@@ -2133,7 +2133,7 @@ BIP_exit: + #ifndef PLATFORM_FREEBSD + #if defined(CONFIG_TDLS) + /* compress 512-bits */ +-static int sha256_compress(struct sha256_state *md, unsigned char *buf) ++static int sha256_compress(struct rtl_sha256_state *md, unsigned char *buf) + { + u32 S[8], W[64], t0, t1; + u32 t; +@@ -2181,7 +2181,7 @@ static int sha256_compress(struct sha256_state *md, unsigned char *buf) + } + + /* Initialize the hash state */ +-static void sha256_init(struct sha256_state *md) ++static void sha256_init(struct rtl_sha256_state *md) + { + md->curlen = 0; + md->length = 0; +@@ -2202,7 +2202,7 @@ static void sha256_init(struct sha256_state *md) + @param inlen The length of the data (octets) + @return CRYPT_OK if successful + */ +-static int sha256_process(struct sha256_state *md, unsigned char *in, ++static int sha256_process(struct rtl_sha256_state *md, unsigned char *in, + unsigned long inlen) + { + unsigned long n; +@@ -2243,7 +2243,7 @@ static int sha256_process(struct sha256_state *md, unsigned char *in, + @param out [out] The destination of the hash (32 bytes) + @return CRYPT_OK if successful + */ +-static int sha256_done(struct sha256_state *md, unsigned char *out) ++static int sha256_done(struct rtl_sha256_state *md, unsigned char *out) + { + int i; + +@@ -2293,7 +2293,7 @@ static int sha256_done(struct sha256_state *md, unsigned char *out) + static int sha256_vector(size_t num_elem, u8 *addr[], size_t *len, + u8 *mac) + { +- struct sha256_state ctx; ++ struct rtl_sha256_state ctx; + size_t i; + + sha256_init(&ctx); +diff --git a/drivers/net/wireless/rtl8188eu/include/rtw_security.h b/drivers/net/wireless/rtl8188eu/include/rtw_security.h +index 0adc700..2a9cf9d 100644 +--- a/drivers/net/wireless/rtl8188eu/include/rtw_security.h ++++ b/drivers/net/wireless/rtl8188eu/include/rtw_security.h +@@ -249,7 +249,7 @@ struct security_priv { + #define SEC_IS_BIP_KEY_INSTALLED(sec) _FALSE + #endif + +-struct sha256_state { ++struct rtl_sha256_state { + u64 length; + u32 state[8], curlen; + u8 buf[64]; +diff --git a/drivers/net/wireless/rtl8188eu/core/rtw_security.c b/drivers/net/wireless/rtl8188eu/core/rtw_security.c +index 5807521..0b3eed2 100644 +--- a/drivers/net/wireless/rtl8188eu/core/rtw_security.c ++++ b/drivers/net/wireless/rtl8188eu/core/rtw_security.c +@@ -2133,7 +2133,7 @@ BIP_exit: + #ifndef PLATFORM_FREEBSD + #if defined(CONFIG_TDLS) + /* compress 512-bits */ +-static int sha256_compress(struct sha256_state *md, unsigned char *buf) ++static int sha256_compress(struct rtl_sha256_state *md, unsigned char *buf) + { + u32 S[8], W[64], t0, t1; + u32 t; +@@ -2181,7 +2181,7 @@ static int sha256_compress(struct sha256_state *md, unsigned char *buf) + } + + /* Initialize the hash state */ +-static void sha256_init(struct sha256_state *md) ++static void sha256_init(struct rtl_sha256_state *md) + { + md->curlen = 0; + md->length = 0; +@@ -2202,7 +2202,7 @@ static void sha256_init(struct sha256_state *md) + @param inlen The length of the data (octets) + @return CRYPT_OK if successful + */ +-static int sha256_process(struct sha256_state *md, unsigned char *in, ++static int sha256_process(struct rtl_sha256_state *md, unsigned char *in, + unsigned long inlen) + { + unsigned long n; +@@ -2243,7 +2243,7 @@ static int sha256_process(struct sha256_state *md, unsigned char *in, + @param out [out] The destination of the hash (32 bytes) + @return CRYPT_OK if successful + */ +-static int sha256_done(struct sha256_state *md, unsigned char *out) ++static int sha256_done(struct rtl_sha256_state *md, unsigned char *out) + { + int i; + +@@ -2293,7 +2293,7 @@ static int sha256_done(struct sha256_state *md, unsigned char *out) + static int sha256_vector(size_t num_elem, u8 *addr[], size_t *len, + u8 *mac) + { +- struct sha256_state ctx; ++ struct rtl_sha256_state ctx; + size_t i; + + sha256_init(&ctx); +diff --git a/drivers/net/wireless/rtl88x2bu/include/rtw_security.h b/drivers/net/wireless/rtl88x2bu/include/rtw_security.h +index ac8432e..5f74fb7 100644 +--- a/drivers/net/wireless/rtl88x2bu/include/rtw_security.h ++++ b/drivers/net/wireless/rtl88x2bu/include/rtw_security.h +@@ -249,7 +249,7 @@ struct security_priv { + #define SEC_IS_BIP_KEY_INSTALLED(sec) _FALSE + #endif + +-struct sha256_state { ++struct rtl_sha256_state { + u64 length; + u32 state[8], curlen; + u8 buf[64]; +diff --git a/drivers/net/wireless/rtl88x2bu/core/rtw_security.c b/drivers/net/wireless/rtl88x2bu/core/rtw_security.c +index b537a26..f8c42f4 100644 +--- a/drivers/net/wireless/rtl88x2bu/core/rtw_security.c ++++ b/drivers/net/wireless/rtl88x2bu/core/rtw_security.c +@@ -2133,7 +2133,7 @@ BIP_exit: + #ifndef PLATFORM_FREEBSD + #if defined(CONFIG_TDLS) + /* compress 512-bits */ +-static int sha256_compress(struct sha256_state *md, unsigned char *buf) ++static int sha256_compress(struct rtl_sha256_state *md, unsigned char *buf) + { + u32 S[8], W[64], t0, t1; + u32 t; +@@ -2181,7 +2181,7 @@ static int sha256_compress(struct sha256_state *md, unsigned char *buf) + } + + /* Initialize the hash state */ +-static void sha256_init(struct sha256_state *md) ++static void sha256_init(struct rtl_sha256_state *md) + { + md->curlen = 0; + md->length = 0; +@@ -2202,7 +2202,7 @@ static void sha256_init(struct sha256_state *md) + @param inlen The length of the data (octets) + @return CRYPT_OK if successful + */ +-static int sha256_process(struct sha256_state *md, unsigned char *in, ++static int sha256_process(struct rtl_sha256_state *md, unsigned char *in, + unsigned long inlen) + { + unsigned long n; +@@ -2243,7 +2243,7 @@ static int sha256_process(struct sha256_state *md, unsigned char *in, + @param out [out] The destination of the hash (32 bytes) + @return CRYPT_OK if successful + */ +-static int sha256_done(struct sha256_state *md, unsigned char *out) ++static int sha256_done(struct rtl_sha256_state *md, unsigned char *out) + { + int i; + +@@ -2293,7 +2293,7 @@ static int sha256_done(struct sha256_state *md, unsigned char *out) + static int sha256_vector(size_t num_elem, u8 *addr[], size_t *len, + u8 *mac) + { +- struct sha256_state ctx; ++ struct rtl_sha256_state ctx; + size_t i; + + sha256_init(&ctx); diff --git a/patch/kernel/rk322x-current/wifi-4004-fix-cfg80211-for-5.8.patch b/patch/kernel/rk322x-current/wifi-4004-fix-cfg80211-for-5.8.patch new file mode 100644 index 000000000..587d60460 --- /dev/null +++ b/patch/kernel/rk322x-current/wifi-4004-fix-cfg80211-for-5.8.patch @@ -0,0 +1,236 @@ +diff --git a/drivers/net/wireless/rtl8189es/os_dep/linux/ioctl_cfg80211.c b/drivers/net/wireless/rtl8189es/os_dep/linux/ioctl_cfg80211.c +index d77cc17..32cc240 100644 +--- a/drivers/net/wireless/rtl8189es/os_dep/linux/ioctl_cfg80211.c ++++ b/drivers/net/wireless/rtl8189es/os_dep/linux/ioctl_cfg80211.c +@@ -5567,6 +5567,33 @@ exit: + return ret; + } + ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0)) ++ ++static void ++cfg80211_rtw_update_mgmt_frame_registrations(struct wiphy *wiphy, ++ struct wireless_dev *wdev, ++ struct mgmt_frame_regs *upd) ++{ ++ struct net_device *ndev = wdev_to_ndev(wdev); ++ struct rtw_wdev_priv *pwdev_priv; ++ _adapter *adapter; ++ ++ if (ndev == NULL) ++ return; ++ ++ adapter = (_adapter *)rtw_netdev_priv(ndev); ++ pwdev_priv = adapter_wdev_data(adapter); ++ ++#ifdef CONFIG_DEBUG_CFG80211 ++ RTW_INFO(FUNC_ADPT_FMT" stypes:%x\n", FUNC_ADPT_ARG(adapter), ++ upd->interface_stypes); ++#endif ++ ++ /* not implemented, see bellow */ ++} ++ ++#else ++ + static void cfg80211_rtw_mgmt_frame_register(struct wiphy *wiphy, + #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) + struct wireless_dev *wdev, +@@ -5611,6 +5638,8 @@ exit: + return; + } + ++#endif ++ + #if defined(CONFIG_TDLS) && (LINUX_VERSION_CODE >= KERNEL_VERSION(3,2,0)) + static int cfg80211_rtw_tdls_mgmt(struct wiphy *wiphy, + struct net_device *ndev, +@@ -6505,7 +6534,11 @@ static struct cfg80211_ops rtw_cfg80211_ops = { + + #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37)) || defined(COMPAT_KERNEL_RELEASE) + .mgmt_tx = cfg80211_rtw_mgmt_tx, ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0)) ++ .update_mgmt_frame_registrations = cfg80211_rtw_update_mgmt_frame_registrations, ++#else + .mgmt_frame_register = cfg80211_rtw_mgmt_frame_register, ++#endif + #elif (LINUX_VERSION_CODE>=KERNEL_VERSION(2,6,34) && LINUX_VERSION_CODE<=KERNEL_VERSION(2,6,35)) + .action = cfg80211_rtw_mgmt_tx, + #endif +diff --git a/drivers/net/wireless/rtl8811cu/os_dep/linux/ioctl_cfg80211.c b/drivers/net/wireless/rtl8811cu/os_dep/linux/ioctl_cfg80211.c +index c0df148..9bff924 100755 +--- a/drivers/net/wireless/rtl8811cu/os_dep/linux/ioctl_cfg80211.c ++++ b/drivers/net/wireless/rtl8811cu/os_dep/linux/ioctl_cfg80211.c +@@ -7143,6 +7143,33 @@ exit: + return ret; + } + ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0)) ++ ++static void ++cfg80211_rtw_update_mgmt_frame_registrations(struct wiphy *wiphy, ++ struct wireless_dev *wdev, ++ struct mgmt_frame_regs *upd) ++{ ++ struct net_device *ndev = wdev_to_ndev(wdev); ++ struct rtw_wdev_priv *pwdev_priv; ++ _adapter *adapter; ++ ++ if (ndev == NULL) ++ return; ++ ++ adapter = (_adapter *)rtw_netdev_priv(ndev); ++ pwdev_priv = adapter_wdev_data(adapter); ++ ++#ifdef CONFIG_DEBUG_CFG80211 ++ RTW_INFO(FUNC_ADPT_FMT" stypes:%x\n", FUNC_ADPT_ARG(adapter), ++ upd->interface_stypes); ++#endif ++ ++ /* not implemented, see bellow */ ++} ++ ++#else ++ + static void cfg80211_rtw_mgmt_frame_register(struct wiphy *wiphy, + #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) + struct wireless_dev *wdev, +@@ -7187,6 +7214,8 @@ exit: + return; + } + ++#endif ++ + #if defined(CONFIG_TDLS) && (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)) + static int cfg80211_rtw_tdls_mgmt(struct wiphy *wiphy, + struct net_device *ndev, +@@ -9457,7 +9486,11 @@ static struct cfg80211_ops rtw_cfg80211_ops = { + + #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)) || defined(COMPAT_KERNEL_RELEASE) + .mgmt_tx = cfg80211_rtw_mgmt_tx, ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0)) ++ .update_mgmt_frame_registrations = cfg80211_rtw_update_mgmt_frame_registrations, ++#else + .mgmt_frame_register = cfg80211_rtw_mgmt_frame_register, ++#endif + #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 34) && LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 35)) + .action = cfg80211_rtw_mgmt_tx, + #endif +diff --git a/drivers/net/wireless/rtl8188eu/os_dep/linux/ioctl_cfg80211.c b/drivers/net/wireless/rtl8188eu/os_dep/linux/ioctl_cfg80211.c +index 721723e..62fd530 100644 +--- a/drivers/net/wireless/rtl8188eu/os_dep/linux/ioctl_cfg80211.c ++++ b/drivers/net/wireless/rtl8188eu/os_dep/linux/ioctl_cfg80211.c +@@ -7470,6 +7470,33 @@ exit: + return ret; + } + ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0)) ++ ++static void ++cfg80211_rtw_update_mgmt_frame_registrations(struct wiphy *wiphy, ++ struct wireless_dev *wdev, ++ struct mgmt_frame_regs *upd) ++{ ++ struct net_device *ndev = wdev_to_ndev(wdev); ++ struct rtw_wdev_priv *pwdev_priv; ++ _adapter *adapter; ++ ++ if (ndev == NULL) ++ return; ++ ++ adapter = (_adapter *)rtw_netdev_priv(ndev); ++ pwdev_priv = adapter_wdev_data(adapter); ++ ++#ifdef CONFIG_DEBUG_CFG80211 ++ RTW_INFO(FUNC_ADPT_FMT" stypes:%x\n", FUNC_ADPT_ARG(adapter), ++ upd->interface_stypes); ++#endif ++ ++ /* not implemented, see bellow */ ++} ++ ++#else ++ + static void cfg80211_rtw_mgmt_frame_register(struct wiphy *wiphy, + #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) + struct wireless_dev *wdev, +@@ -7525,6 +7552,8 @@ exit: + return; + } + ++#endif ++ + #if defined(CONFIG_TDLS) && (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)) + static int cfg80211_rtw_tdls_mgmt(struct wiphy *wiphy, + struct net_device *ndev, +@@ -9903,7 +9932,11 @@ static struct cfg80211_ops rtw_cfg80211_ops = { + + #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)) || defined(COMPAT_KERNEL_RELEASE) + .mgmt_tx = cfg80211_rtw_mgmt_tx, ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0)) ++ .update_mgmt_frame_registrations = cfg80211_rtw_update_mgmt_frame_registrations, ++#else + .mgmt_frame_register = cfg80211_rtw_mgmt_frame_register, ++#endif + #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 34) && LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 35)) + .action = cfg80211_rtw_mgmt_tx, + #endif +diff --git a/drivers/net/wireless/rtl88x2bu/os_dep/linux/ioctl_cfg80211.c b/drivers/net/wireless/rtl88x2bu/os_dep/linux/ioctl_cfg80211.c +index 2fd4e28..b463e55 100755 +--- a/drivers/net/wireless/rtl88x2bu/os_dep/linux/ioctl_cfg80211.c ++++ b/drivers/net/wireless/rtl88x2bu/os_dep/linux/ioctl_cfg80211.c +@@ -7325,6 +7325,33 @@ exit: + return ret; + } + ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0)) ++ ++static void ++cfg80211_rtw_update_mgmt_frame_registrations(struct wiphy *wiphy, ++ struct wireless_dev *wdev, ++ struct mgmt_frame_regs *upd) ++{ ++ struct net_device *ndev = wdev_to_ndev(wdev); ++ struct rtw_wdev_priv *pwdev_priv; ++ _adapter *adapter; ++ ++ if (ndev == NULL) ++ return; ++ ++ adapter = (_adapter *)rtw_netdev_priv(ndev); ++ pwdev_priv = adapter_wdev_data(adapter); ++ ++#ifdef CONFIG_DEBUG_CFG80211 ++ RTW_INFO(FUNC_ADPT_FMT" stypes:%x\n", FUNC_ADPT_ARG(adapter), ++ upd->interface_stypes); ++#endif ++ ++ /* not implemented, see bellow */ ++} ++ ++#else ++ + static void cfg80211_rtw_mgmt_frame_register(struct wiphy *wiphy, + #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) + struct wireless_dev *wdev, +@@ -7369,6 +7396,8 @@ exit: + return; + } + ++#endif ++ + #if defined(CONFIG_TDLS) && (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)) + static int cfg80211_rtw_tdls_mgmt(struct wiphy *wiphy, + struct net_device *ndev, +@@ -9652,7 +9681,11 @@ static struct cfg80211_ops rtw_cfg80211_ops = { + + #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)) || defined(COMPAT_KERNEL_RELEASE) + .mgmt_tx = cfg80211_rtw_mgmt_tx, ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0)) ++ .update_mgmt_frame_registrations = cfg80211_rtw_update_mgmt_frame_registrations, ++#else + .mgmt_frame_register = cfg80211_rtw_mgmt_frame_register, ++#endif + #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 34) && LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 35)) + .action = cfg80211_rtw_mgmt_tx, + #endif diff --git a/patch/kernel/rk322x-dev/01-linux-0001-rockchip-from-5.9.patch b/patch/kernel/rk322x-dev/01-linux-0001-rockchip-from-5.9.patch new file mode 100644 index 000000000..d8845599b --- /dev/null +++ b/patch/kernel/rk322x-dev/01-linux-0001-rockchip-from-5.9.patch @@ -0,0 +1,3987 @@ +From df792eba98fd6a729c254623ea28968f642efd1e Mon Sep 17 00:00:00 2001 +From: Tobias Schramm +Date: Thu, 28 May 2020 19:25:50 +0200 +Subject: [PATCH] arm64: dts: rockchip: add fuel gauge to Pinebook Pro dts + +This commit adds cw2015 fuel gauge and battery to the Pinebook Pro dts. + +Signed-off-by: Tobias Schramm +Link: https://lore.kernel.org/r/20200528172550.2324722-2-t.schramm@manjaro.org +Signed-off-by: Heiko Stuebner +(cherry picked from commit c7c4d698cd2882c4d095aeed43bbad6fc990e998) +--- + .../boot/dts/rockchip/rk3399-pinebook-pro.dts | 25 +++++++++++++++++++ + 1 file changed, 25 insertions(+) + +diff --git a/arch/arm64/boot/dts/rockchip/rk3399-pinebook-pro.dts b/arch/arm64/boot/dts/rockchip/rk3399-pinebook-pro.dts +index cb0245d2226d..8f5b2df01560 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3399-pinebook-pro.dts ++++ b/arch/arm64/boot/dts/rockchip/rk3399-pinebook-pro.dts +@@ -28,6 +28,13 @@ backlight: edp-backlight { + pwms = <&pwm0 0 740740 0>; + }; + ++ bat: battery { ++ compatible = "simple-battery"; ++ charge-full-design-microamp-hours = <9800000>; ++ voltage-max-design-microvolt = <4350000>; ++ voltage-min-design-microvolt = <3000000>; ++ }; ++ + edp_panel: edp-panel { + compatible = "boe,nv140fhmn49"; + backlight = <&backlight>; +@@ -741,6 +748,24 @@ usbc_dp: endpoint { + }; + }; + }; ++ ++ cw2015@62 { ++ compatible = "cellwise,cw2015"; ++ reg = <0x62>; ++ cellwise,battery-profile = /bits/ 8 < ++ 0x17 0x67 0x80 0x73 0x6E 0x6C 0x6B 0x63 ++ 0x77 0x51 0x5C 0x58 0x50 0x4C 0x48 0x36 ++ 0x15 0x0C 0x0C 0x19 0x5B 0x7D 0x6F 0x69 ++ 0x69 0x5B 0x0C 0x29 0x20 0x40 0x52 0x59 ++ 0x57 0x56 0x54 0x4F 0x3B 0x1F 0x7F 0x17 ++ 0x06 0x1A 0x30 0x5A 0x85 0x93 0x96 0x2D ++ 0x48 0x77 0x9C 0xB3 0x80 0x52 0x94 0xCB ++ 0x2F 0x00 0x64 0xA5 0xB5 0x11 0xF0 0x11 ++ >; ++ cellwise,monitor-interval-ms = <5000>; ++ monitored-battery = <&bat>; ++ power-supplies = <&mains_charger>, <&fusb0>; ++ }; + }; + + &i2s1 { + +From 279f038076d9ccc8a78c938eaf8008ff626ccb10 Mon Sep 17 00:00:00 2001 +From: Peter Geis +Date: Sun, 14 Jun 2020 14:29:51 +0000 +Subject: [PATCH] arm64: dts: rockchip: set rockpro64 usbc dr_mode as host + +The usb-c port on the rockpro64 does not detect devices reliably when in otg mode. +Setting the mode to "host" allows the port to work reliably. +This aligns with the pinebook-pro configuration. + +Signed-off-by: Peter Geis +Link: https://lore.kernel.org/r/20200614142950.1120694-1-pgwipeout@gmail.com +Signed-off-by: Heiko Stuebner +(cherry picked from commit 75152d66315521a48c4997305f4e01c5f139e160) +--- + arch/arm64/boot/dts/rockchip/rk3399-rockpro64.dtsi | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/rockchip/rk3399-rockpro64.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-rockpro64.dtsi +index 6788ab28f89a..3456ee97c288 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3399-rockpro64.dtsi ++++ b/arch/arm64/boot/dts/rockchip/rk3399-rockpro64.dtsi +@@ -795,7 +795,7 @@ &usbdrd3_0 { + + &usbdrd_dwc3_0 { + status = "okay"; +- dr_mode = "otg"; ++ dr_mode = "host"; + }; + + &usbdrd3_1 { + +From f739ccdaa19eac37af51d49e2d56e84b0bf62bfa Mon Sep 17 00:00:00 2001 +From: Johan Jonker +Date: Sun, 24 May 2020 18:06:36 +0200 +Subject: [PATCH] arm64: dts: rockchip: rename label and nodename pinctrl + subnodes that end with gpio + +A test with the command below gives for example this error: + +arch/arm64/boot/dts/rockchip/rk3326-odroid-go2.dt.yaml: +tsadc: tsadc-otp-gpio: +{'phandle': [[90]], 'rockchip,pins': [[0, 6, 0, 123]]} +is not of type 'array' + +'gpio' is a sort of reserved nodename and should not be used +for pinctrl in combination with 'rockchip,pins', so change +nodes that end with 'gpio' to end with 'pin' or 'pins'. + +make ARCH=arm64 dtbs_check +DT_SCHEMA_FILES=~/.local/lib/python3.5/site-packages/ +dtschema/schemas/gpio/gpio.yaml + +Signed-off-by: Johan Jonker +Link: https://lore.kernel.org/r/20200524160636.16547-2-jbx6244@gmail.com +Signed-off-by: Heiko Stuebner +(cherry picked from commit 2bc65fef4fe424f5f8295175f1b42f8b94c6df01) +--- + arch/arm64/boot/dts/rockchip/px30.dtsi | 6 +- + arch/arm64/boot/dts/rockchip/rk3308.dtsi | 6 +- + arch/arm64/boot/dts/rockchip/rk3328-evb.dts | 2 +- + .../arm64/boot/dts/rockchip/rk3328-roc-cc.dts | 2 +- + .../arm64/boot/dts/rockchip/rk3328-rock64.dts | 2 +- + arch/arm64/boot/dts/rockchip/rk3328.dtsi | 24 +++--- + .../boot/dts/rockchip/rk3368-lion-haikou.dts | 2 +- + arch/arm64/boot/dts/rockchip/rk3368.dtsi | 6 +- + .../boot/dts/rockchip/rk3399-firefly.dts | 4 +- + .../boot/dts/rockchip/rk3399-gru-scarlet.dtsi | 2 +- + arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi | 4 +- + .../boot/dts/rockchip/rk3399-hugsun-x99.dts | 8 +- + .../boot/dts/rockchip/rk3399-leez-p710.dts | 8 +- + .../boot/dts/rockchip/rk3399-pinebook-pro.dts | 74 +++++++++---------- + .../boot/dts/rockchip/rk3399-roc-pc.dtsi | 8 +- + .../boot/dts/rockchip/rk3399-rock-pi-4.dts | 8 +- + .../boot/dts/rockchip/rk3399-rock960.dtsi | 4 +- + .../boot/dts/rockchip/rk3399-rockpro64.dtsi | 8 +- + .../boot/dts/rockchip/rk3399-sapphire.dtsi | 4 +- + arch/arm64/boot/dts/rockchip/rk3399.dtsi | 6 +- + 20 files changed, 94 insertions(+), 94 deletions(-) + +diff --git a/arch/arm64/boot/dts/rockchip/px30.dtsi b/arch/arm64/boot/dts/rockchip/px30.dtsi +index a6b8427156d5..e9bb2b97ae55 100644 +--- a/arch/arm64/boot/dts/rockchip/px30.dtsi ++++ b/arch/arm64/boot/dts/rockchip/px30.dtsi +@@ -733,9 +733,9 @@ tsadc: tsadc@ff280000 { + rockchip,grf = <&grf>; + rockchip,hw-tshut-temp = <120000>; + pinctrl-names = "init", "default", "sleep"; +- pinctrl-0 = <&tsadc_otp_gpio>; ++ pinctrl-0 = <&tsadc_otp_pin>; + pinctrl-1 = <&tsadc_otp_out>; +- pinctrl-2 = <&tsadc_otp_gpio>; ++ pinctrl-2 = <&tsadc_otp_pin>; + #thermal-sensor-cells = <1>; + status = "disabled"; + }; +@@ -1373,7 +1373,7 @@ i2c3_xfer: i2c3-xfer { + }; + + tsadc { +- tsadc_otp_gpio: tsadc-otp-gpio { ++ tsadc_otp_pin: tsadc-otp-pin { + rockchip,pins = + <0 RK_PA6 RK_FUNC_GPIO &pcfg_pull_none>; + }; +diff --git a/arch/arm64/boot/dts/rockchip/rk3308.dtsi b/arch/arm64/boot/dts/rockchip/rk3308.dtsi +index ac7f694079d0..ba1c71568164 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3308.dtsi ++++ b/arch/arm64/boot/dts/rockchip/rk3308.dtsi +@@ -1629,7 +1629,7 @@ spi2_mosi: spi2-mosi { + }; + + tsadc { +- tsadc_otp_gpio: tsadc-otp-gpio { ++ tsadc_otp_pin: tsadc-otp-pin { + rockchip,pins = + <0 RK_PB2 0 &pcfg_pull_none>; + }; +@@ -1657,7 +1657,7 @@ uart0_rts: uart0-rts { + <2 RK_PA3 1 &pcfg_pull_none>; + }; + +- uart0_rts_gpio: uart0-rts-gpio { ++ uart0_rts_pin: uart0-rts-pin { + rockchip,pins = + <2 RK_PA3 0 &pcfg_pull_none>; + }; +@@ -1730,7 +1730,7 @@ uart4_rts: uart4-rts { + <4 RK_PA7 1 &pcfg_pull_none>; + }; + +- uart4_rts_gpio: uart4-rts-gpio { ++ uart4_rts_pin: uart4-rts-pin { + rockchip,pins = + <4 RK_PA7 0 &pcfg_pull_none>; + }; +diff --git a/arch/arm64/boot/dts/rockchip/rk3328-evb.dts b/arch/arm64/boot/dts/rockchip/rk3328-evb.dts +index ac29c2744d08..1969dab84138 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3328-evb.dts ++++ b/arch/arm64/boot/dts/rockchip/rk3328-evb.dts +@@ -41,7 +41,7 @@ vcc_sd: sdmmc-regulator { + compatible = "regulator-fixed"; + gpio = <&gpio0 30 GPIO_ACTIVE_LOW>; + pinctrl-names = "default"; +- pinctrl-0 = <&sdmmc0m1_gpio>; ++ pinctrl-0 = <&sdmmc0m1_pin>; + regulator-name = "vcc_sd"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; +diff --git a/arch/arm64/boot/dts/rockchip/rk3328-roc-cc.dts b/arch/arm64/boot/dts/rockchip/rk3328-roc-cc.dts +index 34db48c274e5..b70ffb1c6a63 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3328-roc-cc.dts ++++ b/arch/arm64/boot/dts/rockchip/rk3328-roc-cc.dts +@@ -34,7 +34,7 @@ vcc_sd: sdmmc-regulator { + compatible = "regulator-fixed"; + gpio = <&gpio0 RK_PD6 GPIO_ACTIVE_LOW>; + pinctrl-names = "default"; +- pinctrl-0 = <&sdmmc0m1_gpio>; ++ pinctrl-0 = <&sdmmc0m1_pin>; + regulator-boot-on; + regulator-name = "vcc_sd"; + regulator-min-microvolt = <3300000>; +diff --git a/arch/arm64/boot/dts/rockchip/rk3328-rock64.dts b/arch/arm64/boot/dts/rockchip/rk3328-rock64.dts +index 6e09c223ed57..86cfb5c50a94 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3328-rock64.dts ++++ b/arch/arm64/boot/dts/rockchip/rk3328-rock64.dts +@@ -25,7 +25,7 @@ vcc_sd: sdmmc-regulator { + compatible = "regulator-fixed"; + gpio = <&gpio0 RK_PD6 GPIO_ACTIVE_LOW>; + pinctrl-names = "default"; +- pinctrl-0 = <&sdmmc0m1_gpio>; ++ pinctrl-0 = <&sdmmc0m1_pin>; + regulator-name = "vcc_sd"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; +diff --git a/arch/arm64/boot/dts/rockchip/rk3328.dtsi b/arch/arm64/boot/dts/rockchip/rk3328.dtsi +index d399883d4b75..72e655020560 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3328.dtsi ++++ b/arch/arm64/boot/dts/rockchip/rk3328.dtsi +@@ -552,9 +552,9 @@ tsadc: tsadc@ff250000 { + clocks = <&cru SCLK_TSADC>, <&cru PCLK_TSADC>; + clock-names = "tsadc", "apb_pclk"; + pinctrl-names = "init", "default", "sleep"; +- pinctrl-0 = <&otp_gpio>; ++ pinctrl-0 = <&otp_pin>; + pinctrl-1 = <&otp_out>; +- pinctrl-2 = <&otp_gpio>; ++ pinctrl-2 = <&otp_pin>; + resets = <&cru SRST_TSADC>; + reset-names = "tsadc-apb"; + rockchip,grf = <&grf>; +@@ -1154,7 +1154,7 @@ i2c3_xfer: i2c3-xfer { + rockchip,pins = <0 RK_PA5 2 &pcfg_pull_none>, + <0 RK_PA6 2 &pcfg_pull_none>; + }; +- i2c3_gpio: i2c3-gpio { ++ i2c3_pins: i2c3-pins { + rockchip,pins = + <0 RK_PA5 RK_FUNC_GPIO &pcfg_pull_none>, + <0 RK_PA6 RK_FUNC_GPIO &pcfg_pull_none>; +@@ -1225,7 +1225,7 @@ pdmm0_fsync_sleep: pdmm0-fsync-sleep { + }; + + tsadc { +- otp_gpio: otp-gpio { ++ otp_pin: otp-pin { + rockchip,pins = <2 RK_PB5 RK_FUNC_GPIO &pcfg_pull_none>; + }; + +@@ -1248,7 +1248,7 @@ uart0_rts: uart0-rts { + rockchip,pins = <1 RK_PB2 1 &pcfg_pull_none>; + }; + +- uart0_rts_gpio: uart0-rts-gpio { ++ uart0_rts_pin: uart0-rts-pin { + rockchip,pins = <1 RK_PB2 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; +@@ -1267,7 +1267,7 @@ uart1_rts: uart1-rts { + rockchip,pins = <3 RK_PA5 4 &pcfg_pull_none>; + }; + +- uart1_rts_gpio: uart1-rts-gpio { ++ uart1_rts_pin: uart1-rts-pin { + rockchip,pins = <3 RK_PA5 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; +@@ -1493,7 +1493,7 @@ sdmmc0m0_pwren: sdmmc0m0-pwren { + rockchip,pins = <2 RK_PA7 1 &pcfg_pull_up_4ma>; + }; + +- sdmmc0m0_gpio: sdmmc0m0-gpio { ++ sdmmc0m0_pin: sdmmc0m0-pin { + rockchip,pins = <2 RK_PA7 RK_FUNC_GPIO &pcfg_pull_up_4ma>; + }; + }; +@@ -1503,7 +1503,7 @@ sdmmc0m1_pwren: sdmmc0m1-pwren { + rockchip,pins = <0 RK_PD6 3 &pcfg_pull_up_4ma>; + }; + +- sdmmc0m1_gpio: sdmmc0m1-gpio { ++ sdmmc0m1_pin: sdmmc0m1-pin { + rockchip,pins = <0 RK_PD6 RK_FUNC_GPIO &pcfg_pull_up_4ma>; + }; + }; +@@ -1536,7 +1536,7 @@ sdmmc0_bus4: sdmmc0-bus4 { + <1 RK_PA3 1 &pcfg_pull_up_8ma>; + }; + +- sdmmc0_gpio: sdmmc0-gpio { ++ sdmmc0_pins: sdmmc0-pins { + rockchip,pins = + <1 RK_PA6 RK_FUNC_GPIO &pcfg_pull_up_4ma>, + <1 RK_PA4 RK_FUNC_GPIO &pcfg_pull_up_4ma>, +@@ -1578,7 +1578,7 @@ sdmmc0ext_bus4: sdmmc0ext-bus4 { + <3 RK_PA7 3 &pcfg_pull_up_4ma>; + }; + +- sdmmc0ext_gpio: sdmmc0ext-gpio { ++ sdmmc0ext_pins: sdmmc0ext-pins { + rockchip,pins = + <3 RK_PA0 RK_FUNC_GPIO &pcfg_pull_up_4ma>, + <3 RK_PA1 RK_FUNC_GPIO &pcfg_pull_up_4ma>, +@@ -1623,7 +1623,7 @@ sdmmc1_bus4: sdmmc1-bus4 { + <1 RK_PC1 1 &pcfg_pull_up_8ma>; + }; + +- sdmmc1_gpio: sdmmc1-gpio { ++ sdmmc1_pins: sdmmc1-pins { + rockchip,pins = + <1 RK_PB4 RK_FUNC_GPIO &pcfg_pull_up_4ma>, + <1 RK_PB5 RK_FUNC_GPIO &pcfg_pull_up_4ma>, +@@ -1817,7 +1817,7 @@ tsadc_pin { + tsadc_int: tsadc-int { + rockchip,pins = <2 RK_PB5 2 &pcfg_pull_none>; + }; +- tsadc_gpio: tsadc-gpio { ++ tsadc_pin: tsadc-pin { + rockchip,pins = <2 RK_PB5 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; +diff --git a/arch/arm64/boot/dts/rockchip/rk3368-lion-haikou.dts b/arch/arm64/boot/dts/rockchip/rk3368-lion-haikou.dts +index cbde279ae81d..dbd2caba322f 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3368-lion-haikou.dts ++++ b/arch/arm64/boot/dts/rockchip/rk3368-lion-haikou.dts +@@ -125,7 +125,7 @@ led_sd_haikou: led-sd-gpio { + }; + + sdmmc { +- sdmmc_cd_gpio: sdmmc-cd-gpio { ++ sdmmc_cd_pin: sdmmc-cd-pin { + rockchip,pins = + <2 RK_PB3 RK_FUNC_GPIO &pcfg_pull_none>; + }; +diff --git a/arch/arm64/boot/dts/rockchip/rk3368.dtsi b/arch/arm64/boot/dts/rockchip/rk3368.dtsi +index 1ebb0eef42da..5d25a9d04051 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3368.dtsi ++++ b/arch/arm64/boot/dts/rockchip/rk3368.dtsi +@@ -483,9 +483,9 @@ tsadc: tsadc@ff280000 { + resets = <&cru SRST_TSADC>; + reset-names = "tsadc-apb"; + pinctrl-names = "init", "default", "sleep"; +- pinctrl-0 = <&otp_gpio>; ++ pinctrl-0 = <&otp_pin>; + pinctrl-1 = <&otp_out>; +- pinctrl-2 = <&otp_gpio>; ++ pinctrl-2 = <&otp_pin>; + #thermal-sensor-cells = <1>; + rockchip,hw-tshut-temp = <95000>; + status = "disabled"; +@@ -1145,7 +1145,7 @@ spi2_tx: spi2-tx { + }; + + tsadc { +- otp_gpio: otp-gpio { ++ otp_pin: otp-pin { + rockchip,pins = <0 RK_PA3 RK_FUNC_GPIO &pcfg_pull_none>; + }; + +diff --git a/arch/arm64/boot/dts/rockchip/rk3399-firefly.dts b/arch/arm64/boot/dts/rockchip/rk3399-firefly.dts +index 20b5599f5e78..6db18808b9c5 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3399-firefly.dts ++++ b/arch/arm64/boot/dts/rockchip/rk3399-firefly.dts +@@ -589,11 +589,11 @@ pcie_3g_drv: pcie-3g-drv { + }; + + pmic { +- vsel1_gpio: vsel1-gpio { ++ vsel1_pin: vsel1-pin { + rockchip,pins = <1 RK_PC2 RK_FUNC_GPIO &pcfg_pull_down>; + }; + +- vsel2_gpio: vsel2-gpio { ++ vsel2_pin: vsel2-pin { + rockchip,pins = <1 RK_PB6 RK_FUNC_GPIO &pcfg_pull_down>; + }; + }; +diff --git a/arch/arm64/boot/dts/rockchip/rk3399-gru-scarlet.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-gru-scarlet.dtsi +index 4373ed732af7..60cd1c18cd4e 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3399-gru-scarlet.dtsi ++++ b/arch/arm64/boot/dts/rockchip/rk3399-gru-scarlet.dtsi +@@ -499,7 +499,7 @@ &i2s0_8ch_bus { + }; + + /* there is no external pull up, so need to set this pin pull up */ +-&sdmmc_cd_gpio { ++&sdmmc_cd_pin { + rockchip,pins = <1 RK_PB3 RK_FUNC_GPIO &pcfg_pull_up>; + }; + +diff --git a/arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi +index 2f3997740068..32dcaf210085 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi ++++ b/arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi +@@ -516,7 +516,7 @@ &sdmmc { + * configured as SDMMC and not JTAG. + */ + pinctrl-names = "default"; +- pinctrl-0 = <&sdmmc_clk &sdmmc_cmd &sdmmc_cd &sdmmc_cd_gpio ++ pinctrl-0 = <&sdmmc_clk &sdmmc_cmd &sdmmc_cd &sdmmc_cd_pin + &sdmmc_bus4>; + + bus-width = <4>; +@@ -767,7 +767,7 @@ sdmmc_cd: sdmmc-cd { + }; + + /* This is where we actually hook up CD; has external pull */ +- sdmmc_cd_gpio: sdmmc-cd-gpio { ++ sdmmc_cd_pin: sdmmc-cd-pin { + rockchip,pins = <4 RK_PD0 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; +diff --git a/arch/arm64/boot/dts/rockchip/rk3399-hugsun-x99.dts b/arch/arm64/boot/dts/rockchip/rk3399-hugsun-x99.dts +index bf87fa32d3b1..341d074ed996 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3399-hugsun-x99.dts ++++ b/arch/arm64/boot/dts/rockchip/rk3399-hugsun-x99.dts +@@ -205,7 +205,7 @@ vdd_cpu_b: syr827@40 { + compatible = "silergy,syr827"; + reg = <0x40>; + regulator-compatible = "fan53555-reg"; +- pinctrl-0 = <&vsel1_gpio>; ++ pinctrl-0 = <&vsel1_pin>; + regulator-name = "vdd_cpu_b"; + regulator-min-microvolt = <712500>; + regulator-max-microvolt = <1500000>; +@@ -223,7 +223,7 @@ vdd_gpu: syr828@41 { + compatible = "silergy,syr828"; + reg = <0x41>; + regulator-compatible = "fan53555-reg"; +- pinctrl-0 = <&vsel2_gpio>; ++ pinctrl-0 = <&vsel2_pin>; + regulator-name = "vdd_gpu"; + regulator-min-microvolt = <712500>; + regulator-max-microvolt = <1500000>; +@@ -521,12 +521,12 @@ pmic_int_l: pmic-int-l { + <1 RK_PC5 RK_FUNC_GPIO &pcfg_pull_up>; + }; + +- vsel1_gpio: vsel1-gpio { ++ vsel1_pin: vsel1-pin { + rockchip,pins = + <1 RK_PC1 RK_FUNC_GPIO &pcfg_pull_down>; + }; + +- vsel2_gpio: vsel2-gpio { ++ vsel2_pin: vsel2-pin { + rockchip,pins = + <1 RK_PB6 RK_FUNC_GPIO &pcfg_pull_down>; + }; +diff --git a/arch/arm64/boot/dts/rockchip/rk3399-leez-p710.dts b/arch/arm64/boot/dts/rockchip/rk3399-leez-p710.dts +index 73be38a53796..1fa80ac15464 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3399-leez-p710.dts ++++ b/arch/arm64/boot/dts/rockchip/rk3399-leez-p710.dts +@@ -341,7 +341,7 @@ vdd_cpu_b: regulator@40 { + reg = <0x40>; + fcs,suspend-voltage-selector = <1>; + pinctrl-names = "default"; +- pinctrl-0 = <&vsel1_gpio>; ++ pinctrl-0 = <&vsel1_pin>; + regulator-name = "vdd_cpu_b"; + regulator-min-microvolt = <712500>; + regulator-max-microvolt = <1500000>; +@@ -360,7 +360,7 @@ vdd_gpu: regulator@41 { + reg = <0x41>; + fcs,suspend-voltage-selector = <1>; + pinctrl-names = "default"; +- pinctrl-0 = <&vsel2_gpio>; ++ pinctrl-0 = <&vsel2_pin>; + regulator-name = "vdd_gpu"; + regulator-min-microvolt = <712500>; + regulator-max-microvolt = <1500000>; +@@ -447,11 +447,11 @@ pmic_int_l: pmic-int-l { + rockchip,pins = <1 RK_PC5 RK_FUNC_GPIO &pcfg_pull_up>; + }; + +- vsel1_gpio: vsel1-gpio { ++ vsel1_pin: vsel1-pin { + rockchip,pins = <1 RK_PC1 RK_FUNC_GPIO &pcfg_pull_down>; + }; + +- vsel2_gpio: vsel2-gpio { ++ vsel2_pin: vsel2-pin { + rockchip,pins = <1 RK_PB6 RK_FUNC_GPIO &pcfg_pull_down>; + }; + }; +diff --git a/arch/arm64/boot/dts/rockchip/rk3399-pinebook-pro.dts b/arch/arm64/boot/dts/rockchip/rk3399-pinebook-pro.dts +index 8f5b2df01560..06d48338c836 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3399-pinebook-pro.dts ++++ b/arch/arm64/boot/dts/rockchip/rk3399-pinebook-pro.dts +@@ -40,7 +40,7 @@ edp_panel: edp-panel { + backlight = <&backlight>; + enable-gpios = <&gpio1 RK_PA0 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; +- pinctrl-0 = <&panel_en_gpio>; ++ pinctrl-0 = <&panel_en_pin>; + power-supply = <&vcc3v3_panel>; + + ports { +@@ -67,7 +67,7 @@ panel_in_edp: endpoint@0 { + gpio-key-lid { + compatible = "gpio-keys"; + pinctrl-names = "default"; +- pinctrl-0 = <&lidbtn_gpio>; ++ pinctrl-0 = <&lidbtn_pin>; + + lid { + debounce-interval = <20>; +@@ -83,7 +83,7 @@ lid { + gpio-key-power { + compatible = "gpio-keys"; + pinctrl-names = "default"; +- pinctrl-0 = <&pwrbtn_gpio>; ++ pinctrl-0 = <&pwrbtn_pin>; + + power { + debounce-interval = <20>; +@@ -124,7 +124,7 @@ sdio_pwrseq: sdio-pwrseq { + clocks = <&rk808 1>; + clock-names = "ext_clock"; + pinctrl-names = "default"; +- pinctrl-0 = <&wifi_enable_h_gpio>; ++ pinctrl-0 = <&wifi_enable_h_pin>; + post-power-on-delay-ms = <100>; + power-off-delay-us = <500000>; + +@@ -136,7 +136,7 @@ sdio_pwrseq: sdio-pwrseq { + es8316-sound { + compatible = "simple-audio-card"; + pinctrl-names = "default"; +- pinctrl-0 = <&hp_det_gpio>; ++ pinctrl-0 = <&hp_det_pin>; + simple-audio-card,name = "rockchip,es8316-codec"; + simple-audio-card,format = "i2s"; + simple-audio-card,mclk-fs = <256>; +@@ -220,7 +220,7 @@ vcc5v0_usb: pa_5v: vcc5v0-usb-regulator { + enable-active-high; + gpio = <&gpio1 RK_PB5 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; +- pinctrl-0 = <&pwr_5v_gpio>; ++ pinctrl-0 = <&pwr_5v_pin>; + regulator-name = "vcc5v0_usb"; + regulator-always-on; + regulator-min-microvolt = <5000000>; +@@ -277,7 +277,7 @@ vcc3v0_sd: vcc3v0-sd { + enable-active-high; + gpio = <&gpio0 RK_PA1 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; +- pinctrl-0 = <&sdmmc0_pwr_h_gpio>; ++ pinctrl-0 = <&sdmmc0_pwr_h_pin>; + regulator-name = "vcc3v0_sd"; + regulator-always-on; + regulator-min-microvolt = <3000000>; +@@ -295,7 +295,7 @@ vcc3v3_panel: vcc3v3-panel { + enable-active-high; + gpio = <&gpio1 RK_PC6 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; +- pinctrl-0 = <&lcdvcc_en_gpio>; ++ pinctrl-0 = <&lcdvcc_en_pin>; + regulator-name = "vcc3v3_panel"; + regulator-always-on; + regulator-min-microvolt = <3300000>; +@@ -324,7 +324,7 @@ vcc5v0_otg: vcc5v0-otg { + enable-active-high; + gpio = <&gpio4 RK_PD2 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; +- pinctrl-0 = <&vcc5v0_host_en_gpio>; ++ pinctrl-0 = <&vcc5v0_host_en_pin>; + regulator-name = "vcc5v0_otg"; + regulator-always-on; + regulator-min-microvolt = <5000000>; +@@ -343,7 +343,7 @@ vbus_5vout: vbus_typec: vbus-5vout { + enable-active-high; + gpio = <&gpio1 RK_PA3 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; +- pinctrl-0 = <&vcc5v0_typec0_en_gpio>; ++ pinctrl-0 = <&vcc5v0_typec0_en_pin>; + regulator-name = "vbus_5vout"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; +@@ -375,7 +375,7 @@ mains_charger: dc-charger { + + /* Also triggered by USB charger */ + pinctrl-names = "default"; +- pinctrl-0 = <&dc_det_gpio>; ++ pinctrl-0 = <&dc_det_pin>; + }; + }; + +@@ -454,7 +454,7 @@ rk808: pmic@1b { + interrupt-parent = <&gpio3>; + interrupts = <10 IRQ_TYPE_LEVEL_LOW>; + pinctrl-names = "default"; +- pinctrl-0 = <&pmic_int_l_gpio>; ++ pinctrl-0 = <&pmic_int_l_pin>; + rockchip,system-power-controller; + wakeup-source; + +@@ -634,7 +634,7 @@ vdd_cpu_b: regulator@40 { + reg = <0x40>; + fcs,suspend-voltage-selector = <1>; + pinctrl-names = "default"; +- pinctrl-0 = <&vsel1_gpio>; ++ pinctrl-0 = <&vsel1_pin>; + regulator-name = "vdd_cpu_b"; + regulator-always-on; + regulator-boot-on; +@@ -653,7 +653,7 @@ vdd_gpu: regulator@41 { + reg = <0x41>; + fcs,suspend-voltage-selector = <1>; + pinctrl-names = "default"; +- pinctrl-0 = <&vsel2_gpio>; ++ pinctrl-0 = <&vsel2_pin>; + regulator-name = "vdd_gpu"; + regulator-always-on; + regulator-boot-on; +@@ -700,7 +700,7 @@ fusb0: fusb30x@22 { + interrupt-parent = <&gpio1>; + interrupts = ; + pinctrl-names = "default"; +- pinctrl-0 = <&fusb0_int_gpio>; ++ pinctrl-0 = <&fusb0_int_pin>; + vbus-supply = <&vbus_typec>; + + connector { +@@ -770,7 +770,7 @@ cw2015@62 { + + &i2s1 { + pinctrl-names = "default"; +- pinctrl-0 = <&i2s_8ch_mclk_gpio>, <&i2s1_2ch_bus>; ++ pinctrl-0 = <&i2s_8ch_mclk_pin>, <&i2s1_2ch_bus>; + rockchip,capture-channels = <8>; + rockchip,playback-channels = <8>; + status = "okay"; +@@ -802,49 +802,49 @@ &pcie0 { + + &pinctrl { + buttons { +- pwrbtn_gpio: pwrbtn-gpio { ++ pwrbtn_pin: pwrbtn-pin { + rockchip,pins = <0 RK_PA5 RK_FUNC_GPIO &pcfg_pull_up>; + }; + +- lidbtn_gpio: lidbtn-gpio { ++ lidbtn_pin: lidbtn-pin { + rockchip,pins = <1 RK_PA1 RK_FUNC_GPIO &pcfg_pull_up>; + }; + }; + + dc-charger { +- dc_det_gpio: dc-det-gpio { ++ dc_det_pin: dc-det-pin { + rockchip,pins = <4 RK_PD0 RK_FUNC_GPIO &pcfg_pull_up>; + }; + }; + + es8316 { +- hp_det_gpio: hp-det-gpio { ++ hp_det_pin: hp-det-pin { + rockchip,pins = <0 RK_PB0 RK_FUNC_GPIO &pcfg_pull_up>; + }; + }; + + fusb302x { +- fusb0_int_gpio: fusb0-int-gpio { ++ fusb0_int_pin: fusb0-int-pin { + rockchip,pins = <1 RK_PA2 RK_FUNC_GPIO &pcfg_pull_up>; + }; + }; + + i2s1 { +- i2s_8ch_mclk_gpio: i2s-8ch-mclk-gpio { ++ i2s_8ch_mclk_pin: i2s-8ch-mclk-pin { + rockchip,pins = <4 RK_PA0 1 &pcfg_pull_none>; + }; + }; + + lcd-panel { +- lcdvcc_en_gpio: lcdvcc-en-gpio { ++ lcdvcc_en_pin: lcdvcc-en-pin { + rockchip,pins = <1 RK_PC6 RK_FUNC_GPIO &pcfg_pull_none>; + }; + +- panel_en_gpio: panel-en-gpio { ++ panel_en_pin: panel-en-pin { + rockchip,pins = <1 RK_PA0 RK_FUNC_GPIO &pcfg_pull_none>; + }; + +- lcd_panel_reset_gpio: lcd-panel-reset-gpio { ++ lcd_panel_reset_pin: lcd-panel-reset-pin { + rockchip,pins = <4 RK_PD6 RK_FUNC_GPIO &pcfg_pull_up>; + }; + }; +@@ -860,58 +860,58 @@ slp_led_pin: slp-led-pin { + }; + + pmic { +- pmic_int_l_gpio: pmic-int-l-gpio { ++ pmic_int_l_pin: pmic-int-l-pin { + rockchip,pins = <3 RK_PB2 RK_FUNC_GPIO &pcfg_pull_up>; + }; + +- vsel1_gpio: vsel1-gpio { ++ vsel1_pin: vsel1-pin { + rockchip,pins = <1 RK_PC1 RK_FUNC_GPIO &pcfg_pull_down>; + }; + +- vsel2_gpio: vsel2-gpio { ++ vsel2_pin: vsel2-pin { + rockchip,pins = <1 RK_PB6 RK_FUNC_GPIO &pcfg_pull_down>; + }; + }; + + sdcard { +- sdmmc0_pwr_h_gpio: sdmmc0-pwr-h-gpio { ++ sdmmc0_pwr_h_pin: sdmmc0-pwr-h-pin { + rockchip,pins = <0 RK_PA1 RK_FUNC_GPIO &pcfg_pull_none>; + }; + + }; + + sdio-pwrseq { +- wifi_enable_h_gpio: wifi-enable-h-gpio { ++ wifi_enable_h_pin: wifi-enable-h-pin { + rockchip,pins = <0 RK_PB2 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + + usb-typec { +- vcc5v0_typec0_en_gpio: vcc5v0-typec0-en-gpio { ++ vcc5v0_typec0_en_pin: vcc5v0-typec0-en-pin { + rockchip,pins = <1 RK_PA3 RK_FUNC_GPIO &pcfg_pull_up>; + }; + }; + + usb2 { +- pwr_5v_gpio: pwr-5v-gpio { ++ pwr_5v_pin: pwr-5v-pin { + rockchip,pins = <1 RK_PB5 RK_FUNC_GPIO &pcfg_pull_none>; + }; + +- vcc5v0_host_en_gpio: vcc5v0-host-en-gpio { ++ vcc5v0_host_en_pin: vcc5v0-host-en-pin { + rockchip,pins = <4 RK_PD2 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + + wireless-bluetooth { +- bt_wake_gpio: bt-wake-gpio { ++ bt_wake_pin: bt-wake-pin { + rockchip,pins = <2 RK_PD3 RK_FUNC_GPIO &pcfg_pull_none>; + }; + +- bt_host_wake_gpio: bt-host-wake-gpio { ++ bt_host_wake_pin: bt-host-wake-pin { + rockchip,pins = <0 RK_PA4 RK_FUNC_GPIO &pcfg_pull_none>; + }; + +- bt_reset_gpio: bt-reset-gpio { ++ bt_reset_pin: bt-reset-pin { + rockchip,pins = <0 RK_PB1 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; +@@ -1059,7 +1059,7 @@ bluetooth { + host-wakeup-gpios = <&gpio0 RK_PA4 GPIO_ACTIVE_HIGH>; + max-speed = <1500000>; + pinctrl-names = "default"; +- pinctrl-0 = <&bt_host_wake_gpio &bt_wake_gpio &bt_reset_gpio>; ++ pinctrl-0 = <&bt_host_wake_pin &bt_wake_pin &bt_reset_pin>; + shutdown-gpios = <&gpio0 RK_PB1 GPIO_ACTIVE_HIGH>; + vbat-supply = <&wifi_bat>; + vddio-supply = <&vcc_wl>; +diff --git a/arch/arm64/boot/dts/rockchip/rk3399-roc-pc.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-roc-pc.dtsi +index 9f225e9c3d54..59b89d6ccdef 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3399-roc-pc.dtsi ++++ b/arch/arm64/boot/dts/rockchip/rk3399-roc-pc.dtsi +@@ -456,7 +456,7 @@ vdd_cpu_b: regulator@40 { + reg = <0x40>; + fcs,suspend-voltage-selector = <1>; + pinctrl-names = "default"; +- pinctrl-0 = <&vsel1_gpio>; ++ pinctrl-0 = <&vsel1_pin>; + regulator-name = "vdd_cpu_b"; + regulator-min-microvolt = <712500>; + regulator-max-microvolt = <1500000>; +@@ -475,7 +475,7 @@ vdd_gpu: regulator@41 { + reg = <0x41>; + fcs,suspend-voltage-selector = <1>; + pinctrl-names = "default"; +- pinctrl-0 = <&vsel2_gpio>; ++ pinctrl-0 = <&vsel2_pin>; + regulator-name = "vdd_gpu"; + regulator-min-microvolt = <712500>; + regulator-max-microvolt = <1500000>; +@@ -609,11 +609,11 @@ yellow_led_gpio: yellow_led-gpio { + }; + + pmic { +- vsel1_gpio: vsel1-gpio { ++ vsel1_pin: vsel1-pin { + rockchip,pins = <1 RK_PC2 RK_FUNC_GPIO &pcfg_pull_down>; + }; + +- vsel2_gpio: vsel2-gpio { ++ vsel2_pin: vsel2-pin { + rockchip,pins = <1 RK_PB6 RK_FUNC_GPIO &pcfg_pull_down>; + }; + }; +diff --git a/arch/arm64/boot/dts/rockchip/rk3399-rock-pi-4.dts b/arch/arm64/boot/dts/rockchip/rk3399-rock-pi-4.dts +index 3923ec01ef66..60f98a3e19d8 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3399-rock-pi-4.dts ++++ b/arch/arm64/boot/dts/rockchip/rk3399-rock-pi-4.dts +@@ -390,7 +390,7 @@ vdd_cpu_b: regulator@40 { + reg = <0x40>; + fcs,suspend-voltage-selector = <1>; + pinctrl-names = "default"; +- pinctrl-0 = <&vsel1_gpio>; ++ pinctrl-0 = <&vsel1_pin>; + regulator-name = "vdd_cpu_b"; + regulator-min-microvolt = <712500>; + regulator-max-microvolt = <1500000>; +@@ -409,7 +409,7 @@ vdd_gpu: regulator@41 { + reg = <0x41>; + fcs,suspend-voltage-selector = <1>; + pinctrl-names = "default"; +- pinctrl-0 = <&vsel2_gpio>; ++ pinctrl-0 = <&vsel2_pin>; + regulator-name = "vdd_gpu"; + regulator-min-microvolt = <712500>; + regulator-max-microvolt = <1500000>; +@@ -532,11 +532,11 @@ pmic_int_l: pmic-int-l { + rockchip,pins = <1 RK_PC5 RK_FUNC_GPIO &pcfg_pull_up>; + }; + +- vsel1_gpio: vsel1-gpio { ++ vsel1_pin: vsel1-pin { + rockchip,pins = <1 RK_PC1 RK_FUNC_GPIO &pcfg_pull_down>; + }; + +- vsel2_gpio: vsel2-gpio { ++ vsel2_pin: vsel2-pin { + rockchip,pins = <1 RK_PB6 RK_FUNC_GPIO &pcfg_pull_down>; + }; + }; +diff --git a/arch/arm64/boot/dts/rockchip/rk3399-rock960.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-rock960.dtsi +index ba7c75c9f2a1..5e3ac589bc54 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3399-rock960.dtsi ++++ b/arch/arm64/boot/dts/rockchip/rk3399-rock960.dtsi +@@ -470,12 +470,12 @@ pmic_int_l: pmic-int-l { + <1 RK_PC5 RK_FUNC_GPIO &pcfg_pull_up>; + }; + +- vsel1_gpio: vsel1-gpio { ++ vsel1_pin: vsel1-pin { + rockchip,pins = + <1 RK_PC1 RK_FUNC_GPIO &pcfg_pull_down>; + }; + +- vsel2_gpio: vsel2-gpio { ++ vsel2_pin: vsel2-pin { + rockchip,pins = + <1 RK_PB6 RK_FUNC_GPIO &pcfg_pull_down>; + }; +diff --git a/arch/arm64/boot/dts/rockchip/rk3399-rockpro64.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-rockpro64.dtsi +index 3456ee97c288..c84cad16118a 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3399-rockpro64.dtsi ++++ b/arch/arm64/boot/dts/rockchip/rk3399-rockpro64.dtsi +@@ -445,7 +445,7 @@ vdd_cpu_b: regulator@40 { + reg = <0x40>; + fcs,suspend-voltage-selector = <1>; + pinctrl-names = "default"; +- pinctrl-0 = <&vsel1_gpio>; ++ pinctrl-0 = <&vsel1_pin>; + regulator-name = "vdd_cpu_b"; + regulator-min-microvolt = <712500>; + regulator-max-microvolt = <1500000>; +@@ -464,7 +464,7 @@ vdd_gpu: regulator@41 { + reg = <0x41>; + fcs,suspend-voltage-selector = <1>; + pinctrl-names = "default"; +- pinctrl-0 = <&vsel2_gpio>; ++ pinctrl-0 = <&vsel2_pin>; + regulator-name = "vdd_gpu"; + regulator-min-microvolt = <712500>; + regulator-max-microvolt = <1500000>; +@@ -612,11 +612,11 @@ pmic_int_l: pmic-int-l { + rockchip,pins = <3 RK_PB2 RK_FUNC_GPIO &pcfg_pull_up>; + }; + +- vsel1_gpio: vsel1-gpio { ++ vsel1_pin: vsel1-pin { + rockchip,pins = <1 RK_PC1 RK_FUNC_GPIO &pcfg_pull_down>; + }; + +- vsel2_gpio: vsel2-gpio { ++ vsel2_pin: vsel2-pin { + rockchip,pins = <1 RK_PB6 RK_FUNC_GPIO &pcfg_pull_down>; + }; + }; +diff --git a/arch/arm64/boot/dts/rockchip/rk3399-sapphire.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-sapphire.dtsi +index 1bc1579674e5..701a567d7638 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3399-sapphire.dtsi ++++ b/arch/arm64/boot/dts/rockchip/rk3399-sapphire.dtsi +@@ -481,11 +481,11 @@ pmic_int_l: pmic-int-l { + <1 RK_PC5 RK_FUNC_GPIO &pcfg_pull_up>; + }; + +- vsel1_gpio: vsel1-gpio { ++ vsel1_pin: vsel1-pin { + rockchip,pins = <1 RK_PC1 RK_FUNC_GPIO &pcfg_pull_down>; + }; + +- vsel2_gpio: vsel2-gpio { ++ vsel2_pin: vsel2-pin { + rockchip,pins = <1 RK_PB6 RK_FUNC_GPIO &pcfg_pull_down>; + }; + }; +diff --git a/arch/arm64/boot/dts/rockchip/rk3399.dtsi b/arch/arm64/boot/dts/rockchip/rk3399.dtsi +index 2581e9cc7a1d..781b5c2cdb4d 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3399.dtsi ++++ b/arch/arm64/boot/dts/rockchip/rk3399.dtsi +@@ -845,9 +845,9 @@ tsadc: tsadc@ff260000 { + rockchip,grf = <&grf>; + rockchip,hw-tshut-temp = <95000>; + pinctrl-names = "init", "default", "sleep"; +- pinctrl-0 = <&otp_gpio>; ++ pinctrl-0 = <&otp_pin>; + pinctrl-1 = <&otp_out>; +- pinctrl-2 = <&otp_gpio>; ++ pinctrl-2 = <&otp_pin>; + #thermal-sensor-cells = <1>; + status = "disabled"; + }; +@@ -2485,7 +2485,7 @@ test_clkout2: test-clkout2 { + }; + + tsadc { +- otp_gpio: otp-gpio { ++ otp_pin: otp-pin { + rockchip,pins = <1 RK_PA6 RK_FUNC_GPIO &pcfg_pull_none>; + }; + + +From b73a18f9f69f893cb7ae0155770d4eac8cc9874f Mon Sep 17 00:00:00 2001 +From: Johan Jonker +Date: Fri, 22 May 2020 17:46:57 +0200 +Subject: [PATCH] arm64: dts: rockchip: rename and label gpio-led subnodes part + 2 + +Current dts files with 'gpio-led' nodes were manually verified. +In order to automate this process leds-gpio.txt +has been converted to yaml. With this conversion a check +for pattern properties was added. In part 2 rename and label +gpio-led subnodes that passed the regex, but still don't have +the preferred form. Any pin subnode that ends with '-gpio' +in the pinctrl node generates a warning. + +Fix with help of the following rules: + +1: Add nodename in the preferred form. + +2: Always add a label that ends with '_led' to prevent conflicts + with other labels such as 'power' and 'mmc' + +3: If leds need pinctrl add a label that ends with '_led_pin' + also to prevent conflicts with other labels. + +patternProperties: + # The first form is preferred, but fall back to just 'led' + # anywhere in the node name to at least catch some child nodes. + "(^led-[0-9a-f]$|led)": + +make ARCH=arm64 dtbs_check +DT_SCHEMA_FILES=Documentation/devicetree/bindings/leds/ +leds-gpio.yaml + +make ARCH=arm64 dtbs_check +DT_SCHEMA_FILES=~/.local/lib/python3.5/site-packages/dtschema/ +schemas/gpio/gpio.yaml + +Signed-off-by: Johan Jonker +Link: https://lore.kernel.org/r/20200522154657.9472-1-jbx6244@gmail.com +Signed-off-by: Heiko Stuebner +(cherry picked from commit 6dd5e12c0b9bba40b3947ac1a9fd2f992585b5c6) +--- + .../arm64/boot/dts/rockchip/rk3368-lion-haikou.dts | 6 +++--- + arch/arm64/boot/dts/rockchip/rk3368-lion.dtsi | 8 ++++---- + .../boot/dts/rockchip/rk3399-khadas-edge.dtsi | 10 +++++----- + arch/arm64/boot/dts/rockchip/rk3399-nanopi4.dtsi | 6 +++--- + .../arm64/boot/dts/rockchip/rk3399-puma-haikou.dts | 6 +++--- + arch/arm64/boot/dts/rockchip/rk3399-puma.dtsi | 6 +++--- + arch/arm64/boot/dts/rockchip/rk3399-roc-pc.dtsi | 14 +++++++------- + arch/arm64/boot/dts/rockchip/rk3399-rockpro64.dtsi | 10 +++++----- + 8 files changed, 33 insertions(+), 33 deletions(-) + +diff --git a/arch/arm64/boot/dts/rockchip/rk3368-lion-haikou.dts b/arch/arm64/boot/dts/rockchip/rk3368-lion-haikou.dts +index dbd2caba322f..7fcb1eacea8a 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3368-lion-haikou.dts ++++ b/arch/arm64/boot/dts/rockchip/rk3368-lion-haikou.dts +@@ -25,9 +25,9 @@ eeprom: eeprom@50 { + }; + + leds { +- pinctrl-0 = <&led_pins_module>, <&led_sd_haikou>; ++ pinctrl-0 = <&module_led_pins>, <&sd_card_led_pin>; + +- sd-card-led { ++ sd_card_led: led-3 { + label = "sd_card_led"; + gpios = <&gpio0 RK_PD2 GPIO_ACTIVE_HIGH>; + linux,default-trigger = "mmc0"; +@@ -118,7 +118,7 @@ haikou_pin_hog: haikou-pin-hog { + }; + + leds { +- led_sd_haikou: led-sd-gpio { ++ sd_card_led_pin: sd-card-led-pin { + rockchip,pins = + <0 RK_PD2 RK_FUNC_GPIO &pcfg_pull_none>; + }; +diff --git a/arch/arm64/boot/dts/rockchip/rk3368-lion.dtsi b/arch/arm64/boot/dts/rockchip/rk3368-lion.dtsi +index 216aafd90e7f..24d28be4736c 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3368-lion.dtsi ++++ b/arch/arm64/boot/dts/rockchip/rk3368-lion.dtsi +@@ -76,16 +76,16 @@ i2c@1 { + leds { + compatible = "gpio-leds"; + pinctrl-names = "default"; +- pinctrl-0 = <&led_pins_module>; ++ pinctrl-0 = <&module_led_pins>; + +- module_led1 { ++ module_led1: led-1 { + label = "module_led1"; + gpios = <&gpio2 RK_PB5 GPIO_ACTIVE_HIGH>; + linux,default-trigger = "heartbeat"; + panic-indicator; + }; + +- module_led2 { ++ module_led2: led-2 { + label = "module_led2"; + gpios = <&gpio3 RK_PA3 GPIO_ACTIVE_HIGH>; + default-state = "off"; +@@ -270,7 +270,7 @@ &i2c2 { + + &pinctrl { + leds { +- led_pins_module: led-module-gpio { ++ module_led_pins: module-led-pins { + rockchip,pins = + <2 RK_PB5 RK_FUNC_GPIO &pcfg_pull_none>, + <3 RK_PA3 RK_FUNC_GPIO &pcfg_pull_none>; +diff --git a/arch/arm64/boot/dts/rockchip/rk3399-khadas-edge.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-khadas-edge.dtsi +index e87a04477440..e36837c04dc7 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3399-khadas-edge.dtsi ++++ b/arch/arm64/boot/dts/rockchip/rk3399-khadas-edge.dtsi +@@ -141,15 +141,15 @@ power { + leds { + compatible = "gpio-leds"; + pinctrl-names = "default"; +- pinctrl-0 = <&sys_led_gpio>, <&user_led_gpio>; ++ pinctrl-0 = <&sys_led_pin>, <&user_led_pin>; + +- sys-led { ++ sys_led: led-0 { + label = "sys_led"; + linux,default-trigger = "heartbeat"; + gpios = <&gpio0 RK_PA6 GPIO_ACTIVE_HIGH>; + }; + +- user-led { ++ user_led: led-1 { + label = "user_led"; + default-state = "off"; + gpios = <&gpio4 RK_PD0 GPIO_ACTIVE_HIGH>; +@@ -586,11 +586,11 @@ pwrbtn: pwrbtn { + }; + + leds { +- sys_led_gpio: sys_led-gpio { ++ sys_led_pin: sys-led-pin { + rockchip,pins = <0 RK_PA6 RK_FUNC_GPIO &pcfg_pull_none>; + }; + +- user_led_gpio: user_led-gpio { ++ user_led_pin: user-led-pin { + rockchip,pins = <4 RK_PD0 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; +diff --git a/arch/arm64/boot/dts/rockchip/rk3399-nanopi4.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-nanopi4.dtsi +index 1d246c2caa3c..76a8b40a93c6 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3399-nanopi4.dtsi ++++ b/arch/arm64/boot/dts/rockchip/rk3399-nanopi4.dtsi +@@ -117,9 +117,9 @@ power { + leds: gpio-leds { + compatible = "gpio-leds"; + pinctrl-names = "default"; +- pinctrl-0 = <&leds_gpio>; ++ pinctrl-0 = <&status_led_pin>; + +- status { ++ status_led: led-0 { + gpios = <&gpio0 RK_PB5 GPIO_ACTIVE_HIGH>; + label = "status_led"; + linux,default-trigger = "heartbeat"; +@@ -520,7 +520,7 @@ fusb0_int: fusb0-int { + }; + + gpio-leds { +- leds_gpio: leds-gpio { ++ status_led_pin: status-led-pin { + rockchip,pins = <0 RK_PB5 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; +diff --git a/arch/arm64/boot/dts/rockchip/rk3399-puma-haikou.dts b/arch/arm64/boot/dts/rockchip/rk3399-puma-haikou.dts +index d80d6b726820..a8d363568fd6 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3399-puma-haikou.dts ++++ b/arch/arm64/boot/dts/rockchip/rk3399-puma-haikou.dts +@@ -15,9 +15,9 @@ chosen { + }; + + leds { +- pinctrl-0 = <&led_pin_module>, <&led_sd_haikou>; ++ pinctrl-0 = <&module_led_pin>, <&sd_card_led_pin>; + +- sd-card-led { ++ sd_card_led: led-1 { + label = "sd_card_led"; + gpios = <&gpio1 RK_PA2 GPIO_ACTIVE_HIGH>; + linux,default-trigger = "mmc0"; +@@ -179,7 +179,7 @@ haikou_pin_hog: haikou-pin-hog { + }; + + leds { +- led_sd_haikou: led-sd-gpio { ++ sd_card_led_pin: sd-card-led-pin { + rockchip,pins = + <1 RK_PA2 RK_FUNC_GPIO &pcfg_pull_none>; + }; +diff --git a/arch/arm64/boot/dts/rockchip/rk3399-puma.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-puma.dtsi +index 72c06abd27ea..4660416c8f38 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3399-puma.dtsi ++++ b/arch/arm64/boot/dts/rockchip/rk3399-puma.dtsi +@@ -11,9 +11,9 @@ / { + leds { + compatible = "gpio-leds"; + pinctrl-names = "default"; +- pinctrl-0 = <&led_pin_module>; ++ pinctrl-0 = <&module_led_pin>; + +- module-led { ++ module_led: led-0 { + label = "module_led"; + gpios = <&gpio2 RK_PD1 GPIO_ACTIVE_HIGH>; + linux,default-trigger = "heartbeat"; +@@ -450,7 +450,7 @@ i2c8_xfer_a: i2c8-xfer { + }; + + leds { +- led_pin_module: led-module-gpio { ++ module_led_pin: module-led-pin { + rockchip,pins = + <2 RK_PD1 RK_FUNC_GPIO &pcfg_pull_none>; + }; +diff --git a/arch/arm64/boot/dts/rockchip/rk3399-roc-pc.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-roc-pc.dtsi +index 59b89d6ccdef..b85ec31cd283 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3399-roc-pc.dtsi ++++ b/arch/arm64/boot/dts/rockchip/rk3399-roc-pc.dtsi +@@ -61,23 +61,23 @@ power { + leds { + compatible = "gpio-leds"; + pinctrl-names = "default"; +- pinctrl-0 = <&work_led_gpio>, <&diy_led_gpio>, <&yellow_led_gpio>; ++ pinctrl-0 = <&work_led_pin>, <&diy_led_pin>, <&yellow_led_pin>; + +- work-led { ++ work_led: led-0 { + label = "green:work"; + gpios = <&gpio2 RK_PD3 GPIO_ACTIVE_HIGH>; + default-state = "on"; + linux,default-trigger = "heartbeat"; + }; + +- diy-led { ++ diy_led: led-1 { + label = "red:diy"; + gpios = <&gpio0 RK_PB5 GPIO_ACTIVE_HIGH>; + default-state = "off"; + linux,default-trigger = "mmc1"; + }; + +- yellow-led { ++ yellow_led: led-2 { + label = "yellow:yellow-led"; + gpios = <&gpio0 RK_PA2 GPIO_ACTIVE_HIGH>; + default-state = "off"; +@@ -595,15 +595,15 @@ lcd_panel_reset: lcd-panel-reset { + }; + + leds { +- diy_led_gpio: diy_led-gpio { ++ diy_led_pin: diy-led-pin { + rockchip,pins = <0 RK_PB5 RK_FUNC_GPIO &pcfg_pull_none>; + }; + +- work_led_gpio: work_led-gpio { ++ work_led_pin: work-led-pin { + rockchip,pins = <2 RK_PD3 RK_FUNC_GPIO &pcfg_pull_none>; + }; + +- yellow_led_gpio: yellow_led-gpio { ++ yellow_led_pin: yellow-led-pin { + rockchip,pins = <0 RK_PA2 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; +diff --git a/arch/arm64/boot/dts/rockchip/rk3399-rockpro64.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-rockpro64.dtsi +index c84cad16118a..6e553ff47534 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3399-rockpro64.dtsi ++++ b/arch/arm64/boot/dts/rockchip/rk3399-rockpro64.dtsi +@@ -39,15 +39,15 @@ power { + leds { + compatible = "gpio-leds"; + pinctrl-names = "default"; +- pinctrl-0 = <&work_led_gpio>, <&diy_led_gpio>; ++ pinctrl-0 = <&work_led_pin>, <&diy_led_pin>; + +- work-led { ++ work_led: led-0 { + label = "work"; + default-state = "on"; + gpios = <&gpio0 RK_PB3 GPIO_ACTIVE_HIGH>; + }; + +- diy-led { ++ diy_led: led-1 { + label = "diy"; + default-state = "off"; + gpios = <&gpio0 RK_PA2 GPIO_ACTIVE_HIGH>; +@@ -588,11 +588,11 @@ fusb0_int: fusb0-int { + }; + + leds { +- work_led_gpio: work_led-gpio { ++ work_led_pin: work-led-pin { + rockchip,pins = <0 RK_PB3 RK_FUNC_GPIO &pcfg_pull_none>; + }; + +- diy_led_gpio: diy_led-gpio { ++ diy_led_pin: diy-led-pin { + rockchip,pins = <0 RK_PA2 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + +From c40071fd1c70da63fdd7cc308114b34623d7eb91 Mon Sep 17 00:00:00 2001 +From: Johan Jonker +Date: Sun, 24 May 2020 18:06:35 +0200 +Subject: [PATCH] ARM: dts: rockchip: rename label and nodename pinctrl + subnodes that end with gpio + +A test with the command below gives for example this error: + +arch/arm/boot/dts/rk3288-tinker.dt.yaml: tsadc: otp-gpio: +{'phandle': [[54]], 'rockchip,pins': [[0, 10, 0, 118]]} +is not of type 'array' + +'gpio' is a sort of reserved nodename and should not be used +for pinctrl in combination with 'rockchip,pins', so change +nodes that end with 'gpio' to end with 'pin' or 'pins'. + +make ARCH=arm dtbs_check +DT_SCHEMA_FILES=~/.local/lib/python3.5/site-packages/ +dtschema/schemas/gpio/gpio.yaml + +Signed-off-by: Johan Jonker +Link: https://lore.kernel.org/r/20200524160636.16547-1-jbx6244@gmail.com +Signed-off-by: Heiko Stuebner +(cherry picked from commit fff987e7328951f7d6fb2d0545de8635ceafa89f) +--- + arch/arm/boot/dts/rk322x.dtsi | 6 +++--- + arch/arm/boot/dts/rk3288-veyron-jaq.dts | 2 +- + arch/arm/boot/dts/rk3288-veyron-jerry.dts | 2 +- + arch/arm/boot/dts/rk3288-veyron-mighty.dts | 6 +++--- + arch/arm/boot/dts/rk3288-veyron-minnie.dts | 2 +- + arch/arm/boot/dts/rk3288-veyron-pinky.dts | 6 +++--- + arch/arm/boot/dts/rk3288-veyron-sdmmc.dtsi | 2 +- + arch/arm/boot/dts/rk3288-veyron-speedy.dts | 2 +- + arch/arm/boot/dts/rk3288.dtsi | 6 +++--- + arch/arm/boot/dts/rv1108.dtsi | 12 ++++++------ + 10 files changed, 23 insertions(+), 23 deletions(-) + +diff --git a/arch/arm/boot/dts/rk322x.dtsi b/arch/arm/boot/dts/rk322x.dtsi +index b0fd92befdeb..3236abb0aba9 100644 +--- a/arch/arm/boot/dts/rk322x.dtsi ++++ b/arch/arm/boot/dts/rk322x.dtsi +@@ -520,9 +520,9 @@ tsadc: tsadc@11150000 { + resets = <&cru SRST_TSADC>; + reset-names = "tsadc-apb"; + pinctrl-names = "init", "default", "sleep"; +- pinctrl-0 = <&otp_gpio>; ++ pinctrl-0 = <&otp_pin>; + pinctrl-1 = <&otp_out>; +- pinctrl-2 = <&otp_gpio>; ++ pinctrl-2 = <&otp_pin>; + #thermal-sensor-cells = <0>; + rockchip,hw-tshut-temp = <95000>; + status = "disabled"; +@@ -1111,7 +1111,7 @@ spdif_tx: spdif-tx { + }; + + tsadc { +- otp_gpio: otp-gpio { ++ otp_pin: otp-pin { + rockchip,pins = <0 RK_PD0 RK_FUNC_GPIO &pcfg_pull_none>; + }; + +diff --git a/arch/arm/boot/dts/rk3288-veyron-jaq.dts b/arch/arm/boot/dts/rk3288-veyron-jaq.dts +index 171ba6185b6d..8efba9deae3c 100644 +--- a/arch/arm/boot/dts/rk3288-veyron-jaq.dts ++++ b/arch/arm/boot/dts/rk3288-veyron-jaq.dts +@@ -47,7 +47,7 @@ regulator-state-mem { + &sdmmc { + disable-wp; + pinctrl-names = "default"; +- pinctrl-0 = <&sdmmc_clk &sdmmc_cmd &sdmmc_cd_disabled &sdmmc_cd_gpio ++ pinctrl-0 = <&sdmmc_clk &sdmmc_cmd &sdmmc_cd_disabled &sdmmc_cd_pin + &sdmmc_bus4>; + }; + +diff --git a/arch/arm/boot/dts/rk3288-veyron-jerry.dts b/arch/arm/boot/dts/rk3288-veyron-jerry.dts +index 66f00d28801a..2c916c50dda5 100644 +--- a/arch/arm/boot/dts/rk3288-veyron-jerry.dts ++++ b/arch/arm/boot/dts/rk3288-veyron-jerry.dts +@@ -192,7 +192,7 @@ mwifiex: wifi@1 { + &sdmmc { + disable-wp; + pinctrl-names = "default"; +- pinctrl-0 = <&sdmmc_clk &sdmmc_cmd &sdmmc_cd_disabled &sdmmc_cd_gpio ++ pinctrl-0 = <&sdmmc_clk &sdmmc_cmd &sdmmc_cd_disabled &sdmmc_cd_pin + &sdmmc_bus4>; + }; + +diff --git a/arch/arm/boot/dts/rk3288-veyron-mighty.dts b/arch/arm/boot/dts/rk3288-veyron-mighty.dts +index 27fbc07476d2..fa695a88f236 100644 +--- a/arch/arm/boot/dts/rk3288-veyron-mighty.dts ++++ b/arch/arm/boot/dts/rk3288-veyron-mighty.dts +@@ -18,8 +18,8 @@ / { + }; + + &sdmmc { +- pinctrl-0 = <&sdmmc_clk &sdmmc_cmd &sdmmc_cd_disabled &sdmmc_cd_gpio +- &sdmmc_wp_gpio &sdmmc_bus4>; ++ pinctrl-0 = <&sdmmc_clk &sdmmc_cmd &sdmmc_cd_disabled &sdmmc_cd_pin ++ &sdmmc_wp_pin &sdmmc_bus4>; + wp-gpios = <&gpio7 10 GPIO_ACTIVE_HIGH>; + + /delete-property/ disable-wp; +@@ -27,7 +27,7 @@ &sdmmc { + + &pinctrl { + sdmmc { +- sdmmc_wp_gpio: sdmmc-wp-gpio { ++ sdmmc_wp_pin: sdmmc-wp-pin { + rockchip,pins = <7 RK_PB2 RK_FUNC_GPIO &pcfg_pull_up>; + }; + }; +diff --git a/arch/arm/boot/dts/rk3288-veyron-minnie.dts b/arch/arm/boot/dts/rk3288-veyron-minnie.dts +index 383fad1a88a1..f8b69e0a16a0 100644 +--- a/arch/arm/boot/dts/rk3288-veyron-minnie.dts ++++ b/arch/arm/boot/dts/rk3288-veyron-minnie.dts +@@ -114,7 +114,7 @@ regulator-state-mem { + &sdmmc { + disable-wp; + pinctrl-names = "default"; +- pinctrl-0 = <&sdmmc_clk &sdmmc_cmd &sdmmc_cd_disabled &sdmmc_cd_gpio ++ pinctrl-0 = <&sdmmc_clk &sdmmc_cmd &sdmmc_cd_disabled &sdmmc_cd_pin + &sdmmc_bus4>; + }; + +diff --git a/arch/arm/boot/dts/rk3288-veyron-pinky.dts b/arch/arm/boot/dts/rk3288-veyron-pinky.dts +index 71e6629cc208..4e9fdb0f722d 100644 +--- a/arch/arm/boot/dts/rk3288-veyron-pinky.dts ++++ b/arch/arm/boot/dts/rk3288-veyron-pinky.dts +@@ -105,7 +105,7 @@ emmc_reset: emmc-reset { + }; + + sdmmc { +- sdmmc_wp_gpio: sdmmc-wp-gpio { ++ sdmmc_wp_pin: sdmmc-wp-pin { + rockchip,pins = <7 RK_PB2 RK_FUNC_GPIO &pcfg_pull_up>; + }; + }; +@@ -126,8 +126,8 @@ regulator-state-mem { + + &sdmmc { + pinctrl-names = "default"; +- pinctrl-0 = <&sdmmc_clk &sdmmc_cmd &sdmmc_cd_disabled &sdmmc_cd_gpio +- &sdmmc_wp_gpio &sdmmc_bus4>; ++ pinctrl-0 = <&sdmmc_clk &sdmmc_cmd &sdmmc_cd_disabled &sdmmc_cd_pin ++ &sdmmc_wp_pin &sdmmc_bus4>; + wp-gpios = <&gpio7 RK_PB2 GPIO_ACTIVE_HIGH>; + }; + +diff --git a/arch/arm/boot/dts/rk3288-veyron-sdmmc.dtsi b/arch/arm/boot/dts/rk3288-veyron-sdmmc.dtsi +index fe950f9863e8..27fb06ce907e 100644 +--- a/arch/arm/boot/dts/rk3288-veyron-sdmmc.dtsi ++++ b/arch/arm/boot/dts/rk3288-veyron-sdmmc.dtsi +@@ -41,7 +41,7 @@ sdmmc_cd_disabled: sdmmc-cd-disabled { + }; + + /* This is where we actually hook up CD */ +- sdmmc_cd_gpio: sdmmc-cd-gpio { ++ sdmmc_cd_pin: sdmmc-cd-pin { + rockchip,pins = <7 RK_PA5 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; +diff --git a/arch/arm/boot/dts/rk3288-veyron-speedy.dts b/arch/arm/boot/dts/rk3288-veyron-speedy.dts +index e354c61a45e7..4a3ea934d03e 100644 +--- a/arch/arm/boot/dts/rk3288-veyron-speedy.dts ++++ b/arch/arm/boot/dts/rk3288-veyron-speedy.dts +@@ -54,7 +54,7 @@ &rk808 { + &sdmmc { + disable-wp; + pinctrl-names = "default"; +- pinctrl-0 = <&sdmmc_clk &sdmmc_cmd &sdmmc_cd_disabled &sdmmc_cd_gpio ++ pinctrl-0 = <&sdmmc_clk &sdmmc_cmd &sdmmc_cd_disabled &sdmmc_cd_pin + &sdmmc_bus4>; + }; + +diff --git a/arch/arm/boot/dts/rk3288.dtsi b/arch/arm/boot/dts/rk3288.dtsi +index 2e1edd85f04a..84d59469035e 100644 +--- a/arch/arm/boot/dts/rk3288.dtsi ++++ b/arch/arm/boot/dts/rk3288.dtsi +@@ -574,9 +574,9 @@ tsadc: tsadc@ff280000 { + resets = <&cru SRST_TSADC>; + reset-names = "tsadc-apb"; + pinctrl-names = "init", "default", "sleep"; +- pinctrl-0 = <&otp_gpio>; ++ pinctrl-0 = <&otp_pin>; + pinctrl-1 = <&otp_out>; +- pinctrl-2 = <&otp_gpio>; ++ pinctrl-2 = <&otp_pin>; + #thermal-sensor-cells = <1>; + rockchip,grf = <&grf>; + rockchip,hw-tshut-temp = <95000>; +@@ -1929,7 +1929,7 @@ uart4_rts: uart4-rts { + }; + + tsadc { +- otp_gpio: otp-gpio { ++ otp_pin: otp-pin { + rockchip,pins = <0 RK_PB2 RK_FUNC_GPIO &pcfg_pull_none>; + }; + +diff --git a/arch/arm/boot/dts/rv1108.dtsi b/arch/arm/boot/dts/rv1108.dtsi +index f9cfe2c80791..a5d130bd0547 100644 +--- a/arch/arm/boot/dts/rv1108.dtsi ++++ b/arch/arm/boot/dts/rv1108.dtsi +@@ -351,9 +351,9 @@ tsadc: tsadc@10370000 { + clocks = <&cru SCLK_TSADC>, <&cru PCLK_TSADC>; + clock-names = "tsadc", "apb_pclk"; + pinctrl-names = "init", "default", "sleep"; +- pinctrl-0 = <&otp_gpio>; ++ pinctrl-0 = <&otp_pin>; + pinctrl-1 = <&otp_out>; +- pinctrl-2 = <&otp_gpio>; ++ pinctrl-2 = <&otp_pin>; + resets = <&cru SRST_TSADC>; + reset-names = "tsadc-apb"; + rockchip,hw-tshut-temp = <120000>; +@@ -728,7 +728,7 @@ i2c2m1_xfer: i2c2m1-xfer { + <0 RK_PC6 3 &pcfg_pull_none>; + }; + +- i2c2m1_gpio: i2c2m1-gpio { ++ i2c2m1_pins: i2c2m1-pins { + rockchip,pins = <0 RK_PC2 RK_FUNC_GPIO &pcfg_pull_none>, + <0 RK_PC6 RK_FUNC_GPIO &pcfg_pull_none>; + }; +@@ -740,7 +740,7 @@ i2c2m05v_xfer: i2c2m05v-xfer { + <1 RK_PD4 2 &pcfg_pull_none>; + }; + +- i2c2m05v_gpio: i2c2m05v-gpio { ++ i2c2m05v_pins: i2c2m05v-pins { + rockchip,pins = <1 RK_PD5 RK_FUNC_GPIO &pcfg_pull_none>, + <1 RK_PD4 RK_FUNC_GPIO &pcfg_pull_none>; + }; +@@ -867,7 +867,7 @@ otp_out: otp-out { + rockchip,pins = <0 RK_PB7 1 &pcfg_pull_none>; + }; + +- otp_gpio: otp-gpio { ++ otp_pin: otp-pin { + rockchip,pins = <0 RK_PB7 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; +@@ -886,7 +886,7 @@ uart0_rts: uart0-rts { + rockchip,pins = <3 RK_PA3 1 &pcfg_pull_none>; + }; + +- uart0_rts_gpio: uart0-rts-gpio { ++ uart0_rts_pin: uart0-rts-pin { + rockchip,pins = <3 RK_PA3 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + +From c07b527960a7909caa8adb15247362f2319f1653 Mon Sep 17 00:00:00 2001 +From: Abhishek Pandit-Subedi +Date: Fri, 12 Jun 2020 13:02:48 -0700 +Subject: [PATCH] ARM: dts: rockchip: Add marvell BT irq config + +Veyron Jaq and Mighty both use the Marvel 8897 WiFi+BT chip. Add wakeup +and pinctrl block to devicetree so the btmrvl driver can correctly +configure the wakeup interrupt. + +Signed-off-by: Abhishek Pandit-Subedi +Reviewed-by: Douglas Anderson +Link: https://lore.kernel.org/r/20200612130219.v2.1.I66864be898aa835ccb66b6cd5220d0b082338a81@changeid +Signed-off-by: Heiko Stuebner +(cherry picked from commit 6c2b99a2e7a073575b4ee91abf7d16470991c1f4) +--- + arch/arm/boot/dts/rk3288-veyron-jaq.dts | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +diff --git a/arch/arm/boot/dts/rk3288-veyron-jaq.dts b/arch/arm/boot/dts/rk3288-veyron-jaq.dts +index 8efba9deae3c..af77ab20586d 100644 +--- a/arch/arm/boot/dts/rk3288-veyron-jaq.dts ++++ b/arch/arm/boot/dts/rk3288-veyron-jaq.dts +@@ -44,6 +44,21 @@ regulator-state-mem { + }; + }; + ++&sdio0 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ btmrvl: btmrvl@2 { ++ compatible = "marvell,sd8897-bt"; ++ reg = <2>; ++ interrupt-parent = <&gpio4>; ++ interrupts = ; ++ marvell,wakeup-pin = /bits/ 16 <13>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&bt_host_wake_l>; ++ }; ++}; ++ + &sdmmc { + disable-wp; + pinctrl-names = "default"; + +From f0ee8fdc42d8bb5a2cb126df71302324fb23866b Mon Sep 17 00:00:00 2001 +From: Sugar Zhang +Date: Thu, 4 Jun 2020 09:36:38 +0800 +Subject: [PATCH] dmaengine: pl330: Make sure the debug is idle before doing + DMAGO + +According to the datasheet of pl330: + +Example 2-1 Using DMAGO with the debug instruction registers + +1. Create a program for the DMA channel +2. Store the program in a region of system memory +3. Poll the DBGSTATUS Register to ensure that the debug is idle +4. Write to the DBGINST0 Register +5. Write to the DBGINST1 Register +6. Write zero to the DBGCMD Register + +so, we should make sure the debug is idle before step 4/5/6, not +only step 6. if not, there maybe a risk that fail to write DBGINST0/1. + +Signed-off-by: Sugar Zhang +Link: https://lore.kernel.org/r/1591234598-78919-1-git-send-email-sugar.zhang@rock-chips.com +Signed-off-by: Vinod Koul +(cherry picked from commit d12ea5591eddf625b7707c018b72e46e8674c3c2) +--- + drivers/dma/pl330.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c +index 88b884cbb7c1..6a158eef6b8a 100644 +--- a/drivers/dma/pl330.c ++++ b/drivers/dma/pl330.c +@@ -885,6 +885,12 @@ static inline void _execute_DBGINSN(struct pl330_thread *thrd, + void __iomem *regs = thrd->dmac->base; + u32 val; + ++ /* If timed out due to halted state-machine */ ++ if (_until_dmac_idle(thrd)) { ++ dev_err(thrd->dmac->ddma.dev, "DMAC halted!\n"); ++ return; ++ } ++ + val = (insn[0] << 16) | (insn[1] << 24); + if (!as_manager) { + val |= (1 << 0); +@@ -895,12 +901,6 @@ static inline void _execute_DBGINSN(struct pl330_thread *thrd, + val = le32_to_cpu(*((__le32 *)&insn[2])); + writel(val, regs + DBGINST1); + +- /* If timed out due to halted state-machine */ +- if (_until_dmac_idle(thrd)) { +- dev_err(thrd->dmac->ddma.dev, "DMAC halted!\n"); +- return; +- } +- + /* Get going */ + writel(0, regs + DBGCMD); + } + +From e5214dd97994bfdb32dcae94e03f18a794c43947 Mon Sep 17 00:00:00 2001 +From: Shunqian Zheng +Date: Fri, 3 Apr 2020 13:15:37 -0300 +Subject: [PATCH] arm64: dts: rockchip: add rx0 mipi-phy for rk3399 + +Designware MIPI D-PHY, used for ISP0 in rk3399. + +Verified with: +make ARCH=arm64 dtbs_check DT_SCHEMA_FILES=Documentation/devicetree/bindings/phy/rockchip-mipi-dphy-rx0.yaml + +Signed-off-by: Shunqian Zheng +Signed-off-by: Jacob Chen +Signed-off-by: Helen Koike +Link: https://lore.kernel.org/r/20200403161538.1375908-9-helen.koike@collabora.com +Signed-off-by: Heiko Stuebner +(cherry picked from commit e4bfde13e323f9ee5f2f38aa5cac0676dd656f8e) +--- + arch/arm64/boot/dts/rockchip/rk3399.dtsi | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/arch/arm64/boot/dts/rockchip/rk3399.dtsi b/arch/arm64/boot/dts/rockchip/rk3399.dtsi +index 781b5c2cdb4d..f2ef0d8ba54b 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3399.dtsi ++++ b/arch/arm64/boot/dts/rockchip/rk3399.dtsi +@@ -1397,6 +1397,17 @@ io_domains: io-domains { + status = "disabled"; + }; + ++ mipi_dphy_rx0: mipi-dphy-rx0 { ++ compatible = "rockchip,rk3399-mipi-dphy-rx0"; ++ clocks = <&cru SCLK_MIPIDPHY_REF>, ++ <&cru SCLK_DPHY_RX0_CFG>, ++ <&cru PCLK_VIO_GRF>; ++ clock-names = "dphy-ref", "dphy-cfg", "grf"; ++ power-domains = <&power RK3399_PD_VIO>; ++ #phy-cells = <0>; ++ status = "disabled"; ++ }; ++ + u2phy0: usb2-phy@e450 { + compatible = "rockchip,rk3399-usb2phy"; + reg = <0xe450 0x10>; + +From d2266424a494804c6709ea8231fc44e1ca376138 Mon Sep 17 00:00:00 2001 +From: Pierre-Louis Bossart +Date: Tue, 7 Jul 2020 14:06:10 -0500 +Subject: [PATCH] ASoC: codecs: es8316: fix 'defined but not used' warning + +Fix W=1 warning + +sound/soc/codecs/es8316.c:842:36: warning: 'es8316_acpi_match' defined +but not used [-Wunused-const-variable=] + 842 | static const struct acpi_device_id es8316_acpi_match[] = { + | ^~~~~~~~~~~~~~~~~ + +Signed-off-by: Pierre-Louis Bossart +Link: https://lore.kernel.org/r/20200707190612.97799-12-pierre-louis.bossart@linux.intel.com +Signed-off-by: Mark Brown +(cherry picked from commit 07ac670981fc5932ca3799ce7d96431d80afce0e) +--- + sound/soc/codecs/es8316.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/sound/soc/codecs/es8316.c b/sound/soc/codecs/es8316.c +index 36eef1fb3d18..70af35c5f727 100644 +--- a/sound/soc/codecs/es8316.c ++++ b/sound/soc/codecs/es8316.c +@@ -839,11 +839,13 @@ static const struct of_device_id es8316_of_match[] = { + }; + MODULE_DEVICE_TABLE(of, es8316_of_match); + ++#ifdef CONFIG_ACPI + static const struct acpi_device_id es8316_acpi_match[] = { + {"ESSX8316", 0}, + {}, + }; + MODULE_DEVICE_TABLE(acpi, es8316_acpi_match); ++#endif + + static struct i2c_driver es8316_i2c_driver = { + .driver = { + +From 2a38a809f8b033a5ddae29b81fb1209a897689f5 Mon Sep 17 00:00:00 2001 +From: Vinod Koul +Date: Wed, 8 Jul 2020 18:58:07 +0530 +Subject: [PATCH] phy: rockchip-typec: use correct format for structure + description + +We get warning with W=1 build: +drivers/phy/rockchip/phy-rockchip-typec.c:360: warning: cannot +understand function prototype: 'struct rockchip_usb3phy_port_cfg ' + +The 'struct rockchip_usb3phy_port_cfg ' is commented properly but uses +wrong format, so fix that up + +Link: https://lore.kernel.org/r/20200708132809.265967-4-vkoul@kernel.org +Signed-off-by: Vinod Koul +(cherry picked from commit 72fbf95f36218ec2a901e0eb7c3aa0bea6f1f396) +--- + drivers/phy/rockchip/phy-rockchip-typec.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/phy/rockchip/phy-rockchip-typec.c b/drivers/phy/rockchip/phy-rockchip-typec.c +index 24563160197f..70a31251b202 100644 +--- a/drivers/phy/rockchip/phy-rockchip-typec.c ++++ b/drivers/phy/rockchip/phy-rockchip-typec.c +@@ -347,7 +347,7 @@ struct usb3phy_reg { + }; + + /** +- * struct rockchip_usb3phy_port_cfg: usb3-phy port configuration. ++ * struct rockchip_usb3phy_port_cfg - usb3-phy port configuration. + * @reg: the base address for usb3-phy config. + * @typec_conn_dir: the register of type-c connector direction. + * @usb3tousb2_en: the register of type-c force usb2 to usb2 enable. + +From 4210b54dbec5ef3259494989feab48ffde364bb2 Mon Sep 17 00:00:00 2001 +From: Sugar Zhang +Date: Mon, 13 Jul 2020 18:26:00 +0800 +Subject: [PATCH] ASoC: rockchip: spdif: Handle clk by pm runtime + +This patch handle the clk by pm runtime mechanism to simplify +the clk management. + +Signed-off-by: Sugar Zhang +Link: https://lore.kernel.org/r/1594635960-67855-1-git-send-email-sugar.zhang@rock-chips.com +Signed-off-by: Mark Brown +(cherry picked from commit f50d67f9eff62f8078fe6e98ede3f4fb1defc361) +--- + sound/soc/rockchip/rockchip_spdif.c | 59 +++++++++-------------------- + 1 file changed, 17 insertions(+), 42 deletions(-) + +diff --git a/sound/soc/rockchip/rockchip_spdif.c b/sound/soc/rockchip/rockchip_spdif.c +index 6635145a26c4..674810851fbc 100644 +--- a/sound/soc/rockchip/rockchip_spdif.c ++++ b/sound/soc/rockchip/rockchip_spdif.c +@@ -306,44 +306,22 @@ static int rk_spdif_probe(struct platform_device *pdev) + return -ENOMEM; + + spdif->hclk = devm_clk_get(&pdev->dev, "hclk"); +- if (IS_ERR(spdif->hclk)) { +- dev_err(&pdev->dev, "Can't retrieve rk_spdif bus clock\n"); ++ if (IS_ERR(spdif->hclk)) + return PTR_ERR(spdif->hclk); +- } +- ret = clk_prepare_enable(spdif->hclk); +- if (ret) { +- dev_err(spdif->dev, "hclock enable failed %d\n", ret); +- return ret; +- } + + spdif->mclk = devm_clk_get(&pdev->dev, "mclk"); +- if (IS_ERR(spdif->mclk)) { +- dev_err(&pdev->dev, "Can't retrieve rk_spdif master clock\n"); +- ret = PTR_ERR(spdif->mclk); +- goto err_disable_hclk; +- } +- +- ret = clk_prepare_enable(spdif->mclk); +- if (ret) { +- dev_err(spdif->dev, "clock enable failed %d\n", ret); +- goto err_disable_clocks; +- } ++ if (IS_ERR(spdif->mclk)) ++ return PTR_ERR(spdif->mclk); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + regs = devm_ioremap_resource(&pdev->dev, res); +- if (IS_ERR(regs)) { +- ret = PTR_ERR(regs); +- goto err_disable_clocks; +- } ++ if (IS_ERR(regs)) ++ return PTR_ERR(regs); + + spdif->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "hclk", regs, + &rk_spdif_regmap_config); +- if (IS_ERR(spdif->regmap)) { +- dev_err(&pdev->dev, +- "Failed to initialise managed register map\n"); +- ret = PTR_ERR(spdif->regmap); +- goto err_disable_clocks; +- } ++ if (IS_ERR(spdif->regmap)) ++ return PTR_ERR(spdif->regmap); + + spdif->playback_dma_data.addr = res->start + SPDIF_SMPDR; + spdif->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; +@@ -352,47 +330,44 @@ static int rk_spdif_probe(struct platform_device *pdev) + spdif->dev = &pdev->dev; + dev_set_drvdata(&pdev->dev, spdif); + +- pm_runtime_set_active(&pdev->dev); + pm_runtime_enable(&pdev->dev); +- pm_request_idle(&pdev->dev); ++ if (!pm_runtime_enabled(&pdev->dev)) { ++ ret = rk_spdif_runtime_resume(&pdev->dev); ++ if (ret) ++ goto err_pm_runtime; ++ } + + ret = devm_snd_soc_register_component(&pdev->dev, + &rk_spdif_component, + &rk_spdif_dai, 1); + if (ret) { + dev_err(&pdev->dev, "Could not register DAI\n"); +- goto err_pm_runtime; ++ goto err_pm_suspend; + } + + ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0); + if (ret) { + dev_err(&pdev->dev, "Could not register PCM\n"); +- goto err_pm_runtime; ++ goto err_pm_suspend; + } + + return 0; + ++err_pm_suspend: ++ if (!pm_runtime_status_suspended(&pdev->dev)) ++ rk_spdif_runtime_suspend(&pdev->dev); + err_pm_runtime: + pm_runtime_disable(&pdev->dev); +-err_disable_clocks: +- clk_disable_unprepare(spdif->mclk); +-err_disable_hclk: +- clk_disable_unprepare(spdif->hclk); + + return ret; + } + + static int rk_spdif_remove(struct platform_device *pdev) + { +- struct rk_spdif_dev *spdif = dev_get_drvdata(&pdev->dev); +- + pm_runtime_disable(&pdev->dev); + if (!pm_runtime_status_suspended(&pdev->dev)) + rk_spdif_runtime_suspend(&pdev->dev); + +- clk_disable_unprepare(spdif->mclk); +- clk_disable_unprepare(spdif->hclk); +- + return 0; + } + + +From 6af0776af231629c2331f81faa2fdb311cf3ed44 Mon Sep 17 00:00:00 2001 +From: Katsuhiro Suzuki +Date: Tue, 14 Jul 2020 16:32:47 +0900 +Subject: [PATCH] ASoC: convert rk3328 codec binding to yaml + +This patch converts Rockchip rk3328 audio codec binding to DT schema. +And adds description about "mclk" clock and fixes some errors in +original example. + +Signed-off-by: Katsuhiro Suzuki +Reviewed-by: Rob Herring +Link: https://lore.kernel.org/r/20200714073247.172859-1-katsuhiro@katsuster.net +Signed-off-by: Mark Brown +(cherry picked from commit 3f6597ad2f9ed8ed89dbd2a9ec0b0c892774f9d2) +--- + .../bindings/sound/rockchip,rk3328-codec.txt | 28 -------- + .../bindings/sound/rockchip,rk3328-codec.yaml | 69 +++++++++++++++++++ + 2 files changed, 69 insertions(+), 28 deletions(-) + delete mode 100644 Documentation/devicetree/bindings/sound/rockchip,rk3328-codec.txt + create mode 100644 Documentation/devicetree/bindings/sound/rockchip,rk3328-codec.yaml + +diff --git a/Documentation/devicetree/bindings/sound/rockchip,rk3328-codec.txt b/Documentation/devicetree/bindings/sound/rockchip,rk3328-codec.txt +deleted file mode 100644 +index 1ecd75d2032a..000000000000 +--- a/Documentation/devicetree/bindings/sound/rockchip,rk3328-codec.txt ++++ /dev/null +@@ -1,28 +0,0 @@ +-* Rockchip Rk3328 internal codec +- +-Required properties: +- +-- compatible: "rockchip,rk3328-codec" +-- reg: physical base address of the controller and length of memory mapped +- region. +-- rockchip,grf: the phandle of the syscon node for GRF register. +-- clocks: a list of phandle + clock-specifer pairs, one for each entry in clock-names. +-- clock-names: should be "pclk". +-- spk-depop-time-ms: speak depop time msec. +- +-Optional properties: +- +-- mute-gpios: GPIO specifier for external line driver control (typically the +- dedicated GPIO_MUTE pin) +- +-Example for rk3328 internal codec: +- +-codec: codec@ff410000 { +- compatible = "rockchip,rk3328-codec"; +- reg = <0x0 0xff410000 0x0 0x1000>; +- rockchip,grf = <&grf>; +- clocks = <&cru PCLK_ACODEC>; +- clock-names = "pclk"; +- mute-gpios = <&grf_gpio 0 GPIO_ACTIVE_LOW>; +- spk-depop-time-ms = 100; +-}; +diff --git a/Documentation/devicetree/bindings/sound/rockchip,rk3328-codec.yaml b/Documentation/devicetree/bindings/sound/rockchip,rk3328-codec.yaml +new file mode 100644 +index 000000000000..5b85ad5e4834 +--- /dev/null ++++ b/Documentation/devicetree/bindings/sound/rockchip,rk3328-codec.yaml +@@ -0,0 +1,69 @@ ++# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/sound/rockchip,rk3328-codec.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: Rockchip rk3328 internal codec ++ ++maintainers: ++ - Heiko Stuebner ++ ++properties: ++ compatible: ++ const: rockchip,rk3328-codec ++ ++ reg: ++ maxItems: 1 ++ ++ clocks: ++ items: ++ - description: clock for audio codec ++ - description: clock for I2S master clock ++ ++ clock-names: ++ items: ++ - const: pclk ++ - const: mclk ++ ++ rockchip,grf: ++ $ref: /schemas/types.yaml#/definitions/phandle ++ description: ++ The phandle of the syscon node for the GRF register. ++ ++ spk-depop-time-ms: ++ default: 200 ++ description: ++ Speaker depop time in msec. ++ ++ mute-gpios: ++ maxItems: 1 ++ description: ++ GPIO specifier for external line driver control (typically the ++ dedicated GPIO_MUTE pin) ++ ++ "#sound-dai-cells": ++ const: 0 ++ ++required: ++ - compatible ++ - reg ++ - clocks ++ - clock-names ++ - rockchip,grf ++ - "#sound-dai-cells" ++ ++examples: ++ - | ++ #include ++ #include ++ codec: codec@ff410000 { ++ compatible = "rockchip,rk3328-codec"; ++ reg = <0xff410000 0x1000>; ++ clocks = <&cru PCLK_ACODECPHY>, <&cru SCLK_I2S1>; ++ clock-names = "pclk", "mclk"; ++ rockchip,grf = <&grf>; ++ mute-gpios = <&grf_gpio 0 GPIO_ACTIVE_LOW>; ++ spk-depop-time-ms = <100>; ++ #sound-dai-cells = <0>; ++ }; + +From 6917bb6287536dbdd26511d0ba6e6b82bc0f5d86 Mon Sep 17 00:00:00 2001 +From: Sugar Zhang +Date: Mon, 29 Jun 2020 22:05:42 +0800 +Subject: [PATCH] dmaengine: pl330: Remove the burst limit for quirk + 'NO-FLUSHP' + +There is no reason to limit the performance on the 'NO-FLUSHP' SoCs, +because 'FLUSHP' instruction is broken on these platforms, so remove +the limit to improve the efficiency. + +Signed-off-by: Sugar Zhang +Link: https://lore.kernel.org/r/1593439555-68130-2-git-send-email-sugar.zhang@rock-chips.com +Signed-off-by: Vinod Koul +(cherry picked from commit 05611a93b8ffa3fe7d2eb43dd6c11e37ead5908a) +--- + drivers/dma/pl330.c | 10 ++-------- + 1 file changed, 2 insertions(+), 8 deletions(-) + +diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c +index 6a158eef6b8a..7686292bc1db 100644 +--- a/drivers/dma/pl330.c ++++ b/drivers/dma/pl330.c +@@ -1183,9 +1183,6 @@ static inline int _ldst_peripheral(struct pl330_dmac *pl330, + { + int off = 0; + +- if (pl330->quirks & PL330_QUIRK_BROKEN_NO_FLUSHP) +- cond = BURST; +- + /* + * do FLUSHP at beginning to clear any stale dma requests before the + * first WFP. +@@ -2221,9 +2218,7 @@ static bool pl330_prep_slave_fifo(struct dma_pl330_chan *pch, + + static int fixup_burst_len(int max_burst_len, int quirks) + { +- if (quirks & PL330_QUIRK_BROKEN_NO_FLUSHP) +- return 1; +- else if (max_burst_len > PL330_MAX_BURST) ++ if (max_burst_len > PL330_MAX_BURST) + return PL330_MAX_BURST; + else if (max_burst_len < 1) + return 1; +@@ -3128,8 +3123,7 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id) + pd->dst_addr_widths = PL330_DMA_BUSWIDTHS; + pd->directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV); + pd->residue_granularity = DMA_RESIDUE_GRANULARITY_BURST; +- pd->max_burst = ((pl330->quirks & PL330_QUIRK_BROKEN_NO_FLUSHP) ? +- 1 : PL330_MAX_BURST); ++ pd->max_burst = PL330_MAX_BURST; + + ret = dma_async_device_register(pd); + if (ret) { + +From cb00fa158b947abf47ce2f256139a849b3bc8f2e Mon Sep 17 00:00:00 2001 +From: Sugar Zhang +Date: Mon, 29 Jun 2020 22:05:43 +0800 +Subject: [PATCH] dmaengine: pl330: Improve transfer efficiency for the dregs + +Only the unaligned burst transfers have the dregs. +so, still use BURST transfer with a reduced size +for better performance. + +Signed-off-by: Sugar Zhang +Link: https://lore.kernel.org/r/1593439555-68130-3-git-send-email-sugar.zhang@rock-chips.com +Signed-off-by: Vinod Koul +(cherry picked from commit 3e7f0bd872087bf4653eeee9a83050f91baae907) +--- + drivers/dma/pl330.c | 32 +++++++++++++++++++++----------- + 1 file changed, 21 insertions(+), 11 deletions(-) + +diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c +index 7686292bc1db..f1f0176c6c05 100644 +--- a/drivers/dma/pl330.c ++++ b/drivers/dma/pl330.c +@@ -1228,8 +1228,9 @@ static int _bursts(struct pl330_dmac *pl330, unsigned dry_run, u8 buf[], + } + + /* +- * transfer dregs with single transfers to peripheral, or a reduced size burst +- * for mem-to-mem. ++ * only the unaligned burst transfers have the dregs. ++ * so, still transfer dregs with a reduced size burst ++ * for mem-to-mem, mem-to-dev or dev-to-mem. + */ + static int _dregs(struct pl330_dmac *pl330, unsigned int dry_run, u8 buf[], + const struct _xfer_spec *pxs, int transfer_length) +@@ -1240,22 +1241,31 @@ static int _dregs(struct pl330_dmac *pl330, unsigned int dry_run, u8 buf[], + if (transfer_length == 0) + return off; + ++ /* ++ * dregs_len = (total bytes - BURST_TO_BYTE(bursts, ccr)) / ++ * BRST_SIZE(ccr) ++ * the dregs len must be smaller than burst len, ++ * so, for higher efficiency, we can modify CCR ++ * to use a reduced size burst len for the dregs. ++ */ ++ dregs_ccr = pxs->ccr; ++ dregs_ccr &= ~((0xf << CC_SRCBRSTLEN_SHFT) | ++ (0xf << CC_DSTBRSTLEN_SHFT)); ++ dregs_ccr |= (((transfer_length - 1) & 0xf) << ++ CC_SRCBRSTLEN_SHFT); ++ dregs_ccr |= (((transfer_length - 1) & 0xf) << ++ CC_DSTBRSTLEN_SHFT); ++ + switch (pxs->desc->rqtype) { + case DMA_MEM_TO_DEV: + /* fall through */ + case DMA_DEV_TO_MEM: +- off += _ldst_peripheral(pl330, dry_run, &buf[off], pxs, +- transfer_length, SINGLE); ++ off += _emit_MOV(dry_run, &buf[off], CCR, dregs_ccr); ++ off += _ldst_peripheral(pl330, dry_run, &buf[off], pxs, 1, ++ BURST); + break; + + case DMA_MEM_TO_MEM: +- dregs_ccr = pxs->ccr; +- dregs_ccr &= ~((0xf << CC_SRCBRSTLEN_SHFT) | +- (0xf << CC_DSTBRSTLEN_SHFT)); +- dregs_ccr |= (((transfer_length - 1) & 0xf) << +- CC_SRCBRSTLEN_SHFT); +- dregs_ccr |= (((transfer_length - 1) & 0xf) << +- CC_DSTBRSTLEN_SHFT); + off += _emit_MOV(dry_run, &buf[off], CCR, dregs_ccr); + off += _ldst_memtomem(dry_run, &buf[off], pxs, 1); + break; + +From 73de2b83dab82d5b7ad55360f14b1aa35e55eb8f Mon Sep 17 00:00:00 2001 +From: Sugar Zhang +Date: Mon, 29 Jun 2020 22:05:45 +0800 +Subject: [PATCH] dmaengine: pl330: Add quirk 'arm,pl330-periph-burst' + +This patch adds the qurik to use burst transfers only +for pl330 controller, even for request with a length of 1. + +Although, the correct way should be: if the peripheral request +length is 1, the peripheral should use SINGLE request, and then +notify the dmac using SINGLE mode by src/dst_maxburst with 1. + +For example, on the Rockchip SoCs, all the peripherals can use +SINGLE or BURST request by setting GRF registers. it is possible +that if these peripheral drivers are used only for Rockchip SoCs. +Unfortunately, it's not, such as dw uart, which is used so widely, +and we can't set src/dst_maxburst according to the SoCs' specific +to compatible with all the other SoCs. + +So, for convenience, all the peripherals are set as BURST request +by default on the Rockchip SoCs. even for request with a length of 1. +the current pl330 driver will perform SINGLE transfer if the client's +maxburst is 1, which still should be working according to chapter 2.6.6 +of datasheet which describe how DMAC performs SINGLE transfers for +a BURST request. Unfortunately, it's broken on the Rockchip SoCs, +which support only matching transfers, such as BURST transfer for +BURST request, SINGLE transfer for SINGLE request. + +Finally, we add the quirk to specify pl330 to use burst transfers only. + +Signed-off-by: Sugar Zhang +Link: https://lore.kernel.org/r/1593439555-68130-5-git-send-email-sugar.zhang@rock-chips.com +Signed-off-by: Vinod Koul +(cherry picked from commit 5fb9e3a3423313fe6169d5069e471bfdab6e0b79) +--- + drivers/dma/pl330.c | 10 +++++++++- + 1 file changed, 9 insertions(+), 1 deletion(-) + +diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c +index f1f0176c6c05..3be8d462eab4 100644 +--- a/drivers/dma/pl330.c ++++ b/drivers/dma/pl330.c +@@ -33,7 +33,8 @@ + #define PL330_MAX_PERI 32 + #define PL330_MAX_BURST 16 + +-#define PL330_QUIRK_BROKEN_NO_FLUSHP BIT(0) ++#define PL330_QUIRK_BROKEN_NO_FLUSHP BIT(0) ++#define PL330_QUIRK_PERIPH_BURST BIT(1) + + enum pl330_cachectrl { + CCTRL0, /* Noncacheable and nonbufferable */ +@@ -509,6 +510,10 @@ static struct pl330_of_quirks { + { + .quirk = "arm,pl330-broken-no-flushp", + .id = PL330_QUIRK_BROKEN_NO_FLUSHP, ++ }, ++ { ++ .quirk = "arm,pl330-periph-burst", ++ .id = PL330_QUIRK_PERIPH_BURST, + } + }; + +@@ -1206,6 +1211,9 @@ static int _bursts(struct pl330_dmac *pl330, unsigned dry_run, u8 buf[], + int off = 0; + enum pl330_cond cond = BRST_LEN(pxs->ccr) > 1 ? BURST : SINGLE; + ++ if (pl330->quirks & PL330_QUIRK_PERIPH_BURST) ++ cond = BURST; ++ + switch (pxs->desc->rqtype) { + case DMA_MEM_TO_DEV: + /* fall through */ + +From e02c5f202e532c3107f055ff4938852675c9effd Mon Sep 17 00:00:00 2001 +From: Lee Jones +Date: Tue, 14 Jul 2020 12:15:34 +0100 +Subject: [PATCH] dmaengine: pl330: Demote obvious misuse of kerneldoc to + standard comment block + +No 'struct' title is provided. Nor are any attribute descriptions. + +Fixes the following W=1 kernel build warning(s): + + drivers/dma/pl330.c:295: warning: cannot understand function prototype: 'struct pl330_reqcfg ' + +Signed-off-by: Lee Jones +Cc: Philipp Zabel +Cc: Jaswinder Singh +Link: https://lore.kernel.org/r/20200714111546.1755231-6-lee.jones@linaro.org +Signed-off-by: Vinod Koul +(cherry picked from commit f9e036df575d8efce6fd469acd9df3148c2adf6e) +--- + drivers/dma/pl330.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c +index 3be8d462eab4..2c508ee672b9 100644 +--- a/drivers/dma/pl330.c ++++ b/drivers/dma/pl330.c +@@ -285,7 +285,7 @@ struct pl330_config { + u32 irq_ns; + }; + +-/** ++/* + * Request Configuration. + * The PL330 core does not modify this and uses the last + * working configuration if the request doesn't provide any. + +From 90e0dc93ec0461e912927d1667f31be40a277954 Mon Sep 17 00:00:00 2001 +From: Kuninori Morimoto +Date: Thu, 9 Jul 2020 10:55:36 +0900 +Subject: [PATCH] ASoC: hdmi-codec: return -ENOTSUPP for digital_mute + +snd_soc_dai_digital_mute() will return -ENOTSUPP if driver doesn't +support mute. +In hdmi-codec case, hdmi_codec_digital_mute() will be used for it, +and each driver has .digital_mute() callback. +hdmi_codec_digital_mute() want to return -ENOTSUPP to follow it. + +Signed-off-by: Kuninori Morimoto +Link: https://lore.kernel.org/r/87fta1xxjc.wl-kuninori.morimoto.gx@renesas.com +Signed-off-by: Mark Brown +(cherry picked from commit e07e49c0d1e3693facf588142c4cbde45904b3f8) +--- + sound/soc/codecs/hdmi-codec.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c +index f005751da2cc..926ab447a96b 100644 +--- a/sound/soc/codecs/hdmi-codec.c ++++ b/sound/soc/codecs/hdmi-codec.c +@@ -566,7 +566,7 @@ static int hdmi_codec_digital_mute(struct snd_soc_dai *dai, int mute) + return hcp->hcd.ops->digital_mute(dai->dev->parent, + hcp->hcd.data, mute); + +- return 0; ++ return -ENOTSUPP; + } + + static const struct snd_soc_dai_ops hdmi_codec_i2s_dai_ops = { + +From f7c70c0be79698095f473dc90a266d98a4a5d12d Mon Sep 17 00:00:00 2001 +From: Johan Jonker +Date: Wed, 15 Jul 2020 09:09:54 +0200 +Subject: [PATCH] arm64: dts: rockchip: remove bus-width from mmc nodes in px30 + dts files + +'bus-width' has been added to px30.dtsi mmc nodes, so now it can be +removed from the dts files that include it. + +Signed-off-by: Johan Jonker +Link: https://lore.kernel.org/r/20200715070954.1992-1-jbx6244@gmail.com +Signed-off-by: Heiko Stuebner +(cherry picked from commit e7e46a1f6b755248058db531b1cff3b0cc580650) +--- + arch/arm64/boot/dts/rockchip/px30-evb.dts | 3 --- + arch/arm64/boot/dts/rockchip/rk3326-odroid-go2.dts | 1 - + 2 files changed, 4 deletions(-) + +diff --git a/arch/arm64/boot/dts/rockchip/px30-evb.dts b/arch/arm64/boot/dts/rockchip/px30-evb.dts +index 0a680257d9c2..5fe905fae9a8 100644 +--- a/arch/arm64/boot/dts/rockchip/px30-evb.dts ++++ b/arch/arm64/boot/dts/rockchip/px30-evb.dts +@@ -145,7 +145,6 @@ &dsi_dphy { + }; + + &emmc { +- bus-width = <8>; + cap-mmc-highspeed; + mmc-hs200-1_8v; + non-removable; +@@ -499,7 +498,6 @@ &saradc { + }; + + &sdmmc { +- bus-width = <4>; + cap-mmc-highspeed; + cap-sd-highspeed; + card-detect-delay = <800>; +@@ -513,7 +511,6 @@ &sdmmc { + }; + + &sdio { +- bus-width = <4>; + cap-sd-highspeed; + keep-power-in-suspend; + non-removable; +diff --git a/arch/arm64/boot/dts/rockchip/rk3326-odroid-go2.dts b/arch/arm64/boot/dts/rockchip/rk3326-odroid-go2.dts +index b3a8f936578f..35bd6b904b9c 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3326-odroid-go2.dts ++++ b/arch/arm64/boot/dts/rockchip/rk3326-odroid-go2.dts +@@ -445,7 +445,6 @@ &saradc { + }; + + &sdmmc { +- bus-width = <4>; + cap-sd-highspeed; + card-detect-delay = <200>; + cd-gpios = <&gpio0 RK_PA3 GPIO_ACTIVE_LOW>; /*[> CD GPIO <]*/ + +From 3abee17c54e34c806bacab0a257b88ea3d75ab80 Mon Sep 17 00:00:00 2001 +From: Sugar Zhang +Date: Mon, 29 Jun 2020 22:12:11 +0800 +Subject: [PATCH] arm64: dts: rockchip: Add 'arm,pl330-periph-burst' for dmac + +This patch Add the quirk to specify to use burst transfer +for better compatible and higher performance. + +Signed-off-by: Sugar Zhang + +Link: https://lore.kernel.org/r/1593439935-68540-1-git-send-email-sugar.zhang@rock-chips.com +Signed-off-by: Heiko Stuebner +(cherry picked from commit 505af9184ec0a0222bb883486137fac32731e01d) +--- + arch/arm64/boot/dts/rockchip/px30.dtsi | 1 + + arch/arm64/boot/dts/rockchip/rk3308.dtsi | 2 ++ + arch/arm64/boot/dts/rockchip/rk3328.dtsi | 1 + + arch/arm64/boot/dts/rockchip/rk3368.dtsi | 2 ++ + arch/arm64/boot/dts/rockchip/rk3399.dtsi | 2 ++ + 5 files changed, 8 insertions(+) + +diff --git a/arch/arm64/boot/dts/rockchip/px30.dtsi b/arch/arm64/boot/dts/rockchip/px30.dtsi +index e9bb2b97ae55..2695ea8cda14 100644 +--- a/arch/arm64/boot/dts/rockchip/px30.dtsi ++++ b/arch/arm64/boot/dts/rockchip/px30.dtsi +@@ -714,6 +714,7 @@ dmac: dmac@ff240000 { + reg = <0x0 0xff240000 0x0 0x4000>; + interrupts = , + ; ++ arm,pl330-periph-burst; + clocks = <&cru ACLK_DMAC>; + clock-names = "apb_pclk"; + #dma-cells = <1>; +diff --git a/arch/arm64/boot/dts/rockchip/rk3308.dtsi b/arch/arm64/boot/dts/rockchip/rk3308.dtsi +index ba1c71568164..e8b754d415d8 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3308.dtsi ++++ b/arch/arm64/boot/dts/rockchip/rk3308.dtsi +@@ -524,6 +524,7 @@ dmac0: dma-controller@ff2c0000 { + reg = <0x0 0xff2c0000 0x0 0x4000>; + interrupts = , + ; ++ arm,pl330-periph-burst; + clocks = <&cru ACLK_DMAC0>; + clock-names = "apb_pclk"; + #dma-cells = <1>; +@@ -534,6 +535,7 @@ dmac1: dma-controller@ff2d0000 { + reg = <0x0 0xff2d0000 0x0 0x4000>; + interrupts = , + ; ++ arm,pl330-periph-burst; + clocks = <&cru ACLK_DMAC1>; + clock-names = "apb_pclk"; + #dma-cells = <1>; +diff --git a/arch/arm64/boot/dts/rockchip/rk3328.dtsi b/arch/arm64/boot/dts/rockchip/rk3328.dtsi +index 72e655020560..bbdb19a3e85d 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3328.dtsi ++++ b/arch/arm64/boot/dts/rockchip/rk3328.dtsi +@@ -153,6 +153,7 @@ dmac: dmac@ff1f0000 { + reg = <0x0 0xff1f0000 0x0 0x4000>; + interrupts = , + ; ++ arm,pl330-periph-burst; + clocks = <&cru ACLK_DMAC>; + clock-names = "apb_pclk"; + #dma-cells = <1>; +diff --git a/arch/arm64/boot/dts/rockchip/rk3368.dtsi b/arch/arm64/boot/dts/rockchip/rk3368.dtsi +index 5d25a9d04051..3746f23dc3df 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3368.dtsi ++++ b/arch/arm64/boot/dts/rockchip/rk3368.dtsi +@@ -149,6 +149,7 @@ dmac_peri: dma-controller@ff250000 { + ; + #dma-cells = <1>; + arm,pl330-broken-no-flushp; ++ arm,pl330-periph-burst; + clocks = <&cru ACLK_DMAC_PERI>; + clock-names = "apb_pclk"; + }; +@@ -160,6 +161,7 @@ dmac_bus: dma-controller@ff600000 { + ; + #dma-cells = <1>; + arm,pl330-broken-no-flushp; ++ arm,pl330-periph-burst; + clocks = <&cru ACLK_DMAC_BUS>; + clock-names = "apb_pclk"; + }; +diff --git a/arch/arm64/boot/dts/rockchip/rk3399.dtsi b/arch/arm64/boot/dts/rockchip/rk3399.dtsi +index f2ef0d8ba54b..ada724b12f01 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3399.dtsi ++++ b/arch/arm64/boot/dts/rockchip/rk3399.dtsi +@@ -209,6 +209,7 @@ dmac_bus: dma-controller@ff6d0000 { + interrupts = , + ; + #dma-cells = <1>; ++ arm,pl330-periph-burst; + clocks = <&cru ACLK_DMAC0_PERILP>; + clock-names = "apb_pclk"; + }; +@@ -219,6 +220,7 @@ dmac_peri: dma-controller@ff6e0000 { + interrupts = , + ; + #dma-cells = <1>; ++ arm,pl330-periph-burst; + clocks = <&cru ACLK_DMAC1_PERILP>; + clock-names = "apb_pclk"; + }; + +From 932b4a4d3d1ea833e2ac81c122879e4671ee2429 Mon Sep 17 00:00:00 2001 +From: Sugar Zhang +Date: Mon, 29 Jun 2020 22:10:57 +0800 +Subject: [PATCH] ARM: dts: rockchip: Add 'arm,pl330-periph-burst' for dmac + +This patch Add the quirk to specify to use burst transfer +for better compatible and higher performance. + +Signed-off-by: Sugar Zhang + +Link: https://lore.kernel.org/r/1593439866-68459-1-git-send-email-sugar.zhang@rock-chips.com +Signed-off-by: Heiko Stuebner +(cherry picked from commit fb082df317823463eaf09ac88de19fb3319e4f58) +--- + arch/arm/boot/dts/rk3036.dtsi | 1 + + arch/arm/boot/dts/rk322x.dtsi | 1 + + arch/arm/boot/dts/rk3288.dtsi | 3 +++ + arch/arm/boot/dts/rk3xxx.dtsi | 3 +++ + arch/arm/boot/dts/rv1108.dtsi | 1 + + 5 files changed, 9 insertions(+) + +diff --git a/arch/arm/boot/dts/rk3036.dtsi b/arch/arm/boot/dts/rk3036.dtsi +index d9a0c9a29b68..093567022386 100644 +--- a/arch/arm/boot/dts/rk3036.dtsi ++++ b/arch/arm/boot/dts/rk3036.dtsi +@@ -67,6 +67,7 @@ pdma: pdma@20078000 { + ; + #dma-cells = <1>; + arm,pl330-broken-no-flushp; ++ arm,pl330-periph-burst; + clocks = <&cru ACLK_DMAC2>; + clock-names = "apb_pclk"; + }; +diff --git a/arch/arm/boot/dts/rk322x.dtsi b/arch/arm/boot/dts/rk322x.dtsi +index 3236abb0aba9..48e6e8d44a1a 100644 +--- a/arch/arm/boot/dts/rk322x.dtsi ++++ b/arch/arm/boot/dts/rk322x.dtsi +@@ -107,6 +107,7 @@ pdma: pdma@110f0000 { + interrupts = , + ; + #dma-cells = <1>; ++ arm,pl330-periph-burst; + clocks = <&cru ACLK_DMAC>; + clock-names = "apb_pclk"; + }; +diff --git a/arch/arm/boot/dts/rk3288.dtsi b/arch/arm/boot/dts/rk3288.dtsi +index 84d59469035e..9fa11b9f4522 100644 +--- a/arch/arm/boot/dts/rk3288.dtsi ++++ b/arch/arm/boot/dts/rk3288.dtsi +@@ -167,6 +167,7 @@ dmac_peri: dma-controller@ff250000 { + ; + #dma-cells = <1>; + arm,pl330-broken-no-flushp; ++ arm,pl330-periph-burst; + clocks = <&cru ACLK_DMAC2>; + clock-names = "apb_pclk"; + }; +@@ -178,6 +179,7 @@ dmac_bus_ns: dma-controller@ff600000 { + ; + #dma-cells = <1>; + arm,pl330-broken-no-flushp; ++ arm,pl330-periph-burst; + clocks = <&cru ACLK_DMAC1>; + clock-names = "apb_pclk"; + status = "disabled"; +@@ -190,6 +192,7 @@ dmac_bus_s: dma-controller@ffb20000 { + ; + #dma-cells = <1>; + arm,pl330-broken-no-flushp; ++ arm,pl330-periph-burst; + clocks = <&cru ACLK_DMAC1>; + clock-names = "apb_pclk"; + }; +diff --git a/arch/arm/boot/dts/rk3xxx.dtsi b/arch/arm/boot/dts/rk3xxx.dtsi +index d929b60517ab..859a7477909f 100644 +--- a/arch/arm/boot/dts/rk3xxx.dtsi ++++ b/arch/arm/boot/dts/rk3xxx.dtsi +@@ -45,6 +45,7 @@ dmac1_s: dma-controller@20018000 { + ; + #dma-cells = <1>; + arm,pl330-broken-no-flushp; ++ arm,pl330-periph-burst; + clocks = <&cru ACLK_DMA1>; + clock-names = "apb_pclk"; + }; +@@ -56,6 +57,7 @@ dmac1_ns: dma-controller@2001c000 { + ; + #dma-cells = <1>; + arm,pl330-broken-no-flushp; ++ arm,pl330-periph-burst; + clocks = <&cru ACLK_DMA1>; + clock-names = "apb_pclk"; + status = "disabled"; +@@ -68,6 +70,7 @@ dmac2: dma-controller@20078000 { + ; + #dma-cells = <1>; + arm,pl330-broken-no-flushp; ++ arm,pl330-periph-burst; + clocks = <&cru ACLK_DMA2>; + clock-names = "apb_pclk"; + }; +diff --git a/arch/arm/boot/dts/rv1108.dtsi b/arch/arm/boot/dts/rv1108.dtsi +index a5d130bd0547..a1a08cb9364e 100644 +--- a/arch/arm/boot/dts/rv1108.dtsi ++++ b/arch/arm/boot/dts/rv1108.dtsi +@@ -97,6 +97,7 @@ pdma: pdma@102a0000 { + interrupts = ; + #dma-cells = <1>; + arm,pl330-broken-no-flushp; ++ arm,pl330-periph-burst; + clocks = <&cru ACLK_DMAC>; + clock-names = "apb_pclk"; + }; + +From ea1abccee16e018a29011224d0e7b5392d818e70 Mon Sep 17 00:00:00 2001 +From: Jagan Teki +Date: Wed, 15 Jul 2020 14:04:12 +0530 +Subject: [PATCH] ARM: dts: rockchip: dalang-carrier: Move i2c nodes into SOM + +I2C nodes and associated slave devices defined in Carrier board +are specific to rk3399pro vmrac SOM. + +So, move them into SOM dtsi. + +Signed-off-by: Jagan Teki +Link: https://lore.kernel.org/r/20200715083418.112003-2-jagan@amarulasolutions.com +Signed-off-by: Heiko Stuebner +(cherry picked from commit c2f343510d99ab53b46bdfeb184cb48f622e6943) +--- + .../dts/rockchip-radxa-dalang-carrier.dtsi | 32 ------------------- + .../dts/rockchip/rk3399pro-vmarc-som.dtsi | 29 +++++++++++++++++ + 2 files changed, 29 insertions(+), 32 deletions(-) + +diff --git a/arch/arm/boot/dts/rockchip-radxa-dalang-carrier.dtsi b/arch/arm/boot/dts/rockchip-radxa-dalang-carrier.dtsi +index df3712aedf8a..176b53b8e41a 100644 +--- a/arch/arm/boot/dts/rockchip-radxa-dalang-carrier.dtsi ++++ b/arch/arm/boot/dts/rockchip-radxa-dalang-carrier.dtsi +@@ -17,29 +17,6 @@ &gmac { + status = "okay"; + }; + +-&i2c1 { +- status = "okay"; +- i2c-scl-rising-time-ns = <140>; +- i2c-scl-falling-time-ns = <30>; +-}; +- +-&i2c2 { +- status = "okay"; +- clock-frequency = <400000>; +- +- hym8563: hym8563@51 { +- compatible = "haoyu,hym8563"; +- reg = <0x51>; +- #clock-cells = <0>; +- clock-frequency = <32768>; +- clock-output-names = "hym8563"; +- pinctrl-names = "default"; +- pinctrl-0 = <&hym8563_int>; +- interrupt-parent = <&gpio4>; +- interrupts = <30 IRQ_TYPE_LEVEL_LOW>; +- }; +-}; +- + &pwm0 { + status = "okay"; + }; +@@ -70,12 +47,3 @@ &uart0 { + &uart2 { + status = "okay"; + }; +- +-&pinctrl { +- hym8563 { +- hym8563_int: hym8563-int { +- rockchip,pins = +- <4 RK_PD6 0 &pcfg_pull_up>; +- }; +- }; +-}; +diff --git a/arch/arm64/boot/dts/rockchip/rk3399pro-vmarc-som.dtsi b/arch/arm64/boot/dts/rockchip/rk3399pro-vmarc-som.dtsi +index 0a516334f15f..e11538171e67 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3399pro-vmarc-som.dtsi ++++ b/arch/arm64/boot/dts/rockchip/rk3399pro-vmarc-som.dtsi +@@ -297,6 +297,29 @@ regulator-state-mem { + }; + }; + ++&i2c1 { ++ i2c-scl-falling-time-ns = <30>; ++ i2c-scl-rising-time-ns = <140>; ++ status = "okay"; ++}; ++ ++&i2c2 { ++ clock-frequency = <400000>; ++ status = "okay"; ++ ++ hym8563: hym8563@51 { ++ compatible = "haoyu,hym8563"; ++ reg = <0x51>; ++ #clock-cells = <0>; ++ clock-frequency = <32768>; ++ clock-output-names = "hym8563"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&hym8563_int>; ++ interrupt-parent = <&gpio4>; ++ interrupts = ; ++ }; ++}; ++ + &io_domains { + status = "okay"; + bt656-supply = <&vcca_1v8>; +@@ -324,6 +347,12 @@ &tsadc { + }; + + &pinctrl { ++ hym8563 { ++ hym8563_int: hym8563-int { ++ rockchip,pins = <4 RK_PD6 0 &pcfg_pull_up>; ++ }; ++ }; ++ + pmic { + pmic_int_l: pmic-int-l { + rockchip,pins = + +From 2e13dc44e6d147dad03cc7f4024ec9152f329fa9 Mon Sep 17 00:00:00 2001 +From: Jagan Teki +Date: Wed, 15 Jul 2020 14:04:13 +0530 +Subject: [PATCH] arm64: dts: rk3399pro: vmarc-som: Fix sorting nodes, + properties + +Fix node, properties sorting on RockPI N10 board dts(i) files. + +Signed-off-by: Jagan Teki +Link: https://lore.kernel.org/r/20200715083418.112003-3-jagan@amarulasolutions.com +Signed-off-by: Heiko Stuebner +(cherry picked from commit 3047b384a74090f09b994298eb5c40986275233a) +--- + .../dts/rockchip/rk3399pro-rock-pi-n10.dts | 2 +- + .../dts/rockchip/rk3399pro-vmarc-som.dtsi | 35 +++++++++---------- + 2 files changed, 18 insertions(+), 19 deletions(-) + +diff --git a/arch/arm64/boot/dts/rockchip/rk3399pro-rock-pi-n10.dts b/arch/arm64/boot/dts/rockchip/rk3399pro-rock-pi-n10.dts +index a1783e7f769a..539f4005386d 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3399pro-rock-pi-n10.dts ++++ b/arch/arm64/boot/dts/rockchip/rk3399pro-rock-pi-n10.dts +@@ -8,8 +8,8 @@ + /dts-v1/; + #include "rk3399.dtsi" + #include "rk3399-opp.dtsi" +-#include "rk3399pro-vmarc-som.dtsi" + #include ++#include "rk3399pro-vmarc-som.dtsi" + + / { + model = "Radxa ROCK Pi N10"; +diff --git a/arch/arm64/boot/dts/rockchip/rk3399pro-vmarc-som.dtsi b/arch/arm64/boot/dts/rockchip/rk3399pro-vmarc-som.dtsi +index e11538171e67..121a430d6a70 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3399pro-vmarc-som.dtsi ++++ b/arch/arm64/boot/dts/rockchip/rk3399pro-vmarc-som.dtsi +@@ -76,8 +76,8 @@ &gmac { + + &i2c0 { + clock-frequency = <400000>; +- i2c-scl-rising-time-ns = <180>; + i2c-scl-falling-time-ns = <30>; ++ i2c-scl-rising-time-ns = <180>; + status = "okay"; + + rk809: pmic@20 { +@@ -323,8 +323,22 @@ hym8563: hym8563@51 { + &io_domains { + status = "okay"; + bt656-supply = <&vcca_1v8>; +- sdmmc-supply = <&vccio_sd>; + gpio1830-supply = <&vccio_3v0>; ++ sdmmc-supply = <&vccio_sd>; ++}; ++ ++&pinctrl { ++ hym8563 { ++ hym8563_int: hym8563-int { ++ rockchip,pins = <4 RK_PD6 0 &pcfg_pull_up>; ++ }; ++ }; ++ ++ pmic { ++ pmic_int_l: pmic-int-l { ++ rockchip,pins = <1 RK_PC2 0 &pcfg_pull_up>; ++ }; ++ }; + }; + + &pmu_io_domains { +@@ -341,22 +355,7 @@ &sdhci { + }; + + &tsadc { +- status = "okay"; + rockchip,hw-tshut-mode = <1>; + rockchip,hw-tshut-polarity = <1>; +-}; +- +-&pinctrl { +- hym8563 { +- hym8563_int: hym8563-int { +- rockchip,pins = <4 RK_PD6 0 &pcfg_pull_up>; +- }; +- }; +- +- pmic { +- pmic_int_l: pmic-int-l { +- rockchip,pins = +- <1 RK_PC2 0 &pcfg_pull_up>; +- }; +- }; ++ status = "okay"; + }; + +From 4617f4569e155d9512cdfa8defdea925cd30b9e4 Mon Sep 17 00:00:00 2001 +From: Jagan Teki +Date: Wed, 15 Jul 2020 14:04:14 +0530 +Subject: [PATCH] arm64: dts: rk3399pro: vmarc-som: Move supply regulators into + Carrier + +Supply regulators are common across different variants of vmarc SOM's +since the Type C power controller IC is part of the carrier board. + +So, move the supply regulators into carrier board dtsi. + +Signed-off-by: Jagan Teki +Link: https://lore.kernel.org/r/20200715083418.112003-4-jagan@amarulasolutions.com +Signed-off-by: Heiko Stuebner +(cherry picked from commit 4a3ca113c0f3a2ce33e51fc6a48a121b2d707d4f) +--- + .../dts/rockchip-radxa-dalang-carrier.dtsi | 19 +++++++++++++++++++ + .../dts/rockchip/rk3399pro-vmarc-som.dtsi | 19 ------------------- + 2 files changed, 19 insertions(+), 19 deletions(-) + +diff --git a/arch/arm/boot/dts/rockchip-radxa-dalang-carrier.dtsi b/arch/arm/boot/dts/rockchip-radxa-dalang-carrier.dtsi +index 176b53b8e41a..00b200a62263 100644 +--- a/arch/arm/boot/dts/rockchip-radxa-dalang-carrier.dtsi ++++ b/arch/arm/boot/dts/rockchip-radxa-dalang-carrier.dtsi +@@ -11,6 +11,25 @@ / { + chosen { + stdout-path = "serial2:1500000n8"; + }; ++ ++ vcc12v_dcin: vcc12v-dcin-regulator { ++ compatible = "regulator-fixed"; ++ regulator-name = "vcc12v_dcin"; ++ regulator-always-on; ++ regulator-boot-on; ++ regulator-min-microvolt = <12000000>; ++ regulator-max-microvolt = <12000000>; ++ }; ++ ++ vcc5v0_sys: vcc5v0-sys-regulator { ++ compatible = "regulator-fixed"; ++ regulator-name = "vcc5v0_sys"; ++ regulator-always-on; ++ regulator-boot-on; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; ++ vin-supply = <&vcc12v_dcin>; ++ }; + }; + + &gmac { +diff --git a/arch/arm64/boot/dts/rockchip/rk3399pro-vmarc-som.dtsi b/arch/arm64/boot/dts/rockchip/rk3399pro-vmarc-som.dtsi +index 121a430d6a70..d8fa8127d9dc 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3399pro-vmarc-som.dtsi ++++ b/arch/arm64/boot/dts/rockchip/rk3399pro-vmarc-som.dtsi +@@ -18,25 +18,6 @@ clkin_gmac: external-gmac-clock { + clock-output-names = "clkin_gmac"; + #clock-cells = <0>; + }; +- +- vcc12v_dcin: vcc12v-dcin-regulator { +- compatible = "regulator-fixed"; +- regulator-name = "vcc12v_dcin"; +- regulator-always-on; +- regulator-boot-on; +- regulator-min-microvolt = <12000000>; +- regulator-max-microvolt = <12000000>; +- }; +- +- vcc5v0_sys: vcc5v0-sys-regulator { +- compatible = "regulator-fixed"; +- regulator-name = "vcc5v0_sys"; +- regulator-always-on; +- regulator-boot-on; +- regulator-min-microvolt = <5000000>; +- regulator-max-microvolt = <5000000>; +- vin-supply = <&vcc12v_dcin>; +- }; + }; + + &cpu_l0 { + +From 772d02fccf2734a12aaaf22398aa70986a2868c7 Mon Sep 17 00:00:00 2001 +From: Jagan Teki +Date: Wed, 15 Jul 2020 14:04:15 +0530 +Subject: [PATCH] arm64: dts: rk3399pro: vmarc-som: Move common properties into + Carrier + +Some of gmac, sdmmc node properties are common across rk3288 and +rk3399pro SOM's so move them into Carrier dtsi. + +Chosen node is specific to rk3399pro configure SBC, so move it into +RockPI N10 dts. + +Signed-off-by: Jagan Teki +Link: https://lore.kernel.org/r/20200715083418.112003-5-jagan@amarulasolutions.com +Signed-off-by: Heiko Stuebner +(cherry picked from commit a66bd94d0eac017e4846658750acaca2937555bb) +--- + .../dts/rockchip-radxa-dalang-carrier.dtsi | 18 ++++++++++++---- + .../dts/rockchip/rk3399pro-rock-pi-n10.dts | 4 ++++ + .../dts/rockchip/rk3399pro-vmarc-som.dtsi | 21 +++++-------------- + 3 files changed, 23 insertions(+), 20 deletions(-) + +diff --git a/arch/arm/boot/dts/rockchip-radxa-dalang-carrier.dtsi b/arch/arm/boot/dts/rockchip-radxa-dalang-carrier.dtsi +index 00b200a62263..450e5bb5af0b 100644 +--- a/arch/arm/boot/dts/rockchip-radxa-dalang-carrier.dtsi ++++ b/arch/arm/boot/dts/rockchip-radxa-dalang-carrier.dtsi +@@ -8,8 +8,11 @@ + #include + + / { +- chosen { +- stdout-path = "serial2:1500000n8"; ++ clkin_gmac: external-gmac-clock { ++ compatible = "fixed-clock"; ++ clock-frequency = <125000000>; ++ clock-output-names = "clkin_gmac"; ++ #clock-cells = <0>; + }; + + vcc12v_dcin: vcc12v-dcin-regulator { +@@ -33,6 +36,15 @@ vcc5v0_sys: vcc5v0-sys-regulator { + }; + + &gmac { ++ assigned-clock-parents = <&clkin_gmac>; ++ clock_in_out = "input"; ++ phy-mode = "rgmii"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&rgmii_pins>; ++ snps,reset-active-low; ++ snps,reset-delays-us = <0 10000 50000>; ++ tx_delay = <0x28>; ++ rx_delay = <0x11>; + status = "okay"; + }; + +@@ -48,10 +60,8 @@ &sdmmc { + bus-width = <4>; + cap-mmc-highspeed; + cap-sd-highspeed; +- cd-gpios = <&gpio0 RK_PA7 GPIO_ACTIVE_LOW>; + disable-wp; + vqmmc-supply = <&vccio_sd>; +- max-frequency = <150000000>; + pinctrl-names = "default"; + pinctrl-0 = <&sdmmc_clk &sdmmc_cmd &sdmmc_cd &sdmmc_bus4>; + status = "okay"; +diff --git a/arch/arm64/boot/dts/rockchip/rk3399pro-rock-pi-n10.dts b/arch/arm64/boot/dts/rockchip/rk3399pro-rock-pi-n10.dts +index 539f4005386d..369de5dc0ebd 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3399pro-rock-pi-n10.dts ++++ b/arch/arm64/boot/dts/rockchip/rk3399pro-rock-pi-n10.dts +@@ -15,4 +15,8 @@ / { + model = "Radxa ROCK Pi N10"; + compatible = "radxa,rockpi-n10", "vamrs,rk3399pro-vmarc-som", + "rockchip,rk3399pro"; ++ ++ chosen { ++ stdout-path = "serial2:1500000n8"; ++ }; + }; +diff --git a/arch/arm64/boot/dts/rockchip/rk3399pro-vmarc-som.dtsi b/arch/arm64/boot/dts/rockchip/rk3399pro-vmarc-som.dtsi +index d8fa8127d9dc..37ed95d5f7e9 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3399pro-vmarc-som.dtsi ++++ b/arch/arm64/boot/dts/rockchip/rk3399pro-vmarc-som.dtsi +@@ -11,13 +11,6 @@ + + / { + compatible = "vamrs,rk3399pro-vmarc-som", "rockchip,rk3399pro"; +- +- clkin_gmac: external-gmac-clock { +- compatible = "fixed-clock"; +- clock-frequency = <125000000>; +- clock-output-names = "clkin_gmac"; +- #clock-cells = <0>; +- }; + }; + + &cpu_l0 { +@@ -42,17 +35,8 @@ &emmc_phy { + + &gmac { + assigned-clocks = <&cru SCLK_RMII_SRC>; +- assigned-clock-parents = <&clkin_gmac>; +- clock_in_out = "input"; + phy-supply = <&vcc_lan>; +- phy-mode = "rgmii"; +- pinctrl-names = "default"; +- pinctrl-0 = <&rgmii_pins>; + snps,reset-gpio = <&gpio3 RK_PB7 GPIO_ACTIVE_LOW>; +- snps,reset-active-low; +- snps,reset-delays-us = <0 10000 50000>; +- tx_delay = <0x28>; +- rx_delay = <0x11>; + }; + + &i2c0 { +@@ -335,6 +319,11 @@ &sdhci { + status = "okay"; + }; + ++&sdmmc { ++ cd-gpios = <&gpio0 RK_PA7 GPIO_ACTIVE_LOW>; ++ max-frequency = <150000000>; ++}; ++ + &tsadc { + rockchip,hw-tshut-mode = <1>; + rockchip,hw-tshut-polarity = <1>; + +From 916191ead33a0ce0baec3a3cadb386c12d9a1b99 Mon Sep 17 00:00:00 2001 +From: Jagan Teki +Date: Wed, 15 Jul 2020 14:04:16 +0530 +Subject: [PATCH] dt-bindings: arm: rockchip: Add Rock Pi N8 binding + +Rock Pi N8 is a Rockchip RK3288 based SBC, which has +- VMARC RK3288 SOM (as per SMARC standard) from Vamrs. +- Compatible carrier board from Radxa. + +VMARC RK3288 SOM need to mount on top of dalang carrier +board for making Rock PI N8 SBC. + +Add dt-bindings for it. + +Signed-off-by: Jagan Teki +Reviewed-by: Rob Herring +Link: https://lore.kernel.org/r/20200715083418.112003-6-jagan@amarulasolutions.com +Signed-off-by: Heiko Stuebner +(cherry picked from commit 09ee4794270f0010c6397163f033f883f5bff1aa) +--- + Documentation/devicetree/bindings/arm/rockchip.yaml | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/Documentation/devicetree/bindings/arm/rockchip.yaml b/Documentation/devicetree/bindings/arm/rockchip.yaml +index d4a4045092df..db2e35796795 100644 +--- a/Documentation/devicetree/bindings/arm/rockchip.yaml ++++ b/Documentation/devicetree/bindings/arm/rockchip.yaml +@@ -435,6 +435,12 @@ properties: + - const: radxa,rockpi4 + - const: rockchip,rk3399 + ++ - description: Radxa ROCK Pi N8 ++ items: ++ - const: radxa,rockpi-n8 ++ - const: vamrs,rk3288-vmarc-som ++ - const: rockchip,rk3288 ++ + - description: Radxa ROCK Pi N10 + items: + - const: radxa,rockpi-n10 + +From 2a5e46160a746adc9a7b9b952e2000060d6da48a Mon Sep 17 00:00:00 2001 +From: Jagan Teki +Date: Wed, 15 Jul 2020 14:04:17 +0530 +Subject: [PATCH] ARM: dts: rockchip: Add VMARC RK3288 SOM initial support + +VMARC RK3288 SOM is a standard SMARC SOM design with +Rockchip RK3288 SoC, which is designed by Vamrs. + +Specification: +- Rockchip RK3288 +- PMIC: RK808 +- eMMC: 16GB/32GB/64GB +- SD slot +- 2xUSB-2.0, 1xUSB3.0 +- USB-C for power supply +- Ethernet +- HDMI, MIPI-DSI/CSI, eDP + +Add initial support for VMARC RK3288 SOM, this would use +with associated carrier board. + +Signed-off-by: Jagan Teki +Link: https://lore.kernel.org/r/20200715083418.112003-7-jagan@amarulasolutions.com +Signed-off-by: Heiko Stuebner +(cherry picked from commit b8c564d4fa76b1314a10585eea8e97b8c621a77a) +--- + arch/arm/boot/dts/rk3288-vmarc-som.dtsi | 270 ++++++++++++++++++++++++ + 1 file changed, 270 insertions(+) + create mode 100644 arch/arm/boot/dts/rk3288-vmarc-som.dtsi + +diff --git a/arch/arm/boot/dts/rk3288-vmarc-som.dtsi b/arch/arm/boot/dts/rk3288-vmarc-som.dtsi +new file mode 100644 +index 000000000000..cd61b6230f0d +--- /dev/null ++++ b/arch/arm/boot/dts/rk3288-vmarc-som.dtsi +@@ -0,0 +1,270 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR MIT) ++/* ++ * Copyright (c) 2019 Fuzhou Rockchip Electronics Co., Ltd ++ * Copyright (c) 2019 Vamrs Limited ++ * Copyright (c) 2019 Amarula Solutions(India) ++ */ ++ ++#include ++#include ++ ++/ { ++ compatible = "vamrs,rk3288-vmarc-som", "rockchip,rk3288"; ++ ++ vccio_flash: vccio-flash-regulator { ++ compatible = "regulator-fixed"; ++ regulator-name = "vccio_flash"; ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <1800000>; ++ vin-supply = <&vcc_io>; ++ }; ++}; ++ ++&emmc { ++ bus-width = <8>; ++ cap-mmc-highspeed; ++ disable-wp; ++ non-removable; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&emmc_clk &emmc_cmd &emmc_pwr &emmc_bus8>; ++ vmmc-supply = <&vcc_io>; ++ vqmmc-supply = <&vccio_flash>; ++ status = "okay"; ++}; ++ ++&gmac { ++ assigned-clocks = <&cru SCLK_MAC>; ++ phy-supply = <&vcc_io>; ++ snps,reset-gpio = <&gpio4 RK_PA7 GPIO_ACTIVE_HIGH>; ++}; ++ ++&i2c0 { ++ clock-frequency = <400000>; ++ status = "okay"; ++ ++ rk808: pmic@1b { ++ compatible = "rockchip,rk808"; ++ reg = <0x1b>; ++ interrupt-parent = <&gpio0>; ++ interrupts = ; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pmic_int &global_pwroff>; ++ rockchip,system-power-controller; ++ wakeup-source; ++ #clock-cells = <1>; ++ clock-output-names = "rk808-clkout1", "rk808-clkout2"; ++ ++ vcc1-supply = <&vcc5v0_sys>; ++ vcc2-supply = <&vcc5v0_sys>; ++ vcc3-supply = <&vcc5v0_sys>; ++ vcc4-supply = <&vcc5v0_sys>; ++ vcc6-supply = <&vcc5v0_sys>; ++ vcc7-supply = <&vcc5v0_sys>; ++ vcc8-supply = <&vcc_io>; ++ vcc9-supply = <&vcc_io>; ++ vcc10-supply = <&vcc5v0_sys>; ++ vcc11-supply = <&vcc5v0_sys>; ++ vcc12-supply = <&vcc_io>; ++ vddio-supply = <&vcc_io>; ++ ++ regulators { ++ vdd_cpu: DCDC_REG1 { ++ regulator-name = "vdd_arm"; ++ regulator-always-on; ++ regulator-boot-on; ++ regulator-min-microvolt = <750000>; ++ regulator-max-microvolt = <1400000>; ++ regulator-state-mem { ++ regulator-off-in-suspend; ++ }; ++ }; ++ ++ vdd_gpu: DCDC_REG2 { ++ regulator-name = "vdd_gpu"; ++ regulator-always-on; ++ regulator-boot-on; ++ regulator-min-microvolt = <850000>; ++ regulator-max-microvolt = <1250000>; ++ regulator-ramp-delay = <6000>; ++ regulator-state-mem { ++ regulator-off-in-suspend; ++ }; ++ }; ++ ++ vcc_ddr: DCDC_REG3 { ++ regulator-name = "vcc_ddr"; ++ regulator-always-on; ++ regulator-boot-on; ++ regulator-state-mem { ++ regulator-on-in-suspend; ++ }; ++ }; ++ ++ vcc_io: DCDC_REG4 { ++ regulator-name = "vcc_io"; ++ regulator-always-on; ++ regulator-boot-on; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-state-mem { ++ regulator-on-in-suspend; ++ regulator-suspend-microvolt = <3300000>; ++ }; ++ }; ++ ++ vcc_tp: LDO_REG1 { ++ regulator-name = "vcc_tp"; ++ regulator-always-on; ++ regulator-boot-on; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-state-mem { ++ regulator-off-in-suspend; ++ }; ++ }; ++ ++ vcca_codec: LDO_REG2 { ++ regulator-name = "vcca_codec"; ++ regulator-always-on; ++ regulator-boot-on; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-state-mem { ++ regulator-on-in-suspend; ++ regulator-suspend-microvolt = <3300000>; ++ }; ++ }; ++ ++ vdd_10: LDO_REG3 { ++ regulator-name = "vdd_10"; ++ regulator-always-on; ++ regulator-boot-on; ++ regulator-min-microvolt = <1000000>; ++ regulator-max-microvolt = <1000000>; ++ regulator-state-mem { ++ regulator-on-in-suspend; ++ regulator-suspend-microvolt = <1000000>; ++ }; ++ }; ++ ++ vcc_wl: LDO_REG4 { ++ regulator-name = "vcc_wl"; ++ regulator-always-on; ++ regulator-boot-on; ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <1800000>; ++ regulator-state-mem { ++ regulator-on-in-suspend; ++ }; ++ }; ++ ++ vccio_sd: LDO_REG5 { ++ regulator-name = "vccio_sd"; ++ regulator-always-on; ++ regulator-boot-on; ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-state-mem { ++ regulator-on-in-suspend; ++ regulator-suspend-microvolt = <3300000>; ++ }; ++ }; ++ ++ vdd10_lcd: LDO_REG6 { ++ regulator-name = "vdd10_lcd"; ++ regulator-always-on; ++ regulator-boot-on; ++ regulator-min-microvolt = <1000000>; ++ regulator-max-microvolt = <1000000>; ++ regulator-state-mem { ++ regulator-off-in-suspend; ++ }; ++ }; ++ ++ vcc_18: LDO_REG7 { ++ regulator-name = "vcc_18"; ++ regulator-always-on; ++ regulator-boot-on; ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <1800000>; ++ regulator-state-mem { ++ regulator-on-in-suspend; ++ regulator-suspend-microvolt = <1800000>; ++ }; ++ }; ++ ++ vcc18_lcd: LDO_REG8 { ++ regulator-name = "vcc18_lcd"; ++ regulator-always-on; ++ regulator-boot-on; ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <1800000>; ++ regulator-state-mem { ++ regulator-off-in-suspend; ++ }; ++ }; ++ ++ vcc_sd: SWITCH_REG1 { ++ regulator-name = "vcc_sd"; ++ regulator-always-on; ++ regulator-boot-on; ++ regulator-state-mem { ++ regulator-off-in-suspend; ++ }; ++ }; ++ ++ vcc_lcd: SWITCH_REG2 { ++ regulator-name = "vcc_lcd"; ++ regulator-always-on; ++ regulator-boot-on; ++ regulator-state-mem { ++ regulator-off-in-suspend; ++ }; ++ }; ++ }; ++ }; ++}; ++ ++&io_domains { ++ bb-supply = <&vcc_io>; ++ flash0-supply = <&vccio_flash>; ++ gpio1830-supply = <&vcc_18>; ++ gpio30-supply = <&vcc_io>; ++ sdcard-supply = <&vccio_sd>; ++ status = "okay"; ++}; ++ ++&pinctrl { ++ pcfg_pull_none_drv_8ma: pcfg-pull-none-drv-8ma { ++ drive-strength = <8>; ++ }; ++ ++ pcfg_pull_up_drv_8ma: pcfg-pull-up-drv-8ma { ++ bias-pull-up; ++ drive-strength = <8>; ++ }; ++ ++ pmic { ++ pmic_int: pmic-int { ++ rockchip,pins = <0 RK_PA4 RK_FUNC_GPIO &pcfg_pull_up>; ++ }; ++ }; ++ ++ sdmmc { ++ sdmmc_bus4: sdmmc-bus4 { ++ rockchip,pins = ++ <6 RK_PC0 1 &pcfg_pull_up_drv_8ma>, ++ <6 RK_PC1 1 &pcfg_pull_up_drv_8ma>, ++ <6 RK_PC2 1 &pcfg_pull_up_drv_8ma>, ++ <6 RK_PC3 1 &pcfg_pull_up_drv_8ma>; ++ }; ++ ++ sdmmc_clk: sdmmc-clk { ++ rockchip,pins = <6 RK_PC4 1 &pcfg_pull_none_drv_8ma>; ++ }; ++ ++ sdmmc_cmd: sdmmc-cmd { ++ rockchip,pins = <6 RK_PC5 1 &pcfg_pull_up_drv_8ma>; ++ }; ++ }; ++}; + +From 10ff584a4e12d06e7f041b37f806bd6ffac91f94 Mon Sep 17 00:00:00 2001 +From: Michael Trimarchi +Date: Tue, 7 Jul 2020 12:12:14 +0200 +Subject: [PATCH] ARM: dts: rockchip: Fix VBUS on rk3288-vyasa + +Connect the voltage regulator of vbus to the otg connector. +Depending on the current mode this is enabled (in "host" mode") +or disabled (in "peripheral" mode). The regulator must be updated +if the controller is configured in "otg" mode and the status changes +between "host" and "peripheral". + +Signed-off-by: Michael Trimarchi +Link: https://lore.kernel.org/r/20200707101214.2301768-1-michael@amarulasolutions.com +Signed-off-by: Heiko Stuebner +(cherry picked from commit 719646b76a41b8a482f8701825b635e9710ab329) +--- + arch/arm/boot/dts/rk3288-vyasa.dts | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/arch/arm/boot/dts/rk3288-vyasa.dts b/arch/arm/boot/dts/rk3288-vyasa.dts +index 385dd59393e1..1a20854a1317 100644 +--- a/arch/arm/boot/dts/rk3288-vyasa.dts ++++ b/arch/arm/boot/dts/rk3288-vyasa.dts +@@ -99,8 +99,6 @@ vusb1_5v: vusb1-5v { + pinctrl-0 = <&otg_vbus_drv>; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; +- regulator-always-on; +- regulator-boot-on; + vin-supply = <&vsus_5v>; + }; + +@@ -416,6 +414,7 @@ &usb_host1 { + }; + + &usb_otg { ++ vbus-supply = <&vusb1_5v>; + status = "okay"; + }; + + +From 8635890fdcf41e911c4e3dd5213f3ff891513cab Mon Sep 17 00:00:00 2001 +From: Jagan Teki +Date: Mon, 20 Jul 2020 16:28:46 +0530 +Subject: [PATCH] ARM: dts: rockchip: Add usb host0 ohci node for rk3288 + +rk3288 and rk3288w have a usb host0 ohci controller. + +Although rk3288 ohci doesn't actually work on hardware, but +rk3288w ohci can work well. + +So add usb host0 ohci node in rk3288 dtsi and boards +can then enable it if supported. + +Signed-off-by: Jagan Teki +Cc: William Wu +Link: https://lore.kernel.org/r/20200720105846.367776-1-jagan@amarulasolutions.com +Signed-off-by: Heiko Stuebner +(cherry picked from commit 82540defdd9cfc491f564ffb8d01911966636bc7) +--- + arch/arm/boot/dts/rk3288.dtsi | 11 ++++++++++- + 1 file changed, 10 insertions(+), 1 deletion(-) + +diff --git a/arch/arm/boot/dts/rk3288.dtsi b/arch/arm/boot/dts/rk3288.dtsi +index 9fa11b9f4522..68d5a58cfe88 100644 +--- a/arch/arm/boot/dts/rk3288.dtsi ++++ b/arch/arm/boot/dts/rk3288.dtsi +@@ -616,7 +616,16 @@ usb_host0_ehci: usb@ff500000 { + status = "disabled"; + }; + +- /* NOTE: ohci@ff520000 doesn't actually work on hardware */ ++ /* NOTE: doesn't work on RK3288, but was fixed on RK3288W */ ++ usb_host0_ohci: usb@ff520000 { ++ compatible = "generic-ohci"; ++ reg = <0x0 0xff520000 0x0 0x100>; ++ interrupts = ; ++ clocks = <&cru HCLK_USBHOST0>; ++ phys = <&usbphy1>; ++ phy-names = "usb"; ++ status = "disabled"; ++ }; + + usb_host1: usb@ff540000 { + compatible = "rockchip,rk3288-usb", "rockchip,rk3066-usb", + +From cb343a78f51f82997bce9de813c1035f15010e38 Mon Sep 17 00:00:00 2001 +From: Jagan Teki +Date: Mon, 20 Jul 2020 16:32:28 +0530 +Subject: [PATCH] ARM: dts: rockchip: Add USB for RockPI N8/N10 + +Radxa dalang carrier board has 2x USB 2.0 and 1x USB 3.0 +ports. + +This patch adds support to enable all these USB ports for +N10 and N8 combinations SBCs. + +Note that the USB 3.0 port on RockPI N8 combination works +as USB 2.0 OTG since it is driven from RK3288. + +Signed-off-by: Jagan Teki +Link: https://lore.kernel.org/r/20200720110230.367985-1-jagan@amarulasolutions.com +Signed-off-by: Heiko Stuebner +(cherry picked from commit 417b188a985d3557b0ecb5623b27bd9843f03aec) +--- + arch/arm/boot/dts/rk3288-vmarc-som.dtsi | 42 ++++++++++ + .../dts/rockchip-radxa-dalang-carrier.dtsi | 18 +++++ + .../dts/rockchip/rk3399pro-vmarc-som.dtsi | 78 +++++++++++++++++++ + 3 files changed, 138 insertions(+) + +diff --git a/arch/arm/boot/dts/rk3288-vmarc-som.dtsi b/arch/arm/boot/dts/rk3288-vmarc-som.dtsi +index cd61b6230f0d..78164d117248 100644 +--- a/arch/arm/boot/dts/rk3288-vmarc-som.dtsi ++++ b/arch/arm/boot/dts/rk3288-vmarc-som.dtsi +@@ -267,4 +267,46 @@ sdmmc_cmd: sdmmc-cmd { + rockchip,pins = <6 RK_PC5 1 &pcfg_pull_up_drv_8ma>; + }; + }; ++ ++ vbus_host { ++ usb1_en_oc: usb1-en-oc { ++ rockchip,pins = <0 RK_PC1 RK_FUNC_GPIO &pcfg_pull_up>; ++ }; ++ }; ++ ++ vbus_typec { ++ usb0_en_oc: usb0-en-oc { ++ rockchip,pins = <0 RK_PB5 RK_FUNC_GPIO &pcfg_pull_up>; ++ }; ++ }; ++}; ++ ++&usbphy { ++ status = "okay"; ++}; ++ ++&usb_host0_ehci { ++ status = "okay"; ++}; ++ ++&usb_host0_ohci { ++ status = "okay"; ++}; ++ ++&usb_host1 { ++ status = "okay"; ++}; ++ ++&usb_otg { ++ status = "okay"; ++}; ++ ++&vbus_host { ++ enable-active-high; ++ gpio = <&gpio0 RK_PC1 GPIO_ACTIVE_HIGH>; /* USB1_EN_OC# */ ++}; ++ ++&vbus_typec { ++ enable-active-high; ++ gpio = <&gpio0 RK_PB5 GPIO_ACTIVE_HIGH>; /* USB0_EN_OC# */ + }; +diff --git a/arch/arm/boot/dts/rockchip-radxa-dalang-carrier.dtsi b/arch/arm/boot/dts/rockchip-radxa-dalang-carrier.dtsi +index 450e5bb5af0b..d2b6ead148a2 100644 +--- a/arch/arm/boot/dts/rockchip-radxa-dalang-carrier.dtsi ++++ b/arch/arm/boot/dts/rockchip-radxa-dalang-carrier.dtsi +@@ -33,6 +33,24 @@ vcc5v0_sys: vcc5v0-sys-regulator { + regulator-max-microvolt = <5000000>; + vin-supply = <&vcc12v_dcin>; + }; ++ ++ vbus_host: vbus-host { ++ compatible = "regulator-fixed"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&usb1_en_oc>; ++ regulator-name = "vbus_host"; /* HOST-5V */ ++ regulator-always-on; ++ vin-supply = <&vcc5v0_sys>; ++ }; ++ ++ vbus_typec: vbus-typec { ++ compatible = "regulator-fixed"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&usb0_en_oc>; ++ regulator-name = "vbus_typec"; ++ regulator-always-on; ++ vin-supply = <&vcc5v0_sys>; ++ }; + }; + + &gmac { +diff --git a/arch/arm64/boot/dts/rockchip/rk3399pro-vmarc-som.dtsi b/arch/arm64/boot/dts/rockchip/rk3399pro-vmarc-som.dtsi +index 37ed95d5f7e9..111d6cf9a4e6 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3399pro-vmarc-som.dtsi ++++ b/arch/arm64/boot/dts/rockchip/rk3399pro-vmarc-som.dtsi +@@ -304,6 +304,18 @@ pmic_int_l: pmic-int-l { + rockchip,pins = <1 RK_PC2 0 &pcfg_pull_up>; + }; + }; ++ ++ vbus_host { ++ usb1_en_oc: usb1-en-oc { ++ rockchip,pins = <4 RK_PD1 RK_FUNC_GPIO &pcfg_pull_up>; ++ }; ++ }; ++ ++ vbus_typec { ++ usb0_en_oc: usb0-en-oc { ++ rockchip,pins = <4 RK_PD2 RK_FUNC_GPIO &pcfg_pull_up>; ++ }; ++ }; + }; + + &pmu_io_domains { +@@ -324,8 +336,74 @@ &sdmmc { + max-frequency = <150000000>; + }; + ++&tcphy0 { ++ status = "okay"; ++}; ++ + &tsadc { + rockchip,hw-tshut-mode = <1>; + rockchip,hw-tshut-polarity = <1>; + status = "okay"; + }; ++ ++&u2phy0 { ++ status = "okay"; ++ ++ u2phy0_otg: otg-port { ++ phy-supply = <&vbus_typec>; ++ status = "okay"; ++ }; ++ ++ u2phy0_host: host-port { ++ phy-supply = <&vbus_host>; ++ status = "okay"; ++ }; ++}; ++ ++ ++&u2phy1 { ++ status = "okay"; ++ ++ u2phy1_host: host-port { ++ phy-supply = <&vbus_host>; ++ status = "okay"; ++ }; ++}; ++ ++&usb_host0_ehci { ++ status = "okay"; ++}; ++ ++&usb_host0_ohci { ++ status = "okay"; ++}; ++ ++&usb_host1_ehci { ++ status = "okay"; ++}; ++ ++&usb_host1_ohci { ++ status = "okay"; ++}; ++ ++&usbdrd3_0 { ++ status = "okay"; ++}; ++ ++&usbdrd_dwc3_0 { ++ status = "okay"; ++}; ++ ++&vbus_host { ++ enable-active-high; ++ gpio = <&gpio4 RK_PD1 GPIO_ACTIVE_HIGH>; /* USB1_EN_OC# */ ++ pinctrl-names = "default"; ++ pinctrl-0 = <&usb1_en_oc>; ++}; ++ ++&vbus_typec { ++ enable-active-high; ++ gpio = <&gpio4 RK_PD2 GPIO_ACTIVE_HIGH>; /* USB0_EN_OC# */ ++ pinctrl-names = "default"; ++ pinctrl-0 = <&usb0_en_oc>; ++}; + +From 3137628a7366f1fc30748b59254d6b25c2c86efd Mon Sep 17 00:00:00 2001 +From: Jagan Teki +Date: Mon, 20 Jul 2020 16:32:29 +0530 +Subject: [PATCH] ARM: dts: rockchip: Add HDMI out for RockPI N8/N10 + +This patch adds support to enable HDMI out for +N10 and N8 combinations SBCs. + +Signed-off-by: Jagan Teki +Signed-off-by: Suniel Mahesh +Link: https://lore.kernel.org/r/20200720110230.367985-2-jagan@amarulasolutions.com +Signed-off-by: Heiko Stuebner +(cherry picked from commit d0cb2f30e7c033f0a8bbe98ec73dbc1db4788942) +--- + arch/arm/boot/dts/rk3288-vmarc-som.dtsi | 10 ++++++++++ + .../dts/rockchip-radxa-dalang-carrier.dtsi | 20 +++++++++++++++++++ + .../dts/rockchip/rk3399pro-vmarc-som.dtsi | 12 +++++++++++ + 3 files changed, 42 insertions(+) + +diff --git a/arch/arm/boot/dts/rk3288-vmarc-som.dtsi b/arch/arm/boot/dts/rk3288-vmarc-som.dtsi +index 78164d117248..4a373f5aa600 100644 +--- a/arch/arm/boot/dts/rk3288-vmarc-som.dtsi ++++ b/arch/arm/boot/dts/rk3288-vmarc-som.dtsi +@@ -38,6 +38,12 @@ &gmac { + snps,reset-gpio = <&gpio4 RK_PA7 GPIO_ACTIVE_HIGH>; + }; + ++&hdmi { ++ ddc-i2c-bus = <&i2c5>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&hdmi_cec_c0>; ++}; ++ + &i2c0 { + clock-frequency = <400000>; + status = "okay"; +@@ -225,6 +231,10 @@ regulator-state-mem { + }; + }; + ++&i2c5 { ++ status = "okay"; ++}; ++ + &io_domains { + bb-supply = <&vcc_io>; + flash0-supply = <&vccio_flash>; +diff --git a/arch/arm/boot/dts/rockchip-radxa-dalang-carrier.dtsi b/arch/arm/boot/dts/rockchip-radxa-dalang-carrier.dtsi +index d2b6ead148a2..26b53eac4706 100644 +--- a/arch/arm/boot/dts/rockchip-radxa-dalang-carrier.dtsi ++++ b/arch/arm/boot/dts/rockchip-radxa-dalang-carrier.dtsi +@@ -66,6 +66,10 @@ &gmac { + status = "okay"; + }; + ++&hdmi { ++ status = "okay"; ++}; ++ + &pwm0 { + status = "okay"; + }; +@@ -94,3 +98,19 @@ &uart0 { + &uart2 { + status = "okay"; + }; ++ ++&vopb { ++ status = "okay"; ++}; ++ ++&vopb_mmu { ++ status = "okay"; ++}; ++ ++&vopl { ++ status = "okay"; ++}; ++ ++&vopl_mmu { ++ status = "okay"; ++}; +diff --git a/arch/arm64/boot/dts/rockchip/rk3399pro-vmarc-som.dtsi b/arch/arm64/boot/dts/rockchip/rk3399pro-vmarc-som.dtsi +index 111d6cf9a4e6..ebccc4a153a2 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3399pro-vmarc-som.dtsi ++++ b/arch/arm64/boot/dts/rockchip/rk3399pro-vmarc-som.dtsi +@@ -39,6 +39,12 @@ &gmac { + snps,reset-gpio = <&gpio3 RK_PB7 GPIO_ACTIVE_LOW>; + }; + ++&hdmi { ++ ddc-i2c-bus = <&i2c3>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&hdmi_cec>; ++}; ++ + &i2c0 { + clock-frequency = <400000>; + i2c-scl-falling-time-ns = <30>; +@@ -285,6 +291,12 @@ hym8563: hym8563@51 { + }; + }; + ++&i2c3 { ++ i2c-scl-rising-time-ns = <450>; ++ i2c-scl-falling-time-ns = <15>; ++ status = "okay"; ++}; ++ + &io_domains { + status = "okay"; + bt656-supply = <&vcca_1v8>; + +From 0d5ba09fbbd6b8a5d9fc7df9d3f760842549c07f Mon Sep 17 00:00:00 2001 +From: Jagan Teki +Date: Mon, 20 Jul 2020 16:32:30 +0530 +Subject: [PATCH] arm64: dts: rockchip: Add PCIe for RockPI N10 + +This patch adds support to enable PCIe for RockPI N10. + +Signed-off-by: Jagan Teki +Link: https://lore.kernel.org/r/20200720110230.367985-3-jagan@amarulasolutions.com +Signed-off-by: Heiko Stuebner +(cherry picked from commit 93ca8ac2e8fcea6feb02a40edd2334144b62fc6e) +--- + .../dts/rockchip/rk3399pro-vmarc-som.dtsi | 40 ++++++++++++++++++- + 1 file changed, 38 insertions(+), 2 deletions(-) + +diff --git a/arch/arm64/boot/dts/rockchip/rk3399pro-vmarc-som.dtsi b/arch/arm64/boot/dts/rockchip/rk3399pro-vmarc-som.dtsi +index ebccc4a153a2..5d087be04af8 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3399pro-vmarc-som.dtsi ++++ b/arch/arm64/boot/dts/rockchip/rk3399pro-vmarc-som.dtsi +@@ -11,6 +11,18 @@ + + / { + compatible = "vamrs,rk3399pro-vmarc-som", "rockchip,rk3399pro"; ++ ++ vcc3v3_pcie: vcc-pcie-regulator { ++ compatible = "regulator-fixed"; ++ enable-active-high; ++ gpio = <&gpio4 RK_PD4 GPIO_ACTIVE_HIGH>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pcie_pwr>; ++ regulator-name = "vcc3v3_pcie"; ++ regulator-always-on; ++ regulator-boot-on; ++ vin-supply = <&vcc5v0_sys>; ++ }; + }; + + &cpu_l0 { +@@ -142,7 +154,8 @@ vcca_0v9: LDO_REG1 { + regulator-min-microvolt = <900000>; + regulator-max-microvolt = <900000>; + regulator-state-mem { +- regulator-off-in-suspend; ++ regulator-on-in-suspend; ++ regulator-suspend-microvolt = <900000>; + }; + }; + +@@ -177,7 +190,8 @@ vcca_1v8: LDO_REG4 { + regulator-min-microvolt = <1850000>; + regulator-max-microvolt = <1850000>; + regulator-state-mem { +- regulator-off-in-suspend; ++ regulator-on-in-suspend; ++ regulator-suspend-microvolt = <1850000>; + }; + }; + +@@ -304,6 +318,22 @@ &io_domains { + sdmmc-supply = <&vccio_sd>; + }; + ++&pcie_phy { ++ status = "okay"; ++}; ++ ++&pcie0 { ++ ep-gpios = <&gpio0 RK_PB4 GPIO_ACTIVE_HIGH>; ++ max-link-speed = <2>; ++ num-lanes = <4>; ++ pinctrl-0 = <&pcie_clkreqnb_cpm>; ++ pinctrl-names = "default"; ++ vpcie0v9-supply = <&vcca_0v9>; /* VCC_0V9_S0 */ ++ vpcie1v8-supply = <&vcca_1v8>; /* VCC_1V8_S0 */ ++ vpcie3v3-supply = <&vcc3v3_pcie>; ++ status = "okay"; ++}; ++ + &pinctrl { + hym8563 { + hym8563_int: hym8563-int { +@@ -311,6 +341,12 @@ hym8563_int: hym8563-int { + }; + }; + ++ pcie { ++ pcie_pwr: pcie-pwr { ++ rockchip,pins = <4 RK_PD4 RK_FUNC_GPIO &pcfg_pull_up>; ++ }; ++ }; ++ + pmic { + pmic_int_l: pmic-int-l { + rockchip,pins = <1 RK_PC2 0 &pcfg_pull_up>; + +From ec258d2b9150088af58b6935bbf3c6c3618ea8f7 Mon Sep 17 00:00:00 2001 +From: Katsuhiro Suzuki +Date: Sat, 25 Jul 2020 00:59:33 +0900 +Subject: [PATCH] ASoC: convert Everest ES8316 binding to yaml + +This patch converts Everest Semiconductor ES8316 low power audio +CODEC binding to DT schema. + +Signed-off-by: Katsuhiro Suzuki +Reviewed-by: Rob Herring +Link: https://lore.kernel.org/r/20200724155933.1040501-1-katsuhiro@katsuster.net +Signed-off-by: Mark Brown +(cherry picked from commit 92e67a9c4f206dc9c859c405e67448a8be59ac5d) +--- + .../bindings/sound/everest,es8316.txt | 23 --------- + .../bindings/sound/everest,es8316.yaml | 50 +++++++++++++++++++ + 2 files changed, 50 insertions(+), 23 deletions(-) + delete mode 100644 Documentation/devicetree/bindings/sound/everest,es8316.txt + create mode 100644 Documentation/devicetree/bindings/sound/everest,es8316.yaml + +diff --git a/Documentation/devicetree/bindings/sound/everest,es8316.txt b/Documentation/devicetree/bindings/sound/everest,es8316.txt +deleted file mode 100644 +index 1bf03c5f2af4..000000000000 +--- a/Documentation/devicetree/bindings/sound/everest,es8316.txt ++++ /dev/null +@@ -1,23 +0,0 @@ +-Everest ES8316 audio CODEC +- +-This device supports both I2C and SPI. +- +-Required properties: +- +- - compatible : should be "everest,es8316" +- - reg : the I2C address of the device for I2C +- +-Optional properties: +- +- - clocks : a list of phandle, should contain entries for clock-names +- - clock-names : should include as follows: +- "mclk" : master clock (MCLK) of the device +- +-Example: +- +-es8316: codec@11 { +- compatible = "everest,es8316"; +- reg = <0x11>; +- clocks = <&clks 10>; +- clock-names = "mclk"; +-}; +diff --git a/Documentation/devicetree/bindings/sound/everest,es8316.yaml b/Documentation/devicetree/bindings/sound/everest,es8316.yaml +new file mode 100644 +index 000000000000..3b752bba748b +--- /dev/null ++++ b/Documentation/devicetree/bindings/sound/everest,es8316.yaml +@@ -0,0 +1,50 @@ ++# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/sound/everest,es8316.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: Everest ES8316 audio CODEC ++ ++maintainers: ++ - Daniel Drake ++ - Katsuhiro Suzuki ++ ++properties: ++ compatible: ++ const: everest,es8316 ++ ++ reg: ++ maxItems: 1 ++ ++ clocks: ++ items: ++ - description: clock for master clock (MCLK) ++ ++ clock-names: ++ items: ++ - const: mclk ++ ++ "#sound-dai-cells": ++ const: 0 ++ ++required: ++ - compatible ++ - reg ++ - "#sound-dai-cells" ++ ++additionalProperties: false ++ ++examples: ++ - | ++ i2c0 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ es8316: codec@11 { ++ compatible = "everest,es8316"; ++ reg = <0x11>; ++ clocks = <&clks 10>; ++ clock-names = "mclk"; ++ #sound-dai-cells = <0>; ++ }; ++ }; + +From f5b60a176251d6e0d1716bbe62a5697a80d38089 Mon Sep 17 00:00:00 2001 +From: Alper Nebi Yasak +Date: Tue, 21 Jul 2020 21:27:10 +0300 +Subject: [PATCH] ASoC: rk3399_gru_sound: Add DAPM pins, kcontrols for jack + detection + +PulseAudio (and perhaps other userspace utilities) can not detect any +jack for rk3399_gru_sound as the driver doesn't expose related Jack +kcontrols. + +This patch adds two DAPM pins to the headset jack, where the +snd_soc_card_jack_new() call automatically creates "Headphones Jack" and +"Headset Mic Jack" kcontrols from them. + +With an appropriate ALSA UCM config specifying JackControl fields for +the "Headphones" and "Headset" (mic) devices, PulseAudio can detect +plug/unplug events for both of them after this patch. + +Signed-off-by: Alper Nebi Yasak +Link: https://lore.kernel.org/r/20200721182709.6895-1-alpernebiyasak@gmail.com +Signed-off-by: Mark Brown +(cherry picked from commit d0508b4f16049a658d68a7c276ba08296c5a76bc) +--- + sound/soc/rockchip/rk3399_gru_sound.c | 17 ++++++++++++++++- + 1 file changed, 16 insertions(+), 1 deletion(-) + +diff --git a/sound/soc/rockchip/rk3399_gru_sound.c b/sound/soc/rockchip/rk3399_gru_sound.c +index 9539b0d024fe..3e45179638ca 100644 +--- a/sound/soc/rockchip/rk3399_gru_sound.c ++++ b/sound/soc/rockchip/rk3399_gru_sound.c +@@ -32,6 +32,19 @@ static unsigned int dmic_wakeup_delay; + + static struct snd_soc_jack rockchip_sound_jack; + ++/* Headset jack detection DAPM pins */ ++static struct snd_soc_jack_pin rockchip_sound_jack_pins[] = { ++ { ++ .pin = "Headphones", ++ .mask = SND_JACK_HEADPHONE, ++ }, ++ { ++ .pin = "Headset Mic", ++ .mask = SND_JACK_MICROPHONE, ++ }, ++ ++}; ++ + static const struct snd_soc_dapm_widget rockchip_dapm_widgets[] = { + SND_SOC_DAPM_HP("Headphones", NULL), + SND_SOC_DAPM_SPK("Speakers", NULL), +@@ -176,7 +189,9 @@ static int rockchip_sound_da7219_init(struct snd_soc_pcm_runtime *rtd) + SND_JACK_HEADSET | SND_JACK_LINEOUT | + SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3, +- &rockchip_sound_jack, NULL, 0); ++ &rockchip_sound_jack, ++ rockchip_sound_jack_pins, ++ ARRAY_SIZE(rockchip_sound_jack_pins)); + + if (ret) { + dev_err(rtd->card->dev, "New Headset Jack failed! (%d)\n", ret); diff --git a/patch/kernel/rk322x-dev/01-linux-0002-rockchip-from-next.patch b/patch/kernel/rk322x-dev/01-linux-0002-rockchip-from-next.patch new file mode 100644 index 000000000..a20e585c6 --- /dev/null +++ b/patch/kernel/rk322x-dev/01-linux-0002-rockchip-from-next.patch @@ -0,0 +1,434 @@ +From 9d29c5e2f20a44575a5a0e483319682d62daa4b3 Mon Sep 17 00:00:00 2001 +From: Heiko Stuebner +Date: Wed, 29 Jan 2020 17:38:19 +0100 +Subject: [PATCH] clk: rockchip: convert rk3399 pll type to use + readl_relaxed_poll_timeout + +Instead of open coding the polling of the lock status, use the handy +readl_relaxed_poll_timeout for this. As the pll locking is normally +blazingly fast and we don't want to incur additional delays, we're +not doing any sleeps similar to for example the imx clk-pllv4 +and define a very safe but still short timeout of 1ms. + +Suggested-by: Stephen Boyd +Signed-off-by: Heiko Stuebner +Reviewed-by: Stephen Boyd +Link: https://lore.kernel.org/r/20200129163821.1547295-1-heiko@sntech.de +(cherry picked from commit bf4237a188f872e535de8cbfc7903c1387b83b01) +--- + drivers/clk/rockchip/clk-pll.c | 23 ++++++++++++----------- + 1 file changed, 12 insertions(+), 11 deletions(-) + +diff --git a/drivers/clk/rockchip/clk-pll.c b/drivers/clk/rockchip/clk-pll.c +index 10560d963baf..28b04aad31ad 100644 +--- a/drivers/clk/rockchip/clk-pll.c ++++ b/drivers/clk/rockchip/clk-pll.c +@@ -589,19 +589,20 @@ static const struct clk_ops rockchip_rk3066_pll_clk_ops = { + static int rockchip_rk3399_pll_wait_lock(struct rockchip_clk_pll *pll) + { + u32 pllcon; +- int delay = 24000000; ++ int ret; + +- /* poll check the lock status in rk3399 xPLLCON2 */ +- while (delay > 0) { +- pllcon = readl_relaxed(pll->reg_base + RK3399_PLLCON(2)); +- if (pllcon & RK3399_PLLCON2_LOCK_STATUS) +- return 0; ++ /* ++ * Lock time typical 250, max 500 input clock cycles @24MHz ++ * So define a very safe maximum of 1000us, meaning 24000 cycles. ++ */ ++ ret = readl_relaxed_poll_timeout(pll->reg_base + RK3399_PLLCON(2), ++ pllcon, ++ pllcon & RK3399_PLLCON2_LOCK_STATUS, ++ 0, 1000); ++ if (ret) ++ pr_err("%s: timeout waiting for pll to lock\n", __func__); + +- delay--; +- } +- +- pr_err("%s: timeout waiting for pll to lock\n", __func__); +- return -ETIMEDOUT; ++ return ret; + } + + static void rockchip_rk3399_pll_get_params(struct rockchip_clk_pll *pll, + +From afe54d66a661ce9d99250431f1371e46f9b6d8a5 Mon Sep 17 00:00:00 2001 +From: Heiko Stuebner +Date: Wed, 29 Jan 2020 17:38:20 +0100 +Subject: [PATCH] clk: rockchip: convert basic pll lock_wait to use + regmap_read_poll_timeout + +Instead of open coding the polling of the lock status, use the +handy regmap_read_poll_timeout for this. As the pll locking is +normally blazingly fast and we don't want to incur additional +delays, we're not doing any sleeps similar to for example the imx +clk-pllv4 and define a very safe but still short timeout of 1ms. + +Suggested-by: Stephen Boyd +Signed-off-by: Heiko Stuebner +Reviewed-by: Stephen Boyd +Link: https://lore.kernel.org/r/20200129163821.1547295-2-heiko@sntech.de +(cherry picked from commit 3507df1a4615113ae6509e0f14f6546f0d1c84b4) +--- + drivers/clk/rockchip/clk-pll.c | 21 ++++++--------------- + 1 file changed, 6 insertions(+), 15 deletions(-) + +diff --git a/drivers/clk/rockchip/clk-pll.c b/drivers/clk/rockchip/clk-pll.c +index 28b04aad31ad..945f8b2cacc1 100644 +--- a/drivers/clk/rockchip/clk-pll.c ++++ b/drivers/clk/rockchip/clk-pll.c +@@ -86,23 +86,14 @@ static int rockchip_pll_wait_lock(struct rockchip_clk_pll *pll) + { + struct regmap *grf = pll->ctx->grf; + unsigned int val; +- int delay = 24000000, ret; +- +- while (delay > 0) { +- ret = regmap_read(grf, pll->lock_offset, &val); +- if (ret) { +- pr_err("%s: failed to read pll lock status: %d\n", +- __func__, ret); +- return ret; +- } ++ int ret; + +- if (val & BIT(pll->lock_shift)) +- return 0; +- delay--; +- } ++ ret = regmap_read_poll_timeout(grf, pll->lock_offset, val, ++ val & BIT(pll->lock_shift), 0, 1000); ++ if (ret) ++ pr_err("%s: timeout waiting for pll to lock\n", __func__); + +- pr_err("%s: timeout waiting for pll to lock\n", __func__); +- return -ETIMEDOUT; ++ return ret; + } + + /** + +From 9a37c781854b2cc475aced9045ba8c35b6838f3a Mon Sep 17 00:00:00 2001 +From: Heiko Stuebner +Date: Wed, 29 Jan 2020 17:38:21 +0100 +Subject: [PATCH] clk: rockchip: convert rk3036 pll type to use internal lock + status + +The rk3036 pll type exposes its lock status in both its pllcon registers +as well as the General Register Files. To remove one dependency convert +it to the "internal" lock status, similar to how rk3399 handles it. + +Signed-off-by: Heiko Stuebner +Reviewed-by: Stephen Boyd +Link: https://lore.kernel.org/r/20200129163821.1547295-3-heiko@sntech.de +(cherry picked from commit 7f6ffbb885d147557bdca471c37b7b1204005798) +--- + drivers/clk/rockchip/clk-pll.c | 26 +++++++++++++++++++++++--- + 1 file changed, 23 insertions(+), 3 deletions(-) + +diff --git a/drivers/clk/rockchip/clk-pll.c b/drivers/clk/rockchip/clk-pll.c +index 945f8b2cacc1..4c6c9167ef50 100644 +--- a/drivers/clk/rockchip/clk-pll.c ++++ b/drivers/clk/rockchip/clk-pll.c +@@ -12,6 +12,7 @@ + #include + #include + #include ++#include + #include + #include + #include "clk.h" +@@ -109,12 +110,31 @@ static int rockchip_pll_wait_lock(struct rockchip_clk_pll *pll) + #define RK3036_PLLCON1_REFDIV_SHIFT 0 + #define RK3036_PLLCON1_POSTDIV2_MASK 0x7 + #define RK3036_PLLCON1_POSTDIV2_SHIFT 6 ++#define RK3036_PLLCON1_LOCK_STATUS BIT(10) + #define RK3036_PLLCON1_DSMPD_MASK 0x1 + #define RK3036_PLLCON1_DSMPD_SHIFT 12 ++#define RK3036_PLLCON1_PWRDOWN BIT(13) + #define RK3036_PLLCON2_FRAC_MASK 0xffffff + #define RK3036_PLLCON2_FRAC_SHIFT 0 + +-#define RK3036_PLLCON1_PWRDOWN (1 << 13) ++static int rockchip_rk3036_pll_wait_lock(struct rockchip_clk_pll *pll) ++{ ++ u32 pllcon; ++ int ret; ++ ++ /* ++ * Lock time typical 250, max 500 input clock cycles @24MHz ++ * So define a very safe maximum of 1000us, meaning 24000 cycles. ++ */ ++ ret = readl_relaxed_poll_timeout(pll->reg_base + RK3036_PLLCON(1), ++ pllcon, ++ pllcon & RK3036_PLLCON1_LOCK_STATUS, ++ 0, 1000); ++ if (ret) ++ pr_err("%s: timeout waiting for pll to lock\n", __func__); ++ ++ return ret; ++} + + static void rockchip_rk3036_pll_get_params(struct rockchip_clk_pll *pll, + struct rockchip_pll_rate_table *rate) +@@ -212,7 +232,7 @@ static int rockchip_rk3036_pll_set_params(struct rockchip_clk_pll *pll, + writel_relaxed(pllcon, pll->reg_base + RK3036_PLLCON(2)); + + /* wait for the pll to lock */ +- ret = rockchip_pll_wait_lock(pll); ++ ret = rockchip_rk3036_pll_wait_lock(pll); + if (ret) { + pr_warn("%s: pll update unsuccessful, trying to restore old params\n", + __func__); +@@ -251,7 +271,7 @@ static int rockchip_rk3036_pll_enable(struct clk_hw *hw) + + writel(HIWORD_UPDATE(0, RK3036_PLLCON1_PWRDOWN, 0), + pll->reg_base + RK3036_PLLCON(1)); +- rockchip_pll_wait_lock(pll); ++ rockchip_rk3036_pll_wait_lock(pll); + + return 0; + } + +From 4e8605e139b42a4b239339fc54016ef2d0704908 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Myl=C3=A8ne=20Josserand?= +Date: Tue, 2 Jun 2020 10:06:43 +0200 +Subject: [PATCH] clk: rockchip: Handle clock tree for rk3288w variant +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The revision rk3288w has a different clock tree about "hclk_vio" +clock, according to the BSP kernel code. + +This patch handles this difference by detecting which device-tree +we are using. If it is a "rockchip,rk3288-cru", let's register +the clock tree as it was before. If the device-tree node is +"rockchip,rk3288w-cru", we will apply the difference with this +version of this SoC. + +Noticed that this new device-tree compatible must be handled in +bootloader such as u-boot. + +Signed-off-by: Mylène Josserand +Link: https://lore.kernel.org/r/20200602080644.11333-2-mylene.josserand@collabora.com +Signed-off-by: Heiko Stuebner +(cherry picked from commit 1627f683636df70fb25358b0a7b39a24e8fce5bf) +--- + drivers/clk/rockchip/clk-rk3288.c | 20 ++++++++++++++++++-- + 1 file changed, 18 insertions(+), 2 deletions(-) + +diff --git a/drivers/clk/rockchip/clk-rk3288.c b/drivers/clk/rockchip/clk-rk3288.c +index cc2a177bbdbf..204976e2d0cb 100644 +--- a/drivers/clk/rockchip/clk-rk3288.c ++++ b/drivers/clk/rockchip/clk-rk3288.c +@@ -425,8 +425,6 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = { + COMPOSITE(0, "aclk_vio0", mux_pll_src_cpll_gpll_usb480m_p, CLK_IGNORE_UNUSED, + RK3288_CLKSEL_CON(31), 6, 2, MFLAGS, 0, 5, DFLAGS, + RK3288_CLKGATE_CON(3), 0, GFLAGS), +- DIV(0, "hclk_vio", "aclk_vio0", 0, +- RK3288_CLKSEL_CON(28), 8, 5, DFLAGS), + COMPOSITE(0, "aclk_vio1", mux_pll_src_cpll_gpll_usb480m_p, CLK_IGNORE_UNUSED, + RK3288_CLKSEL_CON(31), 14, 2, MFLAGS, 8, 5, DFLAGS, + RK3288_CLKGATE_CON(3), 2, GFLAGS), +@@ -819,6 +817,16 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = { + INVERTER(0, "pclk_isp", "pclk_isp_in", RK3288_CLKSEL_CON(29), 3, IFLAGS), + }; + ++static struct rockchip_clk_branch rk3288w_hclkvio_branch[] __initdata = { ++ DIV(0, "hclk_vio", "aclk_vio1", 0, ++ RK3288_CLKSEL_CON(28), 8, 5, DFLAGS), ++}; ++ ++static struct rockchip_clk_branch rk3288_hclkvio_branch[] __initdata = { ++ DIV(0, "hclk_vio", "aclk_vio0", 0, ++ RK3288_CLKSEL_CON(28), 8, 5, DFLAGS), ++}; ++ + static const char *const rk3288_critical_clocks[] __initconst = { + "aclk_cpu", + "aclk_peri", +@@ -936,6 +944,14 @@ static void __init rk3288_clk_init(struct device_node *np) + RK3288_GRF_SOC_STATUS1); + rockchip_clk_register_branches(ctx, rk3288_clk_branches, + ARRAY_SIZE(rk3288_clk_branches)); ++ ++ if (of_device_is_compatible(np, "rockchip,rk3288w-cru")) ++ rockchip_clk_register_branches(ctx, rk3288w_hclkvio_branch, ++ ARRAY_SIZE(rk3288w_hclkvio_branch)); ++ else ++ rockchip_clk_register_branches(ctx, rk3288_hclkvio_branch, ++ ARRAY_SIZE(rk3288_hclkvio_branch)); ++ + rockchip_clk_protect_critical(rk3288_critical_clocks, + ARRAY_SIZE(rk3288_critical_clocks)); + + +From cac2ef41ac59ff839b73fea934e8ffd161d406f2 Mon Sep 17 00:00:00 2001 +From: Heiko Stuebner +Date: Fri, 3 Jul 2020 17:49:48 +0200 +Subject: [PATCH] clk: rockchip: use separate compatibles for rk3288w-cru + +Commit 1627f683636d ("clk: rockchip: Handle clock tree for rk3288w variant") +added the check for rk3288w-specific clock-tree changes but in turn would +require a double-compatible due to re-using the main rockchip,rk3288-cru +compatible as entry point. + +The binding change actually describes the compatibles as one or the other +so adapt the code accordingly and add a real second entry-point for the +clock controller. + +Signed-off-by: Heiko Stuebner +Reviewed-by: Ezequiel Garcia +Reviewed-by: Jagan Teki +Tested-by: Jagan Teki # rock-pi-n8 +Link: https://lore.kernel.org/r/20200703154948.260369-1-heiko@sntech.de +(cherry picked from commit 0a7f99aad259d223ce69c03e792c7e2bfcf8c2c6) +--- + drivers/clk/rockchip/clk-rk3288.c | 21 +++++++++++++++++++-- + 1 file changed, 19 insertions(+), 2 deletions(-) + +diff --git a/drivers/clk/rockchip/clk-rk3288.c b/drivers/clk/rockchip/clk-rk3288.c +index 204976e2d0cb..93c794695c46 100644 +--- a/drivers/clk/rockchip/clk-rk3288.c ++++ b/drivers/clk/rockchip/clk-rk3288.c +@@ -15,6 +15,11 @@ + #define RK3288_GRF_SOC_CON(x) (0x244 + x * 4) + #define RK3288_GRF_SOC_STATUS1 0x284 + ++enum rk3288_variant { ++ RK3288_CRU, ++ RK3288W_CRU, ++}; ++ + enum rk3288_plls { + apll, dpll, cpll, gpll, npll, + }; +@@ -922,7 +927,8 @@ static struct syscore_ops rk3288_clk_syscore_ops = { + .resume = rk3288_clk_resume, + }; + +-static void __init rk3288_clk_init(struct device_node *np) ++static void __init rk3288_common_init(struct device_node *np, ++ enum rk3288_variant soc) + { + struct rockchip_clk_provider *ctx; + +@@ -945,7 +951,7 @@ static void __init rk3288_clk_init(struct device_node *np) + rockchip_clk_register_branches(ctx, rk3288_clk_branches, + ARRAY_SIZE(rk3288_clk_branches)); + +- if (of_device_is_compatible(np, "rockchip,rk3288w-cru")) ++ if (soc == RK3288W_CRU) + rockchip_clk_register_branches(ctx, rk3288w_hclkvio_branch, + ARRAY_SIZE(rk3288w_hclkvio_branch)); + else +@@ -970,4 +976,15 @@ static void __init rk3288_clk_init(struct device_node *np) + + rockchip_clk_of_add_provider(np, ctx); + } ++ ++static void __init rk3288_clk_init(struct device_node *np) ++{ ++ rk3288_common_init(np, RK3288_CRU); ++} + CLK_OF_DECLARE(rk3288_cru, "rockchip,rk3288-cru", rk3288_clk_init); ++ ++static void __init rk3288w_clk_init(struct device_node *np) ++{ ++ rk3288_common_init(np, RK3288W_CRU); ++} ++CLK_OF_DECLARE(rk3288w_cru, "rockchip,rk3288w-cru", rk3288w_clk_init); + +From b80ef30ce22bba6a4bdf9f0aaa9376b6fea24249 Mon Sep 17 00:00:00 2001 +From: Robin Murphy +Date: Thu, 18 Jun 2020 18:56:29 +0100 +Subject: [PATCH] clk: rockchip: Revert "fix wrong mmc sample phase shift for + rk3328" + +This reverts commit 82f4b67f018c88a7cc9337f0067ed3d6ec352648. + +According to a subsequent revert in the vendor kernel, the original +change was based on unclear documentation and was in fact incorrect. + +Emprically, my board's HS200 eMMC at 200MHZ apparently gets lucky with a +phase where this had no impact, but limiting max-frequency to 150MHz to +match the nominal capability of the I/O pins made it virtually unusable, +constantly throwing errors and retuning. With this revert, it starts +behaving perfectly at 150MHz too. + +Fixes: 82f4b67f018c ("clk: rockchip: fix wrong mmc sample phase shift for rk3328") +Signed-off-by: Robin Murphy +Reviewed-by: Shawn Lin +Link: https://lore.kernel.org/r/c80eb52e34c03f817586b6b7912fbd4e31be9079.1589475794.git.robin.murphy@arm.com +Signed-off-by: Heiko Stuebner +(cherry picked from commit 465931e70881476a210d44705102ef8b6ee6cdb0) +--- + drivers/clk/rockchip/clk-rk3328.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/clk/rockchip/clk-rk3328.c b/drivers/clk/rockchip/clk-rk3328.c +index c186a1985bf4..2429b7c2a8b3 100644 +--- a/drivers/clk/rockchip/clk-rk3328.c ++++ b/drivers/clk/rockchip/clk-rk3328.c +@@ -808,22 +808,22 @@ static struct rockchip_clk_branch rk3328_clk_branches[] __initdata = { + MMC(SCLK_SDMMC_DRV, "sdmmc_drv", "clk_sdmmc", + RK3328_SDMMC_CON0, 1), + MMC(SCLK_SDMMC_SAMPLE, "sdmmc_sample", "clk_sdmmc", +- RK3328_SDMMC_CON1, 0), ++ RK3328_SDMMC_CON1, 1), + + MMC(SCLK_SDIO_DRV, "sdio_drv", "clk_sdio", + RK3328_SDIO_CON0, 1), + MMC(SCLK_SDIO_SAMPLE, "sdio_sample", "clk_sdio", +- RK3328_SDIO_CON1, 0), ++ RK3328_SDIO_CON1, 1), + + MMC(SCLK_EMMC_DRV, "emmc_drv", "clk_emmc", + RK3328_EMMC_CON0, 1), + MMC(SCLK_EMMC_SAMPLE, "emmc_sample", "clk_emmc", +- RK3328_EMMC_CON1, 0), ++ RK3328_EMMC_CON1, 1), + + MMC(SCLK_SDMMC_EXT_DRV, "sdmmc_ext_drv", "clk_sdmmc_ext", + RK3328_SDMMC_EXT_CON0, 1), + MMC(SCLK_SDMMC_EXT_SAMPLE, "sdmmc_ext_sample", "clk_sdmmc_ext", +- RK3328_SDMMC_EXT_CON1, 0), ++ RK3328_SDMMC_EXT_CON1, 1), + }; + + static const char *const rk3328_critical_clocks[] __initconst = { + +From 21710a18bfba0cf0993a1ef700f03f540d2648ed Mon Sep 17 00:00:00 2001 +From: Alex Bee +Date: Wed, 22 Jul 2020 18:18:20 +0200 +Subject: [PATCH] clk: rockchip: add sclk_mac_lbtest to rk3188_critical_clocks + +Since the loopbacktest clock is not exported and is not touched in the +driver, it has to be added to rk3188_critical_clocks to be protected from +being disabled and in order to get the emac working. + +Signed-off-by: Alex Bee +Link: https://lore.kernel.org/r/20200722161820.5316-1-knaerzche@gmail.com +Signed-off-by: Heiko Stuebner +(cherry picked from commit ef990bcad58cf1d13c5a49191a2c2342eb8d6709) +--- + drivers/clk/rockchip/clk-rk3188.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/clk/rockchip/clk-rk3188.c b/drivers/clk/rockchip/clk-rk3188.c +index 77aebfb1d6d5..730020fcc7fe 100644 +--- a/drivers/clk/rockchip/clk-rk3188.c ++++ b/drivers/clk/rockchip/clk-rk3188.c +@@ -751,6 +751,7 @@ static const char *const rk3188_critical_clocks[] __initconst = { + "pclk_peri", + "hclk_cpubus", + "hclk_vio_bus", ++ "sclk_mac_lbtest", + }; + + static struct rockchip_clk_provider *__init rk3188_common_clk_init(struct device_node *np) diff --git a/patch/kernel/rk322x-dev/01-linux-0003-rockchip-fromlist.patch b/patch/kernel/rk322x-dev/01-linux-0003-rockchip-fromlist.patch new file mode 100644 index 000000000..1495e0bfe --- /dev/null +++ b/patch/kernel/rk322x-dev/01-linux-0003-rockchip-fromlist.patch @@ -0,0 +1,1956 @@ +From 01b6923a7d4b84609809a0695e58aeb7bd1376f1 Mon Sep 17 00:00:00 2001 +From: Yifeng Zhao +Date: Fri, 17 Jul 2020 17:24:17 +0800 +Subject: [PATCH] dt-bindings: mtd: Describe Rockchip RK3xxx NAND flash + controller + +Documentation support for Rockchip RK3xxx NAND flash controllers + +Signed-off-by: Yifeng Zhao +Reviewed-by: Rob Herring +--- + .../mtd/rockchip,nand-controller.yaml | 162 ++++++++++++++++++ + 1 file changed, 162 insertions(+) + create mode 100644 Documentation/devicetree/bindings/mtd/rockchip,nand-controller.yaml + +diff --git a/Documentation/devicetree/bindings/mtd/rockchip,nand-controller.yaml b/Documentation/devicetree/bindings/mtd/rockchip,nand-controller.yaml +new file mode 100644 +index 000000000000..b9d7a8c79402 +--- /dev/null ++++ b/Documentation/devicetree/bindings/mtd/rockchip,nand-controller.yaml +@@ -0,0 +1,162 @@ ++# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/mtd/rockchip,nand-controller.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: Rockchip SoCs NAND FLASH Controller (NFC) ++ ++allOf: ++ - $ref: "nand-controller.yaml#" ++ ++maintainers: ++ - Heiko Stuebner ++ ++properties: ++ compatible: ++ oneOf: ++ - const: rockchip,px30-nfc ++ - const: rockchip,rk2928-nfc ++ - const: rockchip,rv1108-nfc ++ - items: ++ - const: rockchip,rk3036-nfc ++ - const: rockchip,rk2928-nfc ++ - items: ++ - const: rockchip,rk3308-nfc ++ - const: rockchip,rv1108-nfc ++ ++ reg: ++ maxItems: 1 ++ ++ interrupts: ++ maxItems: 1 ++ ++ clocks: ++ minItems: 1 ++ items: ++ - description: Bus Clock ++ - description: Module Clock ++ ++ clock-names: ++ minItems: 1 ++ items: ++ - const: ahb ++ - const: nfc ++ ++ assigned-clocks: ++ maxItems: 1 ++ ++ assigned-clock-rates: ++ maxItems: 1 ++ ++ power-domains: ++ maxItems: 1 ++ ++patternProperties: ++ "^nand@[0-7]$": ++ type: object ++ properties: ++ reg: ++ minimum: 0 ++ maximum: 7 ++ ++ nand-ecc-mode: ++ const: hw ++ ++ nand-ecc-step-size: ++ const: 1024 ++ ++ nand-ecc-strength: ++ enum: [16, 24, 40, 60, 70] ++ description: ++ The ECC configurations that can be supported are as follows. ++ NFC v600 ECC 16, 24, 40, 60 ++ RK2928, RK3066, RK3188 ++ ++ NFC v622 ECC 16, 24, 40, 60 ++ RK3036, RK3128 ++ ++ NFC v800 ECC 16 ++ RK3308, RV1108 ++ ++ NFC v900 ECC 16, 40, 60, 70 ++ RK3326, PX30 ++ ++ nand-bus-width: ++ const: 8 ++ ++ rockchip,boot-blks: ++ minimum: 2 ++ default: 16 ++ allOf: ++ - $ref: /schemas/types.yaml#/definitions/uint32 ++ description: ++ The NFC driver need this information to select ECC ++ algorithms supported by the boot ROM. ++ Only used in combination with 'nand-is-boot-medium'. ++ ++ rockchip,boot-ecc-strength: ++ enum: [16, 24, 40, 60, 70] ++ allOf: ++ - $ref: /schemas/types.yaml#/definitions/uint32 ++ description: ++ If specified it indicates that a different BCH/ECC setting is ++ supported by the boot ROM. ++ NFC v600 ECC 16, 24 ++ RK2928, RK3066, RK3188 ++ ++ NFC v622 ECC 16, 24, 40, 60 ++ RK3036, RK3128 ++ ++ NFC v800 ECC 16 ++ RK3308, RV1108 ++ ++ NFC v900 ECC 16, 70 ++ RK3326, PX30 ++ ++ Only used in combination with 'nand-is-boot-medium'. ++ ++required: ++ - compatible ++ - reg ++ - interrupts ++ - clocks ++ - clock-names ++ ++unevaluatedProperties: false ++ ++examples: ++ - | ++ #include ++ #include ++ nfc: nand-controller@ff4b0000 { ++ compatible = "rockchip,rk3308-nfc", ++ "rockchip,rv1108-nfc"; ++ reg = <0xff4b0000 0x4000>; ++ interrupts = ; ++ clocks = <&cru HCLK_NANDC>, <&cru SCLK_NANDC>; ++ clock-names = "ahb", "nfc"; ++ assigned-clocks = <&clks SCLK_NANDC>; ++ assigned-clock-rates = <150000000>; ++ ++ pinctrl-0 = <&flash_ale &flash_bus8 &flash_cle &flash_csn0 ++ &flash_rdn &flash_rdy &flash_wrn>; ++ pinctrl-names = "default"; ++ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ nand@0 { ++ reg = <0>; ++ label = "rk-nand"; ++ nand-bus-width = <8>; ++ nand-ecc-mode = "hw"; ++ nand-ecc-step-size = <1024>; ++ nand-ecc-strength = <16>; ++ nand-is-boot-medium; ++ rockchip,boot-blks = <8>; ++ rockchip,boot-ecc-strength = <16>; ++ }; ++ }; ++ ++... + +From 8d00c3eb36f8fbccc159d6456bfd418a2841acff Mon Sep 17 00:00:00 2001 +From: Yifeng Zhao +Date: Fri, 17 Jul 2020 17:24:18 +0800 +Subject: [PATCH] mtd: rawnand: rockchip: NFC drivers for RK3308, RK2928 and + others + +This driver supports Rockchip NFC (NAND Flash Controller) found on RK3308, +RK2928, RKPX30, RV1108 and other SOCs. The driver has been tested using +8-bit NAND interface on the ARM based RK3308 platform. + +Support Rockchip SoCs and NFC versions: +- PX30 and RK3326(NFCv900). + ECC: 16/40/60/70 bits/1KB. + CLOCK: ahb and nfc. +- RK3308 and RV1108(NFCv800). + ECC: 16 bits/1KB. + CLOCK: ahb and nfc. +- RK3036 and RK3128(NFCv622). + ECC: 16/24/40/60 bits/1KB. + CLOCK: ahb and nfc. +- RK3066, RK3188 and RK2928(NFCv600). + ECC: 16/24/40/60 bits/1KB. + CLOCK: ahb. + +Supported features: +- Read full page data by DMA. +- Support HW ECC(one step is 1KB). +- Support 2 - 32K page size. +- Support 8 CS(depend on SoCs) + +Limitations: +- No support for the ecc step size is 512. +- Untested on some SoCs. +- No support for subpages. +- No support for the builtin randomizer. +- The original bad block mask is not supported. It is recommended to use + the BBT(bad block table). + +Signed-off-by: Yifeng Zhao +--- + drivers/mtd/nand/raw/Kconfig | 12 + + drivers/mtd/nand/raw/Makefile | 1 + + .../mtd/nand/raw/rockchip-nand-controller.c | 1422 +++++++++++++++++ + 3 files changed, 1435 insertions(+) + create mode 100644 drivers/mtd/nand/raw/rockchip-nand-controller.c + +diff --git a/drivers/mtd/nand/raw/Kconfig b/drivers/mtd/nand/raw/Kconfig +index 113f61052269..6492855d4a55 100644 +--- a/drivers/mtd/nand/raw/Kconfig ++++ b/drivers/mtd/nand/raw/Kconfig +@@ -461,6 +461,18 @@ config MTD_NAND_ARASAN + Enables the driver for the Arasan NAND flash controller on + Zynq Ultrascale+ MPSoC. + ++config MTD_NAND_ROCKCHIP ++ tristate "Rockchip NAND controller" ++ depends on ARCH_ROCKCHIP && HAS_IOMEM ++ help ++ Enables support for NAND controller on Rockchip SoCs. ++ There are four different versions of NAND FLASH Controllers, ++ including: ++ NFC v600: RK2928, RK3066, RK3188 ++ NFC v622: RK3036, RK3128 ++ NFC v800: RK3308, RV1108 ++ NFC v900: PX30, RK3326 ++ + comment "Misc" + + config MTD_SM_COMMON +diff --git a/drivers/mtd/nand/raw/Makefile b/drivers/mtd/nand/raw/Makefile +index 2930f5b9015d..960c9be25204 100644 +--- a/drivers/mtd/nand/raw/Makefile ++++ b/drivers/mtd/nand/raw/Makefile +@@ -58,6 +58,7 @@ obj-$(CONFIG_MTD_NAND_STM32_FMC2) += stm32_fmc2_nand.o + obj-$(CONFIG_MTD_NAND_MESON) += meson_nand.o + obj-$(CONFIG_MTD_NAND_CADENCE) += cadence-nand-controller.o + obj-$(CONFIG_MTD_NAND_ARASAN) += arasan-nand-controller.o ++obj-$(CONFIG_MTD_NAND_ROCKCHIP) += rockchip-nand-controller.o + + nand-objs := nand_base.o nand_legacy.o nand_bbt.o nand_timings.o nand_ids.o + nand-objs += nand_onfi.o +diff --git a/drivers/mtd/nand/raw/rockchip-nand-controller.c b/drivers/mtd/nand/raw/rockchip-nand-controller.c +new file mode 100644 +index 000000000000..fec1360603e0 +--- /dev/null ++++ b/drivers/mtd/nand/raw/rockchip-nand-controller.c +@@ -0,0 +1,1422 @@ ++// SPDX-License-Identifier: GPL-2.0 OR MIT ++/* ++ * Rockchip NAND Flash controller driver. ++ * Copyright (C) 2020 Rockchip Inc. ++ * Author: Yifeng Zhao ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* ++ * NFC Page Data Layout: ++ * 1024 Bytes Data + 4Bytes sys data + 28Bytes~124Bytes ecc + ++ * 1024 Bytes Data + 4Bytes sys data + 28Bytes~124Bytes ecc + ++ * ...... ++ * NAND Page Data Layout: ++ * 1024 * n Data + m Bytes oob ++ * Original Bad Block Mask Location: ++ * First byte of oob(spare). ++ * nand_chip->oob_poi data layout: ++ * 4Bytes sys data + .... + 4Bytes sys data + ecc data. ++ */ ++ ++/* NAND controller register definition */ ++#define NFC_READ (0) ++#define NFC_WRITE (1) ++#define NFC_FMCTL (0x00) ++#define FMCTL_CE_SEL_M 0xFF ++#define FMCTL_CE_SEL(x) (1 << (x)) ++#define FMCTL_WP BIT(8) ++#define FMCTL_RDY BIT(9) ++#define NFC_FMWAIT (0x04) ++#define FLCTL_RST BIT(0) ++#define FLCTL_WR (1) /* 0: read, 1: write */ ++#define FLCTL_XFER_ST BIT(2) ++#define FLCTL_XFER_EN BIT(3) ++#define FLCTL_ACORRECT BIT(10) /* Auto correct error bits. */ ++#define FLCTL_XFER_READY BIT(20) ++#define FLCTL_XFER_SECTOR (22) ++#define FLCTL_TOG_FIX BIT(29) ++#define BCHCTL_BANK_M (7 << 5) ++#define BCHCTL_BANK (5) ++#define DMA_ST BIT(0) ++#define DMA_WR (1) /* 0: write, 1: read */ ++#define DMA_EN BIT(2) ++#define DMA_AHB_SIZE (3) /* 0: 1, 1: 2, 2: 4 */ ++#define DMA_BURST_SIZE (6) /* 0: 1, 3: 4, 5: 8, 7: 16 */ ++#define DMA_INC_NUM (9) /* 1 - 16 */ ++#define ECC_ERR_CNT(x, e) ((((x) >> (e).low) & (e).low_mask) \ ++ | (((x) >> (e).high) & (e).high_mask) << (e).low_bn) ++#define INT_DMA BIT(0) ++#define NFC_BANK (0x800) ++#define NFC_BANK_STEP (0x100) ++#define BANK_DATA (0x00) ++#define BANK_ADDR (0x04) ++#define BANK_CMD (0x08) ++#define NFC_SRAM0 (0x1000) ++#define NFC_SRAM1 (0x1400) ++#define NFC_SRAM_SIZE (0x400) ++#define NFC_TIMEOUT (500000) ++#define NFC_MAX_OOB_PER_STEP 128 ++#define NFC_MIN_OOB_PER_STEP 64 ++#define MAX_DATA_SIZE 0xFFFC ++#define MAX_ADDRESS_CYC 6 ++#define NFC_ECC_MAX_MODES 4 ++#define NFC_MAX_NSELS (8) /* Some Socs only have 1 or 2 CSs. */ ++#define NFC_SYS_DATA_SIZE (4) /* 4 bytes sys data in oob pre 1024 data.*/ ++#define RK_DEFAULT_CLOCK_RATE (150 * 1000 * 1000) /* 150 Mhz */ ++#define ACCTIMING(csrw, rwpw, rwcs) ((csrw) << 12 | (rwpw) << 5 | (rwcs)) ++ ++enum nfc_type { ++ NFC_V6, ++ NFC_V8, ++ NFC_V9, ++}; ++ ++/** ++ * struct rk_ecc_cnt_status: represent a ecc status data. ++ * @err_flag_bit: error flag bit index at register. ++ * @low: ecc count low bit index at register. ++ * @low_mask: mask bit. ++ * @low_bn: ecc count low bit number. ++ * @high: ecc count high bit index at register. ++ * @high_mask: mask bit ++ */ ++struct ecc_cnt_status { ++ u8 err_flag_bit; ++ u8 low; ++ u8 low_mask; ++ u8 low_bn; ++ u8 high; ++ u8 high_mask; ++}; ++ ++/* ++ * @type: nfc version ++ * @ecc_strengths: ecc strengths ++ * @ecc_cfgs: ecc config values ++ * @flctl_off: FLCTL register offset ++ * @bchctl_off: BCHCTL register offset ++ * @dma_data_buf_off: DMA_DATA_BUF register offset ++ * @dma_oob_buf_off: DMA_OOB_BUF register offset ++ * @dma_cfg_off: DMA_CFG register offset ++ * @dma_st_off: DMA_ST register offset ++ * @bch_st_off: BCG_ST register offset ++ * @randmz_off: RANDMZ register offset ++ * @int_en_off: interrupt enable register offset ++ * @int_clr_off: interrupt clean register offset ++ * @int_st_off: interrupt status register offset ++ * @oob0_off: oob0 register offset ++ * @oob1_off: oob1 register offset ++ * @ecc0: represent ECC0 status data ++ * @ecc1: represent ECC1 status data ++ */ ++struct nfc_cfg { ++ enum nfc_type type; ++ u8 ecc_strengths[NFC_ECC_MAX_MODES]; ++ u32 ecc_cfgs[NFC_ECC_MAX_MODES]; ++ u32 flctl_off; ++ u32 bchctl_off; ++ u32 dma_cfg_off; ++ u32 dma_data_buf_off; ++ u32 dma_oob_buf_off; ++ u32 dma_st_off; ++ u32 bch_st_off; ++ u32 randmz_off; ++ u32 int_en_off; ++ u32 int_clr_off; ++ u32 int_st_off; ++ u32 oob0_off; ++ u32 oob1_off; ++ struct ecc_cnt_status ecc0; ++ struct ecc_cnt_status ecc1; ++}; ++ ++struct rk_nfc_nand_chip { ++ struct list_head node; ++ struct nand_chip chip; ++ ++ u16 spare_per_sector; ++ u16 oob_buf_per_sector; ++ u16 boot_blks; ++ u16 boot_ecc; ++ u16 metadata_size; ++ ++ u8 nsels; ++ u8 sels[0]; ++ /* Nothing after this field. */ ++}; ++ ++struct rk_nfc_clk { ++ int nfc_rate; ++ struct clk *nfc_clk; ++ struct clk *ahb_clk; ++}; ++ ++struct rk_nfc { ++ struct nand_controller controller; ++ struct rk_nfc_clk clk; ++ ++ struct device *dev; ++ const struct nfc_cfg *cfg; ++ void __iomem *regs; ++ ++ int selected_bank; ++ int band_offset; ++ ++ struct completion done; ++ struct list_head chips; ++ ++ u8 *buffer; ++ u8 *page_buf; ++ u32 *oob_buf; ++ ++ unsigned long assigned_cs; ++}; ++ ++static inline struct rk_nfc_nand_chip *to_rknand(struct nand_chip *chip) ++{ ++ return container_of(chip, struct rk_nfc_nand_chip, chip); ++} ++ ++static inline u8 *data_ptr(struct nand_chip *chip, const u8 *p, int i) ++{ ++ return (u8 *)p + i * chip->ecc.size; ++} ++ ++static inline u8 *oob_ptr(struct nand_chip *chip, int i) ++{ ++ u8 *poi; ++ ++ poi = chip->oob_poi + i * NFC_SYS_DATA_SIZE; ++ ++ return poi; ++} ++ ++static inline u8 *oob_ecc_ptr(struct nand_chip *chip, int i) ++{ ++ struct rk_nfc_nand_chip *rknand = to_rknand(chip); ++ u8 *poi; ++ ++ poi = chip->oob_poi + rknand->metadata_size + ++ chip->ecc.bytes * i; ++ ++ return poi; ++} ++ ++static inline int rk_data_len(struct nand_chip *chip) ++{ ++ struct rk_nfc_nand_chip *rknand = to_rknand(chip); ++ ++ return chip->ecc.size + rknand->spare_per_sector; ++} ++ ++static inline u8 *rk_data_ptr(struct nand_chip *chip, int i) ++{ ++ struct rk_nfc *nfc = nand_get_controller_data(chip); ++ ++ return nfc->buffer + i * rk_data_len(chip); ++} ++ ++static inline u8 *rk_oob_ptr(struct nand_chip *chip, int i) ++{ ++ struct rk_nfc *nfc = nand_get_controller_data(chip); ++ ++ return nfc->buffer + i * rk_data_len(chip) + chip->ecc.size; ++} ++ ++static void rk_nfc_select_chip(struct nand_chip *chip, int cs) ++{ ++ struct rk_nfc *nfc = nand_get_controller_data(chip); ++ struct rk_nfc_nand_chip *rknand = to_rknand(chip); ++ u32 val; ++ ++ if (cs < 0) { ++ nfc->selected_bank = -1; ++ /* Deselect the currently selected target. */ ++ val = readl_relaxed(nfc->regs + NFC_FMCTL); ++ val &= ~FMCTL_CE_SEL_M; ++ writel(val, nfc->regs + NFC_FMCTL); ++ return; ++ } ++ ++ nfc->selected_bank = rknand->sels[cs]; ++ nfc->band_offset = NFC_BANK + nfc->selected_bank * NFC_BANK_STEP; ++ ++ val = readl_relaxed(nfc->regs + NFC_FMCTL); ++ val &= ~FMCTL_CE_SEL_M; ++ val |= FMCTL_CE_SEL(nfc->selected_bank); ++ ++ writel(val, nfc->regs + NFC_FMCTL); ++} ++ ++static inline int rk_nfc_wait_ioready(struct rk_nfc *nfc) ++{ ++ int rc; ++ u32 val; ++ ++ rc = readl_poll_timeout_atomic(nfc->regs + NFC_FMCTL, val, ++ val & FMCTL_RDY, 10, NFC_TIMEOUT); ++ ++ return rc; ++} ++ ++static inline u8 rk_nfc_read_byte(struct nand_chip *chip) ++{ ++ struct rk_nfc *nfc = nand_get_controller_data(chip); ++ ++ return readb_relaxed(nfc->regs + nfc->band_offset + BANK_DATA); ++} ++ ++static void rk_nfc_read_buf(struct nand_chip *chip, u8 *buf, int len) ++{ ++ int i; ++ ++ for (i = 0; i < len; i++) ++ buf[i] = rk_nfc_read_byte(chip); ++} ++ ++static void rk_nfc_write_byte(struct nand_chip *chip, u8 byte) ++{ ++ struct rk_nfc *nfc = nand_get_controller_data(chip); ++ ++ writeb(byte, nfc->regs + nfc->band_offset + BANK_DATA); ++} ++ ++static void rk_nfc_write_buf(struct nand_chip *chip, const u8 *buf, int len) ++{ ++ int i; ++ ++ for (i = 0; i < len; i++) ++ rk_nfc_write_byte(chip, buf[i]); ++} ++ ++static int rk_nfc_cmd(struct nand_chip *chip, ++ const struct nand_subop *subop) ++{ ++ struct rk_nfc *nfc = nand_get_controller_data(chip); ++ unsigned int i, j, remaining, start; ++ int reg_offset = nfc->band_offset; ++ void __iomem *data_reg; ++ u8 *inbuf = NULL; ++ const u8 *outbuf; ++ u32 cnt = 0; ++ int ret = 0; ++ ++ for (i = 0; i < subop->ninstrs; i++) { ++ const struct nand_op_instr *instr = &subop->instrs[i]; ++ ++ switch (instr->type) { ++ case NAND_OP_CMD_INSTR: ++ writeb(instr->ctx.cmd.opcode, ++ nfc->regs + reg_offset + BANK_CMD); ++ break; ++ ++ case NAND_OP_ADDR_INSTR: ++ remaining = nand_subop_get_num_addr_cyc(subop, i); ++ start = nand_subop_get_addr_start_off(subop, i); ++ ++ for (j = 0; j < 8 && j + start < remaining; j++) ++ writeb(instr->ctx.addr.addrs[j + start], ++ nfc->regs + reg_offset + BANK_ADDR); ++ break; ++ ++ case NAND_OP_DATA_IN_INSTR: ++ case NAND_OP_DATA_OUT_INSTR: ++ start = nand_subop_get_data_start_off(subop, i); ++ cnt = nand_subop_get_data_len(subop, i); ++ data_reg = nfc->regs + nfc->band_offset + BANK_DATA; ++ ++ if (instr->type == NAND_OP_DATA_OUT_INSTR) { ++ outbuf = instr->ctx.data.buf.out + start; ++ for (j = 0; j < cnt; j++) ++ writeb(outbuf[j], data_reg); ++ } else { ++ inbuf = instr->ctx.data.buf.in + start; ++ for (j = 0; j < cnt; j++) ++ inbuf[j] = readb_relaxed(data_reg); ++ } ++ break; ++ ++ case NAND_OP_WAITRDY_INSTR: ++ if (rk_nfc_wait_ioready(nfc) < 0) { ++ ret = -ETIMEDOUT; ++ dev_err(nfc->dev, "IO not ready\n"); ++ } ++ break; ++ } ++ } ++ ++ return ret; ++} ++ ++static const struct nand_op_parser rk_nfc_op_parser = NAND_OP_PARSER( ++ NAND_OP_PARSER_PATTERN( ++ rk_nfc_cmd, ++ NAND_OP_PARSER_PAT_CMD_ELEM(true), ++ NAND_OP_PARSER_PAT_ADDR_ELEM(true, MAX_ADDRESS_CYC), ++ NAND_OP_PARSER_PAT_CMD_ELEM(true), ++ NAND_OP_PARSER_PAT_WAITRDY_ELEM(true), ++ NAND_OP_PARSER_PAT_DATA_IN_ELEM(true, MAX_DATA_SIZE)), ++ NAND_OP_PARSER_PATTERN( ++ rk_nfc_cmd, ++ NAND_OP_PARSER_PAT_CMD_ELEM(true), ++ NAND_OP_PARSER_PAT_ADDR_ELEM(true, MAX_ADDRESS_CYC), ++ NAND_OP_PARSER_PAT_DATA_OUT_ELEM(true, MAX_DATA_SIZE), ++ NAND_OP_PARSER_PAT_CMD_ELEM(true), ++ NAND_OP_PARSER_PAT_WAITRDY_ELEM(true)), ++); ++ ++static int rk_nfc_exec_op(struct nand_chip *chip, ++ const struct nand_operation *op, ++ bool check_only) ++{ ++ rk_nfc_select_chip(chip, op->cs); ++ return nand_op_parser_exec_op(chip, &rk_nfc_op_parser, op, ++ check_only); ++} ++ ++static int rk_nfc_setup_data_interface(struct nand_chip *chip, int csline, ++ const struct nand_data_interface *conf) ++{ ++ struct rk_nfc *nfc = nand_get_controller_data(chip); ++ const struct nand_sdr_timings *timings; ++ u32 rate, tc2rw, trwpw, trw2c; ++ u32 temp; ++ ++ if (csline == NAND_DATA_IFACE_CHECK_ONLY) ++ return 0; ++ ++ if (!chip->parameters.onfi) ++ return 0; ++ ++ timings = nand_get_sdr_timings(conf); ++ if (IS_ERR(timings)) ++ return -EOPNOTSUPP; ++ ++ if (IS_ERR(nfc->clk.nfc_clk)) ++ rate = clk_get_rate(nfc->clk.ahb_clk); ++ else ++ rate = clk_get_rate(nfc->clk.nfc_clk); ++ ++ /* Turn clock rate into kHz. */ ++ rate /= 1000; ++ ++ tc2rw = 1; ++ trw2c = 1; ++ ++ trwpw = max(timings->tWC_min, timings->tRC_min) / 1000; ++ trwpw = DIV_ROUND_UP(trwpw * rate, 1000000); ++ ++ temp = timings->tREA_max / 1000; ++ temp = DIV_ROUND_UP(temp * rate, 1000000); ++ ++ if (trwpw < temp) ++ trwpw = temp; ++ ++ /* ++ * ACCON: access timing control register ++ * ------------------------------------- ++ * 31:18: reserved ++ * 17:12: csrw, clock cycles from the falling edge of CSn to the ++ falling edge of RDn or WRn ++ * 11:11: reserved ++ * 10:05: rwpw, the width of RDn or WRn in processor clock cycles ++ * 04:00: rwcs, clock cycles from the rising edge of RDn or WRn to the ++ rising edge of CSn ++ */ ++ temp = ACCTIMING(tc2rw, trwpw, trw2c); ++ writel(temp, nfc->regs + NFC_FMWAIT); ++ ++ return 0; ++} ++ ++static int rk_nfc_hw_ecc_setup(struct nand_chip *chip, ++ struct nand_ecc_ctrl *ecc, ++ uint32_t strength) ++{ ++ struct rk_nfc *nfc = nand_get_controller_data(chip); ++ u32 reg, i; ++ ++ for (i = 0; i < NFC_ECC_MAX_MODES; i++) { ++ if (ecc->strength == nfc->cfg->ecc_strengths[i]) { ++ reg = nfc->cfg->ecc_cfgs[i]; ++ break; ++ } ++ } ++ ++ if (i >= NFC_ECC_MAX_MODES) ++ return -EINVAL; ++ ++ writel(reg, nfc->regs + nfc->cfg->bchctl_off); ++ ++ return 0; ++} ++ ++static void rk_nfc_xfer_start(struct rk_nfc *nfc, u8 rw, u8 n_KB, ++ dma_addr_t dma_data, dma_addr_t dma_oob) ++{ ++ u32 dma_reg, fl_reg, bch_reg; ++ ++ dma_reg = DMA_ST | ((!rw) << DMA_WR) | DMA_EN | (2 << DMA_AHB_SIZE) | ++ (7 << DMA_BURST_SIZE) | (16 << DMA_INC_NUM); ++ ++ fl_reg = (rw << FLCTL_WR) | FLCTL_XFER_EN | FLCTL_ACORRECT | ++ (n_KB << FLCTL_XFER_SECTOR) | FLCTL_TOG_FIX; ++ ++ if (nfc->cfg->type == NFC_V6 || nfc->cfg->type == NFC_V8) { ++ bch_reg = readl_relaxed(nfc->regs + nfc->cfg->bchctl_off); ++ bch_reg = (bch_reg & (~BCHCTL_BANK_M)) | ++ (nfc->selected_bank << BCHCTL_BANK); ++ writel(bch_reg, nfc->regs + nfc->cfg->bchctl_off); ++ } ++ ++ writel(dma_reg, nfc->regs + nfc->cfg->dma_cfg_off); ++ writel((u32)dma_data, nfc->regs + nfc->cfg->dma_data_buf_off); ++ writel((u32)dma_oob, nfc->regs + nfc->cfg->dma_oob_buf_off); ++ writel(fl_reg, nfc->regs + nfc->cfg->flctl_off); ++ fl_reg |= FLCTL_XFER_ST; ++ writel(fl_reg, nfc->regs + nfc->cfg->flctl_off); ++} ++ ++static int rk_nfc_wait_for_xfer_done(struct rk_nfc *nfc) ++{ ++ void __iomem *ptr; ++ int ret = 0; ++ u32 reg; ++ ++ ptr = nfc->regs + nfc->cfg->flctl_off; ++ ++ ret = readl_poll_timeout_atomic(ptr, reg, ++ reg & FLCTL_XFER_READY, ++ 10, NFC_TIMEOUT); ++ ++ return ret; ++} ++ ++static int rk_nfc_write_page(struct mtd_info *mtd, struct nand_chip *chip, ++ const u8 *buf, int page, int raw) ++{ ++ struct rk_nfc *nfc = nand_get_controller_data(chip); ++ struct rk_nfc_nand_chip *rknand = to_rknand(chip); ++ struct nand_ecc_ctrl *ecc = &chip->ecc; ++ int oob_step = (ecc->bytes > 60) ? NFC_MAX_OOB_PER_STEP : ++ NFC_MIN_OOB_PER_STEP; ++ int pages_per_blk = mtd->erasesize / mtd->writesize; ++ int ret = 0, i, boot_rom_mode = 0; ++ dma_addr_t dma_data, dma_oob; ++ u32 reg; ++ u8 *oob; ++ ++ nand_prog_page_begin_op(chip, page, 0, NULL, 0); ++ ++ if (!raw) { ++ memcpy(nfc->page_buf, buf, mtd->writesize); ++ memset(nfc->oob_buf, 0xff, oob_step * ecc->steps); ++ ++ /* ++ * The first 8(some devices are 4 or 16) blocks are in use by ++ * the boot ROM and the first 32 bits of oob need to link ++ * to the next page address in the same block. ++ * Config the ECC algorithm supported by the boot ROM. ++ */ ++ if (page < pages_per_blk * rknand->boot_blks && ++ chip->options & NAND_IS_BOOT_MEDIUM) { ++ boot_rom_mode = 1; ++ if (rknand->boot_ecc != ecc->strength) ++ rk_nfc_hw_ecc_setup(chip, ecc, ++ rknand->boot_ecc); ++ } ++ ++ for (i = 0; i < ecc->steps; i++) { ++ if (!i) { ++ reg = 0xFFFFFFFF; ++ } else { ++ oob = chip->oob_poi + (i - 1) * NFC_SYS_DATA_SIZE; ++ reg = oob[0] | oob[1] << 8 | oob[2] << 16 | ++ oob[3] << 24; ++ } ++ if (!i && boot_rom_mode) ++ reg = (page & (pages_per_blk - 1)) * 4; ++ ++ if (nfc->cfg->type == NFC_V9) ++ nfc->oob_buf[i] = reg; ++ else ++ nfc->oob_buf[i * oob_step / 4] = reg; ++ } ++ ++ dma_data = dma_map_single(nfc->dev, (void *)nfc->page_buf, ++ mtd->writesize, DMA_TO_DEVICE); ++ dma_oob = dma_map_single(nfc->dev, nfc->oob_buf, ++ ecc->steps * oob_step, ++ DMA_TO_DEVICE); ++ ++ reinit_completion(&nfc->done); ++ writel(INT_DMA, nfc->regs + nfc->cfg->int_en_off); ++ ++ rk_nfc_xfer_start(nfc, NFC_WRITE, ecc->steps, dma_data, ++ dma_oob); ++ ret = wait_for_completion_timeout(&nfc->done, ++ msecs_to_jiffies(100)); ++ if (!ret) ++ dev_warn(nfc->dev, "write: wait dma done timeout.\n"); ++ /* ++ * Whether the DMA transfer is completed or not. The driver ++ * needs to check the NFC`s status register to see if the data ++ * transfer was completed. ++ */ ++ ret = rk_nfc_wait_for_xfer_done(nfc); ++ ++ dma_unmap_single(nfc->dev, dma_data, mtd->writesize, ++ DMA_TO_DEVICE); ++ dma_unmap_single(nfc->dev, dma_oob, ecc->steps * oob_step, ++ DMA_TO_DEVICE); ++ ++ if (boot_rom_mode && rknand->boot_ecc != ecc->strength) ++ rk_nfc_hw_ecc_setup(chip, ecc, ecc->strength); ++ ++ if (ret) { ++ ret = -EIO; ++ dev_err(nfc->dev, ++ "write: wait transfer done timeout.\n"); ++ } ++ } else { ++ rk_nfc_write_buf(chip, buf, mtd->writesize + mtd->oobsize); ++ } ++ ++ if (ret) ++ return ret; ++ ++ ret = nand_prog_page_end_op(chip); ++ ++ /* Deselect the currently selected target. */ ++ rk_nfc_select_chip(chip, -1); ++ ++ return ret; ++} ++ ++static int rk_nfc_write_page_raw(struct nand_chip *chip, const u8 *buf, ++ int oob_on, int page) ++{ ++ struct mtd_info *mtd = nand_to_mtd(chip); ++ struct rk_nfc *nfc = nand_get_controller_data(chip); ++ u32 i; ++ ++ memset(nfc->buffer, 0xff, mtd->writesize + mtd->oobsize); ++ ++ for (i = 0; i < chip->ecc.steps; i++) { ++ if (buf) ++ memcpy(rk_data_ptr(chip, i), data_ptr(chip, buf, i), ++ chip->ecc.size); ++ ++ if (!i) ++ memcpy(rk_oob_ptr(chip, i), ++ oob_ptr(chip, chip->ecc.steps - 1), ++ NFC_SYS_DATA_SIZE); ++ else ++ memcpy(rk_oob_ptr(chip, i), oob_ptr(chip, i - 1), ++ NFC_SYS_DATA_SIZE); ++ ++ memcpy(rk_oob_ptr(chip, i) + NFC_SYS_DATA_SIZE, ++ oob_ecc_ptr(chip, i), ++ chip->ecc.bytes); ++ } ++ ++ return rk_nfc_write_page(mtd, chip, nfc->buffer, page, 1); ++} ++ ++static int rk_nfc_write_oob_std(struct nand_chip *chip, int page) ++{ ++ return rk_nfc_write_page_raw(chip, NULL, 1, page); ++} ++ ++static int rk_nfc_read_page(struct mtd_info *mtd, struct nand_chip *chip, ++ u32 data_offs, u32 readlen, ++ u8 *buf, int page, int raw) ++{ ++ struct rk_nfc *nfc = nand_get_controller_data(chip); ++ struct rk_nfc_nand_chip *rknand = to_rknand(chip); ++ struct nand_ecc_ctrl *ecc = &chip->ecc; ++ int oob_step = (ecc->bytes > 60) ? NFC_MAX_OOB_PER_STEP : ++ NFC_MIN_OOB_PER_STEP; ++ int pages_per_blk = mtd->erasesize / mtd->writesize; ++ dma_addr_t dma_data, dma_oob; ++ int ret = 0, i, boot_rom_mode = 0; ++ int bitflips = 0, bch_st; ++ u8 *oob; ++ u32 tmp; ++ ++ nand_read_page_op(chip, page, 0, NULL, 0); ++ if (!raw) { ++ dma_data = dma_map_single(nfc->dev, nfc->page_buf, ++ mtd->writesize, ++ DMA_FROM_DEVICE); ++ dma_oob = dma_map_single(nfc->dev, nfc->oob_buf, ++ ecc->steps * oob_step, ++ DMA_FROM_DEVICE); ++ ++ /* ++ * The first 8(some devices are 4 or 16) blocks are in use by ++ * the boot ROM. ++ * Config the ECC algorithm supported by the boot ROM. ++ */ ++ if (page < pages_per_blk * rknand->boot_blks && ++ chip->options & NAND_IS_BOOT_MEDIUM) { ++ boot_rom_mode = 1; ++ if (rknand->boot_ecc != ecc->strength) ++ rk_nfc_hw_ecc_setup(chip, ecc, ++ rknand->boot_ecc); ++ } ++ ++ reinit_completion(&nfc->done); ++ writel(INT_DMA, nfc->regs + nfc->cfg->int_en_off); ++ rk_nfc_xfer_start(nfc, NFC_READ, ecc->steps, dma_data, ++ dma_oob); ++ ret = wait_for_completion_timeout(&nfc->done, ++ msecs_to_jiffies(100)); ++ if (!ret) ++ dev_warn(nfc->dev, "read: wait dma done timeout.\n"); ++ /* ++ * Whether the DMA transfer is completed or not. The driver ++ * needs to check the NFC`s status register to see if the data ++ * transfer was completed. ++ */ ++ ret = rk_nfc_wait_for_xfer_done(nfc); ++ dma_unmap_single(nfc->dev, dma_data, mtd->writesize, ++ DMA_FROM_DEVICE); ++ dma_unmap_single(nfc->dev, dma_oob, ecc->steps * oob_step, ++ DMA_FROM_DEVICE); ++ ++ if (ret) { ++ bitflips = -EIO; ++ dev_err(nfc->dev, ++ "read: wait transfer done timeout.\n"); ++ goto out; ++ } ++ ++ for (i = 1; i < ecc->steps; i++) { ++ oob = chip->oob_poi + (i - 1) * NFC_SYS_DATA_SIZE; ++ if (nfc->cfg->type == NFC_V9) ++ tmp = nfc->oob_buf[i]; ++ else ++ tmp = nfc->oob_buf[i * oob_step / 4]; ++ *oob++ = (u8)tmp; ++ *oob++ = (u8)(tmp >> 8); ++ *oob++ = (u8)(tmp >> 16); ++ *oob++ = (u8)(tmp >> 24); ++ } ++ ++ for (i = 0; i < ecc->steps / 2; i++) { ++ bch_st = readl_relaxed(nfc->regs + ++ nfc->cfg->bch_st_off + i * 4); ++ if (bch_st & BIT(nfc->cfg->ecc0.err_flag_bit) || ++ bch_st & BIT(nfc->cfg->ecc1.err_flag_bit)) { ++ mtd->ecc_stats.failed++; ++ bitflips = -1; ++ } else { ++ ret = ECC_ERR_CNT(bch_st, nfc->cfg->ecc0); ++ mtd->ecc_stats.corrected += ret; ++ bitflips = max_t(u32, bitflips, ret); ++ ++ ret = ECC_ERR_CNT(bch_st, nfc->cfg->ecc1); ++ mtd->ecc_stats.corrected += ret; ++ bitflips = max_t(u32, bitflips, ret); ++ } ++ } ++out: ++ memcpy(buf, nfc->page_buf, mtd->writesize); ++ ++ if (boot_rom_mode && rknand->boot_ecc != ecc->strength) ++ rk_nfc_hw_ecc_setup(chip, ecc, ecc->strength); ++ ++ if (bitflips < 0) ++ dev_err(nfc->dev, "read page: %x ecc error!\n", page); ++ } else { ++ rk_nfc_read_buf(chip, buf, mtd->writesize + mtd->oobsize); ++ } ++ /* Deselect the currently selected target. */ ++ rk_nfc_select_chip(chip, -1); ++ ++ return bitflips; ++} ++ ++static int rk_nfc_write_page_hwecc(struct nand_chip *chip, const u8 *buf, ++ int oob_on, int page) ++{ ++ return rk_nfc_write_page(nand_to_mtd(chip), chip, buf, page, 0); ++} ++ ++static int rk_nfc_read_page_hwecc(struct nand_chip *chip, u8 *p, int oob_on, ++ int pg) ++{ ++ struct mtd_info *mtd = nand_to_mtd(chip); ++ ++ return rk_nfc_read_page(mtd, chip, 0, mtd->writesize, p, pg, 0); ++} ++ ++static int rk_nfc_read_page_raw(struct nand_chip *chip, u8 *buf, int oob_on, ++ int page) ++{ ++ struct mtd_info *mtd = nand_to_mtd(chip); ++ struct rk_nfc *nfc = nand_get_controller_data(chip); ++ int i, ret; ++ ++ ret = rk_nfc_read_page(mtd, chip, 0, mtd->writesize, nfc->buffer, ++ page, 1); ++ if (ret < 0) ++ return ret; ++ ++ for (i = 0; i < chip->ecc.steps; i++) { ++ if (!i) ++ memcpy(oob_ptr(chip, chip->ecc.steps - 1), ++ rk_oob_ptr(chip, i), ++ NFC_SYS_DATA_SIZE); ++ else ++ memcpy(oob_ptr(chip, i - 1), rk_oob_ptr(chip, i), ++ NFC_SYS_DATA_SIZE); ++ ++ memcpy(oob_ecc_ptr(chip, i), ++ rk_oob_ptr(chip, i) + NFC_SYS_DATA_SIZE, ++ chip->ecc.bytes); ++ ++ if (buf) ++ memcpy(data_ptr(chip, buf, i), rk_data_ptr(chip, i), ++ chip->ecc.size); ++ } ++ ++ return ret; ++} ++ ++static int rk_nfc_read_oob_std(struct nand_chip *chip, int page) ++{ ++ return rk_nfc_read_page_raw(chip, NULL, 1, page); ++} ++ ++static inline void rk_nfc_hw_init(struct rk_nfc *nfc) ++{ ++ /* Disable flash wp. */ ++ writel(FMCTL_WP, nfc->regs + NFC_FMCTL); ++ /* Config default timing 40ns at 150 Mhz nfc clock. */ ++ writel(0x1081, nfc->regs + NFC_FMWAIT); ++ /* Disable randomizer and DMA. */ ++ writel(0, nfc->regs + nfc->cfg->randmz_off); ++ writel(0, nfc->regs + nfc->cfg->dma_cfg_off); ++ writel(FLCTL_RST, nfc->regs + nfc->cfg->flctl_off); ++} ++ ++static irqreturn_t rk_nfc_irq(int irq, void *id) ++{ ++ struct rk_nfc *nfc = id; ++ u32 sta, ien; ++ ++ sta = readl_relaxed(nfc->regs + nfc->cfg->int_st_off); ++ ien = readl_relaxed(nfc->regs + nfc->cfg->int_en_off); ++ ++ if (!(sta & ien)) ++ return IRQ_NONE; ++ ++ writel(sta, nfc->regs + nfc->cfg->int_clr_off); ++ writel(~sta & ien, nfc->regs + nfc->cfg->int_en_off); ++ ++ complete(&nfc->done); ++ ++ return IRQ_HANDLED; ++} ++ ++static int rk_nfc_enable_clk(struct device *dev, struct rk_nfc_clk *clk) ++{ ++ int ret; ++ ++ if (!IS_ERR(clk->nfc_clk)) { ++ ret = clk_prepare_enable(clk->nfc_clk); ++ if (ret) { ++ dev_err(dev, "failed to enable nfc clk\n"); ++ return ret; ++ } ++ } ++ ++ ret = clk_prepare_enable(clk->ahb_clk); ++ if (ret) { ++ dev_err(dev, "failed to enable ahb clk\n"); ++ if (!IS_ERR(clk->nfc_clk)) ++ clk_disable_unprepare(clk->nfc_clk); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static void rk_nfc_disable_clk(struct rk_nfc_clk *clk) ++{ ++ if (!IS_ERR(clk->nfc_clk)) ++ clk_disable_unprepare(clk->nfc_clk); ++ clk_disable_unprepare(clk->ahb_clk); ++} ++ ++static int rk_nfc_ooblayout_free(struct mtd_info *mtd, int section, ++ struct mtd_oob_region *oob_region) ++{ ++ struct nand_chip *chip = mtd_to_nand(mtd); ++ struct rk_nfc_nand_chip *rknand = to_rknand(chip); ++ ++ if (section) ++ return -ERANGE; ++ ++ /* ++ * The beginning of the oob area stores the reserved data for the NFC, ++ * the size of the reserved data is NFC_SYS_DATA_SIZE bytes. ++ */ ++ oob_region->length = rknand->metadata_size - NFC_SYS_DATA_SIZE - 2; ++ oob_region->offset = NFC_SYS_DATA_SIZE + 2; ++ ++ return 0; ++} ++ ++static int rk_nfc_ooblayout_ecc(struct mtd_info *mtd, int section, ++ struct mtd_oob_region *oob_region) ++{ ++ struct nand_chip *chip = mtd_to_nand(mtd); ++ struct rk_nfc_nand_chip *rknand = to_rknand(chip); ++ ++ if (section) ++ return -ERANGE; ++ ++ oob_region->offset = rknand->metadata_size; ++ oob_region->length = mtd->oobsize - oob_region->offset; ++ ++ return 0; ++} ++ ++static const struct mtd_ooblayout_ops rk_nfc_ooblayout_ops = { ++ .free = rk_nfc_ooblayout_free, ++ .ecc = rk_nfc_ooblayout_ecc, ++}; ++ ++static int rk_nfc_ecc_init(struct device *dev, struct mtd_info *mtd) ++{ ++ struct nand_chip *chip = mtd_to_nand(mtd); ++ struct rk_nfc *nfc = nand_get_controller_data(chip); ++ struct nand_ecc_ctrl *ecc = &chip->ecc; ++ const u8 *strengths = nfc->cfg->ecc_strengths; ++ u8 max_strength, nfc_max_strength; ++ int i; ++ ++ nfc_max_strength = nfc->cfg->ecc_strengths[0]; ++ /* If optional dt settings not present. */ ++ if (!ecc->size || !ecc->strength || ++ ecc->strength > nfc_max_strength) { ++ /* Use datasheet requirements. */ ++ ecc->strength = chip->base.eccreq.strength; ++ ecc->size = chip->base.eccreq.step_size; ++ ++ /* Align ECC strength and ECC size. */ ++ if (chip->ecc.size < 1024) { ++ if (mtd->writesize > 512) { ++ chip->ecc.size = 1024; ++ chip->ecc.strength <<= 1; ++ } else { ++ dev_err(dev, "Unsupported ecc.size\n"); ++ return -EINVAL; ++ } ++ } else { ++ chip->ecc.size = 1024; ++ } ++ ++ ecc->steps = mtd->writesize / ecc->size; ++ ++ /* ++ * HW ECC always requests the number of ECC bytes per 1024 byte ++ * blocks. 4 Bytes is oob for sys data. ++ */ ++ max_strength = ((mtd->oobsize / ecc->steps) - 4) * 8 / ++ fls(8 * 1024); ++ if (max_strength > nfc_max_strength) ++ max_strength = nfc_max_strength; ++ ++ for (i = 0; i < 4; i++) { ++ if (max_strength >= strengths[i]) ++ break; ++ } ++ ++ if (i >= 4) { ++ dev_err(nfc->dev, "Unsupported ECC strength\n"); ++ return -EOPNOTSUPP; ++ } ++ ++ ecc->strength = strengths[i]; ++ } ++ ecc->steps = mtd->writesize / ecc->size; ++ ecc->bytes = DIV_ROUND_UP(ecc->strength * fls(8 * 1024), 8); ++ /* HW ECC always work with even numbers of ECC bytes. */ ++ ecc->bytes = ALIGN(ecc->bytes, 2); ++ ++ rk_nfc_hw_ecc_setup(chip, ecc, ecc->strength); ++ ++ return 0; ++} ++ ++static int rk_nfc_attach_chip(struct nand_chip *chip) ++{ ++ struct mtd_info *mtd = nand_to_mtd(chip); ++ struct device *dev = mtd->dev.parent; ++ struct rk_nfc *nfc = nand_get_controller_data(chip); ++ struct rk_nfc_nand_chip *rknand = to_rknand(chip); ++ struct nand_ecc_ctrl *ecc = &chip->ecc; ++ int len; ++ int ret; ++ ++ if (chip->options & NAND_BUSWIDTH_16) { ++ dev_err(dev, "16 bits bus width not supported"); ++ return -EINVAL; ++ } ++ ++ if (ecc->mode != NAND_ECC_HW) ++ return 0; ++ ++ ret = rk_nfc_ecc_init(dev, mtd); ++ if (ret) ++ return ret; ++ rknand->spare_per_sector = ecc->bytes + NFC_SYS_DATA_SIZE; ++ rknand->metadata_size = NFC_SYS_DATA_SIZE * ecc->steps; ++ ++ if (rknand->metadata_size < NFC_SYS_DATA_SIZE + 2) { ++ dev_err(dev, ++ "Driver needs at least %d bytes of meta data\n", ++ NFC_SYS_DATA_SIZE + 2); ++ return -EIO; ++ } ++ /* Check buffer first, avoid duplicate alloc buffer. */ ++ if (nfc->buffer) ++ return 0; ++ ++ len = mtd->writesize + mtd->oobsize; ++ nfc->buffer = devm_kzalloc(dev, len, GFP_KERNEL | GFP_DMA); ++ if (!nfc->buffer) ++ return -ENOMEM; ++ ++ nfc->page_buf = nfc->buffer; ++ len = ecc->steps * NFC_MAX_OOB_PER_STEP; ++ nfc->oob_buf = devm_kzalloc(dev, len, GFP_KERNEL | GFP_DMA); ++ if (!nfc->oob_buf) { ++ nfc->buffer = NULL; ++ nfc->oob_buf = NULL; ++ return -ENOMEM; ++ } ++ ++ chip->ecc.write_page_raw = rk_nfc_write_page_raw; ++ chip->ecc.write_page = rk_nfc_write_page_hwecc; ++ chip->ecc.write_oob_raw = rk_nfc_write_oob_std; ++ chip->ecc.write_oob = rk_nfc_write_oob_std; ++ ++ chip->ecc.read_page_raw = rk_nfc_read_page_raw; ++ chip->ecc.read_page = rk_nfc_read_page_hwecc; ++ chip->ecc.read_oob_raw = rk_nfc_read_oob_std; ++ chip->ecc.read_oob = rk_nfc_read_oob_std; ++ ++ return 0; ++} ++ ++static const struct nand_controller_ops rk_nfc_controller_ops = { ++ .attach_chip = rk_nfc_attach_chip, ++ .exec_op = rk_nfc_exec_op, ++ .setup_data_interface = rk_nfc_setup_data_interface, ++}; ++ ++static int rk_nfc_nand_chip_init(struct device *dev, struct rk_nfc *nfc, ++ struct device_node *np) ++{ ++ struct rk_nfc_nand_chip *rknand; ++ struct nand_chip *chip; ++ struct mtd_info *mtd; ++ int nsels; ++ u32 tmp; ++ int ret; ++ int i; ++ ++ if (!of_get_property(np, "reg", &nsels)) ++ return -ENODEV; ++ nsels /= sizeof(u32); ++ if (!nsels || nsels > NFC_MAX_NSELS) { ++ dev_err(dev, "invalid reg property size %d\n", nsels); ++ return -EINVAL; ++ } ++ ++ rknand = devm_kzalloc(dev, sizeof(*rknand) + nsels * sizeof(u8), ++ GFP_KERNEL); ++ if (!rknand) ++ return -ENOMEM; ++ ++ rknand->nsels = nsels; ++ for (i = 0; i < nsels; i++) { ++ ret = of_property_read_u32_index(np, "reg", i, &tmp); ++ if (ret) { ++ dev_err(dev, "reg property failure : %d\n", ret); ++ return ret; ++ } ++ ++ if (tmp >= NFC_MAX_NSELS) { ++ dev_err(dev, "invalid CS: %u\n", tmp); ++ return -EINVAL; ++ } ++ ++ if (test_and_set_bit(tmp, &nfc->assigned_cs)) { ++ dev_err(dev, "CS %u already assigned\n", tmp); ++ return -EINVAL; ++ } ++ ++ rknand->sels[i] = tmp; ++ } ++ ++ chip = &rknand->chip; ++ chip->controller = &nfc->controller; ++ ++ nand_set_flash_node(chip, np); ++ ++ nand_set_controller_data(chip, nfc); ++ ++ chip->options |= NAND_USES_DMA | NAND_NO_SUBPAGE_WRITE; ++ chip->bbt_options = NAND_BBT_USE_FLASH | NAND_BBT_NO_OOB; ++ ++ /* Set default mode in case dt entry is missing. */ ++ chip->ecc.mode = NAND_ECC_HW; ++ ++ mtd = nand_to_mtd(chip); ++ mtd->owner = THIS_MODULE; ++ mtd->dev.parent = dev; ++ ++ if (!mtd->name) { ++ dev_err(nfc->dev, "NAND label property is mandatory\n"); ++ return -EINVAL; ++ } ++ ++ mtd_set_ooblayout(mtd, &rk_nfc_ooblayout_ops); ++ rk_nfc_hw_init(nfc); ++ ret = nand_scan(chip, nsels); ++ if (ret) ++ return ret; ++ ++ if (chip->options & NAND_IS_BOOT_MEDIUM) { ++ ret = of_property_read_u32(np, "rockchip,boot-blks", &tmp); ++ rknand->boot_blks = ret ? 0 : tmp; ++ ++ ret = of_property_read_u32(np, "rockchip,boot-ecc-strength", ++ &tmp); ++ rknand->boot_ecc = ret ? chip->ecc.strength : tmp; ++ } ++ ++ ret = mtd_device_register(mtd, NULL, 0); ++ if (ret) { ++ dev_err(dev, "mtd parse partition error\n"); ++ nand_cleanup(chip); ++ return ret; ++ } ++ ++ list_add_tail(&rknand->node, &nfc->chips); ++ ++ return 0; ++} ++ ++static void rk_nfc_chips_cleanup(struct rk_nfc *nfc) ++{ ++ struct rk_nfc_nand_chip *rknand, *tmp; ++ struct nand_chip *chip; ++ int ret; ++ ++ list_for_each_entry_safe(rknand, tmp, &nfc->chips, node) { ++ chip = &rknand->chip; ++ ret = mtd_device_unregister(nand_to_mtd(chip)); ++ WARN_ON(ret); ++ nand_cleanup(chip); ++ list_del(&rknand->node); ++ } ++} ++ ++static int rk_nfc_nand_chips_init(struct device *dev, struct rk_nfc *nfc) ++{ ++ struct device_node *np = dev->of_node, *nand_np; ++ int nchips = of_get_child_count(np); ++ int ret; ++ ++ if (!nchips || nchips > NFC_MAX_NSELS) { ++ dev_err(nfc->dev, "Incorrect number of NAND chips (%d)\n", ++ nchips); ++ return -EINVAL; ++ } ++ ++ for_each_child_of_node(np, nand_np) { ++ ret = rk_nfc_nand_chip_init(dev, nfc, nand_np); ++ if (ret) { ++ of_node_put(nand_np); ++ rk_nfc_chips_cleanup(nfc); ++ return ret; ++ } ++ } ++ ++ return 0; ++} ++ ++static struct nfc_cfg nfc_v6_cfg = { ++ .type = NFC_V6, ++ .ecc_strengths = {60, 40, 24, 16}, ++ .ecc_cfgs = { ++ 0x00040011, 0x00040001, 0x00000011, 0x00000001, ++ }, ++ .flctl_off = 0x08, ++ .bchctl_off = 0x0C, ++ .dma_cfg_off = 0x10, ++ .dma_data_buf_off = 0x14, ++ .dma_oob_buf_off = 0x18, ++ .dma_st_off = 0x1C, ++ .bch_st_off = 0x20, ++ .randmz_off = 0x150, ++ .int_en_off = 0x16C, ++ .int_clr_off = 0x170, ++ .int_st_off = 0x174, ++ .oob0_off = 0x200, ++ .oob1_off = 0x230, ++ .ecc0 = { ++ .err_flag_bit = 2, ++ .low = 3, ++ .low_mask = 0x1F, ++ .low_bn = 5, ++ .high = 27, ++ .high_mask = 0x1, ++ }, ++ .ecc1 = { ++ .err_flag_bit = 15, ++ .low = 16, ++ .low_mask = 0x1F, ++ .low_bn = 5, ++ .high = 29, ++ .high_mask = 0x1, ++ }, ++}; ++ ++static struct nfc_cfg nfc_v8_cfg = { ++ .type = NFC_V8, ++ .ecc_strengths = {16, 16, 16, 16}, ++ .ecc_cfgs = { ++ 0x00000001, 0x00000001, 0x00000001, 0x00000001, ++ }, ++ .flctl_off = 0x08, ++ .bchctl_off = 0x0C, ++ .dma_cfg_off = 0x10, ++ .dma_data_buf_off = 0x14, ++ .dma_oob_buf_off = 0x18, ++ .dma_st_off = 0x1C, ++ .bch_st_off = 0x20, ++ .randmz_off = 0x150, ++ .int_en_off = 0x16C, ++ .int_clr_off = 0x170, ++ .int_st_off = 0x174, ++ .oob0_off = 0x200, ++ .oob1_off = 0x230, ++ .ecc0 = { ++ .err_flag_bit = 2, ++ .low = 3, ++ .low_mask = 0x1F, ++ .low_bn = 5, ++ .high = 27, ++ .high_mask = 0x1, ++ }, ++ .ecc1 = { ++ .err_flag_bit = 15, ++ .low = 16, ++ .low_mask = 0x1F, ++ .low_bn = 5, ++ .high = 29, ++ .high_mask = 0x1, ++ }, ++}; ++ ++static struct nfc_cfg nfc_v9_cfg = { ++ .type = NFC_V9, ++ .ecc_strengths = {70, 60, 40, 16}, ++ .ecc_cfgs = { ++ 0x00000001, 0x06000001, 0x04000001, 0x02000001, ++ }, ++ .flctl_off = 0x10, ++ .bchctl_off = 0x20, ++ .dma_cfg_off = 0x30, ++ .dma_data_buf_off = 0x34, ++ .dma_oob_buf_off = 0x38, ++ .dma_st_off = 0x3C, ++ .bch_st_off = 0x150, ++ .randmz_off = 0x208, ++ .int_en_off = 0x120, ++ .int_clr_off = 0x124, ++ .int_st_off = 0x128, ++ .oob0_off = 0x200, ++ .oob1_off = 0x204, ++ .ecc0 = { ++ .err_flag_bit = 2, ++ .low = 3, ++ .low_mask = 0x7F, ++ .low_bn = 7, ++ .high = 0, ++ .high_mask = 0x0, ++ }, ++ .ecc1 = { ++ .err_flag_bit = 18, ++ .low = 19, ++ .low_mask = 0x7F, ++ .low_bn = 7, ++ .high = 0, ++ .high_mask = 0x0, ++ }, ++}; ++ ++static const struct of_device_id rk_nfc_id_table[] = { ++ {.compatible = "rockchip,px30-nfc", ++ .data = &nfc_v9_cfg }, ++ {.compatible = "rockchip,rk2928-nfc", ++ .data = &nfc_v6_cfg }, ++ {.compatible = "rockchip,rv1108-nfc", ++ .data = &nfc_v8_cfg }, ++ { /* sentinel */ } ++}; ++MODULE_DEVICE_TABLE(of, rk_nfc_id_table); ++ ++static int rk_nfc_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct rk_nfc *nfc; ++ int ret, irq; ++ ++ nfc = devm_kzalloc(dev, sizeof(*nfc), GFP_KERNEL); ++ if (!nfc) ++ return -ENOMEM; ++ ++ nand_controller_init(&nfc->controller); ++ INIT_LIST_HEAD(&nfc->chips); ++ nfc->controller.ops = &rk_nfc_controller_ops; ++ ++ nfc->cfg = of_device_get_match_data(dev); ++ nfc->dev = dev; ++ ++ init_completion(&nfc->done); ++ ++ nfc->regs = devm_platform_ioremap_resource(pdev, 0); ++ if (IS_ERR(nfc->regs)) { ++ ret = PTR_ERR(nfc->regs); ++ goto release_nfc; ++ } ++ ++ nfc->clk.nfc_clk = devm_clk_get(dev, "nfc"); ++ if (IS_ERR(nfc->clk.nfc_clk)) { ++ dev_dbg(dev, "no nfc clk\n"); ++ /* Some earlier models, such as rk3066, have no nfc clk. */ ++ } ++ ++ nfc->clk.ahb_clk = devm_clk_get(dev, "ahb"); ++ if (IS_ERR(nfc->clk.ahb_clk)) { ++ dev_err(dev, "no ahb clk\n"); ++ ret = PTR_ERR(nfc->clk.ahb_clk); ++ goto release_nfc; ++ } ++ ++ ret = rk_nfc_enable_clk(dev, &nfc->clk); ++ if (ret) ++ goto release_nfc; ++ ++ irq = platform_get_irq(pdev, 0); ++ if (irq < 0) { ++ dev_err(dev, "no nfc irq resource\n"); ++ ret = -EINVAL; ++ goto clk_disable; ++ } ++ ++ writel(0, nfc->regs + nfc->cfg->int_en_off); ++ ret = devm_request_irq(dev, irq, rk_nfc_irq, 0x0, "rk-nand", nfc); ++ if (ret) { ++ dev_err(dev, "failed to request nfc irq\n"); ++ goto clk_disable; ++ } ++ ++ platform_set_drvdata(pdev, nfc); ++ ++ ret = rk_nfc_nand_chips_init(dev, nfc); ++ if (ret) { ++ dev_err(dev, "failed to init NAND chips\n"); ++ goto clk_disable; ++ } ++ return 0; ++ ++clk_disable: ++ rk_nfc_disable_clk(&nfc->clk); ++release_nfc: ++ return ret; ++} ++ ++static int rk_nfc_remove(struct platform_device *pdev) ++{ ++ struct rk_nfc *nfc = platform_get_drvdata(pdev); ++ ++ rk_nfc_chips_cleanup(nfc); ++ rk_nfc_disable_clk(&nfc->clk); ++ ++ return 0; ++} ++ ++static int __maybe_unused rk_nfc_suspend(struct device *dev) ++{ ++ struct rk_nfc *nfc = dev_get_drvdata(dev); ++ ++ rk_nfc_disable_clk(&nfc->clk); ++ ++ return 0; ++} ++ ++static int __maybe_unused rk_nfc_resume(struct device *dev) ++{ ++ struct rk_nfc *nfc = dev_get_drvdata(dev); ++ struct rk_nfc_nand_chip *rknand; ++ struct nand_chip *chip; ++ int ret; ++ u32 i; ++ ++ ret = rk_nfc_enable_clk(dev, &nfc->clk); ++ if (ret) ++ return ret; ++ ++ /* Reset NAND chip if VCC was powered off. */ ++ list_for_each_entry(rknand, &nfc->chips, node) { ++ chip = &rknand->chip; ++ for (i = 0; i < rknand->nsels; i++) ++ nand_reset(chip, i); ++ } ++ ++ return 0; ++} ++ ++static const struct dev_pm_ops rk_nfc_pm_ops = { ++ SET_SYSTEM_SLEEP_PM_OPS(rk_nfc_suspend, rk_nfc_resume) ++}; ++ ++static struct platform_driver rk_nfc_driver = { ++ .probe = rk_nfc_probe, ++ .remove = rk_nfc_remove, ++ .driver = { ++ .name = "rockchip-nfc", ++ .of_match_table = rk_nfc_id_table, ++ .pm = &rk_nfc_pm_ops, ++ }, ++}; ++ ++module_platform_driver(rk_nfc_driver); ++ ++MODULE_LICENSE("Dual MIT/GPL"); ++MODULE_AUTHOR("Yifeng Zhao "); ++MODULE_DESCRIPTION("Rockchip Nand Flash Controller Driver"); ++MODULE_ALIAS("platform:rockchip-nand-controller"); + +From 9f9bc458898c407f25a6d38551713317161b0092 Mon Sep 17 00:00:00 2001 +From: Yifeng Zhao +Date: Fri, 17 Jul 2020 17:24:19 +0800 +Subject: [PATCH] MAINTAINERS: add maintainers to ROCKCHIP NFC + +Add maintainers to ROCKCHIP NFC. + +Signed-off-by: Yifeng Zhao +--- + MAINTAINERS | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/MAINTAINERS b/MAINTAINERS +index 4e2698cc7e23..db98a799f409 100644 +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -2344,12 +2344,12 @@ L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) + L: linux-rockchip@lists.infradead.org + S: Maintained + T: git git://git.kernel.org/pub/scm/linux/kernel/git/mmind/linux-rockchip.git ++F: Documentation/devicetree/bindings/*/*rockchip*.yaml + F: Documentation/devicetree/bindings/i2c/i2c-rk3x.yaml +-F: Documentation/devicetree/bindings/mmc/rockchip-dw-mshc.yaml +-F: Documentation/devicetree/bindings/spi/spi-rockchip.yaml + F: arch/arm/boot/dts/rk3* + F: arch/arm/boot/dts/rv1108* + F: arch/arm/mach-rockchip/ ++F: drivers/*/*/*/*rockchip* + F: drivers/*/*/*rockchip* + F: drivers/*/*rockchip* + F: drivers/clk/rockchip/ + +From 48604da8047dc2bb8009ee7af76655b41fb0c337 Mon Sep 17 00:00:00 2001 +From: Yifeng Zhao +Date: Fri, 17 Jul 2020 17:24:20 +0800 +Subject: [PATCH] arm64: dts: rockchip: Add NFC node for RK3308 SoC + +Add NAND FLASH Controller(NFC) node for RK3308 SoC. + +Signed-off-by: Yifeng Zhao +Signed-off-by: Yifeng Zhao +--- + arch/arm64/boot/dts/rockchip/rk3308.dtsi | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +diff --git a/arch/arm64/boot/dts/rockchip/rk3308.dtsi b/arch/arm64/boot/dts/rockchip/rk3308.dtsi +index e8b754d415d8..e9d8610fccf5 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3308.dtsi ++++ b/arch/arm64/boot/dts/rockchip/rk3308.dtsi +@@ -629,6 +629,21 @@ sdio: mmc@ff4a0000 { + status = "disabled"; + }; + ++ nfc: nand-controller@ff4b0000 { ++ compatible = "rockchip,rk3308-nfc", ++ "rockchip,rv1108-nfc"; ++ reg = <0x0 0xff4b0000 0x0 0x4000>; ++ interrupts = ; ++ clocks = <&cru HCLK_NANDC>, <&cru SCLK_NANDC>; ++ clock-names = "ahb", "nfc"; ++ assigned-clocks = <&cru SCLK_NANDC>; ++ assigned-clock-rates = <150000000>; ++ pinctrl-0 = <&flash_ale &flash_bus8 &flash_cle &flash_csn0 ++ &flash_rdn &flash_rdy &flash_wrn>; ++ pinctrl-names = "default"; ++ status = "disabled"; ++ }; ++ + cru: clock-controller@ff500000 { + compatible = "rockchip,rk3308-cru"; + reg = <0x0 0xff500000 0x0 0x1000>; + +From 046465fffd8f588097ed6f78bc3f193639bd5657 Mon Sep 17 00:00:00 2001 +From: Yifeng Zhao +Date: Fri, 17 Jul 2020 17:25:29 +0800 +Subject: [PATCH] arm64: dts: rockchip: Add NFC node for PX30 SoC + +Add NAND FLASH Controller(NFC) node for PX30 SoC. + +Signed-off-by: Yifeng Zhao +--- + arch/arm64/boot/dts/rockchip/px30.dtsi | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +diff --git a/arch/arm64/boot/dts/rockchip/px30.dtsi b/arch/arm64/boot/dts/rockchip/px30.dtsi +index 2695ea8cda14..6cd67e80d623 100644 +--- a/arch/arm64/boot/dts/rockchip/px30.dtsi ++++ b/arch/arm64/boot/dts/rockchip/px30.dtsi +@@ -973,6 +973,21 @@ emmc: mmc@ff390000 { + status = "disabled"; + }; + ++ nfc: nand-controller@ff3b0000 { ++ compatible = "rockchip,px30-nfc"; ++ reg = <0x0 0xff3b0000 0x0 0x4000>; ++ interrupts = ; ++ clocks = <&cru HCLK_NANDC>, <&cru SCLK_NANDC>; ++ clock-names = "ahb", "nfc"; ++ assigned-clocks = <&cru SCLK_NANDC>; ++ assigned-clock-rates = <150000000>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&flash_ale &flash_bus8 &flash_cle &flash_cs0 ++ &flash_rdn &flash_rdy &flash_wrn &flash_dqs>; ++ power-domains = <&power PX30_PD_MMC_NAND>; ++ status = "disabled"; ++ }; ++ + gpu: gpu@ff400000 { + compatible = "rockchip,px30-mali", "arm,mali-bifrost"; + reg = <0x0 0xff400000 0x0 0x4000>; + +From e67947a6ea98d31eda5e900909bc762714e97062 Mon Sep 17 00:00:00 2001 +From: Yifeng Zhao +Date: Fri, 17 Jul 2020 17:25:30 +0800 +Subject: [PATCH] arm: dts: rockchip: Add NFC node for RV1108 SoC + +Add NAND FLASH Controller(NFC) node for RV1108 SoC. + +Signed-off-by: Yifeng Zhao +--- + arch/arm/boot/dts/rv1108.dtsi | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/arch/arm/boot/dts/rv1108.dtsi b/arch/arm/boot/dts/rv1108.dtsi +index a1a08cb9364e..1696ea19488b 100644 +--- a/arch/arm/boot/dts/rv1108.dtsi ++++ b/arch/arm/boot/dts/rv1108.dtsi +@@ -452,6 +452,17 @@ cru: clock-controller@20200000 { + #reset-cells = <1>; + }; + ++ nfc: nand-controller@30100000 { ++ compatible = "rockchip,rv1108-nfc"; ++ reg = <0x30100000 0x1000>; ++ interrupts = ; ++ clocks = <&cru HCLK_NANDC>, <&cru SCLK_NANDC>; ++ clock-names = "ahb", "nfc"; ++ assigned-clocks = <&cru SCLK_NANDC>; ++ assigned-clock-rates = <150000000>; ++ status = "disabled"; ++ }; ++ + emmc: mmc@30110000 { + compatible = "rockchip,rv1108-dw-mshc", "rockchip,rk3288-dw-mshc"; + reg = <0x30110000 0x4000>; + +From 9f1eb721bf42f1470fe280b4f501526a8addd76e Mon Sep 17 00:00:00 2001 +From: Yifeng Zhao +Date: Fri, 17 Jul 2020 17:25:31 +0800 +Subject: [PATCH] arm: dts: rockchip: Add NFC node for RK2928 and other SoCs + +Add NAND FLASH Controller(NFC) node for RK2928, RK3066, RK3168 +and RK3188 SoCs. + +Signed-off-by: Yifeng Zhao +--- + arch/arm/boot/dts/rk3xxx.dtsi | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/arch/arm/boot/dts/rk3xxx.dtsi b/arch/arm/boot/dts/rk3xxx.dtsi +index 859a7477909f..97415180d5bb 100644 +--- a/arch/arm/boot/dts/rk3xxx.dtsi ++++ b/arch/arm/boot/dts/rk3xxx.dtsi +@@ -276,6 +276,15 @@ emmc: mmc@1021c000 { + status = "disabled"; + }; + ++ nfc: nand-controller@10500000 { ++ compatible = "rockchip,rk2928-nfc"; ++ reg = <0x10500000 0x4000>; ++ interrupts = ; ++ clocks = <&cru HCLK_NANDC0>; ++ clock-names = "ahb"; ++ status = "disabled"; ++ }; ++ + pmu: pmu@20004000 { + compatible = "rockchip,rk3066-pmu", "syscon", "simple-mfd"; + reg = <0x20004000 0x100>; + +From b299d8bd1f7b704e89fcb320b4d851cfc3a6f5e9 Mon Sep 17 00:00:00 2001 +From: Yifeng Zhao +Date: Fri, 17 Jul 2020 17:25:32 +0800 +Subject: [PATCH] arm: dts: rockchip: Add NFC node for RK3036 SoC + +Add NAND FLASH Controller(NFC) node for RK3036 SoC. + +Signed-off-by: Yifeng Zhao +--- + arch/arm/boot/dts/rk3036.dtsi | 52 +++++++++++++++++++++++++++++++++++ + 1 file changed, 52 insertions(+) + +diff --git a/arch/arm/boot/dts/rk3036.dtsi b/arch/arm/boot/dts/rk3036.dtsi +index 093567022386..dda5a1f79aca 100644 +--- a/arch/arm/boot/dts/rk3036.dtsi ++++ b/arch/arm/boot/dts/rk3036.dtsi +@@ -292,6 +292,21 @@ i2s: i2s@10220000 { + status = "disabled"; + }; + ++ nfc: nand-controller@10500000 { ++ compatible = "rockchip,rk3036-nfc", ++ "rockchip,rk2928-nfc"; ++ reg = <0x10500000 0x4000>; ++ interrupts = ; ++ clocks = <&cru HCLK_NANDC>, <&cru SCLK_NANDC>; ++ clock-names = "ahb", "nfc"; ++ assigned-clocks = <&cru SCLK_NANDC>; ++ assigned-clock-rates = <150000000>; ++ pinctrl-0 = <&flash_ale &flash_bus8 &flash_cle &flash_csn0 ++ &flash_rdn &flash_rdy &flash_wrn>; ++ pinctrl-names = "default"; ++ status = "disabled"; ++ }; ++ + cru: clock-controller@20000000 { + compatible = "rockchip,rk3036-cru"; + reg = <0x20000000 0x1000>; +@@ -643,6 +658,43 @@ emmc_bus8: emmc-bus8 { + }; + }; + ++ nfc { ++ flash_ale: flash-ale { ++ rockchip,pins = <2 RK_PA0 1 &pcfg_pull_default>; ++ }; ++ ++ flash_bus8: flash-bus8 { ++ rockchip,pins = <1 RK_PD0 1 &pcfg_pull_default>, ++ <1 RK_PD1 1 &pcfg_pull_default>, ++ <1 RK_PD2 1 &pcfg_pull_default>, ++ <1 RK_PD3 1 &pcfg_pull_default>, ++ <1 RK_PD4 1 &pcfg_pull_default>, ++ <1 RK_PD5 1 &pcfg_pull_default>, ++ <1 RK_PD6 1 &pcfg_pull_default>, ++ <1 RK_PD7 1 &pcfg_pull_default>; ++ }; ++ ++ flash_cle: flash-cle { ++ rockchip,pins = <2 RK_PA1 1 &pcfg_pull_default>; ++ }; ++ ++ flash_csn0: flash-csn0 { ++ rockchip,pins = <2 RK_PA6 1 &pcfg_pull_default>; ++ }; ++ ++ flash_rdn: flash-rdn { ++ rockchip,pins = <2 RK_PA3 1 &pcfg_pull_default>; ++ }; ++ ++ flash_rdy: flash-rdy { ++ rockchip,pins = <2 RK_PA4 1 &pcfg_pull_default>; ++ }; ++ ++ flash_wrn: flash-wrn { ++ rockchip,pins = <2 RK_PA2 1 &pcfg_pull_default>; ++ }; ++ }; ++ + emac { + emac_xfer: emac-xfer { + rockchip,pins = <2 RK_PB2 1 &pcfg_pull_default>, /* crs_dvalid */ diff --git a/patch/kernel/rk322x-dev/01-linux-0011-v4l2-from-5.9.patch b/patch/kernel/rk322x-dev/01-linux-0011-v4l2-from-5.9.patch new file mode 100644 index 000000000..79efdfdb0 --- /dev/null +++ b/patch/kernel/rk322x-dev/01-linux-0011-v4l2-from-5.9.patch @@ -0,0 +1,1190 @@ +From 7ecb99ec97624da3354bc7702179e21309fb3a4e Mon Sep 17 00:00:00 2001 +From: Ezequiel Garcia +Date: Wed, 1 Jul 2020 15:17:30 +0200 +Subject: [PATCH] v4l2-core: Print control name in VIDIOC_S/G_(EXT)_CTRL(S) + +While debugging, it's currently really hard to identify controls +by their ID. Print the control name making the print more helpful. + +With this change, the print changes from: + +video1: VIDIOC_S_EXT_CTRLS: which=0xf010000, count=5, error_idx=4, request_fd=45, id/size=0x990ce8/1048, id/size=0x990ce9/12, id/size=0x990cea/480, id/size=0x990ceb/896, id/size=0x990cec/400 + +video1: VIDIOC_S_EXT_CTRLS: which=0xf010000, count=5, error_idx=4, request_fd=42, name=H264 Sequence Parameter Set, id/size=0x990ce8/1048, name=H264 Picture Parameter Set, id/size=0x990ce9/12, name=H264 Scaling Matrix, id/size=0x990cea/480, name=H264 Slice Parameters, id/size=0x990ceb/896, name=H264 Decode Parameters, id/size=0x990cec/400 + +For instance, this is specially helpful when the ioctl fails. Consider +the following example: + +v4l2-ctrls: prepare_ext_ctrls: video1: pointer control id 0x990cec size too small, 400 bytes but 784 bytes needed +v4l2-ctrls: try_set_ext_ctrls: video1: video1: try_set_ext_ctrls_common failed (-14) +video1: VIDIOC_S_EXT_CTRLS: error -14: which=0xf010000, count=5, error_idx=5, request_fd=39, name=H264 Sequence Parameter Set, id/size=0x990ce8/1048, name=H264 Picture Parameter Set, id/size=0x990ce9/12, name=H264 Scaling Matrix, id/size=0x990cea/480, name=H264 Slice Parameters, id/size=0x990ceb/896, name=H264 Decode Parameters, id/size=0x990cec/400 + +Signed-off-by: Ezequiel Garcia +Signed-off-by: Hans Verkuil +Signed-off-by: Mauro Carvalho Chehab +(cherry picked from commit a69a7a33268308ddcc9abf0f7d7cd61ec4300cbe) +--- + drivers/media/v4l2-core/v4l2-ioctl.c | 14 ++++++++++---- + 1 file changed, 10 insertions(+), 4 deletions(-) + +diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c +index 5e057f798a15..ccf947632a3b 100644 +--- a/drivers/media/v4l2-core/v4l2-ioctl.c ++++ b/drivers/media/v4l2-core/v4l2-ioctl.c +@@ -582,7 +582,10 @@ static void v4l_print_querymenu(const void *arg, bool write_only) + static void v4l_print_control(const void *arg, bool write_only) + { + const struct v4l2_control *p = arg; ++ const char *name = v4l2_ctrl_get_name(p->id); + ++ if (name) ++ pr_cont("name=%s, ", name); + pr_cont("id=0x%x, value=%d\n", p->id, p->value); + } + +@@ -594,12 +597,15 @@ static void v4l_print_ext_controls(const void *arg, bool write_only) + pr_cont("which=0x%x, count=%d, error_idx=%d, request_fd=%d", + p->which, p->count, p->error_idx, p->request_fd); + for (i = 0; i < p->count; i++) { ++ unsigned int id = p->controls[i].id; ++ const char *name = v4l2_ctrl_get_name(id); ++ ++ if (name) ++ pr_cont(", name=%s", name); + if (!p->controls[i].size) +- pr_cont(", id/val=0x%x/0x%x", +- p->controls[i].id, p->controls[i].value); ++ pr_cont(", id/val=0x%x/0x%x", id, p->controls[i].value); + else +- pr_cont(", id/size=0x%x/%u", +- p->controls[i].id, p->controls[i].size); ++ pr_cont(", id/size=0x%x/%u", id, p->controls[i].size); + } + pr_cont("\n"); + } + +From d524e0ef051dcccefbdff08e1023489922da198f Mon Sep 17 00:00:00 2001 +From: Ezequiel Garcia +Date: Wed, 24 Jun 2020 21:28:00 +0200 +Subject: [PATCH] media: Add V4L2_TYPE_IS_CAPTURE helper + +It's all too easy to get confused by the V4L2_TYPE_IS_OUTPUT +macro, when it's used as !V4L2_TYPE_IS_OUTPUT. + +Reduce the risk of confusion with macro to explicitly +check for the CAPTURE queue type case. + +This change does not affect functionality, and it's +only intended to make the code more readable. + +Suggested-by: Nicolas Dufresne +Signed-off-by: Ezequiel Garcia +Signed-off-by: Hans Verkuil +[hverkuil-cisco@xs4all.nl: checkpatch: align with parenthesis] +Signed-off-by: Mauro Carvalho Chehab +(cherry picked from commit b3ab1c6058fad8cd5726f24e9ed9053e43bb2af4) +--- + drivers/media/common/videobuf2/videobuf2-v4l2.c | 4 ++-- + drivers/media/platform/exynos-gsc/gsc-core.c | 2 +- + drivers/media/platform/exynos-gsc/gsc-m2m.c | 2 +- + drivers/media/platform/mtk-jpeg/mtk_jpeg_core.c | 2 +- + drivers/media/platform/mtk-mdp/mtk_mdp_m2m.c | 7 +++---- + drivers/media/platform/rcar_jpu.c | 2 +- + drivers/media/platform/sti/hva/hva-v4l2.c | 2 +- + drivers/media/platform/ti-vpe/vpe.c | 2 +- + drivers/media/test-drivers/vicodec/vicodec-core.c | 6 +++--- + drivers/media/v4l2-core/v4l2-mem2mem.c | 6 +++--- + drivers/staging/media/hantro/hantro_v4l2.c | 2 +- + drivers/staging/media/rkvdec/rkvdec.c | 2 +- + include/uapi/linux/videodev2.h | 2 ++ + 13 files changed, 21 insertions(+), 20 deletions(-) + +diff --git a/drivers/media/common/videobuf2/videobuf2-v4l2.c b/drivers/media/common/videobuf2/videobuf2-v4l2.c +index eb5d5db96552..fd32c2e64809 100644 +--- a/drivers/media/common/videobuf2/videobuf2-v4l2.c ++++ b/drivers/media/common/videobuf2/videobuf2-v4l2.c +@@ -94,7 +94,7 @@ static int __verify_length(struct vb2_buffer *vb, const struct v4l2_buffer *b) + unsigned int bytesused; + unsigned int plane; + +- if (!V4L2_TYPE_IS_OUTPUT(b->type)) ++ if (V4L2_TYPE_IS_CAPTURE(b->type)) + return 0; + + if (V4L2_TYPE_IS_MULTIPLANAR(b->type)) { +@@ -307,7 +307,7 @@ static int vb2_fill_vb2_v4l2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b + + /* Zero flags that we handle */ + vbuf->flags = b->flags & ~V4L2_BUFFER_MASK_FLAGS; +- if (!vb->vb2_queue->copy_timestamp || !V4L2_TYPE_IS_OUTPUT(b->type)) { ++ if (!vb->vb2_queue->copy_timestamp || V4L2_TYPE_IS_CAPTURE(b->type)) { + /* + * Non-COPY timestamps and non-OUTPUT queues will get + * their timestamp and timestamp source flags from the +diff --git a/drivers/media/platform/exynos-gsc/gsc-core.c b/drivers/media/platform/exynos-gsc/gsc-core.c +index f6650b45bc3d..9f41c2e7097a 100644 +--- a/drivers/media/platform/exynos-gsc/gsc-core.c ++++ b/drivers/media/platform/exynos-gsc/gsc-core.c +@@ -577,7 +577,7 @@ int gsc_try_selection(struct gsc_ctx *ctx, struct v4l2_selection *s) + v4l_bound_align_image(&tmp_w, min_w, max_w, mod_x, + &tmp_h, min_h, max_h, mod_y, 0); + +- if (!V4L2_TYPE_IS_OUTPUT(s->type) && ++ if (V4L2_TYPE_IS_CAPTURE(s->type) && + (ctx->gsc_ctrls.rotate->val == 90 || + ctx->gsc_ctrls.rotate->val == 270)) + gsc_check_crop_change(tmp_h, tmp_w, +diff --git a/drivers/media/platform/exynos-gsc/gsc-m2m.c b/drivers/media/platform/exynos-gsc/gsc-m2m.c +index e2c162635f72..27a3c92c73bc 100644 +--- a/drivers/media/platform/exynos-gsc/gsc-m2m.c ++++ b/drivers/media/platform/exynos-gsc/gsc-m2m.c +@@ -255,7 +255,7 @@ static int gsc_m2m_buf_prepare(struct vb2_buffer *vb) + if (IS_ERR(frame)) + return PTR_ERR(frame); + +- if (!V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type)) { ++ if (V4L2_TYPE_IS_CAPTURE(vb->vb2_queue->type)) { + for (i = 0; i < frame->fmt->num_planes; i++) + vb2_set_plane_payload(vb, i, frame->payload[i]); + } +diff --git a/drivers/media/platform/mtk-jpeg/mtk_jpeg_core.c b/drivers/media/platform/mtk-jpeg/mtk_jpeg_core.c +index f82a81a3bdee..61fed1e35a00 100644 +--- a/drivers/media/platform/mtk-jpeg/mtk_jpeg_core.c ++++ b/drivers/media/platform/mtk-jpeg/mtk_jpeg_core.c +@@ -731,7 +731,7 @@ static void mtk_jpeg_stop_streaming(struct vb2_queue *q) + * subsampling. Update capture queue when the stream is off. + */ + if (ctx->state == MTK_JPEG_SOURCE_CHANGE && +- !V4L2_TYPE_IS_OUTPUT(q->type)) { ++ V4L2_TYPE_IS_CAPTURE(q->type)) { + struct mtk_jpeg_src_buf *src_buf; + + vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); +diff --git a/drivers/media/platform/mtk-mdp/mtk_mdp_m2m.c b/drivers/media/platform/mtk-mdp/mtk_mdp_m2m.c +index 821f2cf325f0..a6ea22b57416 100644 +--- a/drivers/media/platform/mtk-mdp/mtk_mdp_m2m.c ++++ b/drivers/media/platform/mtk-mdp/mtk_mdp_m2m.c +@@ -193,7 +193,7 @@ static const struct mtk_mdp_fmt *mtk_mdp_try_fmt_mplane(struct mtk_mdp_ctx *ctx, + + pix_mp->field = V4L2_FIELD_NONE; + pix_mp->pixelformat = fmt->pixelformat; +- if (!V4L2_TYPE_IS_OUTPUT(f->type)) { ++ if (V4L2_TYPE_IS_CAPTURE(f->type)) { + pix_mp->colorspace = ctx->colorspace; + pix_mp->xfer_func = ctx->xfer_func; + pix_mp->ycbcr_enc = ctx->ycbcr_enc; +@@ -327,9 +327,8 @@ static int mtk_mdp_try_crop(struct mtk_mdp_ctx *ctx, u32 type, + mtk_mdp_bound_align_image(&new_w, min_w, max_w, align_w, + &new_h, min_h, max_h, align_h); + +- if (!V4L2_TYPE_IS_OUTPUT(type) && +- (ctx->ctrls.rotate->val == 90 || +- ctx->ctrls.rotate->val == 270)) ++ if (V4L2_TYPE_IS_CAPTURE(type) && ++ (ctx->ctrls.rotate->val == 90 || ctx->ctrls.rotate->val == 270)) + mtk_mdp_check_crop_change(new_h, new_w, + &r->width, &r->height); + else +diff --git a/drivers/media/platform/rcar_jpu.c b/drivers/media/platform/rcar_jpu.c +index 5250a14324e9..9b99ff368698 100644 +--- a/drivers/media/platform/rcar_jpu.c ++++ b/drivers/media/platform/rcar_jpu.c +@@ -1066,7 +1066,7 @@ static int jpu_buf_prepare(struct vb2_buffer *vb) + } + + /* decoder capture queue */ +- if (!ctx->encoder && !V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type)) ++ if (!ctx->encoder && V4L2_TYPE_IS_CAPTURE(vb->vb2_queue->type)) + vb2_set_plane_payload(vb, i, size); + } + +diff --git a/drivers/media/platform/sti/hva/hva-v4l2.c b/drivers/media/platform/sti/hva/hva-v4l2.c +index 197b99d8fd9c..bb34d6997d99 100644 +--- a/drivers/media/platform/sti/hva/hva-v4l2.c ++++ b/drivers/media/platform/sti/hva/hva-v4l2.c +@@ -1087,7 +1087,7 @@ static void hva_stop_streaming(struct vb2_queue *vq) + + if ((V4L2_TYPE_IS_OUTPUT(vq->type) && + vb2_is_streaming(&ctx->fh.m2m_ctx->cap_q_ctx.q)) || +- (!V4L2_TYPE_IS_OUTPUT(vq->type) && ++ (V4L2_TYPE_IS_CAPTURE(vq->type) && + vb2_is_streaming(&ctx->fh.m2m_ctx->out_q_ctx.q))) { + dev_dbg(dev, "%s %s out=%d cap=%d\n", + ctx->name, to_type_str(vq->type), +diff --git a/drivers/media/platform/ti-vpe/vpe.c b/drivers/media/platform/ti-vpe/vpe.c +index cff2fcd6d812..346f8212791c 100644 +--- a/drivers/media/platform/ti-vpe/vpe.c ++++ b/drivers/media/platform/ti-vpe/vpe.c +@@ -1576,7 +1576,7 @@ static int vpe_g_fmt(struct file *file, void *priv, struct v4l2_format *f) + + *f = q_data->format; + +- if (!V4L2_TYPE_IS_OUTPUT(f->type)) { ++ if (V4L2_TYPE_IS_CAPTURE(f->type)) { + struct vpe_q_data *s_q_data; + struct v4l2_pix_format_mplane *spix; + +diff --git a/drivers/media/test-drivers/vicodec/vicodec-core.c b/drivers/media/test-drivers/vicodec/vicodec-core.c +index e879290727ef..8941d73f6611 100644 +--- a/drivers/media/test-drivers/vicodec/vicodec-core.c ++++ b/drivers/media/test-drivers/vicodec/vicodec-core.c +@@ -1442,7 +1442,7 @@ static void vicodec_buf_queue(struct vb2_buffer *vb) + .u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION, + }; + +- if (!V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type) && ++ if (V4L2_TYPE_IS_CAPTURE(vb->vb2_queue->type) && + vb2_is_streaming(vb->vb2_queue) && + v4l2_m2m_dst_buf_is_last(ctx->fh.m2m_ctx)) { + unsigned int i; +@@ -1479,7 +1479,7 @@ static void vicodec_buf_queue(struct vb2_buffer *vb) + * in the compressed stream + */ + if (ctx->is_stateless || ctx->is_enc || +- !V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type)) { ++ V4L2_TYPE_IS_CAPTURE(vb->vb2_queue->type)) { + v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf); + return; + } +@@ -1574,7 +1574,7 @@ static int vicodec_start_streaming(struct vb2_queue *q, + state->gop_cnt = 0; + + if ((V4L2_TYPE_IS_OUTPUT(q->type) && !ctx->is_enc) || +- (!V4L2_TYPE_IS_OUTPUT(q->type) && ctx->is_enc)) ++ (V4L2_TYPE_IS_CAPTURE(q->type) && ctx->is_enc)) + return 0; + + if (info->id == V4L2_PIX_FMT_FWHT || +diff --git a/drivers/media/v4l2-core/v4l2-mem2mem.c b/drivers/media/v4l2-core/v4l2-mem2mem.c +index 62ac9424c92a..95a8f2dc5341 100644 +--- a/drivers/media/v4l2-core/v4l2-mem2mem.c ++++ b/drivers/media/v4l2-core/v4l2-mem2mem.c +@@ -556,7 +556,7 @@ int v4l2_m2m_querybuf(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, + ret = vb2_querybuf(vq, buf); + + /* Adjust MMAP memory offsets for the CAPTURE queue */ +- if (buf->memory == V4L2_MEMORY_MMAP && !V4L2_TYPE_IS_OUTPUT(vq->type)) { ++ if (buf->memory == V4L2_MEMORY_MMAP && V4L2_TYPE_IS_CAPTURE(vq->type)) { + if (V4L2_TYPE_IS_MULTIPLANAR(vq->type)) { + for (i = 0; i < buf->length; ++i) + buf->m.planes[i].m.mem_offset +@@ -712,7 +712,7 @@ int v4l2_m2m_qbuf(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, + int ret; + + vq = v4l2_m2m_get_vq(m2m_ctx, buf->type); +- if (!V4L2_TYPE_IS_OUTPUT(vq->type) && ++ if (V4L2_TYPE_IS_CAPTURE(vq->type) && + (buf->flags & V4L2_BUF_FLAG_REQUEST_FD)) { + dprintk("%s: requests cannot be used with capture buffers\n", + __func__); +@@ -729,7 +729,7 @@ int v4l2_m2m_qbuf(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, + * buffer as DONE with LAST flag since it won't be queued on the + * device. + */ +- if (!V4L2_TYPE_IS_OUTPUT(vq->type) && ++ if (V4L2_TYPE_IS_CAPTURE(vq->type) && + vb2_is_streaming(vq) && !vb2_start_streaming_called(vq) && + (v4l2_m2m_has_stopped(m2m_ctx) || v4l2_m2m_dst_buf_is_last(m2m_ctx))) + v4l2_m2m_force_last_buf_done(m2m_ctx, vq); +diff --git a/drivers/staging/media/hantro/hantro_v4l2.c b/drivers/staging/media/hantro/hantro_v4l2.c +index f28a94e2fa93..63859e8a0923 100644 +--- a/drivers/staging/media/hantro/hantro_v4l2.c ++++ b/drivers/staging/media/hantro/hantro_v4l2.c +@@ -237,7 +237,7 @@ static int hantro_try_fmt(const struct hantro_ctx *ctx, + enum v4l2_buf_type type) + { + const struct hantro_fmt *fmt, *vpu_fmt; +- bool capture = !V4L2_TYPE_IS_OUTPUT(type); ++ bool capture = V4L2_TYPE_IS_CAPTURE(type); + bool coded; + + coded = capture == hantro_is_encoder_ctx(ctx); +diff --git a/drivers/staging/media/rkvdec/rkvdec.c b/drivers/staging/media/rkvdec/rkvdec.c +index 225eeca73356..fd68671f0286 100644 +--- a/drivers/staging/media/rkvdec/rkvdec.c ++++ b/drivers/staging/media/rkvdec/rkvdec.c +@@ -489,7 +489,7 @@ static int rkvdec_start_streaming(struct vb2_queue *q, unsigned int count) + const struct rkvdec_coded_fmt_desc *desc; + int ret; + +- if (!V4L2_TYPE_IS_OUTPUT(q->type)) ++ if (V4L2_TYPE_IS_CAPTURE(q->type)) + return 0; + + desc = ctx->coded_fmt_desc; +diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h +index c3a1cf1c507f..6fe8822d2cb4 100644 +--- a/include/uapi/linux/videodev2.h ++++ b/include/uapi/linux/videodev2.h +@@ -171,6 +171,8 @@ enum v4l2_buf_type { + || (type) == V4L2_BUF_TYPE_SDR_OUTPUT \ + || (type) == V4L2_BUF_TYPE_META_OUTPUT) + ++#define V4L2_TYPE_IS_CAPTURE(type) (!V4L2_TYPE_IS_OUTPUT(type)) ++ + enum v4l2_tuner_type { + V4L2_TUNER_RADIO = 1, + V4L2_TUNER_ANALOG_TV = 2, + +From 728f96ea31862791706eb9390cb865e4fd8fa09d Mon Sep 17 00:00:00 2001 +From: Ezequiel Garcia +Date: Wed, 1 Jul 2020 15:16:02 +0200 +Subject: [PATCH] hantro: h264: Remove unused macro definition + +The generic H264 reference list builder moved all +the users of this macro, but left the macro. + +Remove it. + +Signed-off-by: Ezequiel Garcia +Reviewed-by: Philipp Zabel +Signed-off-by: Hans Verkuil +Signed-off-by: Mauro Carvalho Chehab +(cherry picked from commit 3ebf271b1dee6df816bd8f2135218640c478dedd) +--- + drivers/staging/media/hantro/hantro_h264.c | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/drivers/staging/media/hantro/hantro_h264.c b/drivers/staging/media/hantro/hantro_h264.c +index d561f125085a..dd935d7009bf 100644 +--- a/drivers/staging/media/hantro/hantro_h264.c ++++ b/drivers/staging/media/hantro/hantro_h264.c +@@ -22,8 +22,6 @@ + #define POC_BUFFER_SIZE 34 + #define SCALING_LIST_SIZE (6 * 16 + 2 * 64) + +-#define HANTRO_CMP(a, b) ((a) < (b) ? -1 : 1) +- + /* Data structure describing auxiliary buffer format. */ + struct hantro_h264_dec_priv_tbl { + u32 cabac_table[CABAC_INIT_BUFFER_SIZE]; + +From ad6f6337541843af2f943f603636f64a6a55e215 Mon Sep 17 00:00:00 2001 +From: Ezequiel Garcia +Date: Wed, 1 Jul 2020 15:16:03 +0200 +Subject: [PATCH] hantro: h264: Rename scaling list handling function + +Commit e17f08e31666 ("media: hantro: Do not reorder +H264 scaling list") removed the scaling list reordering, +which was wrong and not needed. + +However, the name of the function stayed, which is +confusing for anyone reading the code. Rename +from "reorder" to "assemble" which is cleaner. + +This is just a cosmetic cleanup. + +Signed-off-by: Ezequiel Garcia +Reviewed-by: Philipp Zabel +Signed-off-by: Hans Verkuil +Signed-off-by: Mauro Carvalho Chehab +(cherry picked from commit 4df3a47e3422a9de1f3ce1a4ba8a0447a73e7567) +--- + drivers/staging/media/hantro/hantro_h264.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/staging/media/hantro/hantro_h264.c b/drivers/staging/media/hantro/hantro_h264.c +index dd935d7009bf..194d05848077 100644 +--- a/drivers/staging/media/hantro/hantro_h264.c ++++ b/drivers/staging/media/hantro/hantro_h264.c +@@ -193,7 +193,7 @@ static const u32 h264_cabac_table[] = { + }; + + static void +-reorder_scaling_list(struct hantro_ctx *ctx) ++assemble_scaling_list(struct hantro_ctx *ctx) + { + const struct hantro_h264_dec_ctrls *ctrls = &ctx->h264_dec.ctrls; + const struct v4l2_ctrl_h264_scaling_matrix *scaling = ctrls->scaling; +@@ -235,7 +235,7 @@ static void prepare_table(struct hantro_ctx *ctx) + tbl->poc[32] = dec_param->top_field_order_cnt; + tbl->poc[33] = dec_param->bottom_field_order_cnt; + +- reorder_scaling_list(ctx); ++ assemble_scaling_list(ctx); + } + + static bool dpb_entry_match(const struct v4l2_h264_dpb_entry *a, + +From 63c05ac390a6fb9d4930804931732630dd0e20ac Mon Sep 17 00:00:00 2001 +From: Ezequiel Garcia +Date: Wed, 1 Jul 2020 15:16:04 +0200 +Subject: [PATCH] hantro: Rework how encoder and decoder are identified + +So far we've been using the .buf_finish hook to distinguish +decoder from encoder. This is unnecessarily obfuscated. + +Moreover, we want to move the buf_finish, so use a cleaner +scheme to distinguish the driver decoder/encoder type. + +Signed-off-by: Ezequiel Garcia +Reviewed-by: Philipp Zabel +Signed-off-by: Hans Verkuil +Signed-off-by: Mauro Carvalho Chehab +(cherry picked from commit 21f0315b7b3ee6ca909d81a963744671fb27bf71) +--- + drivers/staging/media/hantro/hantro.h | 6 ++--- + drivers/staging/media/hantro/hantro_drv.c | 9 +++---- + drivers/staging/media/hantro/hantro_v4l2.c | 28 +++++++++++----------- + 3 files changed, 20 insertions(+), 23 deletions(-) + +diff --git a/drivers/staging/media/hantro/hantro.h b/drivers/staging/media/hantro/hantro.h +index 3005207fc6fb..2284e23d8500 100644 +--- a/drivers/staging/media/hantro/hantro.h ++++ b/drivers/staging/media/hantro/hantro.h +@@ -199,6 +199,7 @@ struct hantro_dev { + * + * @dev: VPU driver data to which the context belongs. + * @fh: V4L2 file handler. ++ * @is_encoder: Decoder or encoder context? + * + * @sequence_cap: Sequence counter for capture queue + * @sequence_out: Sequence counter for output queue +@@ -223,6 +224,7 @@ struct hantro_dev { + struct hantro_ctx { + struct hantro_dev *dev; + struct v4l2_fh fh; ++ bool is_encoder; + + u32 sequence_cap; + u32 sequence_out; +@@ -399,8 +401,6 @@ static inline void hantro_reg_write_s(struct hantro_dev *vpu, + vdpu_write(vpu, vdpu_read_mask(vpu, reg, val), reg->base); + } + +-bool hantro_is_encoder_ctx(const struct hantro_ctx *ctx); +- + void *hantro_get_ctrl(struct hantro_ctx *ctx, u32 id); + dma_addr_t hantro_get_ref(struct hantro_ctx *ctx, u64 ts); + +@@ -420,7 +420,7 @@ static inline bool + hantro_needs_postproc(const struct hantro_ctx *ctx, + const struct hantro_fmt *fmt) + { +- return !hantro_is_encoder_ctx(ctx) && fmt->fourcc != V4L2_PIX_FMT_NV12; ++ return !ctx->is_encoder && fmt->fourcc != V4L2_PIX_FMT_NV12; + } + + static inline dma_addr_t +diff --git a/drivers/staging/media/hantro/hantro_drv.c b/drivers/staging/media/hantro/hantro_drv.c +index 0db8ad455160..9145d02e5d3c 100644 +--- a/drivers/staging/media/hantro/hantro_drv.c ++++ b/drivers/staging/media/hantro/hantro_drv.c +@@ -195,11 +195,6 @@ static void device_run(void *priv) + hantro_job_finish(ctx->dev, ctx, 0, VB2_BUF_STATE_ERROR); + } + +-bool hantro_is_encoder_ctx(const struct hantro_ctx *ctx) +-{ +- return ctx->buf_finish == hantro_enc_buf_finish; +-} +- + static struct v4l2_m2m_ops vpu_m2m_ops = { + .device_run = device_run, + }; +@@ -240,7 +235,7 @@ queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq) + * + * For the DMA destination buffer, we use a bounce buffer. + */ +- if (hantro_is_encoder_ctx(ctx)) { ++ if (ctx->is_encoder) { + dst_vq->mem_ops = &vb2_vmalloc_memops; + } else { + dst_vq->bidirectional = true; +@@ -420,8 +415,10 @@ static int hantro_open(struct file *filp) + if (func->id == MEDIA_ENT_F_PROC_VIDEO_ENCODER) { + allowed_codecs = vpu->variant->codec & HANTRO_ENCODERS; + ctx->buf_finish = hantro_enc_buf_finish; ++ ctx->is_encoder = true; + } else if (func->id == MEDIA_ENT_F_PROC_VIDEO_DECODER) { + allowed_codecs = vpu->variant->codec & HANTRO_DECODERS; ++ ctx->is_encoder = false; + } else { + ret = -ENODEV; + goto err_ctx_free; +diff --git a/drivers/staging/media/hantro/hantro_v4l2.c b/drivers/staging/media/hantro/hantro_v4l2.c +index 63859e8a0923..b668a82d40ad 100644 +--- a/drivers/staging/media/hantro/hantro_v4l2.c ++++ b/drivers/staging/media/hantro/hantro_v4l2.c +@@ -40,7 +40,7 @@ hantro_get_formats(const struct hantro_ctx *ctx, unsigned int *num_fmts) + { + const struct hantro_fmt *formats; + +- if (hantro_is_encoder_ctx(ctx)) { ++ if (ctx->is_encoder) { + formats = ctx->dev->variant->enc_fmts; + *num_fmts = ctx->dev->variant->num_enc_fmts; + } else { +@@ -55,7 +55,7 @@ static const struct hantro_fmt * + hantro_get_postproc_formats(const struct hantro_ctx *ctx, + unsigned int *num_fmts) + { +- if (hantro_is_encoder_ctx(ctx)) { ++ if (ctx->is_encoder) { + *num_fmts = 0; + return NULL; + } +@@ -158,7 +158,7 @@ static int vidioc_enum_fmt(struct file *file, void *priv, + * not MODE_NONE. + * - on the output side we want to filter out all MODE_NONE formats. + */ +- skip_mode_none = capture == hantro_is_encoder_ctx(ctx); ++ skip_mode_none = capture == ctx->is_encoder; + + formats = hantro_get_formats(ctx, &num_fmts); + for (i = 0; i < num_fmts; i++) { +@@ -240,7 +240,7 @@ static int hantro_try_fmt(const struct hantro_ctx *ctx, + bool capture = V4L2_TYPE_IS_CAPTURE(type); + bool coded; + +- coded = capture == hantro_is_encoder_ctx(ctx); ++ coded = capture == ctx->is_encoder; + + vpu_debug(4, "trying format %c%c%c%c\n", + (pix_mp->pixelformat & 0x7f), +@@ -257,7 +257,7 @@ static int hantro_try_fmt(const struct hantro_ctx *ctx, + if (coded) { + pix_mp->num_planes = 1; + vpu_fmt = fmt; +- } else if (hantro_is_encoder_ctx(ctx)) { ++ } else if (ctx->is_encoder) { + vpu_fmt = ctx->vpu_dst_fmt; + } else { + vpu_fmt = ctx->vpu_src_fmt; +@@ -330,7 +330,7 @@ hantro_reset_encoded_fmt(struct hantro_ctx *ctx) + + vpu_fmt = hantro_get_default_fmt(ctx, true); + +- if (hantro_is_encoder_ctx(ctx)) { ++ if (ctx->is_encoder) { + ctx->vpu_dst_fmt = vpu_fmt; + fmt = &ctx->dst_fmt; + } else { +@@ -341,7 +341,7 @@ hantro_reset_encoded_fmt(struct hantro_ctx *ctx) + hantro_reset_fmt(fmt, vpu_fmt); + fmt->width = vpu_fmt->frmsize.min_width; + fmt->height = vpu_fmt->frmsize.min_height; +- if (hantro_is_encoder_ctx(ctx)) ++ if (ctx->is_encoder) + hantro_set_fmt_cap(ctx, fmt); + else + hantro_set_fmt_out(ctx, fmt); +@@ -355,7 +355,7 @@ hantro_reset_raw_fmt(struct hantro_ctx *ctx) + + raw_vpu_fmt = hantro_get_default_fmt(ctx, false); + +- if (hantro_is_encoder_ctx(ctx)) { ++ if (ctx->is_encoder) { + ctx->vpu_src_fmt = raw_vpu_fmt; + raw_fmt = &ctx->src_fmt; + encoded_fmt = &ctx->dst_fmt; +@@ -368,7 +368,7 @@ hantro_reset_raw_fmt(struct hantro_ctx *ctx) + hantro_reset_fmt(raw_fmt, raw_vpu_fmt); + raw_fmt->width = encoded_fmt->width; + raw_fmt->width = encoded_fmt->width; +- if (hantro_is_encoder_ctx(ctx)) ++ if (ctx->is_encoder) + hantro_set_fmt_out(ctx, raw_fmt); + else + hantro_set_fmt_cap(ctx, raw_fmt); +@@ -409,7 +409,7 @@ static int hantro_set_fmt_out(struct hantro_ctx *ctx, + if (ret) + return ret; + +- if (!hantro_is_encoder_ctx(ctx)) { ++ if (!ctx->is_encoder) { + struct vb2_queue *peer_vq; + + /* +@@ -450,7 +450,7 @@ static int hantro_set_fmt_out(struct hantro_ctx *ctx, + * Note that hantro_reset_raw_fmt() also propagates size + * changes to the raw format. + */ +- if (!hantro_is_encoder_ctx(ctx)) ++ if (!ctx->is_encoder) + hantro_reset_raw_fmt(ctx); + + /* Colorimetry information are always propagated. */ +@@ -479,7 +479,7 @@ static int hantro_set_fmt_cap(struct hantro_ctx *ctx, + if (vb2_is_busy(vq)) + return -EBUSY; + +- if (hantro_is_encoder_ctx(ctx)) { ++ if (ctx->is_encoder) { + struct vb2_queue *peer_vq; + + /* +@@ -512,7 +512,7 @@ static int hantro_set_fmt_cap(struct hantro_ctx *ctx, + * Note that hantro_reset_raw_fmt() also propagates size + * changes to the raw format. + */ +- if (hantro_is_encoder_ctx(ctx)) ++ if (ctx->is_encoder) + hantro_reset_raw_fmt(ctx); + + /* Colorimetry information are always propagated. */ +@@ -655,7 +655,7 @@ static bool hantro_vq_is_coded(struct vb2_queue *q) + { + struct hantro_ctx *ctx = vb2_get_drv_priv(q); + +- return hantro_is_encoder_ctx(ctx) != V4L2_TYPE_IS_OUTPUT(q->type); ++ return ctx->is_encoder != V4L2_TYPE_IS_OUTPUT(q->type); + } + + static int hantro_start_streaming(struct vb2_queue *q, unsigned int count) + +From 9067e59021400f6924e6fe593585bb6a561ef251 Mon Sep 17 00:00:00 2001 +From: Ezequiel Garcia +Date: Wed, 1 Jul 2020 15:16:05 +0200 +Subject: [PATCH] hantro: Move hantro_enc_buf_finish to JPEG codec_ops.done + +hantro_enc_buf_finish is used only for JPEG, and so should +be moved to JPEG codec_ops.done. + +This cleanup is also taking care of addressing +a subtle issue: checking the non-NULL bounce buffer +using ctx->jpeg_enc, which is a member of a union is +confusing and error-prone. + +Note that the issue is currently innocuous because an +encoder context only supports JPEG. + +The codec_ops.done has an argument that codec-specific code +shouldn't need, so drop that as well. + +Signed-off-by: Ezequiel Garcia +Reviewed-by: Philipp Zabel +Signed-off-by: Hans Verkuil +Signed-off-by: Mauro Carvalho Chehab +(cherry picked from commit e765dba11ec26d7ea42974ec4d470b5ce00be3de) +--- + drivers/staging/media/hantro/hantro.h | 7 ---- + drivers/staging/media/hantro/hantro_drv.c | 37 ++----------------- + .../staging/media/hantro/hantro_h1_jpeg_enc.c | 17 +++++++++ + drivers/staging/media/hantro/hantro_hw.h | 3 +- + drivers/staging/media/hantro/rk3288_vpu_hw.c | 1 + + 5 files changed, 24 insertions(+), 41 deletions(-) + +diff --git a/drivers/staging/media/hantro/hantro.h b/drivers/staging/media/hantro/hantro.h +index 2284e23d8500..65f9f7ea7dcf 100644 +--- a/drivers/staging/media/hantro/hantro.h ++++ b/drivers/staging/media/hantro/hantro.h +@@ -212,9 +212,6 @@ struct hantro_dev { + * @ctrl_handler: Control handler used to register controls. + * @jpeg_quality: User-specified JPEG compression quality. + * +- * @buf_finish: Buffer finish. This depends on encoder or decoder +- * context, and it's called right before +- * calling v4l2_m2m_job_finish. + * @codec_ops: Set of operations related to codec mode. + * @postproc: Post-processing context. + * @jpeg_enc: JPEG-encoding context. +@@ -237,10 +234,6 @@ struct hantro_ctx { + struct v4l2_ctrl_handler ctrl_handler; + int jpeg_quality; + +- int (*buf_finish)(struct hantro_ctx *ctx, +- struct vb2_buffer *buf, +- unsigned int bytesused); +- + const struct hantro_codec_ops *codec_ops; + struct hantro_postproc_ctx postproc; + +diff --git a/drivers/staging/media/hantro/hantro_drv.c b/drivers/staging/media/hantro/hantro_drv.c +index 9145d02e5d3c..88b5c5989d83 100644 +--- a/drivers/staging/media/hantro/hantro_drv.c ++++ b/drivers/staging/media/hantro/hantro_drv.c +@@ -56,37 +56,12 @@ dma_addr_t hantro_get_ref(struct hantro_ctx *ctx, u64 ts) + return hantro_get_dec_buf_addr(ctx, buf); + } + +-static int +-hantro_enc_buf_finish(struct hantro_ctx *ctx, struct vb2_buffer *buf, +- unsigned int bytesused) +-{ +- size_t avail_size; +- +- avail_size = vb2_plane_size(buf, 0) - ctx->vpu_dst_fmt->header_size; +- if (bytesused > avail_size) +- return -EINVAL; +- /* +- * The bounce buffer is only for the JPEG encoder. +- * TODO: Rework the JPEG encoder to eliminate the need +- * for a bounce buffer. +- */ +- if (ctx->jpeg_enc.bounce_buffer.cpu) { +- memcpy(vb2_plane_vaddr(buf, 0) + +- ctx->vpu_dst_fmt->header_size, +- ctx->jpeg_enc.bounce_buffer.cpu, bytesused); +- } +- buf->planes[0].bytesused = +- ctx->vpu_dst_fmt->header_size + bytesused; +- return 0; +-} +- + static void hantro_job_finish(struct hantro_dev *vpu, + struct hantro_ctx *ctx, + unsigned int bytesused, + enum vb2_buffer_state result) + { + struct vb2_v4l2_buffer *src, *dst; +- int ret; + + pm_runtime_mark_last_busy(vpu->dev); + pm_runtime_put_autosuspend(vpu->dev); +@@ -103,12 +78,6 @@ static void hantro_job_finish(struct hantro_dev *vpu, + src->sequence = ctx->sequence_out++; + dst->sequence = ctx->sequence_cap++; + +- if (ctx->buf_finish) { +- ret = ctx->buf_finish(ctx, &dst->vb2_buf, bytesused); +- if (ret) +- result = VB2_BUF_STATE_ERROR; +- } +- + v4l2_m2m_buf_done_and_job_finish(ctx->dev->m2m_dev, ctx->fh.m2m_ctx, + result); + } +@@ -124,8 +93,11 @@ void hantro_irq_done(struct hantro_dev *vpu, unsigned int bytesused, + * the timeout expired. The watchdog is running, + * and will take care of finishing the job. + */ +- if (cancel_delayed_work(&vpu->watchdog_work)) ++ if (cancel_delayed_work(&vpu->watchdog_work)) { ++ if (result == VB2_BUF_STATE_DONE && ctx->codec_ops->done) ++ ctx->codec_ops->done(ctx); + hantro_job_finish(vpu, ctx, bytesused, result); ++ } + } + + void hantro_watchdog(struct work_struct *work) +@@ -414,7 +386,6 @@ static int hantro_open(struct file *filp) + ctx->dev = vpu; + if (func->id == MEDIA_ENT_F_PROC_VIDEO_ENCODER) { + allowed_codecs = vpu->variant->codec & HANTRO_ENCODERS; +- ctx->buf_finish = hantro_enc_buf_finish; + ctx->is_encoder = true; + } else if (func->id == MEDIA_ENT_F_PROC_VIDEO_DECODER) { + allowed_codecs = vpu->variant->codec & HANTRO_DECODERS; +diff --git a/drivers/staging/media/hantro/hantro_h1_jpeg_enc.c b/drivers/staging/media/hantro/hantro_h1_jpeg_enc.c +index b22418436823..b88dc4ed06db 100644 +--- a/drivers/staging/media/hantro/hantro_h1_jpeg_enc.c ++++ b/drivers/staging/media/hantro/hantro_h1_jpeg_enc.c +@@ -137,3 +137,20 @@ void hantro_h1_jpeg_enc_run(struct hantro_ctx *ctx) + + vepu_write(vpu, reg, H1_REG_ENC_CTRL); + } ++ ++void hantro_jpeg_enc_done(struct hantro_ctx *ctx) ++{ ++ struct hantro_dev *vpu = ctx->dev; ++ u32 bytesused = vepu_read(vpu, H1_REG_STR_BUF_LIMIT) / 8; ++ struct vb2_v4l2_buffer *dst_buf = hantro_get_dst_buf(ctx); ++ ++ /* ++ * TODO: Rework the JPEG encoder to eliminate the need ++ * for a bounce buffer. ++ */ ++ memcpy(vb2_plane_vaddr(&dst_buf->vb2_buf, 0) + ++ ctx->vpu_dst_fmt->header_size, ++ ctx->jpeg_enc.bounce_buffer.cpu, bytesused); ++ vb2_set_plane_payload(&dst_buf->vb2_buf, 0, ++ ctx->vpu_dst_fmt->header_size + bytesused); ++} +diff --git a/drivers/staging/media/hantro/hantro_hw.h b/drivers/staging/media/hantro/hantro_hw.h +index 4053d8710e04..2d6323cd6732 100644 +--- a/drivers/staging/media/hantro/hantro_hw.h ++++ b/drivers/staging/media/hantro/hantro_hw.h +@@ -138,7 +138,7 @@ struct hantro_codec_ops { + int (*init)(struct hantro_ctx *ctx); + void (*exit)(struct hantro_ctx *ctx); + void (*run)(struct hantro_ctx *ctx); +- void (*done)(struct hantro_ctx *ctx, enum vb2_buffer_state); ++ void (*done)(struct hantro_ctx *ctx); + void (*reset)(struct hantro_ctx *ctx); + }; + +@@ -172,6 +172,7 @@ void hantro_h1_jpeg_enc_run(struct hantro_ctx *ctx); + void rk3399_vpu_jpeg_enc_run(struct hantro_ctx *ctx); + int hantro_jpeg_enc_init(struct hantro_ctx *ctx); + void hantro_jpeg_enc_exit(struct hantro_ctx *ctx); ++void hantro_jpeg_enc_done(struct hantro_ctx *ctx); + + dma_addr_t hantro_h264_get_ref_buf(struct hantro_ctx *ctx, + unsigned int dpb_idx); +diff --git a/drivers/staging/media/hantro/rk3288_vpu_hw.c b/drivers/staging/media/hantro/rk3288_vpu_hw.c +index 2f914b37b9e5..b1cf2abb972f 100644 +--- a/drivers/staging/media/hantro/rk3288_vpu_hw.c ++++ b/drivers/staging/media/hantro/rk3288_vpu_hw.c +@@ -180,6 +180,7 @@ static const struct hantro_codec_ops rk3288_vpu_codec_ops[] = { + .run = hantro_h1_jpeg_enc_run, + .reset = rk3288_vpu_enc_reset, + .init = hantro_jpeg_enc_init, ++ .done = hantro_jpeg_enc_done, + .exit = hantro_jpeg_enc_exit, + }, + [HANTRO_MODE_H264_DEC] = { + +From 7d3bf1fa2170bacf99bd02ccd7dc0f5fdc1fbc45 Mon Sep 17 00:00:00 2001 +From: Ezequiel Garcia +Date: Wed, 1 Jul 2020 15:16:06 +0200 +Subject: [PATCH] hantro: Remove unused bytesused argument + +The driver doesn't need the bytesused argument. + +For decoders, the plane bytesused is known and therefore, +buf_prepare is used to set it. For encoders, it's +handled by the codec_ops.done hook. + +Signed-off-by: Ezequiel Garcia +Reviewed-by: Philipp Zabel +Signed-off-by: Hans Verkuil +Signed-off-by: Mauro Carvalho Chehab +(cherry picked from commit b72a6342dd240ce8e15b7acf1c38c67a0c56092b) +--- + drivers/staging/media/hantro/hantro_drv.c | 9 ++++----- + drivers/staging/media/hantro/hantro_hw.h | 2 +- + drivers/staging/media/hantro/imx8m_vpu_hw.c | 2 +- + drivers/staging/media/hantro/rk3288_vpu_hw.c | 7 +++---- + drivers/staging/media/hantro/rk3399_vpu_hw.c | 7 +++---- + 5 files changed, 12 insertions(+), 15 deletions(-) + +diff --git a/drivers/staging/media/hantro/hantro_drv.c b/drivers/staging/media/hantro/hantro_drv.c +index 88b5c5989d83..34367b169011 100644 +--- a/drivers/staging/media/hantro/hantro_drv.c ++++ b/drivers/staging/media/hantro/hantro_drv.c +@@ -58,7 +58,6 @@ dma_addr_t hantro_get_ref(struct hantro_ctx *ctx, u64 ts) + + static void hantro_job_finish(struct hantro_dev *vpu, + struct hantro_ctx *ctx, +- unsigned int bytesused, + enum vb2_buffer_state result) + { + struct vb2_v4l2_buffer *src, *dst; +@@ -82,7 +81,7 @@ static void hantro_job_finish(struct hantro_dev *vpu, + result); + } + +-void hantro_irq_done(struct hantro_dev *vpu, unsigned int bytesused, ++void hantro_irq_done(struct hantro_dev *vpu, + enum vb2_buffer_state result) + { + struct hantro_ctx *ctx = +@@ -96,7 +95,7 @@ void hantro_irq_done(struct hantro_dev *vpu, unsigned int bytesused, + if (cancel_delayed_work(&vpu->watchdog_work)) { + if (result == VB2_BUF_STATE_DONE && ctx->codec_ops->done) + ctx->codec_ops->done(ctx); +- hantro_job_finish(vpu, ctx, bytesused, result); ++ hantro_job_finish(vpu, ctx, result); + } + } + +@@ -111,7 +110,7 @@ void hantro_watchdog(struct work_struct *work) + if (ctx) { + vpu_err("frame processing timed out!\n"); + ctx->codec_ops->reset(ctx); +- hantro_job_finish(vpu, ctx, 0, VB2_BUF_STATE_ERROR); ++ hantro_job_finish(vpu, ctx, VB2_BUF_STATE_ERROR); + } + } + +@@ -164,7 +163,7 @@ static void device_run(void *priv) + return; + + err_cancel_job: +- hantro_job_finish(ctx->dev, ctx, 0, VB2_BUF_STATE_ERROR); ++ hantro_job_finish(ctx->dev, ctx, VB2_BUF_STATE_ERROR); + } + + static struct v4l2_m2m_ops vpu_m2m_ops = { +diff --git a/drivers/staging/media/hantro/hantro_hw.h b/drivers/staging/media/hantro/hantro_hw.h +index 2d6323cd6732..f066de6b592d 100644 +--- a/drivers/staging/media/hantro/hantro_hw.h ++++ b/drivers/staging/media/hantro/hantro_hw.h +@@ -163,7 +163,7 @@ extern const u32 hantro_vp8_dec_mc_filter[8][6]; + + void hantro_watchdog(struct work_struct *work); + void hantro_run(struct hantro_ctx *ctx); +-void hantro_irq_done(struct hantro_dev *vpu, unsigned int bytesused, ++void hantro_irq_done(struct hantro_dev *vpu, + enum vb2_buffer_state result); + void hantro_start_prepare_run(struct hantro_ctx *ctx); + void hantro_end_prepare_run(struct hantro_ctx *ctx); +diff --git a/drivers/staging/media/hantro/imx8m_vpu_hw.c b/drivers/staging/media/hantro/imx8m_vpu_hw.c +index cb2420c5526e..c222de075ef4 100644 +--- a/drivers/staging/media/hantro/imx8m_vpu_hw.c ++++ b/drivers/staging/media/hantro/imx8m_vpu_hw.c +@@ -143,7 +143,7 @@ static irqreturn_t imx8m_vpu_g1_irq(int irq, void *dev_id) + vdpu_write(vpu, 0, G1_REG_INTERRUPT); + vdpu_write(vpu, G1_REG_CONFIG_DEC_CLK_GATE_E, G1_REG_CONFIG); + +- hantro_irq_done(vpu, 0, state); ++ hantro_irq_done(vpu, state); + + return IRQ_HANDLED; + } +diff --git a/drivers/staging/media/hantro/rk3288_vpu_hw.c b/drivers/staging/media/hantro/rk3288_vpu_hw.c +index b1cf2abb972f..7b299ee3e93d 100644 +--- a/drivers/staging/media/hantro/rk3288_vpu_hw.c ++++ b/drivers/staging/media/hantro/rk3288_vpu_hw.c +@@ -113,17 +113,16 @@ static irqreturn_t rk3288_vepu_irq(int irq, void *dev_id) + { + struct hantro_dev *vpu = dev_id; + enum vb2_buffer_state state; +- u32 status, bytesused; ++ u32 status; + + status = vepu_read(vpu, H1_REG_INTERRUPT); +- bytesused = vepu_read(vpu, H1_REG_STR_BUF_LIMIT) / 8; + state = (status & H1_REG_INTERRUPT_FRAME_RDY) ? + VB2_BUF_STATE_DONE : VB2_BUF_STATE_ERROR; + + vepu_write(vpu, 0, H1_REG_INTERRUPT); + vepu_write(vpu, 0, H1_REG_AXI_CTRL); + +- hantro_irq_done(vpu, bytesused, state); ++ hantro_irq_done(vpu, state); + + return IRQ_HANDLED; + } +@@ -141,7 +140,7 @@ static irqreturn_t rk3288_vdpu_irq(int irq, void *dev_id) + vdpu_write(vpu, 0, G1_REG_INTERRUPT); + vdpu_write(vpu, G1_REG_CONFIG_DEC_CLK_GATE_E, G1_REG_CONFIG); + +- hantro_irq_done(vpu, 0, state); ++ hantro_irq_done(vpu, state); + + return IRQ_HANDLED; + } +diff --git a/drivers/staging/media/hantro/rk3399_vpu_hw.c b/drivers/staging/media/hantro/rk3399_vpu_hw.c +index 9ac1f2cb6a16..7a7962cf771e 100644 +--- a/drivers/staging/media/hantro/rk3399_vpu_hw.c ++++ b/drivers/staging/media/hantro/rk3399_vpu_hw.c +@@ -92,17 +92,16 @@ static irqreturn_t rk3399_vepu_irq(int irq, void *dev_id) + { + struct hantro_dev *vpu = dev_id; + enum vb2_buffer_state state; +- u32 status, bytesused; ++ u32 status; + + status = vepu_read(vpu, VEPU_REG_INTERRUPT); +- bytesused = vepu_read(vpu, VEPU_REG_STR_BUF_LIMIT) / 8; + state = (status & VEPU_REG_INTERRUPT_FRAME_READY) ? + VB2_BUF_STATE_DONE : VB2_BUF_STATE_ERROR; + + vepu_write(vpu, 0, VEPU_REG_INTERRUPT); + vepu_write(vpu, 0, VEPU_REG_AXI_CTRL); + +- hantro_irq_done(vpu, bytesused, state); ++ hantro_irq_done(vpu, state); + + return IRQ_HANDLED; + } +@@ -120,7 +119,7 @@ static irqreturn_t rk3399_vdpu_irq(int irq, void *dev_id) + vdpu_write(vpu, 0, VDPU_REG_INTERRUPT); + vdpu_write(vpu, 0, VDPU_REG_AXI_CTRL); + +- hantro_irq_done(vpu, 0, state); ++ hantro_irq_done(vpu, state); + + return IRQ_HANDLED; + } + +From 7e6a3bfc6d6ac30204d5ad0fc6496f1c263f809b Mon Sep 17 00:00:00 2001 +From: Ezequiel Garcia +Date: Wed, 1 Jul 2020 15:16:07 +0200 +Subject: [PATCH] hantro: Make sure we don't use post-processor on an encoder + +Commit 986eee3a5234 ("media: hantro: Prevent encoders from using +post-processing") fixed hantro_needs_postproc condition, +but missed one case. Encoders don't have any post-processor +hardware block, so also can't be disabled. + +Fix it. + +Fixes: 986eee3a5234 ("media: hantro: Prevent encoders from using post-processing") +Signed-off-by: Ezequiel Garcia +Reviewed-by: Philipp Zabel +Signed-off-by: Hans Verkuil +Signed-off-by: Mauro Carvalho Chehab +(cherry picked from commit 46d7aaebbe441d5381e35d8e16df784690e65ef3) +--- + drivers/staging/media/hantro/hantro_drv.c | 10 ++++++---- + 1 file changed, 6 insertions(+), 4 deletions(-) + +diff --git a/drivers/staging/media/hantro/hantro_drv.c b/drivers/staging/media/hantro/hantro_drv.c +index 34367b169011..d32b6b1ab70b 100644 +--- a/drivers/staging/media/hantro/hantro_drv.c ++++ b/drivers/staging/media/hantro/hantro_drv.c +@@ -122,10 +122,12 @@ void hantro_start_prepare_run(struct hantro_ctx *ctx) + v4l2_ctrl_request_setup(src_buf->vb2_buf.req_obj.req, + &ctx->ctrl_handler); + +- if (hantro_needs_postproc(ctx, ctx->vpu_dst_fmt)) +- hantro_postproc_enable(ctx); +- else +- hantro_postproc_disable(ctx); ++ if (!ctx->is_encoder) { ++ if (hantro_needs_postproc(ctx, ctx->vpu_dst_fmt)) ++ hantro_postproc_enable(ctx); ++ else ++ hantro_postproc_disable(ctx); ++ } + } + + void hantro_end_prepare_run(struct hantro_ctx *ctx) + +From 1f833bbde61660aabc0320b314bab5a2f7e42d10 Mon Sep 17 00:00:00 2001 +From: Ezequiel Garcia +Date: Thu, 9 Jul 2020 18:36:34 +0200 +Subject: [PATCH] rkvdec: h264: Refuse to decode unsupported bitstream + +The hardware only supports 4:2:2, 4:2:0 or 4:0:0 (monochrome), +8-bit or 10-bit depth content. + +Verify that the SPS refers to a supported bitstream, and refuse +unsupported bitstreams by failing at TRY_EXT_CTRLS time. + +The driver is currently broken on 10-bit and 4:2:2 +so disallow those as well. + +Signed-off-by: Ezequiel Garcia +Reviewed-by: Jonas Karlman +Signed-off-by: Hans Verkuil +Signed-off-by: Mauro Carvalho Chehab +(cherry picked from commit 9363aa33f6a9acfd16f98c749f17f6c65d184670) +--- + drivers/staging/media/rkvdec/rkvdec.c | 27 +++++++++++++++++++++++++++ + 1 file changed, 27 insertions(+) + +diff --git a/drivers/staging/media/rkvdec/rkvdec.c b/drivers/staging/media/rkvdec/rkvdec.c +index fd68671f0286..c8151328fb70 100644 +--- a/drivers/staging/media/rkvdec/rkvdec.c ++++ b/drivers/staging/media/rkvdec/rkvdec.c +@@ -27,6 +27,32 @@ + #include "rkvdec.h" + #include "rkvdec-regs.h" + ++static int rkvdec_try_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ if (ctrl->id == V4L2_CID_MPEG_VIDEO_H264_SPS) { ++ const struct v4l2_ctrl_h264_sps *sps = ctrl->p_new.p_h264_sps; ++ /* ++ * TODO: The hardware supports 10-bit and 4:2:2 profiles, ++ * but it's currently broken in the driver. ++ * Reject them for now, until it's fixed. ++ */ ++ if (sps->chroma_format_idc > 1) ++ /* Only 4:0:0 and 4:2:0 are supported */ ++ return -EINVAL; ++ if (sps->bit_depth_luma_minus8 != sps->bit_depth_chroma_minus8) ++ /* Luma and chroma bit depth mismatch */ ++ return -EINVAL; ++ if (sps->bit_depth_luma_minus8 != 0) ++ /* Only 8-bit is supported */ ++ return -EINVAL; ++ } ++ return 0; ++} ++ ++static const struct v4l2_ctrl_ops rkvdec_ctrl_ops = { ++ .try_ctrl = rkvdec_try_ctrl, ++}; ++ + static const struct rkvdec_ctrl_desc rkvdec_h264_ctrl_descs[] = { + { + .per_request = true, +@@ -42,6 +68,7 @@ static const struct rkvdec_ctrl_desc rkvdec_h264_ctrl_descs[] = { + .per_request = true, + .mandatory = true, + .cfg.id = V4L2_CID_MPEG_VIDEO_H264_SPS, ++ .cfg.ops = &rkvdec_ctrl_ops, + }, + { + .per_request = true, + +From c09155eb49e230da5fa16f188677120f967bbb36 Mon Sep 17 00:00:00 2001 +From: Ezequiel Garcia +Date: Thu, 9 Jul 2020 18:36:35 +0200 +Subject: [PATCH] hantro: h264: Refuse to decode unsupported bitstream + +The hardware only supports 4:2:0 or 4:0:0 (monochrome), +8-bit depth content. + +Verify that the SPS refers to a supported bitstream, and refuse +unsupported bitstreams by failing at TRY_EXT_CTRLS time. + +Given the JPEG compression level control is the only one +that needs setting, a specific ops is provided. + +Signed-off-by: Ezequiel Garcia +Reviewed-by: Philipp Zabel +Reviewed-by: Jonas Karlman +Signed-off-by: Hans Verkuil +Signed-off-by: Mauro Carvalho Chehab +(cherry picked from commit d70cca7323442026e20c474314518c446cb4766f) +--- + drivers/staging/media/hantro/hantro_drv.c | 29 ++++++++++++++++++++--- + 1 file changed, 26 insertions(+), 3 deletions(-) + +diff --git a/drivers/staging/media/hantro/hantro_drv.c b/drivers/staging/media/hantro/hantro_drv.c +index d32b6b1ab70b..34797507f214 100644 +--- a/drivers/staging/media/hantro/hantro_drv.c ++++ b/drivers/staging/media/hantro/hantro_drv.c +@@ -229,7 +229,25 @@ queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq) + return vb2_queue_init(dst_vq); + } + +-static int hantro_s_ctrl(struct v4l2_ctrl *ctrl) ++static int hantro_try_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ if (ctrl->id == V4L2_CID_MPEG_VIDEO_H264_SPS) { ++ const struct v4l2_ctrl_h264_sps *sps = ctrl->p_new.p_h264_sps; ++ ++ if (sps->chroma_format_idc > 1) ++ /* Only 4:0:0 and 4:2:0 are supported */ ++ return -EINVAL; ++ if (sps->bit_depth_luma_minus8 != sps->bit_depth_chroma_minus8) ++ /* Luma and chroma bit depth mismatch */ ++ return -EINVAL; ++ if (sps->bit_depth_luma_minus8 != 0) ++ /* Only 8-bit is supported */ ++ return -EINVAL; ++ } ++ return 0; ++} ++ ++static int hantro_jpeg_s_ctrl(struct v4l2_ctrl *ctrl) + { + struct hantro_ctx *ctx; + +@@ -250,7 +268,11 @@ static int hantro_s_ctrl(struct v4l2_ctrl *ctrl) + } + + static const struct v4l2_ctrl_ops hantro_ctrl_ops = { +- .s_ctrl = hantro_s_ctrl, ++ .try_ctrl = hantro_try_ctrl, ++}; ++ ++static const struct v4l2_ctrl_ops hantro_jpeg_ctrl_ops = { ++ .s_ctrl = hantro_jpeg_s_ctrl, + }; + + static const struct hantro_ctrl controls[] = { +@@ -262,7 +284,7 @@ static const struct hantro_ctrl controls[] = { + .max = 100, + .step = 1, + .def = 50, +- .ops = &hantro_ctrl_ops, ++ .ops = &hantro_jpeg_ctrl_ops, + }, + }, { + .codec = HANTRO_MPEG2_DECODER, +@@ -293,6 +315,7 @@ static const struct hantro_ctrl controls[] = { + .codec = HANTRO_H264_DECODER, + .cfg = { + .id = V4L2_CID_MPEG_VIDEO_H264_SPS, ++ .ops = &hantro_ctrl_ops, + }, + }, { + .codec = HANTRO_H264_DECODER, diff --git a/patch/kernel/rk322x-dev/01-linux-0012-v4l2-from-next-from-list.patch b/patch/kernel/rk322x-dev/01-linux-0012-v4l2-from-next-from-list.patch new file mode 100644 index 000000000..c06b7447b --- /dev/null +++ b/patch/kernel/rk322x-dev/01-linux-0012-v4l2-from-next-from-list.patch @@ -0,0 +1,7852 @@ +From 337af64a63b5d8d5a60ad8302cca0bfa4d0cc4ad Mon Sep 17 00:00:00 2001 +From: Jacopo Mondi +Date: Fri, 17 Jul 2020 16:53:16 +0200 +Subject: [PATCH] media: i2c: Use the new get_mbus_config pad op + +Move the existing users of the g_mbus_config video operation to use the +newly introduced get_mbus_config pad operations. + +All the ported drivers report a static media bus configuration and do no +support s_mbus_config so the operation implementation has not changed. + +Bridge drivers needs to call the new pad operation and will receive an +-ENOICTLCMD when calling the old g_mbus_config video operation + +Signed-off-by: Jacopo Mondi +Signed-off-by: Hans Verkuil +Signed-off-by: Mauro Carvalho Chehab +--- + drivers/media/i2c/adv7180.c | 7 ++++--- + drivers/media/i2c/ml86v7667.c | 7 ++++--- + drivers/media/i2c/mt9m001.c | 7 ++++--- + drivers/media/i2c/mt9m111.c | 7 ++++--- + drivers/media/i2c/ov9640.c | 7 ++++--- + drivers/media/i2c/tc358743.c | 7 ++++--- + drivers/media/i2c/tvp5150.c | 7 ++++--- + 7 files changed, 28 insertions(+), 21 deletions(-) + +diff --git a/drivers/media/i2c/adv7180.c b/drivers/media/i2c/adv7180.c +index 00159daa6fcd..e8744efe3cf0 100644 +--- a/drivers/media/i2c/adv7180.c ++++ b/drivers/media/i2c/adv7180.c +@@ -760,8 +760,9 @@ static int adv7180_init_cfg(struct v4l2_subdev *sd, + return adv7180_set_pad_format(sd, cfg, &fmt); + } + +-static int adv7180_g_mbus_config(struct v4l2_subdev *sd, +- struct v4l2_mbus_config *cfg) ++static int adv7180_get_mbus_config(struct v4l2_subdev *sd, ++ unsigned int pad, ++ struct v4l2_mbus_config *cfg) + { + struct adv7180_state *state = to_state(sd); + +@@ -852,7 +853,6 @@ static const struct v4l2_subdev_video_ops adv7180_video_ops = { + .querystd = adv7180_querystd, + .g_input_status = adv7180_g_input_status, + .s_routing = adv7180_s_routing, +- .g_mbus_config = adv7180_g_mbus_config, + .g_pixelaspect = adv7180_g_pixelaspect, + .g_tvnorms = adv7180_g_tvnorms, + .s_stream = adv7180_s_stream, +@@ -869,6 +869,7 @@ static const struct v4l2_subdev_pad_ops adv7180_pad_ops = { + .enum_mbus_code = adv7180_enum_mbus_code, + .set_fmt = adv7180_set_pad_format, + .get_fmt = adv7180_get_pad_format, ++ .get_mbus_config = adv7180_get_mbus_config, + }; + + static const struct v4l2_subdev_sensor_ops adv7180_sensor_ops = { +diff --git a/drivers/media/i2c/ml86v7667.c b/drivers/media/i2c/ml86v7667.c +index c444bd6a0658..ff212335326a 100644 +--- a/drivers/media/i2c/ml86v7667.c ++++ b/drivers/media/i2c/ml86v7667.c +@@ -219,8 +219,9 @@ static int ml86v7667_fill_fmt(struct v4l2_subdev *sd, + return 0; + } + +-static int ml86v7667_g_mbus_config(struct v4l2_subdev *sd, +- struct v4l2_mbus_config *cfg) ++static int ml86v7667_get_mbus_config(struct v4l2_subdev *sd, ++ unsigned int pad, ++ struct v4l2_mbus_config *cfg) + { + cfg->flags = V4L2_MBUS_MASTER | V4L2_MBUS_PCLK_SAMPLE_RISING | + V4L2_MBUS_DATA_ACTIVE_HIGH; +@@ -291,13 +292,13 @@ static const struct v4l2_subdev_video_ops ml86v7667_subdev_video_ops = { + .s_std = ml86v7667_s_std, + .querystd = ml86v7667_querystd, + .g_input_status = ml86v7667_g_input_status, +- .g_mbus_config = ml86v7667_g_mbus_config, + }; + + static const struct v4l2_subdev_pad_ops ml86v7667_subdev_pad_ops = { + .enum_mbus_code = ml86v7667_enum_mbus_code, + .get_fmt = ml86v7667_fill_fmt, + .set_fmt = ml86v7667_fill_fmt, ++ .get_mbus_config = ml86v7667_get_mbus_config, + }; + + static const struct v4l2_subdev_core_ops ml86v7667_subdev_core_ops = { +diff --git a/drivers/media/i2c/mt9m001.c b/drivers/media/i2c/mt9m001.c +index 210ea76adb53..3b0ba8ed5233 100644 +--- a/drivers/media/i2c/mt9m001.c ++++ b/drivers/media/i2c/mt9m001.c +@@ -689,8 +689,9 @@ static int mt9m001_enum_mbus_code(struct v4l2_subdev *sd, + return 0; + } + +-static int mt9m001_g_mbus_config(struct v4l2_subdev *sd, +- struct v4l2_mbus_config *cfg) ++static int mt9m001_get_mbus_config(struct v4l2_subdev *sd, ++ unsigned int pad, ++ struct v4l2_mbus_config *cfg) + { + /* MT9M001 has all capture_format parameters fixed */ + cfg->flags = V4L2_MBUS_PCLK_SAMPLE_FALLING | +@@ -703,7 +704,6 @@ static int mt9m001_g_mbus_config(struct v4l2_subdev *sd, + + static const struct v4l2_subdev_video_ops mt9m001_subdev_video_ops = { + .s_stream = mt9m001_s_stream, +- .g_mbus_config = mt9m001_g_mbus_config, + }; + + static const struct v4l2_subdev_sensor_ops mt9m001_subdev_sensor_ops = { +@@ -717,6 +717,7 @@ static const struct v4l2_subdev_pad_ops mt9m001_subdev_pad_ops = { + .set_selection = mt9m001_set_selection, + .get_fmt = mt9m001_get_fmt, + .set_fmt = mt9m001_set_fmt, ++ .get_mbus_config = mt9m001_get_mbus_config, + }; + + static const struct v4l2_subdev_ops mt9m001_subdev_ops = { +diff --git a/drivers/media/i2c/mt9m111.c b/drivers/media/i2c/mt9m111.c +index 17e8253f5748..69697386ffcd 100644 +--- a/drivers/media/i2c/mt9m111.c ++++ b/drivers/media/i2c/mt9m111.c +@@ -1137,8 +1137,9 @@ static int mt9m111_init_cfg(struct v4l2_subdev *sd, + return 0; + } + +-static int mt9m111_g_mbus_config(struct v4l2_subdev *sd, +- struct v4l2_mbus_config *cfg) ++static int mt9m111_get_mbus_config(struct v4l2_subdev *sd, ++ unsigned int pad, ++ struct v4l2_mbus_config *cfg) + { + struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev); + +@@ -1155,7 +1156,6 @@ static int mt9m111_g_mbus_config(struct v4l2_subdev *sd, + } + + static const struct v4l2_subdev_video_ops mt9m111_subdev_video_ops = { +- .g_mbus_config = mt9m111_g_mbus_config, + .s_stream = mt9m111_s_stream, + .g_frame_interval = mt9m111_g_frame_interval, + .s_frame_interval = mt9m111_s_frame_interval, +@@ -1168,6 +1168,7 @@ static const struct v4l2_subdev_pad_ops mt9m111_subdev_pad_ops = { + .set_selection = mt9m111_set_selection, + .get_fmt = mt9m111_get_fmt, + .set_fmt = mt9m111_set_fmt, ++ .get_mbus_config = mt9m111_get_mbus_config, + }; + + static const struct v4l2_subdev_ops mt9m111_subdev_ops = { +diff --git a/drivers/media/i2c/ov9640.c b/drivers/media/i2c/ov9640.c +index 482609665305..0ef5af026d09 100644 +--- a/drivers/media/i2c/ov9640.c ++++ b/drivers/media/i2c/ov9640.c +@@ -648,8 +648,9 @@ static const struct v4l2_subdev_core_ops ov9640_core_ops = { + }; + + /* Request bus settings on camera side */ +-static int ov9640_g_mbus_config(struct v4l2_subdev *sd, +- struct v4l2_mbus_config *cfg) ++static int ov9640_get_mbus_config(struct v4l2_subdev *sd, ++ unsigned int pad, ++ struct v4l2_mbus_config *cfg) + { + cfg->flags = V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_MASTER | + V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_HIGH | +@@ -661,13 +662,13 @@ static int ov9640_g_mbus_config(struct v4l2_subdev *sd, + + static const struct v4l2_subdev_video_ops ov9640_video_ops = { + .s_stream = ov9640_s_stream, +- .g_mbus_config = ov9640_g_mbus_config, + }; + + static const struct v4l2_subdev_pad_ops ov9640_pad_ops = { + .enum_mbus_code = ov9640_enum_mbus_code, + .get_selection = ov9640_get_selection, + .set_fmt = ov9640_set_fmt, ++ .get_mbus_config = ov9640_get_mbus_config, + }; + + static const struct v4l2_subdev_ops ov9640_subdev_ops = { +diff --git a/drivers/media/i2c/tc358743.c b/drivers/media/i2c/tc358743.c +index dbbab75f135e..a03dcab5ce61 100644 +--- a/drivers/media/i2c/tc358743.c ++++ b/drivers/media/i2c/tc358743.c +@@ -1602,8 +1602,9 @@ static int tc358743_dv_timings_cap(struct v4l2_subdev *sd, + return 0; + } + +-static int tc358743_g_mbus_config(struct v4l2_subdev *sd, +- struct v4l2_mbus_config *cfg) ++static int tc358743_get_mbus_config(struct v4l2_subdev *sd, ++ unsigned int pad, ++ struct v4l2_mbus_config *cfg) + { + struct tc358743_state *state = to_state(sd); + +@@ -1836,7 +1837,6 @@ static const struct v4l2_subdev_video_ops tc358743_video_ops = { + .s_dv_timings = tc358743_s_dv_timings, + .g_dv_timings = tc358743_g_dv_timings, + .query_dv_timings = tc358743_query_dv_timings, +- .g_mbus_config = tc358743_g_mbus_config, + .s_stream = tc358743_s_stream, + }; + +@@ -1848,6 +1848,7 @@ static const struct v4l2_subdev_pad_ops tc358743_pad_ops = { + .set_edid = tc358743_s_edid, + .enum_dv_timings = tc358743_enum_dv_timings, + .dv_timings_cap = tc358743_dv_timings_cap, ++ .get_mbus_config = tc358743_get_mbus_config, + }; + + static const struct v4l2_subdev_ops tc358743_ops = { +diff --git a/drivers/media/i2c/tvp5150.c b/drivers/media/i2c/tvp5150.c +index 9df575238952..1c2050944b92 100644 +--- a/drivers/media/i2c/tvp5150.c ++++ b/drivers/media/i2c/tvp5150.c +@@ -1191,8 +1191,9 @@ static int tvp5150_get_selection(struct v4l2_subdev *sd, + } + } + +-static int tvp5150_g_mbus_config(struct v4l2_subdev *sd, +- struct v4l2_mbus_config *cfg) ++static int tvp5150_get_mbus_config(struct v4l2_subdev *sd, ++ unsigned int pad, ++ struct v4l2_mbus_config *cfg) + { + struct tvp5150 *decoder = to_tvp5150(sd); + +@@ -1721,7 +1722,6 @@ static const struct v4l2_subdev_video_ops tvp5150_video_ops = { + .querystd = tvp5150_querystd, + .s_stream = tvp5150_s_stream, + .s_routing = tvp5150_s_routing, +- .g_mbus_config = tvp5150_g_mbus_config, + }; + + static const struct v4l2_subdev_vbi_ops tvp5150_vbi_ops = { +@@ -1739,6 +1739,7 @@ static const struct v4l2_subdev_pad_ops tvp5150_pad_ops = { + .get_fmt = tvp5150_fill_fmt, + .get_selection = tvp5150_get_selection, + .set_selection = tvp5150_set_selection, ++ .get_mbus_config = tvp5150_get_mbus_config, + }; + + static const struct v4l2_subdev_ops tvp5150_ops = { + +From 4cc9a9a8b16549358ea377485df8fe21ea9e1bff Mon Sep 17 00:00:00 2001 +From: Jacopo Mondi +Date: Tue, 21 Jul 2020 09:53:17 +0200 +Subject: [PATCH] media: i2c: ov6650: Use new [get|set]_mbus_config ops + +Use the new get_mbus_config and set_mbus_config pad operations in place +of the video operations currently in use. + +Compared to other drivers where the same conversion has been performed, +ov6650 proved to be a bit more tricky, as the existing g_mbus_config +implementation did not report the currently applied configuration but +the set of all possible configuration options. + +Adapt the driver to support the semantic of the two newly introduced +operations: +- get_mbus_config reports the current media bus configuration +- set_mbus_config applies only changes explicitly requested and updates + the provided cfg parameter to report what has actually been applied to + the hardware. + +Compile-tested only. + +Signed-off-by: Jacopo Mondi +Signed-off-by: Hans Verkuil +Signed-off-by: Mauro Carvalho Chehab +--- + drivers/media/i2c/ov6650.c | 53 ++++++++++++++++++++++++++------------ + 1 file changed, 37 insertions(+), 16 deletions(-) + +diff --git a/drivers/media/i2c/ov6650.c b/drivers/media/i2c/ov6650.c +index 91906b94f978..48493af81198 100644 +--- a/drivers/media/i2c/ov6650.c ++++ b/drivers/media/i2c/ov6650.c +@@ -921,55 +921,74 @@ static const struct v4l2_subdev_core_ops ov6650_core_ops = { + }; + + /* Request bus settings on camera side */ +-static int ov6650_g_mbus_config(struct v4l2_subdev *sd, +- struct v4l2_mbus_config *cfg) ++static int ov6650_get_mbus_config(struct v4l2_subdev *sd, ++ unsigned int pad, ++ struct v4l2_mbus_config *cfg) + { ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ u8 comj, comf; ++ int ret; ++ ++ ret = ov6650_reg_read(client, REG_COMJ, &comj); ++ if (ret) ++ return ret; + +- cfg->flags = V4L2_MBUS_MASTER | +- V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_PCLK_SAMPLE_FALLING | +- V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_LOW | +- V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_LOW | +- V4L2_MBUS_DATA_ACTIVE_HIGH; ++ ret = ov6650_reg_read(client, REG_COMF, &comf); ++ if (ret) ++ return ret; ++ ++ cfg->flags = V4L2_MBUS_MASTER | V4L2_MBUS_DATA_ACTIVE_HIGH ++ | ((comj & COMJ_VSYNC_HIGH) ? V4L2_MBUS_VSYNC_ACTIVE_HIGH ++ : V4L2_MBUS_VSYNC_ACTIVE_LOW) ++ | ((comf & COMF_HREF_LOW) ? V4L2_MBUS_HSYNC_ACTIVE_LOW ++ : V4L2_MBUS_HSYNC_ACTIVE_HIGH) ++ | ((comj & COMJ_PCLK_RISING) ? V4L2_MBUS_PCLK_SAMPLE_RISING ++ : V4L2_MBUS_PCLK_SAMPLE_FALLING); + cfg->type = V4L2_MBUS_PARALLEL; + + return 0; + } + + /* Alter bus settings on camera side */ +-static int ov6650_s_mbus_config(struct v4l2_subdev *sd, +- const struct v4l2_mbus_config *cfg) ++static int ov6650_set_mbus_config(struct v4l2_subdev *sd, ++ unsigned int pad, ++ struct v4l2_mbus_config *cfg) + { + struct i2c_client *client = v4l2_get_subdevdata(sd); +- int ret; ++ int ret = 0; + + if (cfg->flags & V4L2_MBUS_PCLK_SAMPLE_RISING) + ret = ov6650_reg_rmw(client, REG_COMJ, COMJ_PCLK_RISING, 0); +- else ++ else if (cfg->flags & V4L2_MBUS_PCLK_SAMPLE_FALLING) + ret = ov6650_reg_rmw(client, REG_COMJ, 0, COMJ_PCLK_RISING); + if (ret) + return ret; + + if (cfg->flags & V4L2_MBUS_HSYNC_ACTIVE_LOW) + ret = ov6650_reg_rmw(client, REG_COMF, COMF_HREF_LOW, 0); +- else ++ else if (cfg->flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH) + ret = ov6650_reg_rmw(client, REG_COMF, 0, COMF_HREF_LOW); + if (ret) + return ret; + + if (cfg->flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH) + ret = ov6650_reg_rmw(client, REG_COMJ, COMJ_VSYNC_HIGH, 0); +- else ++ else if (cfg->flags & V4L2_MBUS_VSYNC_ACTIVE_LOW) + ret = ov6650_reg_rmw(client, REG_COMJ, 0, COMJ_VSYNC_HIGH); ++ if (ret) ++ return ret; + +- return ret; ++ /* ++ * Update the configuration to report what is actually applied to ++ * the hardware. ++ */ ++ return ov6650_get_mbus_config(sd, pad, cfg); + } + + static const struct v4l2_subdev_video_ops ov6650_video_ops = { + .s_stream = ov6650_s_stream, + .g_frame_interval = ov6650_g_frame_interval, + .s_frame_interval = ov6650_s_frame_interval, +- .g_mbus_config = ov6650_g_mbus_config, +- .s_mbus_config = ov6650_s_mbus_config, + }; + + static const struct v4l2_subdev_pad_ops ov6650_pad_ops = { +@@ -978,6 +997,8 @@ static const struct v4l2_subdev_pad_ops ov6650_pad_ops = { + .set_selection = ov6650_set_selection, + .get_fmt = ov6650_get_fmt, + .set_fmt = ov6650_set_fmt, ++ .get_mbus_config = ov6650_get_mbus_config, ++ .set_mbus_config = ov6650_set_mbus_config, + }; + + static const struct v4l2_subdev_ops ov6650_subdev_ops = { + +From 9b55924aa37a4ba85f84b8c4e382efffdf2b73df Mon Sep 17 00:00:00 2001 +From: Jacopo Mondi +Date: Fri, 17 Jul 2020 16:53:18 +0200 +Subject: [PATCH] media: pxa_camera: Use the new set_mbus_config op + +Move the PXA camera driver to use the new set_mbus_config pad operation. +For this platform the change is not only cosmetic, as the pxa driver is +currently the only driver in mainline to make use of the g_mbus_config +and s_mbus_config video operations. + +The existing driver semantic is the following: +- Collect all supported mbus config flags from the remote end +- Match them with the supported PXA mbus configuration flags +- If the remote subdevice allows multiple options for for VSYNC, HSYNC + and PCLK polarity, use platform data requested settings + +The semantic of the new get_mbus_config and set_mbus_config differs from +the corresponding video ops, particularly in the fact get_mbus_config +reports the current mbus configuration and not the set of supported +configuration options, with set_mbus_config always reporting the actual +mbus configuration applied to the remote subdevice. + +Adapt the driver to perform the following +- Set the remote subdevice mbus configuration according to the PXA + platform data preferences. +- If the applied configuration differs from the requested one (i.e. the + remote subdevice does not allow changing one setting) make sure that + - The remote end does not claim for DATA_ACTIVE_LOW, which seems not + supported by the platform + - The bus mastering roles match + +While at there remove a few checks performed on the media bus +configuration at get_format() time as they do not belong there. + +Compile-tested only. + +Signed-off-by: Jacopo Mondi +Signed-off-by: Hans Verkuil +Signed-off-by: Mauro Carvalho Chehab +--- + drivers/media/platform/pxa_camera.c | 189 ++++++++-------------------- + 1 file changed, 51 insertions(+), 138 deletions(-) + +diff --git a/drivers/media/platform/pxa_camera.c b/drivers/media/platform/pxa_camera.c +index 3c5fe737d36f..3a2cd28178da 100644 +--- a/drivers/media/platform/pxa_camera.c ++++ b/drivers/media/platform/pxa_camera.c +@@ -605,42 +605,6 @@ static const struct pxa_mbus_pixelfmt *pxa_mbus_get_fmtdesc( + return pxa_mbus_find_fmtdesc(code, mbus_fmt, ARRAY_SIZE(mbus_fmt)); + } + +-static unsigned int pxa_mbus_config_compatible(const struct v4l2_mbus_config *cfg, +- unsigned int flags) +-{ +- unsigned long common_flags; +- bool hsync = true, vsync = true, pclk, data, mode; +- bool mipi_lanes, mipi_clock; +- +- common_flags = cfg->flags & flags; +- +- switch (cfg->type) { +- case V4L2_MBUS_PARALLEL: +- hsync = common_flags & (V4L2_MBUS_HSYNC_ACTIVE_HIGH | +- V4L2_MBUS_HSYNC_ACTIVE_LOW); +- vsync = common_flags & (V4L2_MBUS_VSYNC_ACTIVE_HIGH | +- V4L2_MBUS_VSYNC_ACTIVE_LOW); +- /* fall through */ +- case V4L2_MBUS_BT656: +- pclk = common_flags & (V4L2_MBUS_PCLK_SAMPLE_RISING | +- V4L2_MBUS_PCLK_SAMPLE_FALLING); +- data = common_flags & (V4L2_MBUS_DATA_ACTIVE_HIGH | +- V4L2_MBUS_DATA_ACTIVE_LOW); +- mode = common_flags & (V4L2_MBUS_MASTER | V4L2_MBUS_SLAVE); +- return (!hsync || !vsync || !pclk || !data || !mode) ? +- 0 : common_flags; +- case V4L2_MBUS_CSI2_DPHY: +- mipi_lanes = common_flags & V4L2_MBUS_CSI2_LANES; +- mipi_clock = common_flags & (V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK | +- V4L2_MBUS_CSI2_CONTINUOUS_CLOCK); +- return (!mipi_lanes || !mipi_clock) ? 0 : common_flags; +- default: +- WARN_ON(1); +- return -EINVAL; +- } +- return 0; +-} +- + /** + * struct pxa_camera_format_xlate - match between host and sensor formats + * @code: code of a sensor provided format +@@ -1231,31 +1195,6 @@ static irqreturn_t pxa_camera_irq(int irq, void *data) + return IRQ_HANDLED; + } + +-static int test_platform_param(struct pxa_camera_dev *pcdev, +- unsigned char buswidth, unsigned long *flags) +-{ +- /* +- * Platform specified synchronization and pixel clock polarities are +- * only a recommendation and are only used during probing. The PXA270 +- * quick capture interface supports both. +- */ +- *flags = (pcdev->platform_flags & PXA_CAMERA_MASTER ? +- V4L2_MBUS_MASTER : V4L2_MBUS_SLAVE) | +- V4L2_MBUS_HSYNC_ACTIVE_HIGH | +- V4L2_MBUS_HSYNC_ACTIVE_LOW | +- V4L2_MBUS_VSYNC_ACTIVE_HIGH | +- V4L2_MBUS_VSYNC_ACTIVE_LOW | +- V4L2_MBUS_DATA_ACTIVE_HIGH | +- V4L2_MBUS_PCLK_SAMPLE_RISING | +- V4L2_MBUS_PCLK_SAMPLE_FALLING; +- +- /* If requested data width is supported by the platform, use it */ +- if ((1 << (buswidth - 1)) & pcdev->width_flags) +- return 0; +- +- return -EINVAL; +-} +- + static void pxa_camera_setup_cicr(struct pxa_camera_dev *pcdev, + unsigned long flags, __u32 pixfmt) + { +@@ -1598,99 +1537,78 @@ static int pxa_camera_init_videobuf2(struct pxa_camera_dev *pcdev) + */ + static int pxa_camera_set_bus_param(struct pxa_camera_dev *pcdev) + { ++ unsigned int bus_width = pcdev->current_fmt->host_fmt->bits_per_sample; + struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,}; + u32 pixfmt = pcdev->current_fmt->host_fmt->fourcc; +- unsigned long bus_flags, common_flags; ++ int mbus_config; + int ret; + +- ret = test_platform_param(pcdev, +- pcdev->current_fmt->host_fmt->bits_per_sample, +- &bus_flags); +- if (ret < 0) +- return ret; +- +- ret = sensor_call(pcdev, video, g_mbus_config, &cfg); +- if (!ret) { +- common_flags = pxa_mbus_config_compatible(&cfg, +- bus_flags); +- if (!common_flags) { +- dev_warn(pcdev_to_dev(pcdev), +- "Flags incompatible: camera 0x%x, host 0x%lx\n", +- cfg.flags, bus_flags); +- return -EINVAL; +- } +- } else if (ret != -ENOIOCTLCMD) { +- return ret; +- } else { +- common_flags = bus_flags; ++ if (!((1 << (bus_width - 1)) & pcdev->width_flags)) { ++ dev_err(pcdev_to_dev(pcdev), "Unsupported bus width %u", ++ bus_width); ++ return -EINVAL; + } + + pcdev->channels = 1; + + /* Make choices, based on platform preferences */ +- if ((common_flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH) && +- (common_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)) { +- if (pcdev->platform_flags & PXA_CAMERA_HSP) +- common_flags &= ~V4L2_MBUS_HSYNC_ACTIVE_HIGH; +- else +- common_flags &= ~V4L2_MBUS_HSYNC_ACTIVE_LOW; +- } ++ mbus_config = 0; ++ if (pcdev->platform_flags & PXA_CAMERA_MASTER) ++ mbus_config |= V4L2_MBUS_MASTER; ++ else ++ mbus_config |= V4L2_MBUS_SLAVE; + +- if ((common_flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH) && +- (common_flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)) { +- if (pcdev->platform_flags & PXA_CAMERA_VSP) +- common_flags &= ~V4L2_MBUS_VSYNC_ACTIVE_HIGH; +- else +- common_flags &= ~V4L2_MBUS_VSYNC_ACTIVE_LOW; +- } ++ if (pcdev->platform_flags & PXA_CAMERA_HSP) ++ mbus_config |= V4L2_MBUS_HSYNC_ACTIVE_HIGH; ++ else ++ mbus_config |= V4L2_MBUS_HSYNC_ACTIVE_LOW; + +- if ((common_flags & V4L2_MBUS_PCLK_SAMPLE_RISING) && +- (common_flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)) { +- if (pcdev->platform_flags & PXA_CAMERA_PCP) +- common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_RISING; +- else +- common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_FALLING; +- } ++ if (pcdev->platform_flags & PXA_CAMERA_VSP) ++ mbus_config |= V4L2_MBUS_VSYNC_ACTIVE_HIGH; ++ else ++ mbus_config |= V4L2_MBUS_VSYNC_ACTIVE_LOW; + +- cfg.flags = common_flags; +- ret = sensor_call(pcdev, video, s_mbus_config, &cfg); ++ if (pcdev->platform_flags & PXA_CAMERA_PCP) ++ mbus_config |= V4L2_MBUS_PCLK_SAMPLE_RISING; ++ else ++ mbus_config |= V4L2_MBUS_PCLK_SAMPLE_FALLING; ++ mbus_config |= V4L2_MBUS_DATA_ACTIVE_HIGH; ++ ++ cfg.flags = mbus_config; ++ ret = sensor_call(pcdev, pad, set_mbus_config, 0, &cfg); + if (ret < 0 && ret != -ENOIOCTLCMD) { +- dev_dbg(pcdev_to_dev(pcdev), +- "camera s_mbus_config(0x%lx) returned %d\n", +- common_flags, ret); ++ dev_err(pcdev_to_dev(pcdev), ++ "Failed to call set_mbus_config: %d\n", ret); + return ret; + } + +- pxa_camera_setup_cicr(pcdev, common_flags, pixfmt); +- +- return 0; +-} +- +-static int pxa_camera_try_bus_param(struct pxa_camera_dev *pcdev, +- unsigned char buswidth) +-{ +- struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,}; +- unsigned long bus_flags, common_flags; +- int ret = test_platform_param(pcdev, buswidth, &bus_flags); +- +- if (ret < 0) +- return ret; ++ /* ++ * If the requested media bus configuration has not been fully applied ++ * make sure it is supported by the platform. ++ * ++ * PXA does not support V4L2_MBUS_DATA_ACTIVE_LOW and the bus mastering ++ * roles should match. ++ */ ++ if (cfg.flags != mbus_config) { ++ unsigned int pxa_mbus_role = mbus_config & (V4L2_MBUS_MASTER | ++ V4L2_MBUS_SLAVE); ++ if (pxa_mbus_role != (cfg.flags & (V4L2_MBUS_MASTER | ++ V4L2_MBUS_SLAVE))) { ++ dev_err(pcdev_to_dev(pcdev), ++ "Unsupported mbus configuration: bus mastering\n"); ++ return -EINVAL; ++ } + +- ret = sensor_call(pcdev, video, g_mbus_config, &cfg); +- if (!ret) { +- common_flags = pxa_mbus_config_compatible(&cfg, +- bus_flags); +- if (!common_flags) { +- dev_warn(pcdev_to_dev(pcdev), +- "Flags incompatible: camera 0x%x, host 0x%lx\n", +- cfg.flags, bus_flags); ++ if (cfg.flags & V4L2_MBUS_DATA_ACTIVE_LOW) { ++ dev_err(pcdev_to_dev(pcdev), ++ "Unsupported mbus configuration: DATA_ACTIVE_LOW\n"); + return -EINVAL; + } +- } else if (ret == -ENOIOCTLCMD) { +- ret = 0; + } + +- return ret; ++ pxa_camera_setup_cicr(pcdev, cfg.flags, pixfmt); ++ ++ return 0; + } + + static const struct pxa_mbus_pixelfmt pxa_camera_formats[] = { +@@ -1738,11 +1656,6 @@ static int pxa_camera_get_formats(struct v4l2_device *v4l2_dev, + return 0; + } + +- /* This also checks support for the requested bits-per-sample */ +- ret = pxa_camera_try_bus_param(pcdev, fmt->bits_per_sample); +- if (ret < 0) +- return 0; +- + switch (code.code) { + case MEDIA_BUS_FMT_UYVY8_2X8: + formats++; + +From 562b1d8a78c8367d9809491277a6c60441565aa4 Mon Sep 17 00:00:00 2001 +From: Jacopo Mondi +Date: Fri, 17 Jul 2020 16:53:19 +0200 +Subject: [PATCH] media: v4l2-subdev: Remove [s|g]_mbus_config video ops + +With all sensor and platform drivers now converted to use the new +get_mbus_config and set_mbus_config pad operations, remove the +deprecated video operations g_mbus_config and s_mbus_config. + +Signed-off-by: Jacopo Mondi +Signed-off-by: Hans Verkuil +Signed-off-by: Mauro Carvalho Chehab +--- + include/media/v4l2-subdev.h | 10 ---------- + 1 file changed, 10 deletions(-) + +diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h +index f7fe78a6f65a..90098fb1d770 100644 +--- a/include/media/v4l2-subdev.h ++++ b/include/media/v4l2-subdev.h +@@ -402,12 +402,6 @@ struct v4l2_mbus_frame_desc { + * + * @query_dv_timings: callback for VIDIOC_QUERY_DV_TIMINGS() ioctl handler code. + * +- * @g_mbus_config: get supported mediabus configurations +- * +- * @s_mbus_config: set a certain mediabus configuration. This operation is added +- * for compatibility with soc-camera drivers and should not be used by new +- * software. +- * + * @s_rx_buffer: set a host allocated memory buffer for the subdev. The subdev + * can adjust @size to a lower value and must not write more data to the + * buffer starting at @data than the original value of @size. +@@ -435,10 +429,6 @@ struct v4l2_subdev_video_ops { + struct v4l2_dv_timings *timings); + int (*query_dv_timings)(struct v4l2_subdev *sd, + struct v4l2_dv_timings *timings); +- int (*g_mbus_config)(struct v4l2_subdev *sd, +- struct v4l2_mbus_config *cfg); +- int (*s_mbus_config)(struct v4l2_subdev *sd, +- const struct v4l2_mbus_config *cfg); + int (*s_rx_buffer)(struct v4l2_subdev *sd, void *buf, + unsigned int *size); + }; + +From 1ea27db9eaddf1eb44e533e4baa49b5b3a50900f Mon Sep 17 00:00:00 2001 +From: Jacopo Mondi +Date: Fri, 17 Jul 2020 16:53:20 +0200 +Subject: [PATCH] media: v4l2- mediabus: Add usage note for V4L2_MBUS_* + +With the removal of the legacy g_mbus_config and s_mbus_config video +operations, the sole users of V4L2_MBUS_* flags are now the newly +introduced get_mbus_config and set_mbus_config pad operations. + +As the semantic of the new operations differs from the semantic of +the legacy ones, add a usage note in the v4l2-mediabus.h header to +specify how to use the flags. + +Also add a TODO note to record that we intend to replace the existing +flags with fields, to prevent users from mixing conflicting values +in a single operation call. + +Signed-off-by: Jacopo Mondi +Signed-off-by: Hans Verkuil +Signed-off-by: Mauro Carvalho Chehab +--- + include/media/v4l2-mediabus.h | 33 +++++++++++++++++++++++++++++---- + 1 file changed, 29 insertions(+), 4 deletions(-) + +diff --git a/include/media/v4l2-mediabus.h b/include/media/v4l2-mediabus.h +index 45f88f0248c4..59b1de197114 100644 +--- a/include/media/v4l2-mediabus.h ++++ b/include/media/v4l2-mediabus.h +@@ -11,9 +11,34 @@ + #include + #include + ++/* ++ * How to use the V4L2_MBUS_* flags: ++ * Flags are defined for each of the possible states and values of a media ++ * bus configuration parameter. One and only one bit of each group of flags ++ * shall be set by the users of the v4l2_subdev_pad_ops.get_mbus_config and ++ * v4l2_subdev_pad_ops.set_mbus_config operations to ensure that no ++ * conflicting settings are specified when reporting and setting the media bus ++ * configuration with the two operations respectively. For example, it is ++ * invalid to set or clear both the V4L2_MBUS_HSYNC_ACTIVE_HIGH and the ++ * V4L2_MBUS_HSYNC_ACTIVE_LOW flag at the same time. Instead either flag ++ * V4L2_MBUS_HSYNC_ACTIVE_HIGH or flag V4L2_MBUS_HSYNC_ACTIVE_LOW shall be ++ * set. The same is true for the V4L2_MBUS_CSI2_1/2/3/4_LANE flags group: only ++ * one of these four bits shall be set. ++ * ++ * TODO: replace the existing V4L2_MBUS_* flags with structures of fields ++ * to avoid conflicting settings. ++ * ++ * In example: ++ * #define V4L2_MBUS_HSYNC_ACTIVE_HIGH BIT(2) ++ * #define V4L2_MBUS_HSYNC_ACTIVE_LOW BIT(3) ++ * will be replaced by a field whose value reports the intended active state of ++ * the signal: ++ * unsigned int v4l2_mbus_hsync_active : 1; ++ */ ++ + /* Parallel flags */ + /* +- * Can the client run in master or in slave mode. By "Master mode" an operation ++ * The client runs in master or in slave mode. By "Master mode" an operation + * mode is meant, when the client (e.g., a camera sensor) is producing + * horizontal and vertical synchronisation. In "Slave mode" the host is + * providing these signals to the slave. +@@ -45,17 +70,17 @@ + #define V4L2_MBUS_DATA_ENABLE_LOW BIT(15) + + /* Serial flags */ +-/* How many lanes the client can use */ ++/* CSI-2 D-PHY number of data lanes. */ + #define V4L2_MBUS_CSI2_1_LANE BIT(0) + #define V4L2_MBUS_CSI2_2_LANE BIT(1) + #define V4L2_MBUS_CSI2_3_LANE BIT(2) + #define V4L2_MBUS_CSI2_4_LANE BIT(3) +-/* On which channels it can send video data */ ++/* CSI-2 Virtual Channel identifiers. */ + #define V4L2_MBUS_CSI2_CHANNEL_0 BIT(4) + #define V4L2_MBUS_CSI2_CHANNEL_1 BIT(5) + #define V4L2_MBUS_CSI2_CHANNEL_2 BIT(6) + #define V4L2_MBUS_CSI2_CHANNEL_3 BIT(7) +-/* Does it support only continuous or also non-continuous clock mode */ ++/* Clock non-continuous mode support. */ + #define V4L2_MBUS_CSI2_CONTINUOUS_CLOCK BIT(8) + #define V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK BIT(9) + + +From 9aae063d84435edfb0212c7613f887105dd58009 Mon Sep 17 00:00:00 2001 +From: Jacopo Mondi +Date: Fri, 17 Jul 2020 16:53:21 +0200 +Subject: [PATCH] media: staging: media: imx: Update TODO entry + +Update the TODO entry that mentioned a potential use case for the now +removed g_mbus_config video operation. + +Signed-off-by: Jacopo Mondi +Signed-off-by: Hans Verkuil +Signed-off-by: Mauro Carvalho Chehab +--- + drivers/staging/media/imx/TODO | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/drivers/staging/media/imx/TODO b/drivers/staging/media/imx/TODO +index a371cdedcdb0..9cfc1c1e78dc 100644 +--- a/drivers/staging/media/imx/TODO ++++ b/drivers/staging/media/imx/TODO +@@ -10,6 +10,10 @@ + driver uses the parsed DT bus config method until this issue is + resolved. + ++ 2020-06: g_mbus has been removed in favour of the get_mbus_config pad ++ operation which should be used to avoid parsing the remote endpoint ++ configuration. ++ + - This media driver supports inheriting V4L2 controls to the + video capture devices, from the subdevices in the capture device's + pipeline. The controls for each capture device are updated in the + +From 33a781840365c6b8a2b86b1c6cb4aaa86941a5d6 Mon Sep 17 00:00:00 2001 +From: Jacopo Mondi +Date: Fri, 17 Jul 2020 16:53:22 +0200 +Subject: [PATCH] media: i2c: adv748x: Adjust TXA data lanes number +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +When outputting SD-Core output through the TXA MIPI CSI-2 interface, +the number of enabled data lanes should be reduced in order to guarantee +that the two video formats produced by the SD-Core (480i and 576i) +generate a MIPI CSI-2 link clock frequency compatible with the MIPI D-PHY +specifications. + +Limit the number of enabled data lanes to 2, which is guaranteed to +support 480i and 576i formats. + +Cache the number of enabled data lanes to be able to report it through +the new get_mbus_config operation. + +Reviewed-by: Kieran Bingham +Reviewed-by: Laurent Pinchart +Reviewed-by: Niklas Söderlund +Signed-off-by: Jacopo Mondi +Signed-off-by: Hans Verkuil +Signed-off-by: Mauro Carvalho Chehab +--- + drivers/media/i2c/adv748x/adv748x-core.c | 31 ++++++++++++++++++------ + drivers/media/i2c/adv748x/adv748x.h | 1 + + 2 files changed, 25 insertions(+), 7 deletions(-) + +diff --git a/drivers/media/i2c/adv748x/adv748x-core.c b/drivers/media/i2c/adv748x/adv748x-core.c +index 23e02ff27b17..1fe7f97c6d52 100644 +--- a/drivers/media/i2c/adv748x/adv748x-core.c ++++ b/drivers/media/i2c/adv748x/adv748x-core.c +@@ -241,10 +241,10 @@ static int adv748x_power_up_tx(struct adv748x_csi2 *tx) + int ret = 0; + + /* Enable n-lane MIPI */ +- adv748x_write_check(state, page, 0x00, 0x80 | tx->num_lanes, &ret); ++ adv748x_write_check(state, page, 0x00, 0x80 | tx->active_lanes, &ret); + + /* Set Auto DPHY Timing */ +- adv748x_write_check(state, page, 0x00, 0xa0 | tx->num_lanes, &ret); ++ adv748x_write_check(state, page, 0x00, 0xa0 | tx->active_lanes, &ret); + + /* ADI Required Write */ + if (tx->src == &state->hdmi.sd) { +@@ -270,7 +270,7 @@ static int adv748x_power_up_tx(struct adv748x_csi2 *tx) + usleep_range(2000, 2500); + + /* Power-up CSI-TX */ +- adv748x_write_check(state, page, 0x00, 0x20 | tx->num_lanes, &ret); ++ adv748x_write_check(state, page, 0x00, 0x20 | tx->active_lanes, &ret); + usleep_range(1000, 1500); + + /* ADI Required Writes */ +@@ -292,7 +292,7 @@ static int adv748x_power_down_tx(struct adv748x_csi2 *tx) + adv748x_write_check(state, page, 0x1e, 0x00, &ret); + + /* Enable n-lane MIPI */ +- adv748x_write_check(state, page, 0x00, 0x80 | tx->num_lanes, &ret); ++ adv748x_write_check(state, page, 0x00, 0x80 | tx->active_lanes, &ret); + + /* i2c_mipi_pll_en - 1'b1 */ + adv748x_write_check(state, page, 0xda, 0x01, &ret); +@@ -357,14 +357,29 @@ static int adv748x_link_setup(struct media_entity *entity, + if (state->afe.tx) { + /* AFE Requires TXA enabled, even when output to TXB */ + io10 |= ADV748X_IO_10_CSI4_EN; +- if (is_txa(tx)) ++ if (is_txa(tx)) { ++ /* ++ * Output from the SD-core (480i and 576i) from the TXA ++ * interface requires reducing the number of enabled ++ * data lanes in order to guarantee a valid link ++ * frequency. ++ */ ++ tx->active_lanes = min(tx->num_lanes, 2U); + io10 |= ADV748X_IO_10_CSI4_IN_SEL_AFE; +- else ++ } else { ++ /* TXB has a single data lane, no need to adjust. */ + io10 |= ADV748X_IO_10_CSI1_EN; ++ } + } + +- if (state->hdmi.tx) ++ if (state->hdmi.tx) { ++ /* ++ * Restore the number of active lanes, in case we have gone ++ * through an AFE->TXA streaming sessions. ++ */ ++ tx->active_lanes = tx->num_lanes; + io10 |= ADV748X_IO_10_CSI4_EN; ++ } + + return io_clrset(state, ADV748X_IO_10, io10_mask, io10); + } +@@ -596,6 +611,7 @@ static int adv748x_parse_csi2_lanes(struct adv748x_state *state, + } + + state->txa.num_lanes = num_lanes; ++ state->txa.active_lanes = num_lanes; + adv_dbg(state, "TXA: using %u lanes\n", state->txa.num_lanes); + } + +@@ -607,6 +623,7 @@ static int adv748x_parse_csi2_lanes(struct adv748x_state *state, + } + + state->txb.num_lanes = num_lanes; ++ state->txb.active_lanes = num_lanes; + adv_dbg(state, "TXB: using %u lanes\n", state->txb.num_lanes); + } + +diff --git a/drivers/media/i2c/adv748x/adv748x.h b/drivers/media/i2c/adv748x/adv748x.h +index fccb388ce179..1061f425ece5 100644 +--- a/drivers/media/i2c/adv748x/adv748x.h ++++ b/drivers/media/i2c/adv748x/adv748x.h +@@ -79,6 +79,7 @@ struct adv748x_csi2 { + unsigned int page; + unsigned int port; + unsigned int num_lanes; ++ unsigned int active_lanes; + + struct media_pad pads[ADV748X_CSI2_NR_PADS]; + struct v4l2_ctrl_handler ctrl_hdl; + +From 5ccfd4f056cc53beef915bd24985449b7d20affc Mon Sep 17 00:00:00 2001 +From: Jacopo Mondi +Date: Fri, 17 Jul 2020 16:53:23 +0200 +Subject: [PATCH] media: i2c: adv748x: Implement get_mbus_config +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Implement the newly introduced get_mbus_config operation to report the +number of currently used data lanes on the MIPI CSI-2 interface. + +Reviewed-by: Kieran Bingham +Reviewed-by: Niklas Söderlund +Signed-off-by: Jacopo Mondi +Signed-off-by: Hans Verkuil +Signed-off-by: Mauro Carvalho Chehab +--- + drivers/media/i2c/adv748x/adv748x-csi2.c | 31 ++++++++++++++++++++++++ + 1 file changed, 31 insertions(+) + +diff --git a/drivers/media/i2c/adv748x/adv748x-csi2.c b/drivers/media/i2c/adv748x/adv748x-csi2.c +index 2091cda50935..99bb63d05eef 100644 +--- a/drivers/media/i2c/adv748x/adv748x-csi2.c ++++ b/drivers/media/i2c/adv748x/adv748x-csi2.c +@@ -214,9 +214,40 @@ static int adv748x_csi2_set_format(struct v4l2_subdev *sd, + return ret; + } + ++static int adv748x_csi2_get_mbus_config(struct v4l2_subdev *sd, unsigned int pad, ++ struct v4l2_mbus_config *config) ++{ ++ struct adv748x_csi2 *tx = adv748x_sd_to_csi2(sd); ++ ++ if (pad != ADV748X_CSI2_SOURCE) ++ return -EINVAL; ++ ++ config->type = V4L2_MBUS_CSI2_DPHY; ++ switch (tx->active_lanes) { ++ case 1: ++ config->flags = V4L2_MBUS_CSI2_1_LANE; ++ break; ++ ++ case 2: ++ config->flags = V4L2_MBUS_CSI2_2_LANE; ++ break; ++ ++ case 3: ++ config->flags = V4L2_MBUS_CSI2_3_LANE; ++ break; ++ ++ case 4: ++ config->flags = V4L2_MBUS_CSI2_4_LANE; ++ break; ++ } ++ ++ return 0; ++} ++ + static const struct v4l2_subdev_pad_ops adv748x_csi2_pad_ops = { + .get_fmt = adv748x_csi2_get_format, + .set_fmt = adv748x_csi2_set_format, ++ .get_mbus_config = adv748x_csi2_get_mbus_config, + }; + + /* ----------------------------------------------------------------------------- + +From a7053f425fb6140bdf72c009cab1730e9d3094af Mon Sep 17 00:00:00 2001 +From: Jacopo Mondi +Date: Fri, 17 Jul 2020 16:53:24 +0200 +Subject: [PATCH] media: rcar-csi2: Negotiate data lanes number +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Use the newly introduced get_mbus_config() subdevice pad operation to +retrieve the remote subdevice MIPI CSI-2 bus configuration and configure +the number of active data lanes accordingly. + +In order to be able to call the remote subdevice operation cache the +index of the remote pad connected to the single CSI-2 input port. + +Reviewed-by: Niklas Söderlund +Signed-off-by: Jacopo Mondi +Signed-off-by: Hans Verkuil +Signed-off-by: Mauro Carvalho Chehab +--- + drivers/media/platform/rcar-vin/rcar-csi2.c | 75 +++++++++++++++++++-- + 1 file changed, 68 insertions(+), 7 deletions(-) + +diff --git a/drivers/media/platform/rcar-vin/rcar-csi2.c b/drivers/media/platform/rcar-vin/rcar-csi2.c +index 151e6a90c5fb..fe99ae00e690 100644 +--- a/drivers/media/platform/rcar-vin/rcar-csi2.c ++++ b/drivers/media/platform/rcar-vin/rcar-csi2.c +@@ -363,6 +363,7 @@ struct rcar_csi2 { + struct v4l2_async_notifier notifier; + struct v4l2_async_subdev asd; + struct v4l2_subdev *remote; ++ unsigned int remote_pad; + + struct v4l2_mbus_framefmt mf; + +@@ -408,13 +409,14 @@ static void rcsi2_exit_standby(struct rcar_csi2 *priv) + reset_control_deassert(priv->rstc); + } + +-static int rcsi2_wait_phy_start(struct rcar_csi2 *priv) ++static int rcsi2_wait_phy_start(struct rcar_csi2 *priv, ++ unsigned int lanes) + { + unsigned int timeout; + + /* Wait for the clock and data lanes to enter LP-11 state. */ + for (timeout = 0; timeout <= 20; timeout++) { +- const u32 lane_mask = (1 << priv->lanes) - 1; ++ const u32 lane_mask = (1 << lanes) - 1; + + if ((rcsi2_read(priv, PHCLM_REG) & PHCLM_STOPSTATECKL) && + (rcsi2_read(priv, PHDLM_REG) & lane_mask) == lane_mask) +@@ -446,7 +448,8 @@ static int rcsi2_set_phypll(struct rcar_csi2 *priv, unsigned int mbps) + return 0; + } + +-static int rcsi2_calc_mbps(struct rcar_csi2 *priv, unsigned int bpp) ++static int rcsi2_calc_mbps(struct rcar_csi2 *priv, unsigned int bpp, ++ unsigned int lanes) + { + struct v4l2_subdev *source; + struct v4l2_ctrl *ctrl; +@@ -471,15 +474,64 @@ static int rcsi2_calc_mbps(struct rcar_csi2 *priv, unsigned int bpp) + * bps = link_freq * 2 + */ + mbps = v4l2_ctrl_g_ctrl_int64(ctrl) * bpp; +- do_div(mbps, priv->lanes * 1000000); ++ do_div(mbps, lanes * 1000000); + + return mbps; + } + ++static int rcsi2_get_active_lanes(struct rcar_csi2 *priv, ++ unsigned int *lanes) ++{ ++ struct v4l2_mbus_config mbus_config = { 0 }; ++ unsigned int num_lanes = UINT_MAX; ++ int ret; ++ ++ *lanes = priv->lanes; ++ ++ ret = v4l2_subdev_call(priv->remote, pad, get_mbus_config, ++ priv->remote_pad, &mbus_config); ++ if (ret == -ENOIOCTLCMD) { ++ dev_dbg(priv->dev, "No remote mbus configuration available\n"); ++ return 0; ++ } ++ ++ if (ret) { ++ dev_err(priv->dev, "Failed to get remote mbus configuration\n"); ++ return ret; ++ } ++ ++ if (mbus_config.type != V4L2_MBUS_CSI2_DPHY) { ++ dev_err(priv->dev, "Unsupported media bus type %u\n", ++ mbus_config.type); ++ return -EINVAL; ++ } ++ ++ if (mbus_config.flags & V4L2_MBUS_CSI2_1_LANE) ++ num_lanes = 1; ++ else if (mbus_config.flags & V4L2_MBUS_CSI2_2_LANE) ++ num_lanes = 2; ++ else if (mbus_config.flags & V4L2_MBUS_CSI2_3_LANE) ++ num_lanes = 3; ++ else if (mbus_config.flags & V4L2_MBUS_CSI2_4_LANE) ++ num_lanes = 4; ++ ++ if (num_lanes > priv->lanes) { ++ dev_err(priv->dev, ++ "Unsupported mbus config: too many data lanes %u\n", ++ num_lanes); ++ return -EINVAL; ++ } ++ ++ *lanes = num_lanes; ++ ++ return 0; ++} ++ + static int rcsi2_start_receiver(struct rcar_csi2 *priv) + { + const struct rcar_csi2_format *format; + u32 phycnt, vcdt = 0, vcdt2 = 0, fld = 0; ++ unsigned int lanes; + unsigned int i; + int mbps, ret; + +@@ -521,10 +573,18 @@ static int rcsi2_start_receiver(struct rcar_csi2 *priv) + fld |= FLD_FLD_NUM(1); + } + ++ /* ++ * Get the number of active data lanes inspecting the remote mbus ++ * configuration. ++ */ ++ ret = rcsi2_get_active_lanes(priv, &lanes); ++ if (ret) ++ return ret; ++ + phycnt = PHYCNT_ENABLECLK; +- phycnt |= (1 << priv->lanes) - 1; ++ phycnt |= (1 << lanes) - 1; + +- mbps = rcsi2_calc_mbps(priv, format->bpp); ++ mbps = rcsi2_calc_mbps(priv, format->bpp, lanes); + if (mbps < 0) + return mbps; + +@@ -571,7 +631,7 @@ static int rcsi2_start_receiver(struct rcar_csi2 *priv) + rcsi2_write(priv, PHYCNT_REG, phycnt | PHYCNT_SHUTDOWNZ); + rcsi2_write(priv, PHYCNT_REG, phycnt | PHYCNT_SHUTDOWNZ | PHYCNT_RSTZ); + +- ret = rcsi2_wait_phy_start(priv); ++ ret = rcsi2_wait_phy_start(priv, lanes); + if (ret) + return ret; + +@@ -748,6 +808,7 @@ static int rcsi2_notify_bound(struct v4l2_async_notifier *notifier, + } + + priv->remote = subdev; ++ priv->remote_pad = pad; + + dev_dbg(priv->dev, "Bound %s pad: %d\n", subdev->name, pad); + + +From ed9092fbdad008ed58e0bd8079b6d6484839d811 Mon Sep 17 00:00:00 2001 +From: Dinghao Liu +Date: Sun, 28 Jun 2020 07:55:23 +0200 +Subject: [PATCH] media: venus: core: Fix runtime PM imbalance in venus_probe + +pm_runtime_get_sync() increments the runtime PM usage counter even +when it returns an error code. Thus a pairing decrement is needed on +the error handling path to keep the counter balanced. For other error +paths after this call, things are the same. + +Fix this by adding pm_runtime_put_noidle() after 'err_runtime_disable' +label. But in this case, the error path after pm_runtime_put_sync() +will decrease PM usage counter twice. Thus add an extra +pm_runtime_get_noresume() in this path to balance PM counter. + +Signed-off-by: Dinghao Liu +Signed-off-by: Mauro Carvalho Chehab +--- + drivers/media/platform/qcom/venus/core.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/drivers/media/platform/qcom/venus/core.c b/drivers/media/platform/qcom/venus/core.c +index 203c6538044f..b0b932bf8c02 100644 +--- a/drivers/media/platform/qcom/venus/core.c ++++ b/drivers/media/platform/qcom/venus/core.c +@@ -287,8 +287,10 @@ static int venus_probe(struct platform_device *pdev) + goto err_core_deinit; + + ret = pm_runtime_put_sync(dev); +- if (ret) ++ if (ret) { ++ pm_runtime_get_noresume(dev); + goto err_dev_unregister; ++ } + + return 0; + +@@ -299,6 +301,7 @@ static int venus_probe(struct platform_device *pdev) + err_venus_shutdown: + venus_shutdown(core); + err_runtime_disable: ++ pm_runtime_put_noidle(dev); + pm_runtime_set_suspended(dev); + pm_runtime_disable(dev); + hfi_destroy(core); + +From 757449d0037dd11f6b783bc31b27c76c5fa636c8 Mon Sep 17 00:00:00 2001 +From: Rajendra Nayak +Date: Wed, 29 Jul 2020 09:16:42 +0200 +Subject: [PATCH] media: venus: core: Fix error handling in probe + +Post a successful pm_ops->core_get, an error in probe +should exit by doing a pm_ops->core_put which seems +to be missing. So fix it. + +Signed-off-by: Rajendra Nayak +Reviewed-by: Bjorn Andersson +Signed-off-by: Stanimir Varbanov +Signed-off-by: Mauro Carvalho Chehab +--- + drivers/media/platform/qcom/venus/core.c | 15 ++++++++++----- + 1 file changed, 10 insertions(+), 5 deletions(-) + +diff --git a/drivers/media/platform/qcom/venus/core.c b/drivers/media/platform/qcom/venus/core.c +index b0b932bf8c02..321ad77cb6cf 100644 +--- a/drivers/media/platform/qcom/venus/core.c ++++ b/drivers/media/platform/qcom/venus/core.c +@@ -224,13 +224,15 @@ static int venus_probe(struct platform_device *pdev) + + ret = dma_set_mask_and_coherent(dev, core->res->dma_mask); + if (ret) +- return ret; ++ goto err_core_put; + + if (!dev->dma_parms) { + dev->dma_parms = devm_kzalloc(dev, sizeof(*dev->dma_parms), + GFP_KERNEL); +- if (!dev->dma_parms) +- return -ENOMEM; ++ if (!dev->dma_parms) { ++ ret = -ENOMEM; ++ goto err_core_put; ++ } + } + dma_set_max_seg_size(dev, DMA_BIT_MASK(32)); + +@@ -242,11 +244,11 @@ static int venus_probe(struct platform_device *pdev) + IRQF_TRIGGER_HIGH | IRQF_ONESHOT, + "venus", core); + if (ret) +- return ret; ++ goto err_core_put; + + ret = hfi_create(core, &venus_core_ops); + if (ret) +- return ret; ++ goto err_core_put; + + pm_runtime_enable(dev); + +@@ -305,6 +307,9 @@ static int venus_probe(struct platform_device *pdev) + pm_runtime_set_suspended(dev); + pm_runtime_disable(dev); + hfi_destroy(core); ++err_core_put: ++ if (core->pm_ops->core_put) ++ core->pm_ops->core_put(dev); + return ret; + } + + +From 207ffb881dd2058c1a86022671817cef37a9d273 Mon Sep 17 00:00:00 2001 +From: Rajendra Nayak +Date: Wed, 29 Jul 2020 09:16:43 +0200 +Subject: [PATCH] media: venus: core: Add support for opp tables/perf voting + +Add support to add OPP tables and perf voting on the OPP powerdomain. +This is needed so venus votes on the corresponding performance state +for the OPP powerdomain along with setting the core clock rate. + +Signed-off-by: Rajendra Nayak +Reviewed-by: Matthias Kaehlcke +Reviewed-by: Bjorn Andersson +Signed-off-by: Stanimir Varbanov +Signed-off-by: Mauro Carvalho Chehab +--- + drivers/media/platform/qcom/venus/core.c | 2 + + drivers/media/platform/qcom/venus/core.h | 5 + + .../media/platform/qcom/venus/pm_helpers.c | 92 +++++++++++++++++-- + 3 files changed, 92 insertions(+), 7 deletions(-) + +diff --git a/drivers/media/platform/qcom/venus/core.c b/drivers/media/platform/qcom/venus/core.c +index 321ad77cb6cf..5fd70f8cf857 100644 +--- a/drivers/media/platform/qcom/venus/core.c ++++ b/drivers/media/platform/qcom/venus/core.c +@@ -528,6 +528,7 @@ static const struct venus_resources sdm845_res_v2 = { + .vcodec_clks_num = 2, + .vcodec_pmdomains = { "venus", "vcodec0", "vcodec1" }, + .vcodec_pmdomains_num = 3, ++ .opp_pmdomain = (const char *[]) { "cx", NULL }, + .vcodec_num = 2, + .max_load = 3110400, /* 4096x2160@90 */ + .hfi_version = HFI_VERSION_4XX, +@@ -573,6 +574,7 @@ static const struct venus_resources sc7180_res = { + .vcodec_clks_num = 2, + .vcodec_pmdomains = { "venus", "vcodec0" }, + .vcodec_pmdomains_num = 2, ++ .opp_pmdomain = (const char *[]) { "cx", NULL }, + .vcodec_num = 1, + .hfi_version = HFI_VERSION_4XX, + .vmem_id = VIDC_RESOURCE_NONE, +diff --git a/drivers/media/platform/qcom/venus/core.h b/drivers/media/platform/qcom/venus/core.h +index 7118612673c9..b0cc544ad39f 100644 +--- a/drivers/media/platform/qcom/venus/core.h ++++ b/drivers/media/platform/qcom/venus/core.h +@@ -62,6 +62,7 @@ struct venus_resources { + unsigned int vcodec_clks_num; + const char * const vcodec_pmdomains[VIDC_PMDOMAINS_NUM_MAX]; + unsigned int vcodec_pmdomains_num; ++ const char **opp_pmdomain; + unsigned int vcodec_num; + enum hfi_version hfi_version; + u32 max_load; +@@ -145,8 +146,12 @@ struct venus_core { + struct clk *vcodec1_clks[VIDC_VCODEC_CLKS_NUM_MAX]; + struct icc_path *video_path; + struct icc_path *cpucfg_path; ++ struct opp_table *opp_table; ++ bool has_opp_table; + struct device_link *pd_dl_venus; + struct device *pmdomains[VIDC_PMDOMAINS_NUM_MAX]; ++ struct device_link *opp_dl_venus; ++ struct device *opp_pmdomain; + struct video_device *vdev_dec; + struct video_device *vdev_enc; + struct v4l2_device v4l2_dev; +diff --git a/drivers/media/platform/qcom/venus/pm_helpers.c b/drivers/media/platform/qcom/venus/pm_helpers.c +index 531e7a41658f..3127af8985cf 100644 +--- a/drivers/media/platform/qcom/venus/pm_helpers.c ++++ b/drivers/media/platform/qcom/venus/pm_helpers.c +@@ -9,6 +9,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -66,10 +67,9 @@ static void core_clks_disable(struct venus_core *core) + + static int core_clks_set_rate(struct venus_core *core, unsigned long freq) + { +- struct clk *clk = core->clks[0]; + int ret; + +- ret = clk_set_rate(clk, freq); ++ ret = dev_pm_opp_set_rate(core->dev, freq); + if (ret) + return ret; + +@@ -744,13 +744,16 @@ static int venc_power_v4(struct device *dev, int on) + + static int vcodec_domains_get(struct device *dev) + { ++ int ret; ++ struct opp_table *opp_table; ++ struct device **opp_virt_dev; + struct venus_core *core = dev_get_drvdata(dev); + const struct venus_resources *res = core->res; + struct device *pd; + unsigned int i; + + if (!res->vcodec_pmdomains_num) +- return -ENODEV; ++ goto skip_pmdomains; + + for (i = 0; i < res->vcodec_pmdomains_num; i++) { + pd = dev_pm_domain_attach_by_name(dev, +@@ -767,7 +770,41 @@ static int vcodec_domains_get(struct device *dev) + if (!core->pd_dl_venus) + return -ENODEV; + ++skip_pmdomains: ++ if (!core->has_opp_table) ++ return 0; ++ ++ /* Attach the power domain for setting performance state */ ++ opp_table = dev_pm_opp_attach_genpd(dev, res->opp_pmdomain, &opp_virt_dev); ++ if (IS_ERR(opp_table)) { ++ ret = PTR_ERR(opp_table); ++ goto opp_attach_err; ++ } ++ ++ core->opp_pmdomain = *opp_virt_dev; ++ core->opp_dl_venus = device_link_add(dev, core->opp_pmdomain, ++ DL_FLAG_RPM_ACTIVE | ++ DL_FLAG_PM_RUNTIME | ++ DL_FLAG_STATELESS); ++ if (!core->opp_dl_venus) { ++ ret = -ENODEV; ++ goto opp_dl_add_err; ++ } ++ + return 0; ++ ++opp_dl_add_err: ++ dev_pm_domain_detach(core->opp_pmdomain, true); ++opp_attach_err: ++ if (core->pd_dl_venus) { ++ device_link_del(core->pd_dl_venus); ++ for (i = 0; i < res->vcodec_pmdomains_num; i++) { ++ if (IS_ERR_OR_NULL(core->pmdomains[i])) ++ continue; ++ dev_pm_domain_detach(core->pmdomains[i], true); ++ } ++ } ++ return ret; + } + + static void vcodec_domains_put(struct device *dev) +@@ -777,7 +814,7 @@ static void vcodec_domains_put(struct device *dev) + unsigned int i; + + if (!res->vcodec_pmdomains_num) +- return; ++ goto skip_pmdomains; + + if (core->pd_dl_venus) + device_link_del(core->pd_dl_venus); +@@ -787,6 +824,15 @@ static void vcodec_domains_put(struct device *dev) + continue; + dev_pm_domain_detach(core->pmdomains[i], true); + } ++ ++skip_pmdomains: ++ if (!core->has_opp_table) ++ return; ++ ++ if (core->opp_dl_venus) ++ device_link_del(core->opp_dl_venus); ++ ++ dev_pm_domain_detach(core->opp_pmdomain, true); + } + + static int core_get_v4(struct device *dev) +@@ -815,19 +861,46 @@ static int core_get_v4(struct device *dev) + if (legacy_binding) + return 0; + ++ core->opp_table = dev_pm_opp_set_clkname(dev, "core"); ++ if (IS_ERR(core->opp_table)) ++ return PTR_ERR(core->opp_table); ++ ++ if (core->res->opp_pmdomain) { ++ ret = dev_pm_opp_of_add_table(dev); ++ if (!ret) { ++ core->has_opp_table = true; ++ } else if (ret != -ENODEV) { ++ dev_err(dev, "invalid OPP table in device tree\n"); ++ dev_pm_opp_put_clkname(core->opp_table); ++ return ret; ++ } ++ } ++ + ret = vcodec_domains_get(dev); +- if (ret) ++ if (ret) { ++ if (core->has_opp_table) ++ dev_pm_opp_of_remove_table(dev); ++ dev_pm_opp_put_clkname(core->opp_table); + return ret; ++ } + + return 0; + } + + static void core_put_v4(struct device *dev) + { ++ struct venus_core *core = dev_get_drvdata(dev); ++ + if (legacy_binding) + return; + + vcodec_domains_put(dev); ++ ++ if (core->has_opp_table) ++ dev_pm_opp_of_remove_table(dev); ++ if (core->opp_table) ++ dev_pm_opp_put_clkname(core->opp_table); ++ + } + + static int core_power_v4(struct device *dev, int on) +@@ -835,10 +908,15 @@ static int core_power_v4(struct device *dev, int on) + struct venus_core *core = dev_get_drvdata(dev); + int ret = 0; + +- if (on == POWER_ON) ++ if (on == POWER_ON) { + ret = core_clks_enable(core); +- else ++ } else { ++ /* Drop the performance state vote */ ++ if (core->opp_pmdomain) ++ dev_pm_opp_set_rate(dev, 0); ++ + core_clks_disable(core); ++ } + + return ret; + } + +From 3bf1ba10b6ac9cfff7ecd329c38dc31213e88ce1 Mon Sep 17 00:00:00 2001 +From: Ezequiel Garcia +Date: Mon, 27 Jul 2020 14:05:37 -0300 +Subject: [PATCH] hantro: h264: Get the correct fallback reference buffer + +If the bitstream and the application are incorrectly configuring +the reference pictures, the hardware will need to fallback +to using some other reference picture. + +When the post-processor is enabled, the fallback buffer +should be a shadow buffer (postproc.dec_q), and not a +CAPTURE queue buffer, since the latter is post-processed +and not really the output of the decoder core. + +Fixes: 8c2d66b036c77 ("media: hantro: Support color conversion via post-processing") +Signed-off-by: Ezequiel Garcia +--- + drivers/staging/media/hantro/hantro_h264.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/staging/media/hantro/hantro_h264.c b/drivers/staging/media/hantro/hantro_h264.c +index 194d05848077..6dcd47bd9ed3 100644 +--- a/drivers/staging/media/hantro/hantro_h264.c ++++ b/drivers/staging/media/hantro/hantro_h264.c +@@ -325,7 +325,7 @@ dma_addr_t hantro_h264_get_ref_buf(struct hantro_ctx *ctx, + */ + dst_buf = hantro_get_dst_buf(ctx); + buf = &dst_buf->vb2_buf; +- dma_addr = vb2_dma_contig_plane_dma_addr(buf, 0); ++ dma_addr = hantro_get_dec_buf_addr(ctx, buf); + } + + return dma_addr; + +From 28bebe4b9396ef9d2e4ae2a179abdb840ceddb03 Mon Sep 17 00:00:00 2001 +From: Ezequiel Garcia +Date: Mon, 27 Jul 2020 14:05:38 -0300 +Subject: [PATCH] hantro: postproc: Fix motion vector space allocation + +When the post-processor is enabled, the driver allocates +"shadow buffers" which are used for the decoder core, +and exposes the post-processed buffers to userspace. + +For this reason, extra motion vector space has to +be allocated on the shadow buffers, which the driver +wasn't doing. Fix it. + +This fix should address artifacts on high profile bitstreams. + +Fixes: 8c2d66b036c77 ("media: hantro: Support color conversion via post-processing") +Signed-off-by: Ezequiel Garcia +--- + drivers/staging/media/hantro/hantro_postproc.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/staging/media/hantro/hantro_postproc.c b/drivers/staging/media/hantro/hantro_postproc.c +index 44062ffceaea..6d2a8f2a8f0b 100644 +--- a/drivers/staging/media/hantro/hantro_postproc.c ++++ b/drivers/staging/media/hantro/hantro_postproc.c +@@ -118,7 +118,9 @@ int hantro_postproc_alloc(struct hantro_ctx *ctx) + unsigned int num_buffers = cap_queue->num_buffers; + unsigned int i, buf_size; + +- buf_size = ctx->dst_fmt.plane_fmt[0].sizeimage; ++ buf_size = ctx->dst_fmt.plane_fmt[0].sizeimage + ++ hantro_h264_mv_size(ctx->dst_fmt.width, ++ ctx->dst_fmt.height); + + for (i = 0; i < num_buffers; ++i) { + struct hantro_aux_buf *priv = &ctx->postproc.dec_q[i]; + +From be1ec3a445d13ab0bac45fd84edb30a11a2c0b8c Mon Sep 17 00:00:00 2001 +From: Jernej Skrabec +Date: Fri, 14 Aug 2020 10:36:16 -0300 +Subject: [PATCH] media: uapi: h264: Update reference lists + +When dealing with with interlaced frames, reference lists must tell if +each particular reference is meant for top or bottom field. This info +is currently not provided at all in the H264 related controls. + +Make reference lists hold a structure which will also hold an +enumerator type along index into DPB array. The enumerator must +be used to specify if reference is for top or bottom field. + +Currently the only user of these lists is Cedrus which is just compile +fixed here. Actual usage of will come in a following commit. + +Signed-off-by: Jernej Skrabec +Signed-off-by: Ezequiel Garcia +--- + .../media/v4l/ext-ctrls-codec.rst | 44 ++++++++++++++++++- + .../staging/media/sunxi/cedrus/cedrus_h264.c | 6 +-- + include/media/h264-ctrls.h | 23 +++++++--- + 3 files changed, 62 insertions(+), 11 deletions(-) + +diff --git a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst +index d0d506a444b1..b9b2617c3bda 100644 +--- a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst ++++ b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst +@@ -1843,10 +1843,10 @@ enum v4l2_mpeg_video_h264_hierarchical_coding_type - + * - __u32 + - ``slice_group_change_cycle`` + - +- * - __u8 ++ * - struct :c:type:`v4l2_h264_reference` + - ``ref_pic_list0[32]`` + - Reference picture list after applying the per-slice modifications +- * - __u8 ++ * - struct :c:type:`v4l2_h264_reference` + - ``ref_pic_list1[32]`` + - Reference picture list after applying the per-slice modifications + * - __u32 +@@ -1926,6 +1926,46 @@ enum v4l2_mpeg_video_h264_hierarchical_coding_type - + - ``chroma_offset[32][2]`` + - + ++``Picture Reference`` ++ ++.. c:type:: v4l2_h264_reference ++ ++.. cssclass:: longtable ++ ++.. flat-table:: struct v4l2_h264_reference ++ :header-rows: 0 ++ :stub-columns: 0 ++ :widths: 1 1 2 ++ ++ * - enum :c:type:`v4l2_h264_field_reference` ++ - ``reference`` ++ - Specifies how the picture is referenced. ++ * - __u8 ++ - ``index`` ++ - Index into the :c:type:`v4l2_ctrl_h264_decode_params`.dpb array. ++ ++.. c:type:: v4l2_h264_field_reference ++ ++.. cssclass:: longtable ++ ++.. flat-table:: ++ :header-rows: 0 ++ :stub-columns: 0 ++ :widths: 1 1 2 ++ ++ * - ``V4L2_H264_TOP_FIELD_REF`` ++ - 0x1 ++ - The top field in field pair is used for ++ short-term reference. ++ * - ``V4L2_H264_BOTTOM_FIELD_REF`` ++ - 0x2 ++ - The bottom field in field pair is used for ++ short-term reference. ++ * - ``V4L2_H264_FRAME_REF`` ++ - 0x3 ++ - The frame (or the top/bottom fields, if it's a field pair) ++ is used for short-term reference. ++ + ``V4L2_CID_MPEG_VIDEO_H264_DECODE_PARAMS (struct)`` + Specifies the decode parameters (as extracted from the bitstream) + for the associated H264 slice data. This includes the necessary +diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_h264.c b/drivers/staging/media/sunxi/cedrus/cedrus_h264.c +index 54ee2aa423e2..cce527bbdf86 100644 +--- a/drivers/staging/media/sunxi/cedrus/cedrus_h264.c ++++ b/drivers/staging/media/sunxi/cedrus/cedrus_h264.c +@@ -166,8 +166,8 @@ static void cedrus_write_frame_list(struct cedrus_ctx *ctx, + + static void _cedrus_write_ref_list(struct cedrus_ctx *ctx, + struct cedrus_run *run, +- const u8 *ref_list, u8 num_ref, +- enum cedrus_h264_sram_off sram) ++ const struct v4l2_h264_reference *ref_list, ++ u8 num_ref, enum cedrus_h264_sram_off sram) + { + const struct v4l2_ctrl_h264_decode_params *decode = run->h264.decode_params; + struct vb2_queue *cap_q; +@@ -188,7 +188,7 @@ static void _cedrus_write_ref_list(struct cedrus_ctx *ctx, + int buf_idx; + u8 dpb_idx; + +- dpb_idx = ref_list[i]; ++ dpb_idx = ref_list[i].index; + dpb = &decode->dpb[dpb_idx]; + + if (!(dpb->flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE)) +diff --git a/include/media/h264-ctrls.h b/include/media/h264-ctrls.h +index 080fd1293c42..5f635e8d25e2 100644 +--- a/include/media/h264-ctrls.h ++++ b/include/media/h264-ctrls.h +@@ -19,6 +19,8 @@ + */ + #define V4L2_H264_NUM_DPB_ENTRIES 16 + ++#define V4L2_H264_REF_LIST_LEN (2 * V4L2_H264_NUM_DPB_ENTRIES) ++ + /* Our pixel format isn't stable at the moment */ + #define V4L2_PIX_FMT_H264_SLICE v4l2_fourcc('S', '2', '6', '4') /* H264 parsed slices */ + +@@ -140,6 +142,19 @@ struct v4l2_h264_pred_weight_table { + #define V4L2_H264_SLICE_FLAG_DIRECT_SPATIAL_MV_PRED 0x04 + #define V4L2_H264_SLICE_FLAG_SP_FOR_SWITCH 0x08 + ++enum v4l2_h264_field_reference { ++ V4L2_H264_TOP_FIELD_REF = 0x1, ++ V4L2_H264_BOTTOM_FIELD_REF = 0x2, ++ V4L2_H264_FRAME_REF = 0x3, ++}; ++ ++struct v4l2_h264_reference { ++ enum v4l2_h264_field_reference fields; ++ ++ /* Index into v4l2_ctrl_h264_decode_params.dpb[] */ ++ __u8 index; ++}; ++ + struct v4l2_ctrl_h264_slice_params { + /* Size in bytes, including header */ + __u32 size; +@@ -178,12 +193,8 @@ struct v4l2_ctrl_h264_slice_params { + __u8 num_ref_idx_l1_active_minus1; + __u32 slice_group_change_cycle; + +- /* +- * Entries on each list are indices into +- * v4l2_ctrl_h264_decode_params.dpb[]. +- */ +- __u8 ref_pic_list0[32]; +- __u8 ref_pic_list1[32]; ++ struct v4l2_h264_reference ref_pic_list0[V4L2_H264_REF_LIST_LEN]; ++ struct v4l2_h264_reference ref_pic_list1[V4L2_H264_REF_LIST_LEN]; + + __u32 flags; + }; + +From 9e30508e5834c1a37aa07836bf7fc78f96559f82 Mon Sep 17 00:00:00 2001 +From: Ezequiel Garcia +Date: Fri, 14 Aug 2020 10:36:17 -0300 +Subject: [PATCH] media: uapi: h264: Further clarify scaling lists order + +Commit 0b0393d59eb4a ("media: uapi: h264: clarify +expected scaling_list_4x4/8x8 order") improved the +documentation on H264 scaling lists order. + +This commit improves the documentation by clarifying +that the lists themselves are expected in raster scan order. + +Signed-off-by: Ezequiel Garcia +--- + Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst +index b9b2617c3bda..694037ce888a 100644 +--- a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst ++++ b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst +@@ -1725,12 +1725,14 @@ enum v4l2_mpeg_video_h264_hierarchical_coding_type - + - ``scaling_list_4x4[6][16]`` + - Scaling matrix after applying the inverse scanning process. + Expected list order is Intra Y, Intra Cb, Intra Cr, Inter Y, +- Inter Cb, Inter Cr. ++ Inter Cb, Inter Cr. The values on each scaling list are ++ expected in raster scan order. + * - __u8 + - ``scaling_list_8x8[6][64]`` + - Scaling matrix after applying the inverse scanning process. + Expected list order is Intra Y, Inter Y, Intra Cb, Inter Cb, +- Intra Cr, Inter Cr. ++ Intra Cr, Inter Cr. The values on each scaling list are ++ expected in raster scan order. + + ``V4L2_CID_MPEG_VIDEO_H264_SLICE_PARAMS (struct)`` + Specifies the slice parameters (as extracted from the bitstream) + +From da0e200cf7bd3c42b97c8fa8e941a756ffdbfb26 Mon Sep 17 00:00:00 2001 +From: Ezequiel Garcia +Date: Fri, 14 Aug 2020 10:36:18 -0300 +Subject: [PATCH] media: uapi: h264: Split prediction weight parameters + +The prediction weight parameters are only required under +certain conditions, which depend on slice header parameters. + +As specified in section 7.3.3 Slice header syntax, the prediction +weight table is present if: + +((weighted_pred_flag && (slice_type == P || slice_type == SP)) || \ +(weighted_bipred_idc == 1 && slice_type == B)) + +Given its size, it makes sense to move this table to its control, +so applications can avoid passing it if the slice doesn't specify it. + +Before this change struct v4l2_ctrl_h264_slice_params was 960 bytes. +With this change, it's 188 bytes and struct v4l2_ctrl_h264_pred_weight +is 772 bytes. + +Signed-off-by: Ezequiel Garcia +--- + .../media/v4l/ext-ctrls-codec.rst | 19 ++++++++++++------- + drivers/media/v4l2-core/v4l2-ctrls.c | 8 ++++++++ + drivers/staging/media/sunxi/cedrus/cedrus.c | 7 +++++++ + drivers/staging/media/sunxi/cedrus/cedrus.h | 1 + + .../staging/media/sunxi/cedrus/cedrus_dec.c | 2 ++ + .../staging/media/sunxi/cedrus/cedrus_h264.c | 12 +++--------- + include/media/h264-ctrls.h | 12 ++++++++++-- + include/media/v4l2-ctrls.h | 2 ++ + 8 files changed, 45 insertions(+), 18 deletions(-) + +diff --git a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst +index 694037ce888a..ddf9c6af7d0a 100644 +--- a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst ++++ b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst +@@ -1879,18 +1879,23 @@ enum v4l2_mpeg_video_h264_hierarchical_coding_type - + - 0x00000008 + - + +-``Prediction Weight Table`` ++``V4L2_CID_MPEG_VIDEO_H264_PRED_WEIGHTS (struct)`` ++ Prediction weight table defined according to :ref:`h264`, ++ section 7.4.3.2 "Prediction Weight Table Semantics". ++ The prediction weight table must be passed by applications ++ under the conditions explained in section 7.3.3 "Slice header ++ syntax". + +- The bitstream parameters are defined according to :ref:`h264`, +- section 7.4.3.2 "Prediction Weight Table Semantics". For further +- documentation, refer to the above specification, unless there is +- an explicit comment stating otherwise. ++ .. note:: ++ ++ This compound control is not yet part of the public kernel API and ++ it is expected to change. + +-.. c:type:: v4l2_h264_pred_weight_table ++.. c:type:: v4l2_ctrl_h264_pred_weights + + .. cssclass:: longtable + +-.. flat-table:: struct v4l2_h264_pred_weight_table ++.. flat-table:: struct v4l2_ctrl_h264_pred_weights + :header-rows: 0 + :stub-columns: 0 + :widths: 1 1 2 +diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c +index 3f3fbcd60cc6..76c8dc8fb31c 100644 +--- a/drivers/media/v4l2-core/v4l2-ctrls.c ++++ b/drivers/media/v4l2-core/v4l2-ctrls.c +@@ -897,6 +897,7 @@ const char *v4l2_ctrl_get_name(u32 id) + case V4L2_CID_MPEG_VIDEO_H264_DECODE_PARAMS: return "H264 Decode Parameters"; + case V4L2_CID_MPEG_VIDEO_H264_DECODE_MODE: return "H264 Decode Mode"; + case V4L2_CID_MPEG_VIDEO_H264_START_CODE: return "H264 Start Code"; ++ case V4L2_CID_MPEG_VIDEO_H264_PRED_WEIGHTS: return "H264 Prediction Weight Table"; + case V4L2_CID_MPEG_VIDEO_MPEG2_LEVEL: return "MPEG2 Level"; + case V4L2_CID_MPEG_VIDEO_MPEG2_PROFILE: return "MPEG2 Profile"; + case V4L2_CID_MPEG_VIDEO_MPEG4_I_FRAME_QP: return "MPEG4 I-Frame QP Value"; +@@ -1412,6 +1413,9 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type, + case V4L2_CID_MPEG_VIDEO_H264_DECODE_PARAMS: + *type = V4L2_CTRL_TYPE_H264_DECODE_PARAMS; + break; ++ case V4L2_CID_MPEG_VIDEO_H264_PRED_WEIGHTS: ++ *type = V4L2_CTRL_TYPE_H264_PRED_WEIGHTS; ++ break; + case V4L2_CID_MPEG_VIDEO_VP8_FRAME_HEADER: + *type = V4L2_CTRL_TYPE_VP8_FRAME_HEADER; + break; +@@ -1790,6 +1794,7 @@ static int std_validate_compound(const struct v4l2_ctrl *ctrl, u32 idx, + case V4L2_CTRL_TYPE_H264_SPS: + case V4L2_CTRL_TYPE_H264_PPS: + case V4L2_CTRL_TYPE_H264_SCALING_MATRIX: ++ case V4L2_CTRL_TYPE_H264_PRED_WEIGHTS: + case V4L2_CTRL_TYPE_H264_SLICE_PARAMS: + case V4L2_CTRL_TYPE_H264_DECODE_PARAMS: + break; +@@ -2553,6 +2558,9 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl, + case V4L2_CTRL_TYPE_H264_DECODE_PARAMS: + elem_size = sizeof(struct v4l2_ctrl_h264_decode_params); + break; ++ case V4L2_CTRL_TYPE_H264_PRED_WEIGHTS: ++ elem_size = sizeof(struct v4l2_ctrl_h264_pred_weights); ++ break; + case V4L2_CTRL_TYPE_VP8_FRAME_HEADER: + elem_size = sizeof(struct v4l2_ctrl_vp8_frame_header); + break; +diff --git a/drivers/staging/media/sunxi/cedrus/cedrus.c b/drivers/staging/media/sunxi/cedrus/cedrus.c +index bc27f9430eeb..826324faad7e 100644 +--- a/drivers/staging/media/sunxi/cedrus/cedrus.c ++++ b/drivers/staging/media/sunxi/cedrus/cedrus.c +@@ -78,6 +78,13 @@ static const struct cedrus_control cedrus_controls[] = { + .codec = CEDRUS_CODEC_H264, + .required = true, + }, ++ { ++ .cfg = { ++ .id = V4L2_CID_MPEG_VIDEO_H264_PRED_WEIGHTS, ++ }, ++ .codec = CEDRUS_CODEC_H264, ++ .required = false, ++ }, + { + .cfg = { + .id = V4L2_CID_MPEG_VIDEO_H264_DECODE_MODE, +diff --git a/drivers/staging/media/sunxi/cedrus/cedrus.h b/drivers/staging/media/sunxi/cedrus/cedrus.h +index 96765555ab8a..93c843ae14bb 100644 +--- a/drivers/staging/media/sunxi/cedrus/cedrus.h ++++ b/drivers/staging/media/sunxi/cedrus/cedrus.h +@@ -62,6 +62,7 @@ struct cedrus_h264_run { + const struct v4l2_ctrl_h264_scaling_matrix *scaling_matrix; + const struct v4l2_ctrl_h264_slice_params *slice_params; + const struct v4l2_ctrl_h264_sps *sps; ++ const struct v4l2_ctrl_h264_pred_weights *pred_weights; + }; + + struct cedrus_mpeg2_run { +diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_dec.c b/drivers/staging/media/sunxi/cedrus/cedrus_dec.c +index 58c48e4fdfe9..6385026d1b6b 100644 +--- a/drivers/staging/media/sunxi/cedrus/cedrus_dec.c ++++ b/drivers/staging/media/sunxi/cedrus/cedrus_dec.c +@@ -57,6 +57,8 @@ void cedrus_device_run(void *priv) + V4L2_CID_MPEG_VIDEO_H264_SLICE_PARAMS); + run.h264.sps = cedrus_find_control_data(ctx, + V4L2_CID_MPEG_VIDEO_H264_SPS); ++ run.h264.pred_weights = cedrus_find_control_data(ctx, ++ V4L2_CID_MPEG_VIDEO_H264_PRED_WEIGHTS); + break; + + case V4L2_PIX_FMT_HEVC_SLICE: +diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_h264.c b/drivers/staging/media/sunxi/cedrus/cedrus_h264.c +index cce527bbdf86..d5636dbbb622 100644 +--- a/drivers/staging/media/sunxi/cedrus/cedrus_h264.c ++++ b/drivers/staging/media/sunxi/cedrus/cedrus_h264.c +@@ -256,10 +256,8 @@ static void cedrus_write_scaling_lists(struct cedrus_ctx *ctx, + static void cedrus_write_pred_weight_table(struct cedrus_ctx *ctx, + struct cedrus_run *run) + { +- const struct v4l2_ctrl_h264_slice_params *slice = +- run->h264.slice_params; +- const struct v4l2_h264_pred_weight_table *pred_weight = +- &slice->pred_weight_table; ++ const struct v4l2_ctrl_h264_pred_weights *pred_weight = ++ run->h264.pred_weights; + struct cedrus_dev *dev = ctx->dev; + int i, j, k; + +@@ -367,11 +365,7 @@ static void cedrus_set_params(struct cedrus_ctx *ctx, + + cedrus_skip_bits(dev, slice->header_bit_size); + +- if (((pps->flags & V4L2_H264_PPS_FLAG_WEIGHTED_PRED) && +- (slice->slice_type == V4L2_H264_SLICE_TYPE_P || +- slice->slice_type == V4L2_H264_SLICE_TYPE_SP)) || +- (pps->weighted_bipred_idc == 1 && +- slice->slice_type == V4L2_H264_SLICE_TYPE_B)) ++ if (V4L2_H264_CTRL_PRED_WEIGHTS_REQUIRED(pps, slice)) + cedrus_write_pred_weight_table(ctx, run); + + if ((slice->slice_type == V4L2_H264_SLICE_TYPE_P) || +diff --git a/include/media/h264-ctrls.h b/include/media/h264-ctrls.h +index 5f635e8d25e2..d995614be159 100644 +--- a/include/media/h264-ctrls.h ++++ b/include/media/h264-ctrls.h +@@ -36,6 +36,7 @@ + #define V4L2_CID_MPEG_VIDEO_H264_DECODE_PARAMS (V4L2_CID_MPEG_BASE+1004) + #define V4L2_CID_MPEG_VIDEO_H264_DECODE_MODE (V4L2_CID_MPEG_BASE+1005) + #define V4L2_CID_MPEG_VIDEO_H264_START_CODE (V4L2_CID_MPEG_BASE+1006) ++#define V4L2_CID_MPEG_VIDEO_H264_PRED_WEIGHTS (V4L2_CID_MPEG_BASE+1007) + + /* enum v4l2_ctrl_type type values */ + #define V4L2_CTRL_TYPE_H264_SPS 0x0110 +@@ -43,6 +44,7 @@ + #define V4L2_CTRL_TYPE_H264_SCALING_MATRIX 0x0112 + #define V4L2_CTRL_TYPE_H264_SLICE_PARAMS 0x0113 + #define V4L2_CTRL_TYPE_H264_DECODE_PARAMS 0x0114 ++#define V4L2_CTRL_TYPE_H264_PRED_WEIGHTS 0x0115 + + enum v4l2_mpeg_video_h264_decode_mode { + V4L2_MPEG_VIDEO_H264_DECODE_MODE_SLICE_BASED, +@@ -125,7 +127,14 @@ struct v4l2_h264_weight_factors { + __s16 chroma_offset[32][2]; + }; + +-struct v4l2_h264_pred_weight_table { ++#define V4L2_H264_CTRL_PRED_WEIGHTS_REQUIRED(pps, slice) \ ++ ((((pps)->flags & V4L2_H264_PPS_FLAG_WEIGHTED_PRED) && \ ++ ((slice)->slice_type == V4L2_H264_SLICE_TYPE_P || \ ++ (slice)->slice_type == V4L2_H264_SLICE_TYPE_SP)) || \ ++ ((pps)->weighted_bipred_idc == 1 && \ ++ (slice)->slice_type == V4L2_H264_SLICE_TYPE_B)) ++ ++struct v4l2_ctrl_h264_pred_weights { + __u16 luma_log2_weight_denom; + __u16 chroma_log2_weight_denom; + struct v4l2_h264_weight_factors weight_factors[2]; +@@ -177,7 +186,6 @@ struct v4l2_ctrl_h264_slice_params { + __s32 delta_pic_order_cnt0; + __s32 delta_pic_order_cnt1; + +- struct v4l2_h264_pred_weight_table pred_weight_table; + /* Size in bits of dec_ref_pic_marking() syntax element. */ + __u32 dec_ref_pic_marking_bit_size; + /* Size in bits of pic order count syntax. */ +diff --git a/include/media/v4l2-ctrls.h b/include/media/v4l2-ctrls.h +index f40e2cbb21d3..cb25f345e9ad 100644 +--- a/include/media/v4l2-ctrls.h ++++ b/include/media/v4l2-ctrls.h +@@ -51,6 +51,7 @@ struct video_device; + * @p_h264_scaling_matrix: Pointer to a struct v4l2_ctrl_h264_scaling_matrix. + * @p_h264_slice_params: Pointer to a struct v4l2_ctrl_h264_slice_params. + * @p_h264_decode_params: Pointer to a struct v4l2_ctrl_h264_decode_params. ++ * @p_h264_pred_weights: Pointer to a struct v4l2_ctrl_h264_pred_weights. + * @p_vp8_frame_header: Pointer to a VP8 frame header structure. + * @p_hevc_sps: Pointer to an HEVC sequence parameter set structure. + * @p_hevc_pps: Pointer to an HEVC picture parameter set structure. +@@ -74,6 +75,7 @@ union v4l2_ctrl_ptr { + struct v4l2_ctrl_h264_scaling_matrix *p_h264_scaling_matrix; + struct v4l2_ctrl_h264_slice_params *p_h264_slice_params; + struct v4l2_ctrl_h264_decode_params *p_h264_decode_params; ++ struct v4l2_ctrl_h264_pred_weights *p_h264_pred_weights; + struct v4l2_ctrl_vp8_frame_header *p_vp8_frame_header; + struct v4l2_ctrl_hevc_sps *p_hevc_sps; + struct v4l2_ctrl_hevc_pps *p_hevc_pps; + +From 82c12e79f57d0b51b81efb2bb87a91288988d958 Mon Sep 17 00:00:00 2001 +From: Philipp Zabel +Date: Fri, 14 Aug 2020 10:36:19 -0300 +Subject: [PATCH] media: uapi: h264: Clarify pic_order_cnt_bit_size field + +Since pic_order_cnt_bit_size is not a syntax element itself, explicitly +state that it is the total size in bits of the pic_order_cnt_lsb, +delta_pic_order_cnt_bottom, delta_pic_order_cnt[0], and +delta_pic_order_cnt[1] syntax elements contained in the slice. + +Signed-off-by: Philipp Zabel +[Ezequiel: rebase] +Signed-off-by: Ezequiel Garcia +Reviewed-by: Nicolas Dufresne +--- + Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst +index ddf9c6af7d0a..32f3cebf16e5 100644 +--- a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst ++++ b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst +@@ -1815,7 +1815,9 @@ enum v4l2_mpeg_video_h264_hierarchical_coding_type - + - Size in bits of the dec_ref_pic_marking() syntax element. + * - __u32 + - ``pic_order_cnt_bit_size`` +- - ++ - Combined size in bits of the picture order count related syntax ++ elements: pic_order_cnt_lsb, delta_pic_order_cnt_bottom, ++ delta_pic_order_cnt0, and delta_pic_order_cnt1. + * - __u8 + - ``cabac_init_idc`` + - + +From fced897398d6228473f01df99fd09fd4410f623d Mon Sep 17 00:00:00 2001 +From: Ezequiel Garcia +Date: Fri, 14 Aug 2020 10:36:20 -0300 +Subject: [PATCH] media: uapi: h264: Increase size of 'first_mb_in_slice' field + +Slice header syntax element 'first_mb_in_slice' can point +to the last macroblock, currently the field can only reference +65536 macroblocks which is insufficient for 8K videos. + +Although unlikely, a 8192x4320 video (where macroblocks are 16x16), +would contain 138240 macroblocks on a frame. + +As per the H264 specification, 'first_mb_in_slice' can be up to +PicSizeInMbs - 1, so increase the size of the field to 32-bits. + +Note that v4l2_ctrl_h264_slice_params struct will be modified +in a follow-up commit, and so we defer its 64-bit padding. + +Signed-off-by: Ezequiel Garcia +--- + Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst | 2 +- + include/media/h264-ctrls.h | 3 ++- + 2 files changed, 3 insertions(+), 2 deletions(-) + +diff --git a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst +index 32f3cebf16e5..714a8d9ae6a0 100644 +--- a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst ++++ b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst +@@ -1774,7 +1774,7 @@ enum v4l2_mpeg_video_h264_hierarchical_coding_type - + * - __u32 + - ``header_bit_size`` + - +- * - __u16 ++ * - __u32 + - ``first_mb_in_slice`` + - + * - __u8 +diff --git a/include/media/h264-ctrls.h b/include/media/h264-ctrls.h +index d995614be159..9ff085fdc9ab 100644 +--- a/include/media/h264-ctrls.h ++++ b/include/media/h264-ctrls.h +@@ -174,7 +174,8 @@ struct v4l2_ctrl_h264_slice_params { + /* Offset in bits to slice_data() from the beginning of this slice. */ + __u32 header_bit_size; + +- __u16 first_mb_in_slice; ++ __u32 first_mb_in_slice; ++ + __u8 slice_type; + __u8 pic_parameter_set_id; + __u8 colour_plane_id; + +From 52266e3675e9359f13aa4d44a4ab392fd1f079c0 Mon Sep 17 00:00:00 2001 +From: Ezequiel Garcia +Date: Fri, 14 Aug 2020 10:36:21 -0300 +Subject: [PATCH] media: uapi: h264: Clean DPB entry interface + +As discussed recently, the current interface for the +Decoded Picture Buffer is not enough to properly +support field coding. + +This commit introduces enough semantics to support +frame and field coding, and to signal how DPB entries +are "used for reference". + +Signed-off-by: Ezequiel Garcia +--- + .../media/v4l/ext-ctrls-codec.rst | 24 ++++++------------- + drivers/media/v4l2-core/v4l2-h264.c | 4 ++-- + drivers/staging/media/rkvdec/rkvdec-h264.c | 17 ++++++------- + include/media/h264-ctrls.h | 2 +- + 4 files changed, 19 insertions(+), 28 deletions(-) + +diff --git a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst +index 714a8d9ae6a0..d14da8325382 100644 +--- a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst ++++ b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst +@@ -2063,6 +2063,9 @@ enum v4l2_mpeg_video_h264_hierarchical_coding_type - + * - __s32 + - ``bottom_field_order_cnt`` + - ++ * - enum :c:type:`v4l2_h264_field_reference` ++ - ``reference`` ++ - Specifies how the DPB entry is referenced. + * - __u32 + - ``flags`` + - See :ref:`DPB Entry Flags ` +@@ -2080,29 +2083,16 @@ enum v4l2_mpeg_video_h264_hierarchical_coding_type - + + * - ``V4L2_H264_DPB_ENTRY_FLAG_VALID`` + - 0x00000001 +- - The DPB entry is valid and should be considered ++ - The DPB entry is valid (non-empty) and should be considered. + * - ``V4L2_H264_DPB_ENTRY_FLAG_ACTIVE`` + - 0x00000002 +- - The DPB entry is currently being used as a reference frame ++ - The DPB entry is used for reference. + * - ``V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM`` + - 0x00000004 +- - The DPB entry is a long term reference frame ++ - The DPB entry is used for long-term reference. + * - ``V4L2_H264_DPB_ENTRY_FLAG_FIELD`` + - 0x00000008 +- - The DPB entry is a field reference, which means only one of the field +- will be used when decoding the new frame/field. When not set the DPB +- entry is a frame reference (both fields will be used). Note that this +- flag does not say anything about the number of fields contained in the +- reference frame, it just describes the one used to decode the new +- field/frame +- * - ``V4L2_H264_DPB_ENTRY_FLAG_BOTTOM_FIELD`` +- - 0x00000010 +- - The DPB entry is a bottom field reference (only the bottom field of the +- reference frame is needed to decode the new frame/field). Only valid if +- V4L2_H264_DPB_ENTRY_FLAG_FIELD is set. When +- V4L2_H264_DPB_ENTRY_FLAG_FIELD is set but +- V4L2_H264_DPB_ENTRY_FLAG_BOTTOM_FIELD is not, that means the +- DPB entry is a top field reference ++ - The DPB entry is a single field or a complementary field pair. + + ``V4L2_CID_MPEG_VIDEO_H264_DECODE_MODE (enum)`` + Specifies the decoding mode to use. Currently exposes slice-based and +diff --git a/drivers/media/v4l2-core/v4l2-h264.c b/drivers/media/v4l2-core/v4l2-h264.c +index edf6225f0522..12b751c09016 100644 +--- a/drivers/media/v4l2-core/v4l2-h264.c ++++ b/drivers/media/v4l2-core/v4l2-h264.c +@@ -66,10 +66,10 @@ v4l2_h264_init_reflist_builder(struct v4l2_h264_reflist_builder *b, + else + b->refs[i].frame_num = dpb[i].frame_num; + +- if (!(dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_FIELD)) ++ if (dpb[i].reference == V4L2_H264_FRAME_REF) + pic_order_count = min(dpb[i].top_field_order_cnt, + dpb[i].bottom_field_order_cnt); +- else if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_BOTTOM_FIELD) ++ else if (dpb[i].reference & V4L2_H264_BOTTOM_FIELD_REF) + pic_order_count = dpb[i].bottom_field_order_cnt; + else + pic_order_count = dpb[i].top_field_order_cnt; +diff --git a/drivers/staging/media/rkvdec/rkvdec-h264.c b/drivers/staging/media/rkvdec/rkvdec-h264.c +index 7b66e2743a4f..07a80e9a9df2 100644 +--- a/drivers/staging/media/rkvdec/rkvdec-h264.c ++++ b/drivers/staging/media/rkvdec/rkvdec-h264.c +@@ -949,16 +949,17 @@ static void config_registers(struct rkvdec_ctx *ctx, + for (i = 0; i < ARRAY_SIZE(dec_params->dpb); i++) { + struct vb2_buffer *vb_buf = get_ref_buf(ctx, run, i); + +- refer_addr = vb2_dma_contig_plane_dma_addr(vb_buf, 0) | +- RKVDEC_COLMV_USED_FLAG_REF; ++ refer_addr = vb2_dma_contig_plane_dma_addr(vb_buf, 0); + +- if (!(dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_FIELD)) +- refer_addr |= RKVDEC_TOPFIELD_USED_REF | +- RKVDEC_BOTFIELD_USED_REF; +- else if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_BOTTOM_FIELD) +- refer_addr |= RKVDEC_BOTFIELD_USED_REF; +- else ++ if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE) ++ refer_addr |= RKVDEC_COLMV_USED_FLAG_REF; ++ if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_FIELD) ++ refer_addr |= RKVDEC_FIELD_REF; ++ ++ if (dpb[i].reference & V4L2_H264_TOP_FIELD_REF) + refer_addr |= RKVDEC_TOPFIELD_USED_REF; ++ if (dpb[i].reference & V4L2_H264_BOTTOM_FIELD_REF) ++ refer_addr |= RKVDEC_BOTFIELD_USED_REF; + + writel_relaxed(dpb[i].top_field_order_cnt, + rkvdec->regs + poc_reg_tbl_top_field[i]); +diff --git a/include/media/h264-ctrls.h b/include/media/h264-ctrls.h +index 9ff085fdc9ab..4447697e9465 100644 +--- a/include/media/h264-ctrls.h ++++ b/include/media/h264-ctrls.h +@@ -212,7 +212,6 @@ struct v4l2_ctrl_h264_slice_params { + #define V4L2_H264_DPB_ENTRY_FLAG_ACTIVE 0x02 + #define V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM 0x04 + #define V4L2_H264_DPB_ENTRY_FLAG_FIELD 0x08 +-#define V4L2_H264_DPB_ENTRY_FLAG_BOTTOM_FIELD 0x10 + + struct v4l2_h264_dpb_entry { + __u64 reference_ts; +@@ -221,6 +220,7 @@ struct v4l2_h264_dpb_entry { + /* Note that field is indicated by v4l2_buffer.field */ + __s32 top_field_order_cnt; + __s32 bottom_field_order_cnt; ++ enum v4l2_h264_field_reference reference; + __u32 flags; /* V4L2_H264_DPB_ENTRY_FLAG_* */ + }; + + +From cd2980d0ab75400656f854ac48a147ef07b9f9ba Mon Sep 17 00:00:00 2001 +From: Ezequiel Garcia +Date: Fri, 14 Aug 2020 10:36:22 -0300 +Subject: [PATCH] media: uapi: h264: Increase size of DPB entry pic_num + +DPB entry PicNum maximum value is 2*MaxFrameNum for interlaced +content (field_pic_flag=1). + +As specified, MaxFrameNum is 2^(log2_max_frame_num_minus4 + 4) +and log2_max_frame_num_minus4 is in the range of 0 to 12, +which means pic_num should be a 32-bit field. + +The v4l2_h264_dpb_entry struct needs to be padded to avoid a hole, +which might be also useful to allow future uAPI extensions. + +Signed-off-by: Ezequiel Garcia +--- + .../userspace-api/media/v4l/ext-ctrls-codec.rst | 5 ++++- + drivers/media/v4l2-core/v4l2-ctrls.c | 13 +++++++++++++ + include/media/h264-ctrls.h | 3 ++- + include/media/v4l2-h264.h | 2 +- + 4 files changed, 20 insertions(+), 3 deletions(-) + +diff --git a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst +index d14da8325382..c0ae7fda803e 100644 +--- a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst ++++ b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst +@@ -2054,7 +2054,10 @@ enum v4l2_mpeg_video_h264_hierarchical_coding_type - + * - __u16 + - ``frame_num`` + - +- * - __u16 ++ * - __u8 ++ - ``reserved[2]`` ++ - Applications and drivers must set this to zero. ++ * - __u32 + - ``pic_num`` + - + * - __s32 +diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c +index 76c8dc8fb31c..b9457789fa55 100644 +--- a/drivers/media/v4l2-core/v4l2-ctrls.c ++++ b/drivers/media/v4l2-core/v4l2-ctrls.c +@@ -1725,6 +1725,8 @@ static void std_log(const struct v4l2_ctrl *ctrl) + + #define zero_padding(s) \ + memset(&(s).padding, 0, sizeof((s).padding)) ++#define zero_reserved(s) \ ++ memset(&(s).reserved, 0, sizeof((s).reserved)) + + /* + * Compound controls validation requires setting unused fields/flags to zero +@@ -1735,6 +1737,7 @@ static int std_validate_compound(const struct v4l2_ctrl *ctrl, u32 idx, + { + struct v4l2_ctrl_mpeg2_slice_params *p_mpeg2_slice_params; + struct v4l2_ctrl_vp8_frame_header *p_vp8_frame_header; ++ struct v4l2_ctrl_h264_decode_params *p_h264_dec_params; + struct v4l2_ctrl_hevc_sps *p_hevc_sps; + struct v4l2_ctrl_hevc_pps *p_hevc_pps; + struct v4l2_ctrl_hevc_slice_params *p_hevc_slice_params; +@@ -1796,7 +1799,17 @@ static int std_validate_compound(const struct v4l2_ctrl *ctrl, u32 idx, + case V4L2_CTRL_TYPE_H264_SCALING_MATRIX: + case V4L2_CTRL_TYPE_H264_PRED_WEIGHTS: + case V4L2_CTRL_TYPE_H264_SLICE_PARAMS: ++ break; ++ + case V4L2_CTRL_TYPE_H264_DECODE_PARAMS: ++ p_h264_dec_params = p; ++ ++ for (i = 0; i < V4L2_H264_NUM_DPB_ENTRIES; i++) { ++ struct v4l2_h264_dpb_entry *dpb_entry = ++ &p_h264_dec_params->dpb[i]; ++ ++ zero_reserved(*dpb_entry); ++ } + break; + + case V4L2_CTRL_TYPE_VP8_FRAME_HEADER: +diff --git a/include/media/h264-ctrls.h b/include/media/h264-ctrls.h +index 4447697e9465..d178d7ad53b6 100644 +--- a/include/media/h264-ctrls.h ++++ b/include/media/h264-ctrls.h +@@ -216,7 +216,8 @@ struct v4l2_ctrl_h264_slice_params { + struct v4l2_h264_dpb_entry { + __u64 reference_ts; + __u16 frame_num; +- __u16 pic_num; ++ __u8 reserved[2]; ++ __u32 pic_num; + /* Note that field is indicated by v4l2_buffer.field */ + __s32 top_field_order_cnt; + __s32 bottom_field_order_cnt; +diff --git a/include/media/v4l2-h264.h b/include/media/v4l2-h264.h +index bc9ebb560ccf..1a5f26fc2a9a 100644 +--- a/include/media/v4l2-h264.h ++++ b/include/media/v4l2-h264.h +@@ -33,7 +33,7 @@ struct v4l2_h264_reflist_builder { + struct { + s32 pic_order_count; + int frame_num; +- u16 pic_num; ++ u32 pic_num; + u16 longterm : 1; + } refs[V4L2_H264_NUM_DPB_ENTRIES]; + s32 cur_pic_order_count; + +From c380a6c41ab18183ff5d6342d8dc6cf7f22e6ed5 Mon Sep 17 00:00:00 2001 +From: Ezequiel Garcia +Date: Fri, 14 Aug 2020 10:36:23 -0300 +Subject: [PATCH] media: uapi: h264: Drop SLICE_PARAMS 'size' field + +The SLICE_PARAMS control is intended for slice-based +devices. In this mode, the OUTPUT buffer contains +a single slice, and so the buffer's plane payload size +can be used to query the slice size. + +To reduce the API surface drop the size from the +SLICE_PARAMS control. + +A follow-up change will remove other members in SLICE_PARAMS +so we don't need to add padding fields here. + +Signed-off-by: Ezequiel Garcia +--- + Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst | 3 --- + drivers/staging/media/sunxi/cedrus/cedrus_h264.c | 7 +++---- + include/media/h264-ctrls.h | 3 --- + 3 files changed, 3 insertions(+), 10 deletions(-) + +diff --git a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst +index c0ae7fda803e..e88c207d945b 100644 +--- a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst ++++ b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst +@@ -1760,9 +1760,6 @@ enum v4l2_mpeg_video_h264_hierarchical_coding_type - + :stub-columns: 0 + :widths: 1 1 2 + +- * - __u32 +- - ``size`` +- - + * - __u32 + - ``start_byte_offset`` + Offset (in bytes) from the beginning of the OUTPUT buffer to the start +diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_h264.c b/drivers/staging/media/sunxi/cedrus/cedrus_h264.c +index d5636dbbb622..7d9bd5860a1b 100644 +--- a/drivers/staging/media/sunxi/cedrus/cedrus_h264.c ++++ b/drivers/staging/media/sunxi/cedrus/cedrus_h264.c +@@ -324,17 +324,16 @@ static void cedrus_set_params(struct cedrus_ctx *ctx, + struct vb2_buffer *src_buf = &run->src->vb2_buf; + struct cedrus_dev *dev = ctx->dev; + dma_addr_t src_buf_addr; +- u32 len = slice->size * 8; ++ size_t slice_bytes = vb2_get_plane_payload(src_buf, 0); + unsigned int pic_width_in_mbs; + bool mbaff_pic; + u32 reg; + +- cedrus_write(dev, VE_H264_VLD_LEN, len); ++ cedrus_write(dev, VE_H264_VLD_LEN, slice_bytes * 8); + cedrus_write(dev, VE_H264_VLD_OFFSET, 0); + + src_buf_addr = vb2_dma_contig_plane_dma_addr(src_buf, 0); +- cedrus_write(dev, VE_H264_VLD_END, +- src_buf_addr + vb2_get_plane_payload(src_buf, 0)); ++ cedrus_write(dev, VE_H264_VLD_END, src_buf_addr + slice_bytes); + cedrus_write(dev, VE_H264_VLD_ADDR, + VE_H264_VLD_ADDR_VAL(src_buf_addr) | + VE_H264_VLD_ADDR_FIRST | VE_H264_VLD_ADDR_VALID | +diff --git a/include/media/h264-ctrls.h b/include/media/h264-ctrls.h +index d178d7ad53b6..afcae3052085 100644 +--- a/include/media/h264-ctrls.h ++++ b/include/media/h264-ctrls.h +@@ -165,9 +165,6 @@ struct v4l2_h264_reference { + }; + + struct v4l2_ctrl_h264_slice_params { +- /* Size in bytes, including header */ +- __u32 size; +- + /* Offset in bytes to the start of slice in the OUTPUT buffer. */ + __u32 start_byte_offset; + + +From 37293295255bb5ad4063fe1ca6945a6890c65cd4 Mon Sep 17 00:00:00 2001 +From: Ezequiel Garcia +Date: Fri, 14 Aug 2020 10:36:24 -0300 +Subject: [PATCH] media: uapi: h264: Clarify SLICE_BASED mode + +Currently, the SLICE_BASED and FRAME_BASED modes documentation +is misleading and not matching the intended use-cases. + +Drop non-required fields SLICE_PARAMS 'start_byte_offset' and +DECODE_PARAMS 'num_slices' and clarify the decoding modes in the +documentation. + +On SLICE_BASED mode, a single slice is expected per OUTPUT buffer, +and therefore 'start_byte_offset' is not needed (since the offset +to the slice is the start of the buffer). + +This mode requires the use of CAPTURE buffer holding, and so +the number of slices shall not be required. + +On FRAME_BASED mode, the devices are expected to take care of slice +parsing. Neither SLICE_PARAMS are required (and shouldn't be +exposed by frame-based drivers), nor the number of slices. + +Signed-off-by: Ezequiel Garcia +--- + .../media/v4l/ext-ctrls-codec.rst | 39 +++++-------------- + include/media/h264-ctrls.h | 4 -- + 2 files changed, 10 insertions(+), 33 deletions(-) + +diff --git a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst +index e88c207d945b..90caf6a0d5a0 100644 +--- a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst ++++ b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst +@@ -1748,9 +1748,6 @@ enum v4l2_mpeg_video_h264_hierarchical_coding_type - + This compound control is not yet part of the public kernel API + and it is expected to change. + +- This structure is expected to be passed as an array, with one +- entry for each slice included in the bitstream buffer. +- + .. c:type:: v4l2_ctrl_h264_slice_params + + .. cssclass:: longtable +@@ -1760,17 +1757,9 @@ enum v4l2_mpeg_video_h264_hierarchical_coding_type - + :stub-columns: 0 + :widths: 1 1 2 + +- * - __u32 +- - ``start_byte_offset`` +- Offset (in bytes) from the beginning of the OUTPUT buffer to the start +- of the slice. If the slice starts with a start code, then this is the +- offset to such start code. When operating in slice-based decoding mode +- (see :c:type:`v4l2_mpeg_video_h264_decode_mode`), this field should +- be set to 0. When operating in frame-based decoding mode, this field +- should be 0 for the first slice. + * - __u32 + - ``header_bit_size`` +- - ++ - Offset in bits to slice_data() from the beginning of this slice. + * - __u32 + - ``first_mb_in_slice`` + - +@@ -1998,12 +1987,6 @@ enum v4l2_mpeg_video_h264_hierarchical_coding_type - + * - struct :c:type:`v4l2_h264_dpb_entry` + - ``dpb[16]`` + - +- * - __u16 +- - ``num_slices`` +- - Number of slices needed to decode the current frame/field. When +- operating in slice-based decoding mode (see +- :c:type:`v4l2_mpeg_video_h264_decode_mode`), this field +- should always be set to one. + * - __u16 + - ``nal_ref_idc`` + - NAL reference ID value coming from the NAL Unit header +@@ -2121,22 +2104,20 @@ enum v4l2_mpeg_video_h264_hierarchical_coding_type - + * - ``V4L2_MPEG_VIDEO_H264_DECODE_MODE_SLICE_BASED`` + - 0 + - Decoding is done at the slice granularity. +- In this mode, ``num_slices`` field in struct +- :c:type:`v4l2_ctrl_h264_decode_params` should be set to 1, +- and ``start_byte_offset`` in struct +- :c:type:`v4l2_ctrl_h264_slice_params` should be set to 0. + The OUTPUT buffer must contain a single slice. ++ When this mode is selected, the ``V4L2_CID_MPEG_VIDEO_H264_SLICE_PARAMS`` ++ control shall be set. When multiple slices compose a frame, ++ use of ``V4L2_BUF_CAP_SUPPORTS_M2M_HOLD_CAPTURE_BUF`` flag ++ is required. + * - ``V4L2_MPEG_VIDEO_H264_DECODE_MODE_FRAME_BASED`` + - 1 +- - Decoding is done at the frame granularity. +- In this mode, ``num_slices`` field in struct +- :c:type:`v4l2_ctrl_h264_decode_params` should be set to the number +- of slices in the frame, and ``start_byte_offset`` in struct +- :c:type:`v4l2_ctrl_h264_slice_params` should be set accordingly +- for each slice. For the first slice, ``start_byte_offset`` should +- be zero. ++ - Decoding is done at the frame granularity, + The OUTPUT buffer must contain all slices needed to decode the + frame. The OUTPUT buffer must also contain both fields. ++ This mode will be supported by devices that ++ parse the slice(s) header(s) in hardware. When this mode is ++ selected, the ``V4L2_CID_MPEG_VIDEO_H264_SLICE_PARAMS`` ++ control shall not be set. + + ``V4L2_CID_MPEG_VIDEO_H264_START_CODE (enum)`` + Specifies the H264 slice start code expected for each slice. +diff --git a/include/media/h264-ctrls.h b/include/media/h264-ctrls.h +index afcae3052085..e180501e6385 100644 +--- a/include/media/h264-ctrls.h ++++ b/include/media/h264-ctrls.h +@@ -165,9 +165,6 @@ struct v4l2_h264_reference { + }; + + struct v4l2_ctrl_h264_slice_params { +- /* Offset in bytes to the start of slice in the OUTPUT buffer. */ +- __u32 start_byte_offset; +- + /* Offset in bits to slice_data() from the beginning of this slice. */ + __u32 header_bit_size; + +@@ -226,7 +223,6 @@ struct v4l2_h264_dpb_entry { + + struct v4l2_ctrl_h264_decode_params { + struct v4l2_h264_dpb_entry dpb[V4L2_H264_NUM_DPB_ENTRIES]; +- __u16 num_slices; + __u16 nal_ref_idc; + __s32 top_field_order_cnt; + __s32 bottom_field_order_cnt; + +From ff81175260cd33feaa7d0407ef50186422215fae Mon Sep 17 00:00:00 2001 +From: Ezequiel Garcia +Date: Fri, 14 Aug 2020 10:36:25 -0300 +Subject: [PATCH] media: uapi: h264: Clean slice invariants syntax elements + +The H.264 specification requires in section 7.4.3 "Slice header semantics", +that the following values shall be the same in all slice headers: + + pic_parameter_set_id + frame_num + field_pic_flag + bottom_field_flag + idr_pic_id + pic_order_cnt_lsb + delta_pic_order_cnt_bottom + delta_pic_order_cnt[ 0 ] + delta_pic_order_cnt[ 1 ] + sp_for_switch_flag + slice_group_change_cycle + +These bitstream fields are part of the slice header, and therefore +passed redundantly on each slice. The purpose of the redundancy +is to make the codec fault-tolerant in network scenarios. + +This is of course not needed to be reflected in the V4L2 controls, +given the bitstream has already been parsed by applications. +Therefore, move the redundant fields to the per-frame decode +parameters control (DECODE_PARAMS). + +Field 'pic_parameter_set_id' is simply removed in this case, +because the PPS control must currently contain the active PPS. + +Syntax elements dec_ref_pic_marking() and those related +to pic order count, remain invariant as well, and therefore, +the fields dec_ref_pic_marking_bit_size and pic_order_cnt_bit_size +are also common to all slices. + +Signed-off-by: Ezequiel Garcia +Reviewed-by: Nicolas Dufresne +--- + .../media/v4l/ext-ctrls-codec.rst | 86 +++++++++---------- + drivers/media/v4l2-core/v4l2-ctrls.c | 7 ++ + drivers/media/v4l2-core/v4l2-h264.c | 8 +- + .../staging/media/hantro/hantro_g1_h264_dec.c | 21 +++-- + drivers/staging/media/hantro/hantro_h264.c | 3 +- + drivers/staging/media/rkvdec/rkvdec-h264.c | 6 +- + .../staging/media/sunxi/cedrus/cedrus_h264.c | 9 +- + include/media/h264-ctrls.h | 39 +++++---- + include/media/v4l2-h264.h | 1 - + 9 files changed, 90 insertions(+), 90 deletions(-) + +diff --git a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst +index 90caf6a0d5a0..69dd3961b99b 100644 +--- a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst ++++ b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst +@@ -1766,44 +1766,12 @@ enum v4l2_mpeg_video_h264_hierarchical_coding_type - + * - __u8 + - ``slice_type`` + - +- * - __u8 +- - ``pic_parameter_set_id`` +- - + * - __u8 + - ``colour_plane_id`` + - + * - __u8 + - ``redundant_pic_cnt`` + - +- * - __u16 +- - ``frame_num`` +- - +- * - __u16 +- - ``idr_pic_id`` +- - +- * - __u16 +- - ``pic_order_cnt_lsb`` +- - +- * - __s32 +- - ``delta_pic_order_cnt_bottom`` +- - +- * - __s32 +- - ``delta_pic_order_cnt0`` +- - +- * - __s32 +- - ``delta_pic_order_cnt1`` +- - +- * - struct :c:type:`v4l2_h264_pred_weight_table` +- - ``pred_weight_table`` +- - +- * - __u32 +- - ``dec_ref_pic_marking_bit_size`` +- - Size in bits of the dec_ref_pic_marking() syntax element. +- * - __u32 +- - ``pic_order_cnt_bit_size`` +- - Combined size in bits of the picture order count related syntax +- elements: pic_order_cnt_lsb, delta_pic_order_cnt_bottom, +- delta_pic_order_cnt0, and delta_pic_order_cnt1. + * - __u8 + - ``cabac_init_idc`` + - +@@ -1830,9 +1798,9 @@ enum v4l2_mpeg_video_h264_hierarchical_coding_type - + - ``num_ref_idx_l1_active_minus1`` + - If num_ref_idx_active_override_flag is not set, this field must be + set to the value of num_ref_idx_l1_default_active_minus1. +- * - __u32 +- - ``slice_group_change_cycle`` +- - ++ * - __u8 ++ - ``reserved`` ++ - Applications and drivers must set this to zero. + * - struct :c:type:`v4l2_h264_reference` + - ``ref_pic_list0[32]`` + - Reference picture list after applying the per-slice modifications +@@ -1854,17 +1822,11 @@ enum v4l2_mpeg_video_h264_hierarchical_coding_type - + :stub-columns: 0 + :widths: 1 1 2 + +- * - ``V4L2_H264_SLICE_FLAG_FIELD_PIC`` +- - 0x00000001 +- - +- * - ``V4L2_H264_SLICE_FLAG_BOTTOM_FIELD`` +- - 0x00000002 +- - + * - ``V4L2_H264_SLICE_FLAG_DIRECT_SPATIAL_MV_PRED`` +- - 0x00000004 ++ - 0x00000001 + - + * - ``V4L2_H264_SLICE_FLAG_SP_FOR_SWITCH`` +- - 0x00000008 ++ - 0x00000002 + - + + ``V4L2_CID_MPEG_VIDEO_H264_PRED_WEIGHTS (struct)`` +@@ -1990,12 +1952,44 @@ enum v4l2_mpeg_video_h264_hierarchical_coding_type - + * - __u16 + - ``nal_ref_idc`` + - NAL reference ID value coming from the NAL Unit header ++ * - __u16 ++ - ``frame_num`` ++ - + * - __s32 + - ``top_field_order_cnt`` + - Picture Order Count for the coded top field + * - __s32 + - ``bottom_field_order_cnt`` + - Picture Order Count for the coded bottom field ++ * - __u16 ++ - ``idr_pic_id`` ++ - ++ * - __u16 ++ - ``pic_order_cnt_lsb`` ++ - ++ * - __s32 ++ - ``delta_pic_order_cnt_bottom`` ++ - ++ * - __s32 ++ - ``delta_pic_order_cnt0`` ++ - ++ * - __s32 ++ - ``delta_pic_order_cnt1`` ++ - ++ * - __u32 ++ - ``dec_ref_pic_marking_bit_size`` ++ - Size in bits of the dec_ref_pic_marking() syntax element. ++ * - __u32 ++ - ``pic_order_cnt_bit_size`` ++ - Combined size in bits of the picture order count related syntax ++ elements: pic_order_cnt_lsb, delta_pic_order_cnt_bottom, ++ delta_pic_order_cnt0, and delta_pic_order_cnt1. ++ * - __u32 ++ - ``slice_group_change_cycle`` ++ - ++ * - __u32 ++ - ``reserved`` ++ - Applications and drivers must set this to zero. + * - __u32 + - ``flags`` + - See :ref:`Decode Parameters Flags ` +@@ -2014,6 +2008,12 @@ enum v4l2_mpeg_video_h264_hierarchical_coding_type - + * - ``V4L2_H264_DECODE_PARAM_FLAG_IDR_PIC`` + - 0x00000001 + - That picture is an IDR picture ++ * - ``V4L2_H264_DECODE_PARAM_FLAG_FIELD_PIC`` ++ - 0x00000002 ++ - ++ * - ``V4L2_H264_DECODE_PARAM_FLAG_BOTTOM_FIELD`` ++ - 0x00000004 ++ - + + .. c:type:: v4l2_h264_dpb_entry + +diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c +index b9457789fa55..b846f5b089c9 100644 +--- a/drivers/media/v4l2-core/v4l2-ctrls.c ++++ b/drivers/media/v4l2-core/v4l2-ctrls.c +@@ -1737,6 +1737,7 @@ static int std_validate_compound(const struct v4l2_ctrl *ctrl, u32 idx, + { + struct v4l2_ctrl_mpeg2_slice_params *p_mpeg2_slice_params; + struct v4l2_ctrl_vp8_frame_header *p_vp8_frame_header; ++ struct v4l2_ctrl_h264_slice_params *p_h264_slice_params; + struct v4l2_ctrl_h264_decode_params *p_h264_dec_params; + struct v4l2_ctrl_hevc_sps *p_hevc_sps; + struct v4l2_ctrl_hevc_pps *p_hevc_pps; +@@ -1798,7 +1799,12 @@ static int std_validate_compound(const struct v4l2_ctrl *ctrl, u32 idx, + case V4L2_CTRL_TYPE_H264_PPS: + case V4L2_CTRL_TYPE_H264_SCALING_MATRIX: + case V4L2_CTRL_TYPE_H264_PRED_WEIGHTS: ++ break; ++ + case V4L2_CTRL_TYPE_H264_SLICE_PARAMS: ++ p_h264_slice_params = p; ++ ++ zero_reserved(*p_h264_slice_params); + break; + + case V4L2_CTRL_TYPE_H264_DECODE_PARAMS: +@@ -1810,6 +1816,7 @@ static int std_validate_compound(const struct v4l2_ctrl *ctrl, u32 idx, + + zero_reserved(*dpb_entry); + } ++ zero_reserved(*p_h264_dec_params); + break; + + case V4L2_CTRL_TYPE_VP8_FRAME_HEADER: +diff --git a/drivers/media/v4l2-core/v4l2-h264.c b/drivers/media/v4l2-core/v4l2-h264.c +index 12b751c09016..101fdeabfb06 100644 +--- a/drivers/media/v4l2-core/v4l2-h264.c ++++ b/drivers/media/v4l2-core/v4l2-h264.c +@@ -18,14 +18,12 @@ + * + * @b: the builder context to initialize + * @dec_params: decode parameters control +- * @slice_params: first slice parameters control + * @sps: SPS control + * @dpb: DPB to use when creating the reference list + */ + void + v4l2_h264_init_reflist_builder(struct v4l2_h264_reflist_builder *b, + const struct v4l2_ctrl_h264_decode_params *dec_params, +- const struct v4l2_ctrl_h264_slice_params *slice_params, + const struct v4l2_ctrl_h264_sps *sps, + const struct v4l2_h264_dpb_entry dpb[V4L2_H264_NUM_DPB_ENTRIES]) + { +@@ -33,13 +31,13 @@ v4l2_h264_init_reflist_builder(struct v4l2_h264_reflist_builder *b, + unsigned int i; + + max_frame_num = 1 << (sps->log2_max_frame_num_minus4 + 4); +- cur_frame_num = slice_params->frame_num; ++ cur_frame_num = dec_params->frame_num; + + memset(b, 0, sizeof(*b)); +- if (!(slice_params->flags & V4L2_H264_SLICE_FLAG_FIELD_PIC)) ++ if (!(dec_params->flags & V4L2_H264_DECODE_PARAM_FLAG_FIELD_PIC)) + b->cur_pic_order_count = min(dec_params->bottom_field_order_cnt, + dec_params->top_field_order_cnt); +- else if (slice_params->flags & V4L2_H264_SLICE_FLAG_BOTTOM_FIELD) ++ else if (dec_params->flags & V4L2_H264_DECODE_PARAM_FLAG_BOTTOM_FIELD) + b->cur_pic_order_count = dec_params->bottom_field_order_cnt; + else + b->cur_pic_order_count = dec_params->top_field_order_cnt; +diff --git a/drivers/staging/media/hantro/hantro_g1_h264_dec.c b/drivers/staging/media/hantro/hantro_g1_h264_dec.c +index 424c648ce9fc..f9839e9c6da5 100644 +--- a/drivers/staging/media/hantro/hantro_g1_h264_dec.c ++++ b/drivers/staging/media/hantro/hantro_g1_h264_dec.c +@@ -23,7 +23,6 @@ static void set_params(struct hantro_ctx *ctx) + { + const struct hantro_h264_dec_ctrls *ctrls = &ctx->h264_dec.ctrls; + const struct v4l2_ctrl_h264_decode_params *dec_param = ctrls->decode; +- const struct v4l2_ctrl_h264_slice_params *slices = ctrls->slices; + const struct v4l2_ctrl_h264_sps *sps = ctrls->sps; + const struct v4l2_ctrl_h264_pps *pps = ctrls->pps; + struct vb2_v4l2_buffer *src_buf = hantro_get_src_buf(ctx); +@@ -42,11 +41,11 @@ static void set_params(struct hantro_ctx *ctx) + + if (!(sps->flags & V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY) && + (sps->flags & V4L2_H264_SPS_FLAG_MB_ADAPTIVE_FRAME_FIELD || +- slices[0].flags & V4L2_H264_SLICE_FLAG_FIELD_PIC)) ++ dec_param->flags & V4L2_H264_DECODE_PARAM_FLAG_FIELD_PIC)) + reg |= G1_REG_DEC_CTRL0_PIC_INTERLACE_E; +- if (slices[0].flags & V4L2_H264_SLICE_FLAG_FIELD_PIC) ++ if (dec_param->flags & V4L2_H264_DECODE_PARAM_FLAG_FIELD_PIC) + reg |= G1_REG_DEC_CTRL0_PIC_FIELDMODE_E; +- if (!(slices[0].flags & V4L2_H264_SLICE_FLAG_BOTTOM_FIELD)) ++ if (!(dec_param->flags & V4L2_H264_DECODE_PARAM_FLAG_BOTTOM_FIELD)) + reg |= G1_REG_DEC_CTRL0_PIC_TOPFIELD_E; + vdpu_write_relaxed(vpu, reg, G1_REG_DEC_CTRL0); + +@@ -75,7 +74,7 @@ static void set_params(struct hantro_ctx *ctx) + + /* Decoder control register 4. */ + reg = G1_REG_DEC_CTRL4_FRAMENUM_LEN(sps->log2_max_frame_num_minus4 + 4) | +- G1_REG_DEC_CTRL4_FRAMENUM(slices[0].frame_num) | ++ G1_REG_DEC_CTRL4_FRAMENUM(dec_param->frame_num) | + G1_REG_DEC_CTRL4_WEIGHT_BIPR_IDC(pps->weighted_bipred_idc); + if (pps->flags & V4L2_H264_PPS_FLAG_ENTROPY_CODING_MODE) + reg |= G1_REG_DEC_CTRL4_CABAC_E; +@@ -88,8 +87,8 @@ static void set_params(struct hantro_ctx *ctx) + vdpu_write_relaxed(vpu, reg, G1_REG_DEC_CTRL4); + + /* Decoder control register 5. */ +- reg = G1_REG_DEC_CTRL5_REFPIC_MK_LEN(slices[0].dec_ref_pic_marking_bit_size) | +- G1_REG_DEC_CTRL5_IDR_PIC_ID(slices[0].idr_pic_id); ++ reg = G1_REG_DEC_CTRL5_REFPIC_MK_LEN(dec_param->dec_ref_pic_marking_bit_size) | ++ G1_REG_DEC_CTRL5_IDR_PIC_ID(dec_param->idr_pic_id); + if (pps->flags & V4L2_H264_PPS_FLAG_CONSTRAINED_INTRA_PRED) + reg |= G1_REG_DEC_CTRL5_CONST_INTRA_E; + if (pps->flags & V4L2_H264_PPS_FLAG_DEBLOCKING_FILTER_CONTROL_PRESENT) +@@ -103,10 +102,10 @@ static void set_params(struct hantro_ctx *ctx) + vdpu_write_relaxed(vpu, reg, G1_REG_DEC_CTRL5); + + /* Decoder control register 6. */ +- reg = G1_REG_DEC_CTRL6_PPS_ID(slices[0].pic_parameter_set_id) | ++ reg = G1_REG_DEC_CTRL6_PPS_ID(pps->pic_parameter_set_id) | + G1_REG_DEC_CTRL6_REFIDX0_ACTIVE(pps->num_ref_idx_l0_default_active_minus1 + 1) | + G1_REG_DEC_CTRL6_REFIDX1_ACTIVE(pps->num_ref_idx_l1_default_active_minus1 + 1) | +- G1_REG_DEC_CTRL6_POC_LENGTH(slices[0].pic_order_cnt_bit_size); ++ G1_REG_DEC_CTRL6_POC_LENGTH(dec_param->pic_order_cnt_bit_size); + vdpu_write_relaxed(vpu, reg, G1_REG_DEC_CTRL6); + + /* Error concealment register. */ +@@ -246,7 +245,7 @@ static void set_buffers(struct hantro_ctx *ctx) + /* Destination (decoded frame) buffer. */ + dst_dma = hantro_get_dec_buf_addr(ctx, &dst_buf->vb2_buf); + /* Adjust dma addr to start at second line for bottom field */ +- if (ctrls->slices[0].flags & V4L2_H264_SLICE_FLAG_BOTTOM_FIELD) ++ if (ctrls->decode->flags & V4L2_H264_DECODE_PARAM_FLAG_BOTTOM_FIELD) + offset = ALIGN(ctx->src_fmt.width, MB_DIM); + vdpu_write_relaxed(vpu, dst_dma + offset, G1_REG_ADDR_DST); + +@@ -265,7 +264,7 @@ static void set_buffers(struct hantro_ctx *ctx) + * DMV buffer is split in two for field encoded frames, + * adjust offset for bottom field + */ +- if (ctrls->slices[0].flags & V4L2_H264_SLICE_FLAG_BOTTOM_FIELD) ++ if (ctrls->decode->flags & V4L2_H264_DECODE_PARAM_FLAG_BOTTOM_FIELD) + offset += 32 * MB_WIDTH(ctx->src_fmt.width) * + MB_HEIGHT(ctx->src_fmt.height); + vdpu_write_relaxed(vpu, dst_dma + offset, G1_REG_ADDR_DIR_MV); +diff --git a/drivers/staging/media/hantro/hantro_h264.c b/drivers/staging/media/hantro/hantro_h264.c +index 6dcd47bd9ed3..7578a4fc1b16 100644 +--- a/drivers/staging/media/hantro/hantro_h264.c ++++ b/drivers/staging/media/hantro/hantro_h264.c +@@ -372,8 +372,7 @@ int hantro_h264_dec_prepare_run(struct hantro_ctx *ctx) + + /* Build the P/B{0,1} ref lists. */ + v4l2_h264_init_reflist_builder(&reflist_builder, ctrls->decode, +- &ctrls->slices[0], ctrls->sps, +- ctx->h264_dec.dpb); ++ ctrls->sps, ctx->h264_dec.dpb); + v4l2_h264_build_p_ref_list(&reflist_builder, h264_ctx->reflists.p); + v4l2_h264_build_b_ref_lists(&reflist_builder, h264_ctx->reflists.b0, + h264_ctx->reflists.b1); +diff --git a/drivers/staging/media/rkvdec/rkvdec-h264.c b/drivers/staging/media/rkvdec/rkvdec-h264.c +index 07a80e9a9df2..70752e30b3a3 100644 +--- a/drivers/staging/media/rkvdec/rkvdec-h264.c ++++ b/drivers/staging/media/rkvdec/rkvdec-h264.c +@@ -730,7 +730,6 @@ static void assemble_hw_rps(struct rkvdec_ctx *ctx, + struct rkvdec_h264_run *run) + { + const struct v4l2_ctrl_h264_decode_params *dec_params = run->decode_params; +- const struct v4l2_ctrl_h264_slice_params *sl_params = &run->slices_params[0]; + const struct v4l2_h264_dpb_entry *dpb = dec_params->dpb; + struct rkvdec_h264_ctx *h264_ctx = ctx->priv; + const struct v4l2_ctrl_h264_sps *sps = run->sps; +@@ -754,7 +753,7 @@ static void assemble_hw_rps(struct rkvdec_ctx *ctx, + continue; + + if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM || +- dpb[i].frame_num < sl_params->frame_num) { ++ dpb[i].frame_num < dec_params->frame_num) { + p[i] = dpb[i].frame_num; + continue; + } +@@ -1094,8 +1093,7 @@ static int rkvdec_h264_run(struct rkvdec_ctx *ctx) + + /* Build the P/B{0,1} ref lists. */ + v4l2_h264_init_reflist_builder(&reflist_builder, run.decode_params, +- &run.slices_params[0], run.sps, +- run.decode_params->dpb); ++ run.sps, run.decode_params->dpb); + h264_ctx->reflists.num_valid = reflist_builder.num_valid; + v4l2_h264_build_p_ref_list(&reflist_builder, h264_ctx->reflists.p); + v4l2_h264_build_b_ref_lists(&reflist_builder, h264_ctx->reflists.b0, +diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_h264.c b/drivers/staging/media/sunxi/cedrus/cedrus_h264.c +index 7d9bd5860a1b..c8f626fdd3dd 100644 +--- a/drivers/staging/media/sunxi/cedrus/cedrus_h264.c ++++ b/drivers/staging/media/sunxi/cedrus/cedrus_h264.c +@@ -95,7 +95,6 @@ static void cedrus_write_frame_list(struct cedrus_ctx *ctx, + { + struct cedrus_h264_sram_ref_pic pic_list[CEDRUS_H264_FRAME_NUM]; + const struct v4l2_ctrl_h264_decode_params *decode = run->h264.decode_params; +- const struct v4l2_ctrl_h264_slice_params *slice = run->h264.slice_params; + const struct v4l2_ctrl_h264_sps *sps = run->h264.sps; + struct vb2_queue *cap_q; + struct cedrus_buffer *output_buf; +@@ -144,7 +143,7 @@ static void cedrus_write_frame_list(struct cedrus_ctx *ctx, + output_buf = vb2_to_cedrus_buffer(&run->dst->vb2_buf); + output_buf->codec.h264.position = position; + +- if (slice->flags & V4L2_H264_SLICE_FLAG_FIELD_PIC) ++ if (decode->flags & V4L2_H264_DECODE_PARAM_FLAG_FIELD_PIC) + output_buf->codec.h264.pic_type = CEDRUS_H264_PIC_TYPE_FIELD; + else if (sps->flags & V4L2_H264_SPS_FLAG_MB_ADAPTIVE_FRAME_FIELD) + output_buf->codec.h264.pic_type = CEDRUS_H264_PIC_TYPE_MBAFF; +@@ -407,7 +406,7 @@ static void cedrus_set_params(struct cedrus_ctx *ctx, + reg |= VE_H264_SPS_DIRECT_8X8_INFERENCE; + cedrus_write(dev, VE_H264_SPS, reg); + +- mbaff_pic = !(slice->flags & V4L2_H264_SLICE_FLAG_FIELD_PIC) && ++ mbaff_pic = !(decode->flags & V4L2_H264_DECODE_PARAM_FLAG_FIELD_PIC) && + (sps->flags & V4L2_H264_SPS_FLAG_MB_ADAPTIVE_FRAME_FIELD); + pic_width_in_mbs = sps->pic_width_in_mbs_minus1 + 1; + +@@ -421,9 +420,9 @@ static void cedrus_set_params(struct cedrus_ctx *ctx, + reg |= slice->cabac_init_idc & 0x3; + if (ctx->fh.m2m_ctx->new_frame) + reg |= VE_H264_SHS_FIRST_SLICE_IN_PIC; +- if (slice->flags & V4L2_H264_SLICE_FLAG_FIELD_PIC) ++ if (decode->flags & V4L2_H264_DECODE_PARAM_FLAG_FIELD_PIC) + reg |= VE_H264_SHS_FIELD_PIC; +- if (slice->flags & V4L2_H264_SLICE_FLAG_BOTTOM_FIELD) ++ if (decode->flags & V4L2_H264_DECODE_PARAM_FLAG_BOTTOM_FIELD) + reg |= VE_H264_SHS_BOTTOM_FIELD; + if (slice->flags & V4L2_H264_SLICE_FLAG_DIRECT_SPATIAL_MV_PRED) + reg |= VE_H264_SHS_DIRECT_SPATIAL_MV_PRED; +diff --git a/include/media/h264-ctrls.h b/include/media/h264-ctrls.h +index e180501e6385..1217b706128e 100644 +--- a/include/media/h264-ctrls.h ++++ b/include/media/h264-ctrls.h +@@ -146,10 +146,8 @@ struct v4l2_ctrl_h264_pred_weights { + #define V4L2_H264_SLICE_TYPE_SP 3 + #define V4L2_H264_SLICE_TYPE_SI 4 + +-#define V4L2_H264_SLICE_FLAG_FIELD_PIC 0x01 +-#define V4L2_H264_SLICE_FLAG_BOTTOM_FIELD 0x02 +-#define V4L2_H264_SLICE_FLAG_DIRECT_SPATIAL_MV_PRED 0x04 +-#define V4L2_H264_SLICE_FLAG_SP_FOR_SWITCH 0x08 ++#define V4L2_H264_SLICE_FLAG_DIRECT_SPATIAL_MV_PRED 0x01 ++#define V4L2_H264_SLICE_FLAG_SP_FOR_SWITCH 0x02 + + enum v4l2_h264_field_reference { + V4L2_H264_TOP_FIELD_REF = 0x1, +@@ -171,21 +169,8 @@ struct v4l2_ctrl_h264_slice_params { + __u32 first_mb_in_slice; + + __u8 slice_type; +- __u8 pic_parameter_set_id; + __u8 colour_plane_id; + __u8 redundant_pic_cnt; +- __u16 frame_num; +- __u16 idr_pic_id; +- __u16 pic_order_cnt_lsb; +- __s32 delta_pic_order_cnt_bottom; +- __s32 delta_pic_order_cnt0; +- __s32 delta_pic_order_cnt1; +- +- /* Size in bits of dec_ref_pic_marking() syntax element. */ +- __u32 dec_ref_pic_marking_bit_size; +- /* Size in bits of pic order count syntax. */ +- __u32 pic_order_cnt_bit_size; +- + __u8 cabac_init_idc; + __s8 slice_qp_delta; + __s8 slice_qs_delta; +@@ -194,7 +179,8 @@ struct v4l2_ctrl_h264_slice_params { + __s8 slice_beta_offset_div2; + __u8 num_ref_idx_l0_active_minus1; + __u8 num_ref_idx_l1_active_minus1; +- __u32 slice_group_change_cycle; ++ ++ __u8 reserved; + + struct v4l2_h264_reference ref_pic_list0[V4L2_H264_REF_LIST_LEN]; + struct v4l2_h264_reference ref_pic_list1[V4L2_H264_REF_LIST_LEN]; +@@ -219,13 +205,28 @@ struct v4l2_h264_dpb_entry { + __u32 flags; /* V4L2_H264_DPB_ENTRY_FLAG_* */ + }; + +-#define V4L2_H264_DECODE_PARAM_FLAG_IDR_PIC 0x01 ++#define V4L2_H264_DECODE_PARAM_FLAG_IDR_PIC 0x01 ++#define V4L2_H264_DECODE_PARAM_FLAG_FIELD_PIC 0x02 ++#define V4L2_H264_DECODE_PARAM_FLAG_BOTTOM_FIELD 0x04 + + struct v4l2_ctrl_h264_decode_params { + struct v4l2_h264_dpb_entry dpb[V4L2_H264_NUM_DPB_ENTRIES]; + __u16 nal_ref_idc; ++ __u16 frame_num; + __s32 top_field_order_cnt; + __s32 bottom_field_order_cnt; ++ __u16 idr_pic_id; ++ __u16 pic_order_cnt_lsb; ++ __s32 delta_pic_order_cnt_bottom; ++ __s32 delta_pic_order_cnt0; ++ __s32 delta_pic_order_cnt1; ++ /* Size in bits of dec_ref_pic_marking() syntax element. */ ++ __u32 dec_ref_pic_marking_bit_size; ++ /* Size in bits of pic order count syntax. */ ++ __u32 pic_order_cnt_bit_size; ++ __u32 slice_group_change_cycle; ++ ++ __u32 reserved; + __u32 flags; /* V4L2_H264_DECODE_PARAM_FLAG_* */ + }; + +diff --git a/include/media/v4l2-h264.h b/include/media/v4l2-h264.h +index 1a5f26fc2a9a..f08ba181263d 100644 +--- a/include/media/v4l2-h264.h ++++ b/include/media/v4l2-h264.h +@@ -44,7 +44,6 @@ struct v4l2_h264_reflist_builder { + void + v4l2_h264_init_reflist_builder(struct v4l2_h264_reflist_builder *b, + const struct v4l2_ctrl_h264_decode_params *dec_params, +- const struct v4l2_ctrl_h264_slice_params *slice_params, + const struct v4l2_ctrl_h264_sps *sps, + const struct v4l2_h264_dpb_entry dpb[V4L2_H264_NUM_DPB_ENTRIES]); + + +From c94048bd00c4faa5bf1be0b3b01d3cc41cb475bb Mon Sep 17 00:00:00 2001 +From: Ezequiel Garcia +Date: Fri, 14 Aug 2020 10:36:26 -0300 +Subject: [PATCH] media: uapi: h264: Rename and clarify + PPS_FLAG_SCALING_MATRIX_PRESENT + +Applications are expected to fill V4L2_CID_MPEG_VIDEO_H264_SCALING_MATRIX +if a non-flat scaling matrix applies to the picture. This is the case if +SPS scaling_matrix_present_flag or PPS pic_scaling_matrix_present_flag +are set, and should be handled by applications. + +On one hand, the PPS bitstream syntax element signals the presence of a +Picture scaling matrix modifying the Sequence (SPS) scaling matrix. +On the other hand, our flag should indicate if the scaling matrix +V4L2 control is applicable to this request. + +Rename the flag from PPS_FLAG_PIC_SCALING_MATRIX_PRESENT to +PPS_FLAG_SCALING_MATRIX_PRESENT, to avoid mixing this flag with +bitstream syntax element pic_scaling_matrix_present_flag, +and clarify the meaning of our flag. + +Signed-off-by: Ezequiel Garcia +--- + Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst | 5 +++-- + include/media/h264-ctrls.h | 2 +- + 2 files changed, 4 insertions(+), 3 deletions(-) + +diff --git a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst +index 69dd3961b99b..03ce87aa5488 100644 +--- a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst ++++ b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst +@@ -1695,9 +1695,10 @@ enum v4l2_mpeg_video_h264_hierarchical_coding_type - + * - ``V4L2_H264_PPS_FLAG_TRANSFORM_8X8_MODE`` + - 0x00000040 + - +- * - ``V4L2_H264_PPS_FLAG_PIC_SCALING_MATRIX_PRESENT`` ++ * - ``V4L2_H264_PPS_FLAG_SCALING_MATRIX_PRESENT`` + - 0x00000080 +- - ++ - Indicates that ``V4L2_CID_MPEG_VIDEO_H264_SCALING_MATRIX`` ++ must be used for this picture. + + ``V4L2_CID_MPEG_VIDEO_H264_SCALING_MATRIX (struct)`` + Specifies the scaling matrix (as extracted from the bitstream) for +diff --git a/include/media/h264-ctrls.h b/include/media/h264-ctrls.h +index 1217b706128e..070b9499d7bc 100644 +--- a/include/media/h264-ctrls.h ++++ b/include/media/h264-ctrls.h +@@ -99,7 +99,7 @@ struct v4l2_ctrl_h264_sps { + #define V4L2_H264_PPS_FLAG_CONSTRAINED_INTRA_PRED 0x0010 + #define V4L2_H264_PPS_FLAG_REDUNDANT_PIC_CNT_PRESENT 0x0020 + #define V4L2_H264_PPS_FLAG_TRANSFORM_8X8_MODE 0x0040 +-#define V4L2_H264_PPS_FLAG_PIC_SCALING_MATRIX_PRESENT 0x0080 ++#define V4L2_H264_PPS_FLAG_SCALING_MATRIX_PRESENT 0x0080 + + struct v4l2_ctrl_h264_pps { + __u8 pic_parameter_set_id; + +From 2344f270ec7a9f9559e6d1e57a124c6a89ce0602 Mon Sep 17 00:00:00 2001 +From: Ezequiel Garcia +Date: Fri, 14 Aug 2020 10:36:27 -0300 +Subject: [PATCH] media: hantro: Don't require unneeded H264_SLICE_PARAMS + +Now that slice invariant parameters have been moved, +the driver no longer needs this control, so drop it. + +Signed-off-by: Ezequiel Garcia +--- + drivers/staging/media/hantro/hantro_drv.c | 5 ----- + drivers/staging/media/hantro/hantro_h264.c | 5 ----- + drivers/staging/media/hantro/hantro_hw.h | 2 -- + 3 files changed, 12 deletions(-) + +diff --git a/drivers/staging/media/hantro/hantro_drv.c b/drivers/staging/media/hantro/hantro_drv.c +index 34797507f214..3cd00cc0a364 100644 +--- a/drivers/staging/media/hantro/hantro_drv.c ++++ b/drivers/staging/media/hantro/hantro_drv.c +@@ -306,11 +306,6 @@ static const struct hantro_ctrl controls[] = { + .cfg = { + .id = V4L2_CID_MPEG_VIDEO_H264_DECODE_PARAMS, + }, +- }, { +- .codec = HANTRO_H264_DECODER, +- .cfg = { +- .id = V4L2_CID_MPEG_VIDEO_H264_SLICE_PARAMS, +- }, + }, { + .codec = HANTRO_H264_DECODER, + .cfg = { +diff --git a/drivers/staging/media/hantro/hantro_h264.c b/drivers/staging/media/hantro/hantro_h264.c +index 7578a4fc1b16..089bfa9c625b 100644 +--- a/drivers/staging/media/hantro/hantro_h264.c ++++ b/drivers/staging/media/hantro/hantro_h264.c +@@ -349,11 +349,6 @@ int hantro_h264_dec_prepare_run(struct hantro_ctx *ctx) + if (WARN_ON(!ctrls->decode)) + return -EINVAL; + +- ctrls->slices = +- hantro_get_ctrl(ctx, V4L2_CID_MPEG_VIDEO_H264_SLICE_PARAMS); +- if (WARN_ON(!ctrls->slices)) +- return -EINVAL; +- + ctrls->sps = + hantro_get_ctrl(ctx, V4L2_CID_MPEG_VIDEO_H264_SPS); + if (WARN_ON(!ctrls->sps)) +diff --git a/drivers/staging/media/hantro/hantro_hw.h b/drivers/staging/media/hantro/hantro_hw.h +index f066de6b592d..219283a06f52 100644 +--- a/drivers/staging/media/hantro/hantro_hw.h ++++ b/drivers/staging/media/hantro/hantro_hw.h +@@ -56,14 +56,12 @@ struct hantro_jpeg_enc_hw_ctx { + * struct hantro_h264_dec_ctrls + * @decode: Decode params + * @scaling: Scaling info +- * @slice: Slice params + * @sps: SPS info + * @pps: PPS info + */ + struct hantro_h264_dec_ctrls { + const struct v4l2_ctrl_h264_decode_params *decode; + const struct v4l2_ctrl_h264_scaling_matrix *scaling; +- const struct v4l2_ctrl_h264_slice_params *slices; + const struct v4l2_ctrl_h264_sps *sps; + const struct v4l2_ctrl_h264_pps *pps; + }; + +From 419ccc9852409f2553c92ee3be909afa53d24d1d Mon Sep 17 00:00:00 2001 +From: Ezequiel Garcia +Date: Fri, 14 Aug 2020 10:36:28 -0300 +Subject: [PATCH] media: rkvdec: Don't require unneeded H264_SLICE_PARAMS + +Now that slice invariant parameters have been moved, +the driver no longer needs this control, so drop it. + +Signed-off-by: Ezequiel Garcia +Reviewed-by: Jonas Karlman +--- + drivers/staging/media/rkvdec/rkvdec-h264.c | 4 ---- + drivers/staging/media/rkvdec/rkvdec.c | 5 ----- + 2 files changed, 9 deletions(-) + +diff --git a/drivers/staging/media/rkvdec/rkvdec-h264.c b/drivers/staging/media/rkvdec/rkvdec-h264.c +index 70752e30b3a3..584e0d5c493b 100644 +--- a/drivers/staging/media/rkvdec/rkvdec-h264.c ++++ b/drivers/staging/media/rkvdec/rkvdec-h264.c +@@ -109,7 +109,6 @@ struct rkvdec_h264_reflists { + struct rkvdec_h264_run { + struct rkvdec_run base; + const struct v4l2_ctrl_h264_decode_params *decode_params; +- const struct v4l2_ctrl_h264_slice_params *slices_params; + const struct v4l2_ctrl_h264_sps *sps; + const struct v4l2_ctrl_h264_pps *pps; + const struct v4l2_ctrl_h264_scaling_matrix *scaling_matrix; +@@ -1066,9 +1065,6 @@ static void rkvdec_h264_run_preamble(struct rkvdec_ctx *ctx, + ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl, + V4L2_CID_MPEG_VIDEO_H264_DECODE_PARAMS); + run->decode_params = ctrl ? ctrl->p_cur.p : NULL; +- ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl, +- V4L2_CID_MPEG_VIDEO_H264_SLICE_PARAMS); +- run->slices_params = ctrl ? ctrl->p_cur.p : NULL; + ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl, + V4L2_CID_MPEG_VIDEO_H264_SPS); + run->sps = ctrl ? ctrl->p_cur.p : NULL; +diff --git a/drivers/staging/media/rkvdec/rkvdec.c b/drivers/staging/media/rkvdec/rkvdec.c +index c8151328fb70..7c5129593921 100644 +--- a/drivers/staging/media/rkvdec/rkvdec.c ++++ b/drivers/staging/media/rkvdec/rkvdec.c +@@ -59,11 +59,6 @@ static const struct rkvdec_ctrl_desc rkvdec_h264_ctrl_descs[] = { + .mandatory = true, + .cfg.id = V4L2_CID_MPEG_VIDEO_H264_DECODE_PARAMS, + }, +- { +- .per_request = true, +- .mandatory = true, +- .cfg.id = V4L2_CID_MPEG_VIDEO_H264_SLICE_PARAMS, +- }, + { + .per_request = true, + .mandatory = true, + +From 85567a00727331d7a3269bd76319a048ef1ed505 Mon Sep 17 00:00:00 2001 +From: Jernej Skrabec +Date: Fri, 14 Aug 2020 10:36:29 -0300 +Subject: [PATCH] media: cedrus: h264: Properly configure reference field + +When interlaced H264 content is being decoded, references must indicate +which field is being referenced. Currently this was done by checking +capture buffer flags. However, that is not correct because capture +buffer may hold both fields. + +Fix this by checking newly introduced flags in reference lists. + +Signed-off-by: Jernej Skrabec +Reviewed-by: Nicolas Dufresne +--- + drivers/staging/media/sunxi/cedrus/cedrus_h264.c | 6 ++---- + 1 file changed, 2 insertions(+), 4 deletions(-) + +diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_h264.c b/drivers/staging/media/sunxi/cedrus/cedrus_h264.c +index c8f626fdd3dd..1e89a8438f36 100644 +--- a/drivers/staging/media/sunxi/cedrus/cedrus_h264.c ++++ b/drivers/staging/media/sunxi/cedrus/cedrus_h264.c +@@ -182,7 +182,6 @@ static void _cedrus_write_ref_list(struct cedrus_ctx *ctx, + for (i = 0; i < num_ref; i++) { + const struct v4l2_h264_dpb_entry *dpb; + const struct cedrus_buffer *cedrus_buf; +- const struct vb2_v4l2_buffer *ref_buf; + unsigned int position; + int buf_idx; + u8 dpb_idx; +@@ -197,12 +196,11 @@ static void _cedrus_write_ref_list(struct cedrus_ctx *ctx, + if (buf_idx < 0) + continue; + +- ref_buf = to_vb2_v4l2_buffer(cap_q->bufs[buf_idx]); +- cedrus_buf = vb2_v4l2_to_cedrus_buffer(ref_buf); ++ cedrus_buf = vb2_to_cedrus_buffer(cap_q->bufs[buf_idx]); + position = cedrus_buf->codec.h264.position; + + sram_array[i] |= position << 1; +- if (ref_buf->field == V4L2_FIELD_BOTTOM) ++ if (ref_list[i].fields & V4L2_H264_BOTTOM_FIELD_REF) + sram_array[i] |= BIT(0); + } + + +From 102efa220abfcf3c08ceaf0a7c3ac5f88db5bc0c Mon Sep 17 00:00:00 2001 +From: Jernej Skrabec +Date: Fri, 14 Aug 2020 10:36:30 -0300 +Subject: [PATCH] media: cedrus: h264: Fix frame list construction + +Current frame list construction algorithm assumes that decoded image +will be output into its own buffer. That is true for progressive content +but not for interlaced where each field is decoded separately into same +buffer. + +Fix that by checking if capture buffer is listed in DPB. If it is, reuse +it. + +Signed-off-by: Jernej Skrabec +--- + drivers/staging/media/sunxi/cedrus/cedrus_h264.c | 15 +++++++++------ + 1 file changed, 9 insertions(+), 6 deletions(-) + +diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_h264.c b/drivers/staging/media/sunxi/cedrus/cedrus_h264.c +index 1e89a8438f36..fe041b444385 100644 +--- a/drivers/staging/media/sunxi/cedrus/cedrus_h264.c ++++ b/drivers/staging/media/sunxi/cedrus/cedrus_h264.c +@@ -101,7 +101,7 @@ static void cedrus_write_frame_list(struct cedrus_ctx *ctx, + struct cedrus_dev *dev = ctx->dev; + unsigned long used_dpbs = 0; + unsigned int position; +- unsigned int output = 0; ++ int output = -1; + unsigned int i; + + cap_q = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); +@@ -124,6 +124,11 @@ static void cedrus_write_frame_list(struct cedrus_ctx *ctx, + position = cedrus_buf->codec.h264.position; + used_dpbs |= BIT(position); + ++ if (run->dst->vb2_buf.timestamp == dpb->reference_ts) { ++ output = position; ++ continue; ++ } ++ + if (!(dpb->flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE)) + continue; + +@@ -131,13 +136,11 @@ static void cedrus_write_frame_list(struct cedrus_ctx *ctx, + dpb->top_field_order_cnt, + dpb->bottom_field_order_cnt, + &pic_list[position]); +- +- output = max(position, output); + } + +- position = find_next_zero_bit(&used_dpbs, CEDRUS_H264_FRAME_NUM, +- output); +- if (position >= CEDRUS_H264_FRAME_NUM) ++ if (output >= 0) ++ position = output; ++ else + position = find_first_zero_bit(&used_dpbs, CEDRUS_H264_FRAME_NUM); + + output_buf = vb2_to_cedrus_buffer(&run->dst->vb2_buf); + +From 47f1224e5d7f2d3d566d1da9df0f72ee0564a0d1 Mon Sep 17 00:00:00 2001 +From: Ezequiel Garcia +Date: Wed, 19 Aug 2020 11:37:55 -0300 +Subject: [PATCH] media: rkvdec: Drop unneeded per_request driver-specific + control flag + +Currently, the drivers makes no distinction between per_request +and mandatory, as both are used in the same request validate check. + +The driver only cares to know if a given control is +required to be part of a request, so only one flag is needed. + +Signed-off-by: Ezequiel Garcia +--- + drivers/staging/media/rkvdec/rkvdec.c | 8 +------- + drivers/staging/media/rkvdec/rkvdec.h | 1 - + 2 files changed, 1 insertion(+), 8 deletions(-) + +diff --git a/drivers/staging/media/rkvdec/rkvdec.c b/drivers/staging/media/rkvdec/rkvdec.c +index 7c5129593921..9f59dfb62d3f 100644 +--- a/drivers/staging/media/rkvdec/rkvdec.c ++++ b/drivers/staging/media/rkvdec/rkvdec.c +@@ -55,35 +55,29 @@ static const struct v4l2_ctrl_ops rkvdec_ctrl_ops = { + + static const struct rkvdec_ctrl_desc rkvdec_h264_ctrl_descs[] = { + { +- .per_request = true, + .mandatory = true, + .cfg.id = V4L2_CID_MPEG_VIDEO_H264_DECODE_PARAMS, + }, + { +- .per_request = true, + .mandatory = true, + .cfg.id = V4L2_CID_MPEG_VIDEO_H264_SPS, + .cfg.ops = &rkvdec_ctrl_ops, + }, + { +- .per_request = true, + .mandatory = true, + .cfg.id = V4L2_CID_MPEG_VIDEO_H264_PPS, + }, + { +- .per_request = true, + .mandatory = true, + .cfg.id = V4L2_CID_MPEG_VIDEO_H264_SCALING_MATRIX, + }, + { +- .mandatory = true, + .cfg.id = V4L2_CID_MPEG_VIDEO_H264_DECODE_MODE, + .cfg.min = V4L2_MPEG_VIDEO_H264_DECODE_MODE_FRAME_BASED, + .cfg.max = V4L2_MPEG_VIDEO_H264_DECODE_MODE_FRAME_BASED, + .cfg.def = V4L2_MPEG_VIDEO_H264_DECODE_MODE_FRAME_BASED, + }, + { +- .mandatory = true, + .cfg.id = V4L2_CID_MPEG_VIDEO_H264_START_CODE, + .cfg.min = V4L2_MPEG_VIDEO_H264_START_CODE_ANNEX_B, + .cfg.def = V4L2_MPEG_VIDEO_H264_START_CODE_ANNEX_B, +@@ -615,7 +609,7 @@ static int rkvdec_request_validate(struct media_request *req) + u32 id = ctrls->ctrls[i].cfg.id; + struct v4l2_ctrl *ctrl; + +- if (!ctrls->ctrls[i].per_request || !ctrls->ctrls[i].mandatory) ++ if (!ctrls->ctrls[i].mandatory) + continue; + + ctrl = v4l2_ctrl_request_hdl_ctrl_find(hdl, id); +diff --git a/drivers/staging/media/rkvdec/rkvdec.h b/drivers/staging/media/rkvdec/rkvdec.h +index 2fc9f46b6910..77a137cca88e 100644 +--- a/drivers/staging/media/rkvdec/rkvdec.h ++++ b/drivers/staging/media/rkvdec/rkvdec.h +@@ -25,7 +25,6 @@ + struct rkvdec_ctx; + + struct rkvdec_ctrl_desc { +- u32 per_request : 1; + u32 mandatory : 1; + struct v4l2_ctrl_config cfg; + }; + +From 90ea71bc465216778ac6fda4ca151f324df4d516 Mon Sep 17 00:00:00 2001 +From: Ezequiel Garcia +Date: Fri, 14 Aug 2020 10:36:32 -0300 +Subject: [PATCH] media: rkvdec: Use H264_SCALING_MATRIX only when required + +Baseline, Main and Extended profiles are specified to +not support a scaling matrix. Also, High profiles +can optionally specify a scaling matrix, using +SPS and PPS NAL units. + +To meet this expectation, applications are required to +set the V4L2_CID_MPEG_VIDEO_H264_SCALING_MATRIX control +and set the V4L2_H264_PPS_FLAG_SCALING_MATRIX_PRESENT +flag only when a scaling matrix is specified for a picture. + +Implement this on rkvdec, which has hardware support for this +case. + +Signed-off-by: Ezequiel Garcia +--- + drivers/staging/media/rkvdec/rkvdec-h264.c | 10 +++++++--- + drivers/staging/media/rkvdec/rkvdec.c | 1 - + 2 files changed, 7 insertions(+), 4 deletions(-) + +diff --git a/drivers/staging/media/rkvdec/rkvdec-h264.c b/drivers/staging/media/rkvdec/rkvdec-h264.c +index 584e0d5c493b..9233260e14c1 100644 +--- a/drivers/staging/media/rkvdec/rkvdec-h264.c ++++ b/drivers/staging/media/rkvdec/rkvdec-h264.c +@@ -708,9 +708,9 @@ static void assemble_hw_pps(struct rkvdec_ctx *ctx, + WRITE_PPS(pps->second_chroma_qp_index_offset, + SECOND_CHROMA_QP_INDEX_OFFSET); + +- /* always use the matrix sent from userspace */ +- WRITE_PPS(1, SCALING_LIST_ENABLE_FLAG); +- ++ WRITE_PPS(!!(pps->flags & V4L2_H264_PPS_FLAG_SCALING_MATRIX_PRESENT), ++ SCALING_LIST_ENABLE_FLAG); ++ /* To be on the safe side, program the scaling matrix address */ + scaling_distance = offsetof(struct rkvdec_h264_priv_tbl, scaling_list); + scaling_list_address = h264_ctx->priv_tbl.dma + scaling_distance; + WRITE_PPS(scaling_list_address, SCALING_LIST_ADDRESS); +@@ -792,9 +792,13 @@ static void assemble_hw_scaling_list(struct rkvdec_ctx *ctx, + struct rkvdec_h264_run *run) + { + const struct v4l2_ctrl_h264_scaling_matrix *scaling = run->scaling_matrix; ++ const struct v4l2_ctrl_h264_pps *pps = run->pps; + struct rkvdec_h264_ctx *h264_ctx = ctx->priv; + struct rkvdec_h264_priv_tbl *tbl = h264_ctx->priv_tbl.cpu; + ++ if (!(pps->flags & V4L2_H264_PPS_FLAG_SCALING_MATRIX_PRESENT)) ++ return; ++ + BUILD_BUG_ON(sizeof(tbl->scaling_list.scaling_list_4x4) != + sizeof(scaling->scaling_list_4x4)); + BUILD_BUG_ON(sizeof(tbl->scaling_list.scaling_list_8x8) != +diff --git a/drivers/staging/media/rkvdec/rkvdec.c b/drivers/staging/media/rkvdec/rkvdec.c +index 9f59dfb62d3f..d25c4a37e2af 100644 +--- a/drivers/staging/media/rkvdec/rkvdec.c ++++ b/drivers/staging/media/rkvdec/rkvdec.c +@@ -68,7 +68,6 @@ static const struct rkvdec_ctrl_desc rkvdec_h264_ctrl_descs[] = { + .cfg.id = V4L2_CID_MPEG_VIDEO_H264_PPS, + }, + { +- .mandatory = true, + .cfg.id = V4L2_CID_MPEG_VIDEO_H264_SCALING_MATRIX, + }, + { + +From 70d39439f485d511c9c929934a26341ef3b736ef Mon Sep 17 00:00:00 2001 +From: Ezequiel Garcia +Date: Fri, 14 Aug 2020 10:36:33 -0300 +Subject: [PATCH] media: hantro: Use H264_SCALING_MATRIX only when required + +Baseline, Main and Extended profiles are specified to +not support a scaling matrix. Also, High profiles +can optionally specify a scaling matrix, using +SPS and PPS NAL units. + +To meet this expectation, applications are required to +set the V4L2_CID_MPEG_VIDEO_H264_SCALING_MATRIX control +and set the V4L2_H264_PPS_FLAG_SCALING_MATRIX_PRESENT +flag only when a scaling matrix is specified for a picture. + +Implement this on hantro, which has hardware support for this +case. + +Signed-off-by: Ezequiel Garcia +--- + drivers/staging/media/hantro/hantro_g1_h264_dec.c | 5 ++--- + drivers/staging/media/hantro/hantro_h264.c | 4 ++++ + 2 files changed, 6 insertions(+), 3 deletions(-) + +diff --git a/drivers/staging/media/hantro/hantro_g1_h264_dec.c b/drivers/staging/media/hantro/hantro_g1_h264_dec.c +index f9839e9c6da5..845bef73d218 100644 +--- a/drivers/staging/media/hantro/hantro_g1_h264_dec.c ++++ b/drivers/staging/media/hantro/hantro_g1_h264_dec.c +@@ -59,9 +59,8 @@ static void set_params(struct hantro_ctx *ctx) + reg = G1_REG_DEC_CTRL2_CH_QP_OFFSET(pps->chroma_qp_index_offset) | + G1_REG_DEC_CTRL2_CH_QP_OFFSET2(pps->second_chroma_qp_index_offset); + +- /* always use the matrix sent from userspace */ +- reg |= G1_REG_DEC_CTRL2_TYPE1_QUANT_E; +- ++ if (pps->flags & V4L2_H264_PPS_FLAG_SCALING_MATRIX_PRESENT) ++ reg |= G1_REG_DEC_CTRL2_TYPE1_QUANT_E; + if (!(sps->flags & V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY)) + reg |= G1_REG_DEC_CTRL2_FIELDPIC_FLAG_E; + vdpu_write_relaxed(vpu, reg, G1_REG_DEC_CTRL2); +diff --git a/drivers/staging/media/hantro/hantro_h264.c b/drivers/staging/media/hantro/hantro_h264.c +index 089bfa9c625b..b1bdc00ac262 100644 +--- a/drivers/staging/media/hantro/hantro_h264.c ++++ b/drivers/staging/media/hantro/hantro_h264.c +@@ -197,6 +197,7 @@ assemble_scaling_list(struct hantro_ctx *ctx) + { + const struct hantro_h264_dec_ctrls *ctrls = &ctx->h264_dec.ctrls; + const struct v4l2_ctrl_h264_scaling_matrix *scaling = ctrls->scaling; ++ const struct v4l2_ctrl_h264_pps *pps = ctrls->pps; + const size_t num_list_4x4 = ARRAY_SIZE(scaling->scaling_list_4x4); + const size_t list_len_4x4 = ARRAY_SIZE(scaling->scaling_list_4x4[0]); + const size_t list_len_8x8 = ARRAY_SIZE(scaling->scaling_list_8x8[0]); +@@ -205,6 +206,9 @@ assemble_scaling_list(struct hantro_ctx *ctx) + const u32 *src; + int i, j; + ++ if (!(pps->flags & V4L2_H264_PPS_FLAG_SCALING_MATRIX_PRESENT)) ++ return; ++ + for (i = 0; i < num_list_4x4; i++) { + src = (u32 *)&scaling->scaling_list_4x4[i]; + for (j = 0; j < list_len_4x4 / 4; j++) + +From 6390458815944ce231b6282771e2a6c3fc6f2fa6 Mon Sep 17 00:00:00 2001 +From: Ezequiel Garcia +Date: Fri, 14 Aug 2020 10:36:34 -0300 +Subject: [PATCH] media: cedrus: Use H264_SCALING_MATRIX only when required + +Baseline, Main and Extended profiles are specified to +not support a scaling matrix. Also, High profiles +can optionally specify a scaling matrix, using +SPS and PPS NAL units. + +To meet this expectation, applications are required to +set the V4L2_CID_MPEG_VIDEO_H264_SCALING_MATRIX control +and set the V4L2_H264_PPS_FLAG_SCALING_MATRIX_PRESENT +flag only when a scaling matrix is specified for a picture. + +Implement this on cedrus, which has hardware support for this +case. + +Signed-off-by: Ezequiel Garcia +--- + drivers/staging/media/sunxi/cedrus/cedrus.c | 2 +- + drivers/staging/media/sunxi/cedrus/cedrus_h264.c | 6 ++++++ + 2 files changed, 7 insertions(+), 1 deletion(-) + +diff --git a/drivers/staging/media/sunxi/cedrus/cedrus.c b/drivers/staging/media/sunxi/cedrus/cedrus.c +index 826324faad7e..6ebb39e0c0ce 100644 +--- a/drivers/staging/media/sunxi/cedrus/cedrus.c ++++ b/drivers/staging/media/sunxi/cedrus/cedrus.c +@@ -76,7 +76,7 @@ static const struct cedrus_control cedrus_controls[] = { + .id = V4L2_CID_MPEG_VIDEO_H264_SCALING_MATRIX, + }, + .codec = CEDRUS_CODEC_H264, +- .required = true, ++ .required = false, + }, + { + .cfg = { +diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_h264.c b/drivers/staging/media/sunxi/cedrus/cedrus_h264.c +index fe041b444385..28319351e909 100644 +--- a/drivers/staging/media/sunxi/cedrus/cedrus_h264.c ++++ b/drivers/staging/media/sunxi/cedrus/cedrus_h264.c +@@ -238,8 +238,12 @@ static void cedrus_write_scaling_lists(struct cedrus_ctx *ctx, + { + const struct v4l2_ctrl_h264_scaling_matrix *scaling = + run->h264.scaling_matrix; ++ const struct v4l2_ctrl_h264_pps *pps = run->h264.pps; + struct cedrus_dev *dev = ctx->dev; + ++ if (!(pps->flags & V4L2_H264_PPS_FLAG_SCALING_MATRIX_PRESENT)) ++ return; ++ + cedrus_h264_write_sram(dev, CEDRUS_SRAM_H264_SCALING_LIST_8x8_0, + scaling->scaling_list_8x8[0], + sizeof(scaling->scaling_list_8x8[0])); +@@ -442,6 +446,8 @@ static void cedrus_set_params(struct cedrus_ctx *ctx, + reg |= (pps->second_chroma_qp_index_offset & 0x3f) << 16; + reg |= (pps->chroma_qp_index_offset & 0x3f) << 8; + reg |= (pps->pic_init_qp_minus26 + 26 + slice->slice_qp_delta) & 0x3f; ++ if (pps->flags & V4L2_H264_PPS_FLAG_SCALING_MATRIX_PRESENT) ++ reg |= VE_H264_SHS_QP_SCALING_MATRIX_DEFAULT; + cedrus_write(dev, VE_H264_SHS_QP, reg); + + // clear status flags + +From 711f57301ef4368ba23f70f6596994b7242803cc Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Mon, 6 Jul 2020 21:54:33 +0000 +Subject: [PATCH] media: rkvdec: h264: Fix reference frame_num wrap for second + field + +When decoding the second field in a complementary field pair the second +field is sharing the same frame_num with the first field. + +Currently the frame_num for the first field is wrapped when it matches the +field being decoded, this cause issues to decode the second field in a +complementary field pair. + +Fix this by using inclusive comparison, less than or equal. + +Signed-off-by: Jonas Karlman +Reviewed-by: Ezequiel Garcia +--- + drivers/staging/media/rkvdec/rkvdec-h264.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/staging/media/rkvdec/rkvdec-h264.c b/drivers/staging/media/rkvdec/rkvdec-h264.c +index 9233260e14c1..8fab0151b884 100644 +--- a/drivers/staging/media/rkvdec/rkvdec-h264.c ++++ b/drivers/staging/media/rkvdec/rkvdec-h264.c +@@ -752,7 +752,7 @@ static void assemble_hw_rps(struct rkvdec_ctx *ctx, + continue; + + if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM || +- dpb[i].frame_num < dec_params->frame_num) { ++ dpb[i].frame_num <= dec_params->frame_num) { + p[i] = dpb[i].frame_num; + continue; + } + +From a957b522403e98c67b8c184fa3b7709c6e874d40 Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Mon, 6 Jul 2020 21:54:34 +0000 +Subject: [PATCH] media: rkvdec: Ensure decoded resolution fit coded resolution + +Ensure decoded CAPTURE buffer resolution is larger or equal to the coded +OPTUPT buffer resolution. + +Signed-off-by: Jonas Karlman +--- + drivers/staging/media/rkvdec/rkvdec.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/staging/media/rkvdec/rkvdec.c b/drivers/staging/media/rkvdec/rkvdec.c +index d25c4a37e2af..b3e067031c83 100644 +--- a/drivers/staging/media/rkvdec/rkvdec.c ++++ b/drivers/staging/media/rkvdec/rkvdec.c +@@ -223,6 +223,8 @@ static int rkvdec_try_capture_fmt(struct file *file, void *priv, + pix_mp->pixelformat = coded_desc->decoded_fmts[0]; + + /* Always apply the frmsize constraint of the coded end. */ ++ pix_mp->width = max(pix_mp->width, ctx->coded_fmt.fmt.pix_mp.width); ++ pix_mp->height = max(pix_mp->height, ctx->coded_fmt.fmt.pix_mp.height); + v4l2_apply_frmsize_constraints(&pix_mp->width, + &pix_mp->height, + &coded_desc->frmsize); + +From 7c3bb86b8d315c1939a35c4dfe31e120758e5395 Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Mon, 6 Jul 2020 21:54:34 +0000 +Subject: [PATCH] media: rkvdec: h264: Validate and use pic width and height in + mbs + +The width and height in mbs is currently configured based on OUTPUT buffer +resolution, this works for frame pictures but can cause issues for field +pictures. + +When frame_mbs_only_flag is 0 the height in mbs should be height of +the field instead of height of frame. + +Validate pic_width_in_mbs_minus1 and pic_height_in_map_units_minus1 +against OUTPUT buffer resolution and use these values to configure HW. + +Signed-off-by: Jonas Karlman +--- + drivers/staging/media/rkvdec/rkvdec-h264.c | 4 ++-- + drivers/staging/media/rkvdec/rkvdec.c | 10 ++++++++++ + 2 files changed, 12 insertions(+), 2 deletions(-) + +diff --git a/drivers/staging/media/rkvdec/rkvdec-h264.c b/drivers/staging/media/rkvdec/rkvdec-h264.c +index 8fab0151b884..20a783a1bcc7 100644 +--- a/drivers/staging/media/rkvdec/rkvdec-h264.c ++++ b/drivers/staging/media/rkvdec/rkvdec-h264.c +@@ -671,8 +671,8 @@ static void assemble_hw_pps(struct rkvdec_ctx *ctx, + LOG2_MAX_PIC_ORDER_CNT_LSB_MINUS4); + WRITE_PPS(!!(sps->flags & V4L2_H264_SPS_FLAG_DELTA_PIC_ORDER_ALWAYS_ZERO), + DELTA_PIC_ORDER_ALWAYS_ZERO_FLAG); +- WRITE_PPS(DIV_ROUND_UP(ctx->coded_fmt.fmt.pix_mp.width, 16), PIC_WIDTH_IN_MBS); +- WRITE_PPS(DIV_ROUND_UP(ctx->coded_fmt.fmt.pix_mp.height, 16), PIC_HEIGHT_IN_MBS); ++ WRITE_PPS(sps->pic_width_in_mbs_minus1 + 1, PIC_WIDTH_IN_MBS); ++ WRITE_PPS(sps->pic_height_in_map_units_minus1 + 1, PIC_HEIGHT_IN_MBS); + WRITE_PPS(!!(sps->flags & V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY), + FRAME_MBS_ONLY_FLAG); + WRITE_PPS(!!(sps->flags & V4L2_H264_SPS_FLAG_MB_ADAPTIVE_FRAME_FIELD), +diff --git a/drivers/staging/media/rkvdec/rkvdec.c b/drivers/staging/media/rkvdec/rkvdec.c +index b3e067031c83..06fc58440cd3 100644 +--- a/drivers/staging/media/rkvdec/rkvdec.c ++++ b/drivers/staging/media/rkvdec/rkvdec.c +@@ -29,8 +29,11 @@ + + static int rkvdec_try_ctrl(struct v4l2_ctrl *ctrl) + { ++ struct rkvdec_ctx *ctx = container_of(ctrl->handler, struct rkvdec_ctx, ctrl_hdl); ++ + if (ctrl->id == V4L2_CID_MPEG_VIDEO_H264_SPS) { + const struct v4l2_ctrl_h264_sps *sps = ctrl->p_new.p_h264_sps; ++ unsigned int width, height; + /* + * TODO: The hardware supports 10-bit and 4:2:2 profiles, + * but it's currently broken in the driver. +@@ -45,6 +48,13 @@ static int rkvdec_try_ctrl(struct v4l2_ctrl *ctrl) + if (sps->bit_depth_luma_minus8 != 0) + /* Only 8-bit is supported */ + return -EINVAL; ++ ++ width = (sps->pic_width_in_mbs_minus1 + 1) * 16; ++ height = (sps->pic_height_in_map_units_minus1 + 1) * 16; ++ ++ if (width > ctx->coded_fmt.fmt.pix_mp.width || ++ height > ctx->coded_fmt.fmt.pix_mp.height) ++ return -EINVAL; + } + return 0; + } + +From f28529ac6fd75419e2b1806777158b5912ea0cb4 Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Mon, 6 Jul 2020 21:54:35 +0000 +Subject: [PATCH] media: rkvdec: h264: Fix bit depth wrap in pps packet + +The luma and chroma bit depth fields in the pps packet is 3 bits wide. +8 is wrongly added to the bit depth value written to these 3-bit fields. +Because only the 3 LSB is written the hardware is configured correctly. + +Correct this by not adding 8 to the luma and chroma bit depth value. + +Signed-off-by: Jonas Karlman +Reviewed-by: Ezequiel Garcia +--- + drivers/staging/media/rkvdec/rkvdec-h264.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/staging/media/rkvdec/rkvdec-h264.c b/drivers/staging/media/rkvdec/rkvdec-h264.c +index 20a783a1bcc7..f4b61dd45e7f 100644 +--- a/drivers/staging/media/rkvdec/rkvdec-h264.c ++++ b/drivers/staging/media/rkvdec/rkvdec-h264.c +@@ -661,8 +661,8 @@ static void assemble_hw_pps(struct rkvdec_ctx *ctx, + WRITE_PPS(0xff, PROFILE_IDC); + WRITE_PPS(1, CONSTRAINT_SET3_FLAG); + WRITE_PPS(sps->chroma_format_idc, CHROMA_FORMAT_IDC); +- WRITE_PPS(sps->bit_depth_luma_minus8 + 8, BIT_DEPTH_LUMA); +- WRITE_PPS(sps->bit_depth_chroma_minus8 + 8, BIT_DEPTH_CHROMA); ++ WRITE_PPS(sps->bit_depth_luma_minus8, BIT_DEPTH_LUMA); ++ WRITE_PPS(sps->bit_depth_chroma_minus8, BIT_DEPTH_CHROMA); + WRITE_PPS(0, QPPRIME_Y_ZERO_TRANSFORM_BYPASS_FLAG); + WRITE_PPS(sps->log2_max_frame_num_minus4, LOG2_MAX_FRAME_NUM_MINUS4); + WRITE_PPS(sps->max_num_ref_frames, MAX_NUM_REF_FRAMES); + +From a0de7efadd3058c3837714fd1c71e31dd00b9eac Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Mon, 6 Jul 2020 21:54:35 +0000 +Subject: [PATCH] media: rkvdec: h264: Do not override output buffer sizeimage + +The output buffer sizeimage is currently forced to 2 bytes per pixel, this +can lead to high memory usage for 4K content when multiple output buffers +is created by userspace. + +Do not override output buffer sizeimage and let userspace have control of +output buffer sizeimage by only setting sizeimage if none is provided. + +Signed-off-by: Jonas Karlman +--- + drivers/staging/media/rkvdec/rkvdec-h264.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/drivers/staging/media/rkvdec/rkvdec-h264.c b/drivers/staging/media/rkvdec/rkvdec-h264.c +index f4b61dd45e7f..2e7749bac417 100644 +--- a/drivers/staging/media/rkvdec/rkvdec-h264.c ++++ b/drivers/staging/media/rkvdec/rkvdec-h264.c +@@ -1015,8 +1015,9 @@ static int rkvdec_h264_adjust_fmt(struct rkvdec_ctx *ctx, + struct v4l2_pix_format_mplane *fmt = &f->fmt.pix_mp; + + fmt->num_planes = 1; +- fmt->plane_fmt[0].sizeimage = fmt->width * fmt->height * +- RKVDEC_H264_MAX_DEPTH_IN_BYTES; ++ if (!fmt->plane_fmt[0].sizeimage) ++ fmt->plane_fmt[0].sizeimage = fmt->width * fmt->height * ++ RKVDEC_H264_MAX_DEPTH_IN_BYTES; + return 0; + } + + +From 2fd027124722012155dda6bf4af57d978ce0655c Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Mon, 6 Jul 2020 21:54:35 +0000 +Subject: [PATCH] media: v4l2-common: Add helpers to calculate bytesperline and + sizeimage + +Add helper functions to calculate plane bytesperline and sizeimage, these +new helpers consider block width and height when calculating plane +bytesperline and sizeimage. + +This prepare support for new pixel formats added in next patch that make +use of block width and height. + +Signed-off-by: Jonas Karlman +--- + drivers/media/v4l2-core/v4l2-common.c | 77 +++++++++++++-------------- + 1 file changed, 38 insertions(+), 39 deletions(-) + +diff --git a/drivers/media/v4l2-core/v4l2-common.c b/drivers/media/v4l2-core/v4l2-common.c +index 3dc17ebe14fa..4102c373b48a 100644 +--- a/drivers/media/v4l2-core/v4l2-common.c ++++ b/drivers/media/v4l2-core/v4l2-common.c +@@ -333,6 +333,33 @@ static inline unsigned int v4l2_format_block_height(const struct v4l2_format_inf + return info->block_h[plane]; + } + ++static inline unsigned int v4l2_format_plane_width(const struct v4l2_format_info *info, int plane, ++ unsigned int width) ++{ ++ unsigned int hdiv = plane ? info->hdiv : 1; ++ unsigned int bytes = DIV_ROUND_UP(width * info->bpp[plane], ++ v4l2_format_block_width(info, plane) * ++ v4l2_format_block_height(info, plane)); ++ ++ return DIV_ROUND_UP(bytes, hdiv); ++} ++ ++static inline unsigned int v4l2_format_plane_height(const struct v4l2_format_info *info, int plane, ++ unsigned int height) ++{ ++ unsigned int vdiv = plane ? info->vdiv : 1; ++ unsigned int lines = ALIGN(height, v4l2_format_block_height(info, plane)); ++ ++ return DIV_ROUND_UP(lines, vdiv); ++} ++ ++static inline unsigned int v4l2_format_plane_size(const struct v4l2_format_info *info, int plane, ++ unsigned int width, unsigned int height) ++{ ++ return v4l2_format_plane_width(info, plane, width) * ++ v4l2_format_plane_height(info, plane, height); ++} ++ + void v4l2_apply_frmsize_constraints(u32 *width, u32 *height, + const struct v4l2_frmsize_stepwise *frmsize) + { +@@ -368,37 +395,19 @@ int v4l2_fill_pixfmt_mp(struct v4l2_pix_format_mplane *pixfmt, + + if (info->mem_planes == 1) { + plane = &pixfmt->plane_fmt[0]; +- plane->bytesperline = ALIGN(width, v4l2_format_block_width(info, 0)) * info->bpp[0]; ++ plane->bytesperline = v4l2_format_plane_width(info, 0, width); + plane->sizeimage = 0; + +- for (i = 0; i < info->comp_planes; i++) { +- unsigned int hdiv = (i == 0) ? 1 : info->hdiv; +- unsigned int vdiv = (i == 0) ? 1 : info->vdiv; +- unsigned int aligned_width; +- unsigned int aligned_height; +- +- aligned_width = ALIGN(width, v4l2_format_block_width(info, i)); +- aligned_height = ALIGN(height, v4l2_format_block_height(info, i)); +- +- plane->sizeimage += info->bpp[i] * +- DIV_ROUND_UP(aligned_width, hdiv) * +- DIV_ROUND_UP(aligned_height, vdiv); +- } ++ for (i = 0; i < info->comp_planes; i++) ++ plane->sizeimage += ++ v4l2_format_plane_size(info, i, width, height); + } else { + for (i = 0; i < info->comp_planes; i++) { +- unsigned int hdiv = (i == 0) ? 1 : info->hdiv; +- unsigned int vdiv = (i == 0) ? 1 : info->vdiv; +- unsigned int aligned_width; +- unsigned int aligned_height; +- +- aligned_width = ALIGN(width, v4l2_format_block_width(info, i)); +- aligned_height = ALIGN(height, v4l2_format_block_height(info, i)); +- + plane = &pixfmt->plane_fmt[i]; + plane->bytesperline = +- info->bpp[i] * DIV_ROUND_UP(aligned_width, hdiv); +- plane->sizeimage = +- plane->bytesperline * DIV_ROUND_UP(aligned_height, vdiv); ++ v4l2_format_plane_width(info, i, width); ++ plane->sizeimage = plane->bytesperline * ++ v4l2_format_plane_height(info, i, height); + } + } + return 0; +@@ -422,22 +431,12 @@ int v4l2_fill_pixfmt(struct v4l2_pix_format *pixfmt, u32 pixelformat, + pixfmt->width = width; + pixfmt->height = height; + pixfmt->pixelformat = pixelformat; +- pixfmt->bytesperline = ALIGN(width, v4l2_format_block_width(info, 0)) * info->bpp[0]; ++ pixfmt->bytesperline = v4l2_format_plane_width(info, 0, width); + pixfmt->sizeimage = 0; + +- for (i = 0; i < info->comp_planes; i++) { +- unsigned int hdiv = (i == 0) ? 1 : info->hdiv; +- unsigned int vdiv = (i == 0) ? 1 : info->vdiv; +- unsigned int aligned_width; +- unsigned int aligned_height; +- +- aligned_width = ALIGN(width, v4l2_format_block_width(info, i)); +- aligned_height = ALIGN(height, v4l2_format_block_height(info, i)); +- +- pixfmt->sizeimage += info->bpp[i] * +- DIV_ROUND_UP(aligned_width, hdiv) * +- DIV_ROUND_UP(aligned_height, vdiv); +- } ++ for (i = 0; i < info->comp_planes; i++) ++ pixfmt->sizeimage += ++ v4l2_format_plane_size(info, i, width, height); + return 0; + } + EXPORT_SYMBOL_GPL(v4l2_fill_pixfmt); + +From 889f4693a0947c22188ca643ed9ba3579f0abc66 Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Mon, 6 Jul 2020 21:54:36 +0000 +Subject: [PATCH] media: v4l2: Add NV15 and NV20 pixel formats + +Add NV15 and NV20 pixel formats used by the Rockchip Video Decoder for +10-bit buffers. + +NV15 and NV20 is a packed 10-bit 4:2:0/4:2:2 semi-planar Y/CbCr format +similar to P010 and P210 but has no padding between components. Instead, +luminance and chrominance samples are grouped into 4s so that each group is +packed into an integer number of bytes: + +YYYY = UVUV = 4 * 10 bits = 40 bits = 5 bytes + +The '15' and '20' suffix refers to the optimum effective bits per pixel +which is achieved when the total number of luminance samples is a multiple +of 8 for NV15 and 4 for NV20. + +Signed-off-by: Jonas Karlman +--- + .../userspace-api/media/v4l/pixfmt-nv15.rst | 101 ++++++++++++++++++ + .../userspace-api/media/v4l/pixfmt-nv20.rst | 99 +++++++++++++++++ + .../userspace-api/media/v4l/yuv-formats.rst | 2 + + drivers/media/v4l2-core/v4l2-common.c | 3 + + drivers/media/v4l2-core/v4l2-ioctl.c | 2 + + include/uapi/linux/videodev2.h | 3 + + 6 files changed, 210 insertions(+) + create mode 100644 Documentation/userspace-api/media/v4l/pixfmt-nv15.rst + create mode 100644 Documentation/userspace-api/media/v4l/pixfmt-nv20.rst + +diff --git a/Documentation/userspace-api/media/v4l/pixfmt-nv15.rst b/Documentation/userspace-api/media/v4l/pixfmt-nv15.rst +new file mode 100644 +index 000000000000..d059db58c6e0 +--- /dev/null ++++ b/Documentation/userspace-api/media/v4l/pixfmt-nv15.rst +@@ -0,0 +1,101 @@ ++.. Permission is granted to copy, distribute and/or modify this ++.. document under the terms of the GNU Free Documentation License, ++.. Version 1.1 or any later version published by the Free Software ++.. Foundation, with no Invariant Sections, no Front-Cover Texts ++.. and no Back-Cover Texts. A copy of the license is included at ++.. Documentation/userspace-api/media/fdl-appendix.rst. ++.. ++.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections ++ ++.. _V4L2-PIX-FMT-NV15: ++ ++************************** ++V4L2_PIX_FMT_NV15 ('NV15') ++************************** ++ ++Format with ½ horizontal and vertical chroma resolution, also known as ++YUV 4:2:0. One luminance and one chrominance plane with alternating ++chroma samples similar to ``V4L2_PIX_FMT_NV12`` but with 10-bit samples ++that are grouped into four and packed into five bytes. ++ ++The '15' suffix refers to the optimum effective bits per pixel which is ++achieved when the total number of luminance samples is a multiple of 8. ++ ++ ++Description ++=========== ++ ++This is a packed 10-bit two-plane version of the YUV 4:2:0 format. The ++three components are separated into two sub-images or planes. The Y plane ++is first. The Y plane has five bytes per each group of four pixels. A ++combined CbCr plane immediately follows the Y plane in memory. The CbCr ++plane is the same width, in bytes, as the Y plane (and of the image), but ++is half as tall in pixels. Each CbCr pair belongs to four pixels. For ++example, Cb\ :sub:`00`/Cr\ :sub:`00` belongs to Y'\ :sub:`00`, ++Y'\ :sub:`01`, Y'\ :sub:`10`, Y'\ :sub:`11`. ++ ++If the Y plane has pad bytes after each row, then the CbCr plane has as ++many pad bytes after its rows. ++ ++**Byte Order.** ++Little endian. Each cell is one byte. Pixels cross the byte boundary. ++ ++ ++.. flat-table:: ++ :header-rows: 0 ++ :stub-columns: 0 ++ ++ * - start + 0: ++ - Y'\ :sub:`00[7:0]` ++ - Y'\ :sub:`01[5:0]`\ Y'\ :sub:`00[9:8]` ++ - Y'\ :sub:`02[3:0]`\ Y'\ :sub:`01[9:6]` ++ - Y'\ :sub:`03[1:0]`\ Y'\ :sub:`02[9:4]` ++ - Y'\ :sub:`03[9:2]` ++ * - start + 5: ++ - Y'\ :sub:`10[7:0]` ++ - Y'\ :sub:`11[5:0]`\ Y'\ :sub:`10[9:8]` ++ - Y'\ :sub:`12[3:0]`\ Y'\ :sub:`11[9:6]` ++ - Y'\ :sub:`13[1:0]`\ Y'\ :sub:`12[9:4]` ++ - Y'\ :sub:`13[9:2]` ++ * - start + 10: ++ - Cb'\ :sub:`00[7:0]` ++ - Cr'\ :sub:`00[5:0]`\ Cb'\ :sub:`00[9:8]` ++ - Cb'\ :sub:`01[3:0]`\ Cr'\ :sub:`00[9:6]` ++ - Cr'\ :sub:`01[1:0]`\ Cb'\ :sub:`01[9:4]` ++ - Cr'\ :sub:`01[9:2]` ++ ++ ++**Color Sample Location:** ++ ++.. flat-table:: ++ :header-rows: 0 ++ :stub-columns: 0 ++ ++ * - ++ - 0 ++ - ++ - 1 ++ - 2 ++ - ++ - 3 ++ * - 0 ++ - Y ++ - ++ - Y ++ - Y ++ - ++ - Y ++ * - ++ - ++ - C ++ - ++ - ++ - C ++ - ++ * - 1 ++ - Y ++ - ++ - Y ++ - Y ++ - ++ - Y +diff --git a/Documentation/userspace-api/media/v4l/pixfmt-nv20.rst b/Documentation/userspace-api/media/v4l/pixfmt-nv20.rst +new file mode 100644 +index 000000000000..a8123be0baa3 +--- /dev/null ++++ b/Documentation/userspace-api/media/v4l/pixfmt-nv20.rst +@@ -0,0 +1,99 @@ ++.. Permission is granted to copy, distribute and/or modify this ++.. document under the terms of the GNU Free Documentation License, ++.. Version 1.1 or any later version published by the Free Software ++.. Foundation, with no Invariant Sections, no Front-Cover Texts ++.. and no Back-Cover Texts. A copy of the license is included at ++.. Documentation/userspace-api/media/fdl-appendix.rst. ++.. ++.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections ++ ++.. _V4L2-PIX-FMT-NV20: ++ ++************************** ++V4L2_PIX_FMT_NV20 ('NV20') ++************************** ++ ++Format with ½ horizontal chroma resolution, also known as YUV 4:2:2. ++One luminance and one chrominance plane with alternating chroma samples ++similar to ``V4L2_PIX_FMT_NV16`` but with 10-bit samples ++that are grouped into four and packed into five bytes. ++ ++The '20' suffix refers to the optimum effective bits per pixel which is ++achieved when the total number of luminance samples is a multiple of 4. ++ ++ ++Description ++=========== ++ ++This is a packed 10-bit two-plane version of the YUV 4:2:2 format. The ++three components are separated into two sub-images or planes. The Y plane ++is first. The Y plane has five bytes per each group of four pixels. A ++combined CbCr plane immediately follows the Y plane in memory. The CbCr ++plane is the same width and height, in bytes, as the Y plane (and of the ++image). Each CbCr pair belongs to two pixels. For example, ++Cb\ :sub:`00`/Cr\ :sub:`00` belongs to Y'\ :sub:`00`, Y'\ :sub:`01`. ++ ++If the Y plane has pad bytes after each row, then the CbCr plane has as ++many pad bytes after its rows. ++ ++**Byte Order.** ++Little endian. Each cell is one byte. Pixels cross the byte boundary. ++ ++ ++.. flat-table:: ++ :header-rows: 0 ++ :stub-columns: 0 ++ ++ * - start + 0: ++ - Y'\ :sub:`00[7:0]` ++ - Y'\ :sub:`01[5:0]`\ Y'\ :sub:`00[9:8]` ++ - Y'\ :sub:`02[3:0]`\ Y'\ :sub:`01[9:6]` ++ - Y'\ :sub:`03[1:0]`\ Y'\ :sub:`02[9:4]` ++ - Y'\ :sub:`03[9:2]` ++ * - start + 5: ++ - Y'\ :sub:`10[7:0]` ++ - Y'\ :sub:`11[5:0]`\ Y'\ :sub:`10[9:8]` ++ - Y'\ :sub:`12[3:0]`\ Y'\ :sub:`11[9:6]` ++ - Y'\ :sub:`13[1:0]`\ Y'\ :sub:`12[9:4]` ++ - Y'\ :sub:`13[9:2]` ++ * - start + 10: ++ - Cb'\ :sub:`00[7:0]` ++ - Cr'\ :sub:`00[5:0]`\ Cb'\ :sub:`00[9:8]` ++ - Cb'\ :sub:`01[3:0]`\ Cr'\ :sub:`00[9:6]` ++ - Cr'\ :sub:`01[1:0]`\ Cb'\ :sub:`01[9:4]` ++ - Cr'\ :sub:`01[9:2]` ++ * - start + 15: ++ - Cb'\ :sub:`10[7:0]` ++ - Cr'\ :sub:`10[5:0]`\ Cb'\ :sub:`10[9:8]` ++ - Cb'\ :sub:`11[3:0]`\ Cr'\ :sub:`10[9:6]` ++ - Cr'\ :sub:`11[1:0]`\ Cb'\ :sub:`11[9:4]` ++ - Cr'\ :sub:`11[9:2]` ++ ++ ++**Color Sample Location:** ++ ++.. flat-table:: ++ :header-rows: 0 ++ :stub-columns: 0 ++ ++ * - ++ - 0 ++ - ++ - 1 ++ - 2 ++ - ++ - 3 ++ * - 0 ++ - Y ++ - C ++ - Y ++ - Y ++ - C ++ - Y ++ * - 1 ++ - Y ++ - C ++ - Y ++ - Y ++ - C ++ - Y +diff --git a/Documentation/userspace-api/media/v4l/yuv-formats.rst b/Documentation/userspace-api/media/v4l/yuv-formats.rst +index 8ee92d0cd769..7cca883f178a 100644 +--- a/Documentation/userspace-api/media/v4l/yuv-formats.rst ++++ b/Documentation/userspace-api/media/v4l/yuv-formats.rst +@@ -61,4 +61,6 @@ to brightness information. + pixfmt-nv16 + pixfmt-nv16m + pixfmt-nv24 ++ pixfmt-nv15 ++ pixfmt-nv20 + pixfmt-m420 +diff --git a/drivers/media/v4l2-core/v4l2-common.c b/drivers/media/v4l2-core/v4l2-common.c +index 4102c373b48a..0caac755d303 100644 +--- a/drivers/media/v4l2-core/v4l2-common.c ++++ b/drivers/media/v4l2-core/v4l2-common.c +@@ -267,6 +267,9 @@ const struct v4l2_format_info *v4l2_format_info(u32 format) + { .format = V4L2_PIX_FMT_NV24, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, .hdiv = 1, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_NV42, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, .hdiv = 1, .vdiv = 1 }, + ++ { .format = V4L2_PIX_FMT_NV15, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 2, .bpp = { 5, 5, 0, 0 }, .hdiv = 2, .vdiv = 2, .block_w = { 4, 2, 0, 0 }, .block_h = { 1, 1, 0, 0 } }, ++ { .format = V4L2_PIX_FMT_NV20, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 2, .bpp = { 5, 5, 0, 0 }, .hdiv = 2, .vdiv = 1, .block_w = { 4, 2, 0, 0 }, .block_h = { 1, 1, 0, 0 } }, ++ + { .format = V4L2_PIX_FMT_YUV410, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 3, .bpp = { 1, 1, 1, 0 }, .hdiv = 4, .vdiv = 4 }, + { .format = V4L2_PIX_FMT_YVU410, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 3, .bpp = { 1, 1, 1, 0 }, .hdiv = 4, .vdiv = 4 }, + { .format = V4L2_PIX_FMT_YUV411P, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 3, .bpp = { 1, 1, 1, 0 }, .hdiv = 4, .vdiv = 1 }, +diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c +index ccf947632a3b..53de49087938 100644 +--- a/drivers/media/v4l2-core/v4l2-ioctl.c ++++ b/drivers/media/v4l2-core/v4l2-ioctl.c +@@ -1321,6 +1321,8 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt) + case V4L2_PIX_FMT_NV61: descr = "Y/CrCb 4:2:2"; break; + case V4L2_PIX_FMT_NV24: descr = "Y/CbCr 4:4:4"; break; + case V4L2_PIX_FMT_NV42: descr = "Y/CrCb 4:4:4"; break; ++ case V4L2_PIX_FMT_NV15: descr = "10-bit Y/CbCr 4:2:0 (Packed)"; break; ++ case V4L2_PIX_FMT_NV20: descr = "10-bit Y/CbCr 4:2:2 (Packed)"; break; + case V4L2_PIX_FMT_NV12M: descr = "Y/CbCr 4:2:0 (N-C)"; break; + case V4L2_PIX_FMT_NV21M: descr = "Y/CrCb 4:2:0 (N-C)"; break; + case V4L2_PIX_FMT_NV16M: descr = "Y/CbCr 4:2:2 (N-C)"; break; +diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h +index 6fe8822d2cb4..c8d7148cd9ae 100644 +--- a/include/uapi/linux/videodev2.h ++++ b/include/uapi/linux/videodev2.h +@@ -610,6 +610,9 @@ struct v4l2_pix_format { + #define V4L2_PIX_FMT_NV24 v4l2_fourcc('N', 'V', '2', '4') /* 24 Y/CbCr 4:4:4 */ + #define V4L2_PIX_FMT_NV42 v4l2_fourcc('N', 'V', '4', '2') /* 24 Y/CrCb 4:4:4 */ + ++#define V4L2_PIX_FMT_NV15 v4l2_fourcc('N', 'V', '1', '5') /* 15 Y/CbCr 4:2:0 10-bit packed */ ++#define V4L2_PIX_FMT_NV20 v4l2_fourcc('N', 'V', '2', '0') /* 20 Y/CbCr 4:2:2 10-bit packed */ ++ + /* two non contiguous planes - one Y, one Cr + Cb interleaved */ + #define V4L2_PIX_FMT_NV12M v4l2_fourcc('N', 'M', '1', '2') /* 12 Y/CbCr 4:2:0 */ + #define V4L2_PIX_FMT_NV21M v4l2_fourcc('N', 'M', '2', '1') /* 21 Y/CrCb 4:2:0 */ + +From d09e5dfbcc096eddf5c5d11744d53bae5f1f7d00 Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Mon, 6 Jul 2020 21:54:36 +0000 +Subject: [PATCH] media: rkvdec: h264: Use bytesperline and buffer height to + calculate stride + +Use bytesperline and buffer height to calculate the strides configured. + +This does not really change anything other than ensuring the bytesperline +that is signaled to userspace matches what is configured in HW. + +Signed-off-by: Jonas Karlman +--- + drivers/staging/media/rkvdec/rkvdec-h264.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/drivers/staging/media/rkvdec/rkvdec-h264.c b/drivers/staging/media/rkvdec/rkvdec-h264.c +index 2e7749bac417..d33fccc92205 100644 +--- a/drivers/staging/media/rkvdec/rkvdec-h264.c ++++ b/drivers/staging/media/rkvdec/rkvdec-h264.c +@@ -893,9 +893,9 @@ static void config_registers(struct rkvdec_ctx *ctx, + dma_addr_t rlc_addr; + dma_addr_t refer_addr; + u32 rlc_len; +- u32 hor_virstride = 0; +- u32 ver_virstride = 0; +- u32 y_virstride = 0; ++ u32 hor_virstride; ++ u32 ver_virstride; ++ u32 y_virstride; + u32 yuv_virstride = 0; + u32 offset; + dma_addr_t dst_addr; +@@ -906,8 +906,8 @@ static void config_registers(struct rkvdec_ctx *ctx, + + f = &ctx->decoded_fmt; + dst_fmt = &f->fmt.pix_mp; +- hor_virstride = (sps->bit_depth_luma_minus8 + 8) * dst_fmt->width / 8; +- ver_virstride = round_up(dst_fmt->height, 16); ++ hor_virstride = dst_fmt->plane_fmt[0].bytesperline; ++ ver_virstride = dst_fmt->height; + y_virstride = hor_virstride * ver_virstride; + + if (sps->chroma_format_idc == 0) + +From f0e873d66825fcd9ea314dcdab0d214226b2b8b4 Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Mon, 6 Jul 2020 21:54:37 +0000 +Subject: [PATCH] media: rkvdec: Extract rkvdec_fill_decoded_pixfmt helper + method + +This extract setting decoded pixfmt into a helper method, current code is +replaced with a call to the new helper method. + +The helper method is also called from a new function in next patch. + +Signed-off-by: Jonas Karlman +--- + drivers/staging/media/rkvdec/rkvdec.c | 29 ++++++++++++++------------- + 1 file changed, 15 insertions(+), 14 deletions(-) + +diff --git a/drivers/staging/media/rkvdec/rkvdec.c b/drivers/staging/media/rkvdec/rkvdec.c +index 06fc58440cd3..dc16bf8d57a9 100644 +--- a/drivers/staging/media/rkvdec/rkvdec.c ++++ b/drivers/staging/media/rkvdec/rkvdec.c +@@ -27,6 +27,17 @@ + #include "rkvdec.h" + #include "rkvdec-regs.h" + ++static void rkvdec_fill_decoded_pixfmt(struct rkvdec_ctx *ctx, ++ struct v4l2_pix_format_mplane *pix_mp) ++{ ++ v4l2_fill_pixfmt_mp(pix_mp, pix_mp->pixelformat, ++ pix_mp->width, pix_mp->height); ++ pix_mp->plane_fmt[0].sizeimage += 128 * ++ DIV_ROUND_UP(pix_mp->width, 16) * ++ DIV_ROUND_UP(pix_mp->height, 16); ++ pix_mp->field = V4L2_FIELD_NONE; ++} ++ + static int rkvdec_try_ctrl(struct v4l2_ctrl *ctrl) + { + struct rkvdec_ctx *ctx = container_of(ctrl->handler, struct rkvdec_ctx, ctrl_hdl); +@@ -167,13 +178,9 @@ static void rkvdec_reset_decoded_fmt(struct rkvdec_ctx *ctx) + + rkvdec_reset_fmt(ctx, f, ctx->coded_fmt_desc->decoded_fmts[0]); + f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; +- v4l2_fill_pixfmt_mp(&f->fmt.pix_mp, +- ctx->coded_fmt_desc->decoded_fmts[0], +- ctx->coded_fmt.fmt.pix_mp.width, +- ctx->coded_fmt.fmt.pix_mp.height); +- f->fmt.pix_mp.plane_fmt[0].sizeimage += 128 * +- DIV_ROUND_UP(f->fmt.pix_mp.width, 16) * +- DIV_ROUND_UP(f->fmt.pix_mp.height, 16); ++ f->fmt.pix_mp.width = ctx->coded_fmt.fmt.pix_mp.width; ++ f->fmt.pix_mp.height = ctx->coded_fmt.fmt.pix_mp.height; ++ rkvdec_fill_decoded_pixfmt(ctx, &f->fmt.pix_mp); + } + + static int rkvdec_enum_framesizes(struct file *file, void *priv, +@@ -239,13 +246,7 @@ static int rkvdec_try_capture_fmt(struct file *file, void *priv, + &pix_mp->height, + &coded_desc->frmsize); + +- v4l2_fill_pixfmt_mp(pix_mp, pix_mp->pixelformat, +- pix_mp->width, pix_mp->height); +- pix_mp->plane_fmt[0].sizeimage += +- 128 * +- DIV_ROUND_UP(pix_mp->width, 16) * +- DIV_ROUND_UP(pix_mp->height, 16); +- pix_mp->field = V4L2_FIELD_NONE; ++ rkvdec_fill_decoded_pixfmt(ctx, pix_mp); + + return 0; + } + +From 7743a31004da67bfd0f6246deaa59e670230c84e Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Mon, 6 Jul 2020 21:54:37 +0000 +Subject: [PATCH] media: rkvdec: Lock capture pixel format in s_ctrl and s_fmt + +Add an optional valid_fmt operation that should return the valid +pixelformat of CAPTURE buffers. + +This is used in next patch to ensure correct pixelformat is used for 10-bit +and 4:2:2 content. + +Signed-off-by: Jonas Karlman +--- + drivers/staging/media/rkvdec/rkvdec.c | 59 ++++++++++++++++++++++++--- + drivers/staging/media/rkvdec/rkvdec.h | 2 + + 2 files changed, 55 insertions(+), 6 deletions(-) + +diff --git a/drivers/staging/media/rkvdec/rkvdec.c b/drivers/staging/media/rkvdec/rkvdec.c +index dc16bf8d57a9..6b2a2f4164b2 100644 +--- a/drivers/staging/media/rkvdec/rkvdec.c ++++ b/drivers/staging/media/rkvdec/rkvdec.c +@@ -38,6 +38,16 @@ static void rkvdec_fill_decoded_pixfmt(struct rkvdec_ctx *ctx, + pix_mp->field = V4L2_FIELD_NONE; + } + ++static u32 rkvdec_valid_fmt(struct rkvdec_ctx *ctx, struct v4l2_ctrl *ctrl) ++{ ++ const struct rkvdec_coded_fmt_desc *coded_desc = ctx->coded_fmt_desc; ++ ++ if (coded_desc->ops->valid_fmt) ++ return coded_desc->ops->valid_fmt(ctx, ctrl); ++ ++ return ctx->valid_fmt; ++} ++ + static int rkvdec_try_ctrl(struct v4l2_ctrl *ctrl) + { + struct rkvdec_ctx *ctx = container_of(ctrl->handler, struct rkvdec_ctx, ctrl_hdl); +@@ -60,6 +70,10 @@ static int rkvdec_try_ctrl(struct v4l2_ctrl *ctrl) + /* Only 8-bit is supported */ + return -EINVAL; + ++ if (ctx->valid_fmt && ctx->valid_fmt != rkvdec_valid_fmt(ctx, ctrl)) ++ /* Only current valid format */ ++ return -EINVAL; ++ + width = (sps->pic_width_in_mbs_minus1 + 1) * 16; + height = (sps->pic_height_in_map_units_minus1 + 1) * 16; + +@@ -70,8 +84,27 @@ static int rkvdec_try_ctrl(struct v4l2_ctrl *ctrl) + return 0; + } + ++static int rkvdec_s_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ struct rkvdec_ctx *ctx = container_of(ctrl->handler, struct rkvdec_ctx, ctrl_hdl); ++ ++ if (ctrl->id == V4L2_CID_MPEG_VIDEO_H264_SPS && !ctx->valid_fmt) { ++ ctx->valid_fmt = rkvdec_valid_fmt(ctx, ctrl); ++ if (ctx->valid_fmt) { ++ struct v4l2_pix_format_mplane *pix_mp; ++ ++ pix_mp = &ctx->decoded_fmt.fmt.pix_mp; ++ pix_mp->pixelformat = ctx->valid_fmt; ++ rkvdec_fill_decoded_pixfmt(ctx, pix_mp); ++ } ++ } ++ ++ return 0; ++} ++ + static const struct v4l2_ctrl_ops rkvdec_ctrl_ops = { + .try_ctrl = rkvdec_try_ctrl, ++ .s_ctrl = rkvdec_s_ctrl, + }; + + static const struct rkvdec_ctrl_desc rkvdec_h264_ctrl_descs[] = { +@@ -176,6 +209,7 @@ static void rkvdec_reset_decoded_fmt(struct rkvdec_ctx *ctx) + { + struct v4l2_format *f = &ctx->decoded_fmt; + ++ ctx->valid_fmt = 0; + rkvdec_reset_fmt(ctx, f, ctx->coded_fmt_desc->decoded_fmts[0]); + f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + f->fmt.pix_mp.width = ctx->coded_fmt.fmt.pix_mp.width; +@@ -231,13 +265,17 @@ static int rkvdec_try_capture_fmt(struct file *file, void *priv, + if (WARN_ON(!coded_desc)) + return -EINVAL; + +- for (i = 0; i < coded_desc->num_decoded_fmts; i++) { +- if (coded_desc->decoded_fmts[i] == pix_mp->pixelformat) +- break; +- } ++ if (ctx->valid_fmt) { ++ pix_mp->pixelformat = ctx->valid_fmt; ++ } else { ++ for (i = 0; i < coded_desc->num_decoded_fmts; i++) { ++ if (coded_desc->decoded_fmts[i] == pix_mp->pixelformat) ++ break; ++ } + +- if (i == coded_desc->num_decoded_fmts) +- pix_mp->pixelformat = coded_desc->decoded_fmts[0]; ++ if (i == coded_desc->num_decoded_fmts) ++ pix_mp->pixelformat = coded_desc->decoded_fmts[0]; ++ } + + /* Always apply the frmsize constraint of the coded end. */ + pix_mp->width = max(pix_mp->width, ctx->coded_fmt.fmt.pix_mp.width); +@@ -312,6 +350,7 @@ static int rkvdec_s_capture_fmt(struct file *file, void *priv, + return ret; + + ctx->decoded_fmt = *f; ++ ctx->valid_fmt = f->fmt.pix_mp.pixelformat; + return 0; + } + +@@ -401,6 +440,14 @@ static int rkvdec_enum_capture_fmt(struct file *file, void *priv, + if (WARN_ON(!ctx->coded_fmt_desc)) + return -EINVAL; + ++ if (ctx->valid_fmt) { ++ if (f->index) ++ return -EINVAL; ++ ++ f->pixelformat = ctx->valid_fmt; ++ return 0; ++ } ++ + if (f->index >= ctx->coded_fmt_desc->num_decoded_fmts) + return -EINVAL; + +diff --git a/drivers/staging/media/rkvdec/rkvdec.h b/drivers/staging/media/rkvdec/rkvdec.h +index 77a137cca88e..e95c52e3168a 100644 +--- a/drivers/staging/media/rkvdec/rkvdec.h ++++ b/drivers/staging/media/rkvdec/rkvdec.h +@@ -63,6 +63,7 @@ vb2_to_rkvdec_decoded_buf(struct vb2_buffer *buf) + struct rkvdec_coded_fmt_ops { + int (*adjust_fmt)(struct rkvdec_ctx *ctx, + struct v4l2_format *f); ++ u32 (*valid_fmt)(struct rkvdec_ctx *ctx, struct v4l2_ctrl *ctrl); + int (*start)(struct rkvdec_ctx *ctx); + void (*stop)(struct rkvdec_ctx *ctx); + int (*run)(struct rkvdec_ctx *ctx); +@@ -96,6 +97,7 @@ struct rkvdec_ctx { + struct v4l2_fh fh; + struct v4l2_format coded_fmt; + struct v4l2_format decoded_fmt; ++ u32 valid_fmt; + const struct rkvdec_coded_fmt_desc *coded_fmt_desc; + struct v4l2_ctrl_handler ctrl_hdl; + struct rkvdec_dev *dev; + +From 15bb8d006a05aecc371e530769f06bf52c2c65bc Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Mon, 6 Jul 2020 21:54:37 +0000 +Subject: [PATCH] media: rkvdec: h264: Support High 10 and 4:2:2 profiles + +Add support and enable decoding of H264 High 10 and 4:2:2 profiles. + +Decoded CAPTURE buffer width is aligned to 64 pixels to accommodate HW +requirement on 10-bit format buffers. + +The new valid_fmt operation is implemented and return a valid pixelformat +for the provided SPS control. + +Signed-off-by: Jonas Karlman +--- + drivers/staging/media/rkvdec/rkvdec-h264.c | 20 ++++++++++++++++++++ + drivers/staging/media/rkvdec/rkvdec.c | 19 +++++++++---------- + 2 files changed, 29 insertions(+), 10 deletions(-) + +diff --git a/drivers/staging/media/rkvdec/rkvdec-h264.c b/drivers/staging/media/rkvdec/rkvdec-h264.c +index d33fccc92205..afc695d32186 100644 +--- a/drivers/staging/media/rkvdec/rkvdec-h264.c ++++ b/drivers/staging/media/rkvdec/rkvdec-h264.c +@@ -1021,6 +1021,25 @@ static int rkvdec_h264_adjust_fmt(struct rkvdec_ctx *ctx, + return 0; + } + ++static u32 rkvdec_h264_valid_fmt(struct rkvdec_ctx *ctx, struct v4l2_ctrl *ctrl) ++{ ++ const struct v4l2_ctrl_h264_sps *sps = ctrl->p_new.p_h264_sps; ++ ++ if (sps->bit_depth_luma_minus8 == 0) { ++ if (sps->chroma_format_idc == 2) ++ return V4L2_PIX_FMT_NV16; ++ else ++ return V4L2_PIX_FMT_NV12; ++ } else if (sps->bit_depth_luma_minus8 == 2) { ++ if (sps->chroma_format_idc == 2) ++ return V4L2_PIX_FMT_NV20; ++ else ++ return V4L2_PIX_FMT_NV15; ++ } ++ ++ return 0; ++} ++ + static int rkvdec_h264_start(struct rkvdec_ctx *ctx) + { + struct rkvdec_dev *rkvdec = ctx->dev; +@@ -1124,6 +1143,7 @@ static int rkvdec_h264_run(struct rkvdec_ctx *ctx) + + const struct rkvdec_coded_fmt_ops rkvdec_h264_fmt_ops = { + .adjust_fmt = rkvdec_h264_adjust_fmt, ++ .valid_fmt = rkvdec_h264_valid_fmt, + .start = rkvdec_h264_start, + .stop = rkvdec_h264_stop, + .run = rkvdec_h264_run, +diff --git a/drivers/staging/media/rkvdec/rkvdec.c b/drivers/staging/media/rkvdec/rkvdec.c +index 6b2a2f4164b2..bd8ec2915fe9 100644 +--- a/drivers/staging/media/rkvdec/rkvdec.c ++++ b/drivers/staging/media/rkvdec/rkvdec.c +@@ -31,7 +31,7 @@ static void rkvdec_fill_decoded_pixfmt(struct rkvdec_ctx *ctx, + struct v4l2_pix_format_mplane *pix_mp) + { + v4l2_fill_pixfmt_mp(pix_mp, pix_mp->pixelformat, +- pix_mp->width, pix_mp->height); ++ ALIGN(pix_mp->width, 64), pix_mp->height); + pix_mp->plane_fmt[0].sizeimage += 128 * + DIV_ROUND_UP(pix_mp->width, 16) * + DIV_ROUND_UP(pix_mp->height, 16); +@@ -55,19 +55,15 @@ static int rkvdec_try_ctrl(struct v4l2_ctrl *ctrl) + if (ctrl->id == V4L2_CID_MPEG_VIDEO_H264_SPS) { + const struct v4l2_ctrl_h264_sps *sps = ctrl->p_new.p_h264_sps; + unsigned int width, height; +- /* +- * TODO: The hardware supports 10-bit and 4:2:2 profiles, +- * but it's currently broken in the driver. +- * Reject them for now, until it's fixed. +- */ +- if (sps->chroma_format_idc > 1) +- /* Only 4:0:0 and 4:2:0 are supported */ ++ ++ if (sps->chroma_format_idc > 2) ++ /* Only 4:0:0, 4:2:0 and 4:2:2 are supported */ + return -EINVAL; + if (sps->bit_depth_luma_minus8 != sps->bit_depth_chroma_minus8) + /* Luma and chroma bit depth mismatch */ + return -EINVAL; +- if (sps->bit_depth_luma_minus8 != 0) +- /* Only 8-bit is supported */ ++ if (sps->bit_depth_luma_minus8 != 0 && sps->bit_depth_luma_minus8 != 2) ++ /* Only 8-bit and 10-bit is supported */ + return -EINVAL; + + if (ctx->valid_fmt && ctx->valid_fmt != rkvdec_valid_fmt(ctx, ctrl)) +@@ -145,6 +141,9 @@ static const struct rkvdec_ctrls rkvdec_h264_ctrls = { + + static const u32 rkvdec_h264_decoded_fmts[] = { + V4L2_PIX_FMT_NV12, ++ V4L2_PIX_FMT_NV15, ++ V4L2_PIX_FMT_NV16, ++ V4L2_PIX_FMT_NV20, + }; + + static const struct rkvdec_coded_fmt_desc rkvdec_coded_fmts[] = { + +From 26aca7fda4117f4bff16e3fb5349878fb322410b Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Mon, 6 Jul 2020 21:54:38 +0000 +Subject: [PATCH] media: rkvdec: h264: Support profile and level controls + +The Rockchip Video Decoder used in RK3399 supports H.264 profiles from +Baseline to High 4:2:2 up to Level 5.1, except for the Extended profile. + +Expose the V4L2_CID_MPEG_VIDEO_H264_PROFILE and the +V4L2_CID_MPEG_VIDEO_H264_LEVEL control, so that userspace can query the +driver for the list of supported profiles and level. + +Signed-off-by: Jonas Karlman +Reviewed-by: Ezequiel Garcia +--- + drivers/staging/media/rkvdec/rkvdec.c | 13 +++++++++++++ + 1 file changed, 13 insertions(+) + +diff --git a/drivers/staging/media/rkvdec/rkvdec.c b/drivers/staging/media/rkvdec/rkvdec.c +index bd8ec2915fe9..87987a782d75 100644 +--- a/drivers/staging/media/rkvdec/rkvdec.c ++++ b/drivers/staging/media/rkvdec/rkvdec.c +@@ -132,6 +132,19 @@ static const struct rkvdec_ctrl_desc rkvdec_h264_ctrl_descs[] = { + .cfg.def = V4L2_MPEG_VIDEO_H264_START_CODE_ANNEX_B, + .cfg.max = V4L2_MPEG_VIDEO_H264_START_CODE_ANNEX_B, + }, ++ { ++ .cfg.id = V4L2_CID_MPEG_VIDEO_H264_PROFILE, ++ .cfg.min = V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE, ++ .cfg.max = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_422, ++ .cfg.menu_skip_mask = ++ BIT(V4L2_MPEG_VIDEO_H264_PROFILE_EXTENDED), ++ .cfg.def = V4L2_MPEG_VIDEO_H264_PROFILE_MAIN, ++ }, ++ { ++ .cfg.id = V4L2_CID_MPEG_VIDEO_H264_LEVEL, ++ .cfg.min = V4L2_MPEG_VIDEO_H264_LEVEL_1_0, ++ .cfg.max = V4L2_MPEG_VIDEO_H264_LEVEL_5_1, ++ }, + }; + + static const struct rkvdec_ctrls rkvdec_h264_ctrls = { + +From 272e8a34d1803cc88e74de99b10330cd57d18f26 Mon Sep 17 00:00:00 2001 +From: Ezequiel Garcia +Date: Mon, 18 May 2020 14:40:09 -0300 +Subject: [PATCH] media: rkvdec: Fix .buf_prepare + +The driver should only set the payload on .buf_prepare +if the buffer is CAPTURE type, or if an OUTPUT buffer +has a zeroed payload. + +Fix it. + +Fixes: cd33c830448ba ("media: rkvdec: Add the rkvdec driver") +Signed-off-by: Ezequiel Garcia +--- + drivers/staging/media/rkvdec/rkvdec.c | 10 +++++++++- + 1 file changed, 9 insertions(+), 1 deletion(-) + +diff --git a/drivers/staging/media/rkvdec/rkvdec.c b/drivers/staging/media/rkvdec/rkvdec.c +index 87987a782d75..91f8a1bb6176 100644 +--- a/drivers/staging/media/rkvdec/rkvdec.c ++++ b/drivers/staging/media/rkvdec/rkvdec.c +@@ -543,7 +543,15 @@ static int rkvdec_buf_prepare(struct vb2_buffer *vb) + if (vb2_plane_size(vb, i) < sizeimage) + return -EINVAL; + } +- vb2_set_plane_payload(vb, 0, f->fmt.pix_mp.plane_fmt[0].sizeimage); ++ ++ /* ++ * Buffer's bytesused is written by the driver for CAPTURE buffers, ++ * or if the application passed zero bytesused on an OUTPUT buffer. ++ */ ++ if (!V4L2_TYPE_IS_OUTPUT(vq->type) || ++ (V4L2_TYPE_IS_OUTPUT(vq->type) && !vb2_get_plane_payload(vb, 0))) ++ vb2_set_plane_payload(vb, 0, ++ f->fmt.pix_mp.plane_fmt[0].sizeimage); + return 0; + } + + +From 6e771db436797df6146b1fe0ec94d4138bdaa2bc Mon Sep 17 00:00:00 2001 +From: Boris Brezillon +Date: Mon, 18 May 2020 14:40:10 -0300 +Subject: [PATCH] media: uapi: Add VP9 stateless decoder controls + +Add the VP9 stateless decoder controls plus the documentation that goes +with it. + +Signed-off-by: Boris Brezillon +Signed-off-by: Ezequiel Garcia +--- + .../userspace-api/media/v4l/biblio.rst | 10 + + .../media/v4l/ext-ctrls-codec.rst | 550 ++++++++++++++++++ + drivers/media/v4l2-core/v4l2-ctrls.c | 239 ++++++++ + drivers/media/v4l2-core/v4l2-ioctl.c | 1 + + include/media/v4l2-ctrls.h | 1 + + include/media/vp9-ctrls.h | 485 +++++++++++++++ + 6 files changed, 1286 insertions(+) + create mode 100644 include/media/vp9-ctrls.h + +diff --git a/Documentation/userspace-api/media/v4l/biblio.rst b/Documentation/userspace-api/media/v4l/biblio.rst +index 3c9634173e82..e09102e572fd 100644 +--- a/Documentation/userspace-api/media/v4l/biblio.rst ++++ b/Documentation/userspace-api/media/v4l/biblio.rst +@@ -414,3 +414,13 @@ VP8 + :title: RFC 6386: "VP8 Data Format and Decoding Guide" + + :author: J. Bankoski et al. ++ ++.. _vp9: ++ ++VP9 ++=== ++ ++ ++:title: VP9 Bitstream & Decoding Process Specification ++ ++:author: Adrian Grange (Google), Peter de Rivaz (Argon Design), Jonathan Hunt (Argon Design) +diff --git a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst +index 03ce87aa5488..ca13b141d8c2 100644 +--- a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst ++++ b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst +@@ -2689,6 +2689,556 @@ enum v4l2_mpeg_video_h264_hierarchical_coding_type - + - ``padding[3]`` + - Applications and drivers must set this to zero. + ++.. _v4l2-mpeg-vp9: ++ ++``V4L2_CID_MPEG_VIDEO_VP9_FRAME_CONTEXT(0..3) (struct)`` ++ Stores VP9 probabilities attached to a specific frame context. The VP9 ++ specification allows using a maximum of 4 contexts. Each frame being ++ decoded refers to one of those context. See section '7.1.2 Refresh ++ probs semantics' section of :ref:`vp9` for more details about these ++ contexts. ++ ++ This control is bi-directional: ++ ++ * all 4 contexts must be initialized by userspace just after the ++ stream is started and before the first decoding request is submitted. ++ * the referenced context might be read by the kernel when a decoding ++ request is submitted, and will be updated after the decoder is done ++ decoding the frame if the `V4L2_VP9_FRAME_FLAG_REFRESH_FRAME_CTX` flag ++ is set. ++ * contexts will be read back by user space before each decoding request ++ to retrieve the updated probabilities. ++ * userspace will re-initialize the context to their default values when ++ a reset context is required. ++ ++ .. note:: ++ ++ This compound control is not yet part of the public kernel API and ++ it is expected to change. ++ ++.. c:type:: v4l2_ctrl_vp9_frame_ctx ++ ++.. cssclass:: longtable ++ ++.. tabularcolumns:: |p{5.8cm}|p{4.8cm}|p{6.6cm}| ++ ++.. flat-table:: struct v4l2_ctrl_vp9_frame_ctx ++ :header-rows: 0 ++ :stub-columns: 0 ++ :widths: 1 1 2 ++ ++ * - struct :c:type:`v4l2_vp9_probabilities` ++ - ``probs`` ++ - Structure with VP9 probabilities attached to the context. ++ ++.. c:type:: v4l2_vp9_probabilities ++ ++.. cssclass:: longtable ++ ++.. tabularcolumns:: |p{1.5cm}|p{6.3cm}|p{9.4cm}| ++ ++.. flat-table:: struct v4l2_vp9_probabilities ++ :header-rows: 0 ++ :stub-columns: 0 ++ :widths: 1 1 2 ++ ++ * - __u8 ++ - ``tx8[2][1]`` ++ - TX 8x8 probabilities. ++ * - __u8 ++ - ``tx16[2][2]`` ++ - TX 16x16 probabilities. ++ * - __u8 ++ - ``tx32[2][3]`` ++ - TX 32x32 probabilities. ++ * - __u8 ++ - ``coef[4][2][2][6][6][3]`` ++ - Coefficient probabilities. ++ * - __u8 ++ - ``skip[3]`` ++ - Skip probabilities. ++ * - __u8 ++ - ``inter_mode[7][3]`` ++ - Inter prediction mode probabilities. ++ * - __u8 ++ - ``interp_filter[4][2]`` ++ - Interpolation filter probabilities. ++ * - __u8 ++ - ``is_inter[4]`` ++ - Is inter-block probabilities. ++ * - __u8 ++ - ``comp_mode[5]`` ++ - Compound prediction mode probabilities. ++ * - __u8 ++ - ``single_ref[5][2]`` ++ - Single reference probabilities. ++ * - __u8 ++ - ``comp_mode[5]`` ++ - Compound reference probabilities. ++ * - __u8 ++ - ``y_mode[4][9]`` ++ - Y prediction mode probabilities. ++ * - __u8 ++ - ``uv_mode[10][9]`` ++ - UV prediction mode probabilities. ++ * - __u8 ++ - ``partition[16][3]`` ++ - Partition probabilities. ++ * - __u8 ++ - ``mv.joint[3]`` ++ - Motion vector joint probabilities. ++ * - __u8 ++ - ``mv.sign[2]`` ++ - Motion vector sign probabilities. ++ * - __u8 ++ - ``mv.class[2][10]`` ++ - Motion vector class probabilities. ++ * - __u8 ++ - ``mv.class0_bit[2]`` ++ - Motion vector class0 bit probabilities. ++ * - __u8 ++ - ``mv.bits[2][10]`` ++ - Motion vector bits probabilities. ++ * - __u8 ++ - ``mv.class0_fr[2][2][3]`` ++ - Motion vector class0 fractional bit probabilities. ++ * - __u8 ++ - ``mv.fr[2][3]`` ++ - Motion vector fractional bit probabilities. ++ * - __u8 ++ - ``mv.class0_hp[2]`` ++ - Motion vector class0 high precision fractional bit probabilities. ++ * - __u8 ++ - ``mv.hp[2]`` ++ - Motion vector high precision fractional bit probabilities. ++ ++``V4L2_CID_MPEG_VIDEO_VP9_FRAME_DECODE_PARAMS (struct)`` ++ Specifies the frame parameters for the associated VP9 frame decode request. ++ This includes the necessary parameters for configuring a stateless hardware ++ decoding pipeline for VP9. The bitstream parameters are defined according ++ to :ref:`vp9`. ++ ++ .. note:: ++ ++ This compound control is not yet part of the public kernel API and ++ it is expected to change. ++ ++.. c:type:: v4l2_ctrl_vp9_frame_decode_params ++ ++.. cssclass:: longtable ++ ++.. tabularcolumns:: |p{1.5cm}|p{6.3cm}|p{9.4cm}| ++ ++.. flat-table:: struct v4l2_ctrl_vp9_frame_decode_params ++ :header-rows: 0 ++ :stub-columns: 0 ++ :widths: 1 1 2 ++ ++ * - __u32 ++ - ``flags`` ++ - Combination of V4L2_VP9_FRAME_FLAG_* flags. See ++ :c:type:`v4l2_vp9_frame_flags`. ++ * - __u16 ++ - ``compressed_header_size`` ++ - Compressed header size in bytes. ++ * - __u16 ++ - ``uncompressed_header_size`` ++ - Uncompressed header size in bytes. ++ * - __u8 ++ - ``profile`` ++ - VP9 profile. Can be 0, 1, 2 or 3. ++ * - __u8 ++ - ``reset_frame_context`` ++ - Frame context that should be used/updated when decoding the frame. ++ * - __u8 ++ - ``bit_depth`` ++ - Component depth in bits. Must be 8 for profile 0 and 1. Must 10 or 12 ++ for profile 2 and 3. ++ * - __u8 ++ - ``interpolation_filter`` ++ - Specifies the filter selection used for performing inter prediction. See ++ :c:type:`v4l2_vp9_interpolation_filter`. ++ * - __u8 ++ - ``tile_cols_log2`` ++ - Specifies the base 2 logarithm of the width of each tile (where the ++ width is measured in units of 8x8 blocks). Shall be less than or equal ++ to 6. ++ * - __u8 ++ - ``tile_rows_log2`` ++ - Specifies the base 2 logarithm of the height of each tile (where the ++ height is measured in units of 8x8 blocks) ++ * - __u8 ++ - ``tx_mode`` ++ - Specifies the TX mode. See :c:type:`v4l2_vp9_tx_mode`. ++ * - __u8 ++ - ``reference_mode`` ++ - Specifies the type of inter prediction to be used. See ++ :c:type:`v4l2_vp9_reference_mode`. ++ * - __u8 ++ - ``padding`` ++ - Needed to make this struct 64 bit aligned. Shall be filled with zeroes. ++ * - __u16 ++ - ``frame_width_minus_1`` ++ - Add 1 to get the frame width expressed in pixels. ++ * - __u16 ++ - ``frame_height_minus_1`` ++ - Add 1 to to get the frame height expressed in pixels. ++ * - __u16 ++ - ``frame_width_minus_1`` ++ - Add 1 to to get the expected render width expressed in pixels. This is ++ not used during the decoding process but might be used by HW scalers to ++ prepare a frame that's ready for scanout. ++ * - __u16 ++ - frame_height_minus_1 ++ - Add 1 to get the expected render height expressed in pixels. This is ++ not used during the decoding process but might be used by HW scalers to ++ prepare a frame that's ready for scanout. ++ * - __u64 ++ - ``refs[3]`` ++ - Array of reference frame timestamps. ++ * - struct :c:type:`v4l2_vp9_loop_filter` ++ - ``lf`` ++ - Loop filter parameters. See struct :c:type:`v4l2_vp9_loop_filter`. ++ * - struct :c:type:`v4l2_vp9_quantization` ++ - ``quant`` ++ - Quantization parameters. See :c:type:`v4l2_vp9_quantization`. ++ * - struct :c:type:`v4l2_vp9_segmentation` ++ - ``seg`` ++ - Segmentation parameters. See :c:type:`v4l2_vp9_segmentation`. ++ * - struct :c:type:`v4l2_vp9_probabilities` ++ - ``probs`` ++ - Probabilities. See :c:type:`v4l2_vp9_probabilities`. ++ ++.. c:type:: v4l2_vp9_frame_flags ++ ++.. cssclass:: longtable ++ ++.. tabularcolumns:: |p{1.5cm}|p{6.3cm}|p{9.4cm}| ++ ++.. flat-table:: enum v4l2_vp9_frame_flags ++ :header-rows: 0 ++ :stub-columns: 0 ++ :widths: 1 2 ++ ++ * - ``V4L2_VP9_FRAME_FLAG_KEY_FRAME`` ++ - The frame is a key frame. ++ * - ``V4L2_VP9_FRAME_FLAG_SHOW_FRAME`` ++ - The frame should be displayed. ++ * - ``V4L2_VP9_FRAME_FLAG_ERROR_RESILIENT`` ++ - The decoding should be error resilient. ++ * - ``V4L2_VP9_FRAME_FLAG_INTRA_ONLY`` ++ - The frame does not reference other frames. ++ * - ``V4L2_VP9_FRAME_FLAG_ALLOW_HIGH_PREC_MV`` ++ - the frame might can high precision motion vectors. ++ * - ``V4L2_VP9_FRAME_FLAG_REFRESH_FRAME_CTX`` ++ - Frame context should be updated after decoding. ++ * - ``V4L2_VP9_FRAME_FLAG_PARALLEL_DEC_MODE`` ++ - Parallel decoding is used. ++ * - ``V4L2_VP9_FRAME_FLAG_X_SUBSAMPLING`` ++ - Vertical subsampling is enabled. ++ * - ``V4L2_VP9_FRAME_FLAG_Y_SUBSAMPLING`` ++ - Horizontal subsampling is enabled. ++ * - ``V4L2_VP9_FRAME_FLAG_COLOR_RANGE_FULL_SWING`` ++ - The full UV range is used. ++ ++.. c:type:: v4l2_vp9_ref_id ++ ++.. cssclass:: longtable ++ ++.. tabularcolumns:: |p{1.5cm}|p{6.3cm}|p{9.4cm}| ++ ++.. flat-table:: enum v4l2_vp9_ref_id ++ :header-rows: 0 ++ :stub-columns: 0 ++ :widths: 1 2 ++ ++ * - ``V4L2_REF_ID_LAST`` ++ - Last reference frame. ++ * - ``V4L2_REF_ID_GOLDEN`` ++ - Golden reference frame. ++ * - ``V4L2_REF_ID_ALTREF`` ++ - Alternative reference frame. ++ * - ``V4L2_REF_ID_CNT`` ++ - Number of reference frames. ++ ++.. c:type:: v4l2_vp9_tx_mode ++ ++.. cssclass:: longtable ++ ++.. tabularcolumns:: |p{1.5cm}|p{6.3cm}|p{9.4cm}| ++ ++.. flat-table:: enum v4l2_vp9_tx_mode ++ :header-rows: 0 ++ :stub-columns: 0 ++ :widths: 1 2 ++ ++ * - ``V4L2_VP9_TX_MODE_ONLY_4X4`` ++ - Transform size is 4x4. ++ * - ``V4L2_VP9_TX_MODE_ALLOW_8X8`` ++ - Transform size can be up to 8x8. ++ * - ``V4L2_VP9_TX_MODE_ALLOW_16X16`` ++ - Transform size can be up to 16x16. ++ * - ``V4L2_VP9_TX_MODE_ALLOW_32X32`` ++ - transform size can be up to 32x32. ++ * - ``V4L2_VP9_TX_MODE_SELECT`` ++ - Bitstream contains transform size for each block. ++ ++.. c:type:: v4l2_vp9_reference_mode ++ ++.. cssclass:: longtable ++ ++.. tabularcolumns:: |p{1.5cm}|p{6.3cm}|p{9.4cm}| ++ ++.. flat-table:: enum v4l2_vp9_reference_mode ++ :header-rows: 0 ++ :stub-columns: 0 ++ :widths: 1 2 ++ ++ * - ``V4L2_VP9_REF_MODE_SINGLE`` ++ - Indicates that all the inter blocks use only a single reference frame ++ to generate motion compensated prediction. ++ * - ``V4L2_VP9_REF_MODE_COMPOUND`` ++ - Requires all the inter blocks to use compound mode. Single reference ++ frame prediction is not allowed. ++ * - ``V4L2_VP9_REF_MODE_SELECT`` ++ - Allows each individual inter block to select between single and ++ compound prediction modes. ++ ++.. c:type:: v4l2_vp9_interpolation_filter ++ ++.. cssclass:: longtable ++ ++.. tabularcolumns:: |p{1.5cm}|p{6.3cm}|p{9.4cm}| ++ ++.. flat-table:: enum v4l2_vp9_interpolation_filter ++ :header-rows: 0 ++ :stub-columns: 0 ++ :widths: 1 2 ++ ++ * - ``V4L2_VP9_INTERP_FILTER_8TAP`` ++ - Height tap filter. ++ * - ``V4L2_VP9_INTERP_FILTER_8TAP_SMOOTH`` ++ - Height tap smooth filter. ++ * - ``V4L2_VP9_INTERP_FILTER_8TAP_SHARP`` ++ - Height tap sharp filter. ++ * - ``V4L2_VP9_INTERP_FILTER_BILINEAR`` ++ - Bilinear filter. ++ * - ``V4L2_VP9_INTERP_FILTER_SWITCHABLE`` ++ - Filter selection is signaled at the block level. ++ ++.. c:type:: v4l2_vp9_reset_frame_context ++ ++.. cssclass:: longtable ++ ++.. tabularcolumns:: |p{1.5cm}|p{6.3cm}|p{9.4cm}| ++ ++.. flat-table:: enum v4l2_vp9_reset_frame_context ++ :header-rows: 0 ++ :stub-columns: 0 ++ :widths: 1 2 ++ ++ * - ``V4L2_VP9_RESET_FRAME_CTX_NONE`` ++ - Do not reset any frame context. ++ * - ``V4L2_VP9_RESET_FRAME_CTX_SPEC`` ++ - Reset the frame context pointed by ++ :c:type:`v4l2_ctrl_vp9_frame_decode_params`.frame_context_idx. ++ * - ``V4L2_VP9_RESET_FRAME_CTX_ALL`` ++ - Reset all frame contexts. ++ ++.. c:type:: v4l2_vp9_intra_prediction_mode ++ ++.. cssclass:: longtable ++ ++.. tabularcolumns:: |p{1.5cm}|p{6.3cm}|p{9.4cm}| ++ ++.. flat-table:: enum v4l2_vp9_intra_prediction_mode ++ :header-rows: 0 ++ :stub-columns: 0 ++ :widths: 1 2 ++ ++ * - ``V4L2_VP9_INTRA_PRED_DC`` ++ - DC intra prediction. ++ * - ``V4L2_VP9_INTRA_PRED_MODE_V`` ++ - Vertical intra prediction. ++ * - ``V4L2_VP9_INTRA_PRED_MODE_H`` ++ - Horizontal intra prediction. ++ * - ``V4L2_VP9_INTRA_PRED_MODE_D45`` ++ - D45 intra prediction. ++ * - ``V4L2_VP9_INTRA_PRED_MODE_D135`` ++ - D135 intra prediction. ++ * - ``V4L2_VP9_INTRA_PRED_MODE_D117`` ++ - D117 intra prediction. ++ * - ``V4L2_VP9_INTRA_PRED_MODE_D153`` ++ - D153 intra prediction. ++ * - ``V4L2_VP9_INTRA_PRED_MODE_D207`` ++ - D207 intra prediction. ++ * - ``V4L2_VP9_INTRA_PRED_MODE_D63`` ++ - D63 intra prediction. ++ * - ``V4L2_VP9_INTRA_PRED_MODE_TM`` ++ - True motion intra prediction. ++ ++.. c:type:: v4l2_vp9_segmentation ++ ++.. cssclass:: longtable ++ ++.. tabularcolumns:: |p{1.5cm}|p{6.3cm}|p{9.4cm}| ++ ++.. flat-table:: struct v4l2_vp9_segmentation ++ :header-rows: 0 ++ :stub-columns: 0 ++ :widths: 1 1 2 ++ ++ * - __u8 ++ - ``flags`` ++ - Combination of V4L2_VP9_SEGMENTATION_FLAG_* flags. See ++ :c:type:`v4l2_vp9_segmentation_flags`. ++ * - __u8 ++ - ``tree_probs[7]`` ++ - Specifies the probability values to be used when decoding a Segment-ID. ++ See '5.15. Segmentation map' section of :ref:`vp9` for more details. ++ * - __u8 ++ - ``pred_prob[3]`` ++ - Specifies the probability values to be used when decoding a ++ Predicted-Segment-ID. See '6.4.14. Get segment id syntax' ++ section of :ref:`vp9` for more details. ++ * - __u8 ++ - ``padding[5]`` ++ - Used to align this struct on 64 bit. Shall be filled with zeroes. ++ * - __u8 ++ - ``feature_enabled[8]`` ++ - Bitmask defining which features are enabled in each segment. ++ * - __u8 ++ - ``feature_data[8][4]`` ++ - Data attached to each feature. Data entry is only valid if the feature ++ is enabled. ++ ++.. c:type:: v4l2_vp9_segment_feature ++ ++.. cssclass:: longtable ++ ++.. tabularcolumns:: |p{1.5cm}|p{6.3cm}|p{9.4cm}| ++ ++.. flat-table:: enum v4l2_vp9_segment_feature ++ :header-rows: 0 ++ :stub-columns: 0 ++ :widths: 1 2 ++ ++ * - ``V4L2_VP9_SEGMENT_FEATURE_QP_DELTA`` ++ - QP delta segment feature. ++ * - ``V4L2_VP9_SEGMENT_FEATURE_LF`` ++ - Loop filter segment feature. ++ * - ``V4L2_VP9_SEGMENT_FEATURE_REF_FRAME`` ++ - Reference frame segment feature. ++ * - ``V4L2_VP9_SEGMENT_FEATURE_SKIP`` ++ - Skip segment feature. ++ * - ``V4L2_VP9_SEGMENT_FEATURE_CNT`` ++ - Number of segment features. ++ ++.. c:type:: v4l2_vp9_segmentation_flags ++ ++.. cssclass:: longtable ++ ++.. tabularcolumns:: |p{1.5cm}|p{6.3cm}|p{9.4cm}| ++ ++.. flat-table:: enum v4l2_vp9_segmentation_flags ++ :header-rows: 0 ++ :stub-columns: 0 ++ :widths: 1 2 ++ ++ * - ``V4L2_VP9_SEGMENTATION_FLAG_ENABLED`` ++ - Indicates that this frame makes use of the segmentation tool. ++ * - ``V4L2_VP9_SEGMENTATION_FLAG_UPDATE_MAP`` ++ - Indicates that the segmentation map should be updated during the ++ decoding of this frame. ++ * - ``V4L2_VP9_SEGMENTATION_FLAG_TEMPORAL_UPDATE`` ++ - Indicates that the updates to the segmentation map are coded ++ relative to the existing segmentation map. ++ * - ``V4L2_VP9_SEGMENTATION_FLAG_UPDATE_DATA`` ++ - Indicates that new parameters are about to be specified for each ++ segment. ++ * - ``V4L2_VP9_SEGMENTATION_FLAG_ABS_OR_DELTA_UPDATE`` ++ - Indicates that the segmentation parameters represent the actual values ++ to be used. ++ ++.. c:type:: v4l2_vp9_quantization ++ ++.. cssclass:: longtable ++ ++.. tabularcolumns:: |p{1.5cm}|p{6.3cm}|p{9.4cm}| ++ ++.. flat-table:: struct v4l2_vp9_quantization ++ :header-rows: 0 ++ :stub-columns: 0 ++ :widths: 1 1 2 ++ ++ * - __u8 ++ - ``base_q_idx`` ++ - Indicates the base frame qindex. ++ * - __s8 ++ - ``delta_q_y_dc`` ++ - Indicates the Y DC quantizer relative to base_q_idx. ++ * - __s8 ++ - ``delta_q_uv_dc`` ++ - Indicates the UV DC quantizer relative to base_q_idx. ++ * - __s8 ++ - ``delta_q_uv_ac`` ++ - Indicates the UV AC quantizer relative to base_q_idx. ++ * - __u8 ++ - ``padding[4]`` ++ - Padding bytes used to align this struct on 64 bit. Must be set to 0. ++ ++.. c:type:: v4l2_vp9_loop_filter ++ ++.. cssclass:: longtable ++ ++.. tabularcolumns:: |p{1.5cm}|p{6.3cm}|p{9.4cm}| ++ ++.. flat-table:: struct v4l2_vp9_loop_filter ++ :header-rows: 0 ++ :stub-columns: 0 ++ :widths: 1 1 2 ++ ++ * - __u8 ++ - ``flags`` ++ - Combination of V4L2_VP9_LOOP_FILTER_FLAG_* flags. ++ See :c:type:`v4l2_vp9_loop_filter_flags`. ++ * - __u8 ++ - ``level`` ++ - Indicates the loop filter strength. ++ * - __u8 ++ - ``sharpness`` ++ - Indicates the sharpness level. ++ * - __s8 ++ - ``ref_deltas[4]`` ++ - Contains the adjustment needed for the filter level based on the chosen ++ reference frame. ++ * - __s8 ++ - ``mode_deltas[2]`` ++ - Contains the adjustment needed for the filter level based on the chosen ++ mode ++ * - __u8 ++ - ``level_lookup[8][4][2]`` ++ - Level lookup table. ++ ++ ++.. c:type:: v4l2_vp9_loop_filter_flags ++ ++.. cssclass:: longtable ++ ++.. tabularcolumns:: |p{1.5cm}|p{6.3cm}|p{9.4cm}| ++ ++.. flat-table:: enum v4l2_vp9_loop_filter_flags ++ :header-rows: 0 ++ :stub-columns: 0 ++ :widths: 1 2 ++ ++ * - ``V4L2_VP9_LOOP_FILTER_FLAG_DELTA_ENABLED`` ++ - When set, the filter level depends on the mode and reference frame used ++ to predict a block. ++ * - ``V4L2_VP9_LOOP_FILTER_FLAG_DELTA_UPDATE`` ++ - When set, the bitstream contains additional syntax elements that ++ specify which mode and reference frame deltas are to be updated. ++ + .. raw:: latex + + \normalsize +diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c +index b846f5b089c9..5913088cbc6f 100644 +--- a/drivers/media/v4l2-core/v4l2-ctrls.c ++++ b/drivers/media/v4l2-core/v4l2-ctrls.c +@@ -940,6 +940,11 @@ const char *v4l2_ctrl_get_name(u32 id) + case V4L2_CID_MPEG_VIDEO_VP8_PROFILE: return "VP8 Profile"; + case V4L2_CID_MPEG_VIDEO_VP9_PROFILE: return "VP9 Profile"; + case V4L2_CID_MPEG_VIDEO_VP8_FRAME_HEADER: return "VP8 Frame Header"; ++ case V4L2_CID_MPEG_VIDEO_VP9_FRAME_DECODE_PARAMS: return "VP9 Frame Decode Parameters"; ++ case V4L2_CID_MPEG_VIDEO_VP9_FRAME_CONTEXT(0): return "VP9 Frame Context 0"; ++ case V4L2_CID_MPEG_VIDEO_VP9_FRAME_CONTEXT(1): return "VP9 Frame Context 1"; ++ case V4L2_CID_MPEG_VIDEO_VP9_FRAME_CONTEXT(2): return "VP9 Frame Context 2"; ++ case V4L2_CID_MPEG_VIDEO_VP9_FRAME_CONTEXT(3): return "VP9 Frame Context 3"; + + /* HEVC controls */ + case V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_QP: return "HEVC I-Frame QP Value"; +@@ -1419,6 +1424,15 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type, + case V4L2_CID_MPEG_VIDEO_VP8_FRAME_HEADER: + *type = V4L2_CTRL_TYPE_VP8_FRAME_HEADER; + break; ++ case V4L2_CID_MPEG_VIDEO_VP9_FRAME_DECODE_PARAMS: ++ *type = V4L2_CTRL_TYPE_VP9_FRAME_DECODE_PARAMS; ++ break; ++ case V4L2_CID_MPEG_VIDEO_VP9_FRAME_CONTEXT(0): ++ case V4L2_CID_MPEG_VIDEO_VP9_FRAME_CONTEXT(1): ++ case V4L2_CID_MPEG_VIDEO_VP9_FRAME_CONTEXT(2): ++ case V4L2_CID_MPEG_VIDEO_VP9_FRAME_CONTEXT(3): ++ *type = V4L2_CTRL_TYPE_VP9_FRAME_CONTEXT; ++ break; + case V4L2_CID_MPEG_VIDEO_HEVC_SPS: + *type = V4L2_CTRL_TYPE_HEVC_SPS; + break; +@@ -1721,6 +1735,219 @@ static void std_log(const struct v4l2_ctrl *ctrl) + 0; \ + }) + ++static int ++validate_vp9_lf_params(struct v4l2_vp9_loop_filter *lf) ++{ ++ unsigned int i, j, k; ++ ++ if (lf->flags & ++ ~(V4L2_VP9_LOOP_FILTER_FLAG_DELTA_ENABLED | ++ V4L2_VP9_LOOP_FILTER_FLAG_DELTA_UPDATE)) ++ return -EINVAL; ++ ++ /* ++ * V4L2_VP9_LOOP_FILTER_FLAG_DELTA_ENABLED implies ++ * V4L2_VP9_LOOP_FILTER_FLAG_DELTA_UPDATE. ++ */ ++ if (lf->flags & V4L2_VP9_LOOP_FILTER_FLAG_DELTA_UPDATE && ++ !(lf->flags & V4L2_VP9_LOOP_FILTER_FLAG_DELTA_ENABLED)) ++ return -EINVAL; ++ ++ /* That all values are in the accepted range. */ ++ if (lf->level > GENMASK(5, 0)) ++ return -EINVAL; ++ ++ if (lf->sharpness > GENMASK(2, 0)) ++ return -EINVAL; ++ ++ for (i = 0; i < ARRAY_SIZE(lf->ref_deltas); i++) { ++ if (lf->ref_deltas[i] < -63 || lf->ref_deltas[i] > 63) ++ return -EINVAL; ++ } ++ ++ for (i = 0; i < ARRAY_SIZE(lf->mode_deltas); i++) { ++ if (lf->mode_deltas[i] < -63 || lf->mode_deltas[i] > 63) ++ return -EINVAL; ++ } ++ ++ for (i = 0; i < ARRAY_SIZE(lf->level_lookup); i++) { ++ for (j = 0; j < ARRAY_SIZE(lf->level_lookup[0]); j++) { ++ for (k = 0; k < ARRAY_SIZE(lf->level_lookup[0][0]); k++) { ++ if (lf->level_lookup[i][j][k] > 63) ++ return -EINVAL; ++ } ++ } ++ } ++ ++ return 0; ++} ++ ++static int ++validate_vp9_quant_params(struct v4l2_vp9_quantization *quant) ++{ ++ if (quant->delta_q_y_dc < -15 || quant->delta_q_y_dc > 15 || ++ quant->delta_q_uv_dc < -15 || quant->delta_q_uv_dc > 15 || ++ quant->delta_q_uv_ac < -15 || quant->delta_q_uv_ac > 15) ++ return -EINVAL; ++ ++ memset(quant->padding, 0, sizeof(quant->padding)); ++ return 0; ++} ++ ++static int ++validate_vp9_seg_params(struct v4l2_vp9_segmentation *seg) ++{ ++ unsigned int i, j; ++ ++ if (seg->flags & ++ ~(V4L2_VP9_SEGMENTATION_FLAG_ENABLED | ++ V4L2_VP9_SEGMENTATION_FLAG_UPDATE_MAP | ++ V4L2_VP9_SEGMENTATION_FLAG_TEMPORAL_UPDATE | ++ V4L2_VP9_SEGMENTATION_FLAG_UPDATE_DATA | ++ V4L2_VP9_SEGMENTATION_FLAG_ABS_OR_DELTA_UPDATE)) ++ return -EINVAL; ++ ++ /* ++ * V4L2_VP9_SEGMENTATION_FLAG_UPDATE_MAP and ++ * V4L2_VP9_SEGMENTATION_FLAG_UPDATE_DATA imply ++ * V4L2_VP9_SEGMENTATION_FLAG_ENABLED. ++ */ ++ if ((seg->flags & ++ (V4L2_VP9_SEGMENTATION_FLAG_UPDATE_MAP | ++ V4L2_VP9_SEGMENTATION_FLAG_UPDATE_DATA)) && ++ !(seg->flags & V4L2_VP9_SEGMENTATION_FLAG_ENABLED)) ++ return -EINVAL; ++ ++ /* ++ * V4L2_VP9_SEGMENTATION_FLAG_TEMPORAL_UPDATE implies ++ * V4L2_VP9_SEGMENTATION_FLAG_UPDATE_MAP. ++ */ ++ if (seg->flags & V4L2_VP9_SEGMENTATION_FLAG_TEMPORAL_UPDATE && ++ !(seg->flags & V4L2_VP9_SEGMENTATION_FLAG_UPDATE_MAP)) ++ return -EINVAL; ++ ++ /* ++ * V4L2_VP9_SEGMENTATION_FLAG_ABS_OR_DELTA_UPDATE implies ++ * V4L2_VP9_SEGMENTATION_FLAG_UPDATE_DATA. ++ */ ++ if (seg->flags & V4L2_VP9_SEGMENTATION_FLAG_ABS_OR_DELTA_UPDATE && ++ !(seg->flags & V4L2_VP9_SEGMENTATION_FLAG_UPDATE_DATA)) ++ return -EINVAL; ++ ++ for (i = 0; i < ARRAY_SIZE(seg->feature_enabled); i++) { ++ if (seg->feature_enabled[i] & ++ ~(V4L2_VP9_SEGMENT_FEATURE_QP_DELTA | ++ V4L2_VP9_SEGMENT_FEATURE_LF | ++ V4L2_VP9_SEGMENT_FEATURE_REF_FRAME | ++ V4L2_VP9_SEGMENT_FEATURE_SKIP)) ++ return -EINVAL; ++ } ++ ++ for (i = 0; i < ARRAY_SIZE(seg->feature_data); i++) { ++ const int range[] = {255, 63, 3, 0}; ++ ++ for (j = 0; j < ARRAY_SIZE(seg->feature_data[j]); j++) { ++ if (seg->feature_data[i][j] < -range[j] || ++ seg->feature_data[i][j] > range[j]) ++ return -EINVAL; ++ } ++ } ++ ++ memset(seg->padding, 0, sizeof(seg->padding)); ++ return 0; ++} ++ ++static int ++validate_vp9_frame_decode_params(struct v4l2_ctrl_vp9_frame_decode_params *dec_params) ++{ ++ int ret; ++ ++ /* Make sure we're not passed invalid flags. */ ++ if (dec_params->flags & ++ ~(V4L2_VP9_FRAME_FLAG_KEY_FRAME | ++ V4L2_VP9_FRAME_FLAG_SHOW_FRAME | ++ V4L2_VP9_FRAME_FLAG_ERROR_RESILIENT | ++ V4L2_VP9_FRAME_FLAG_INTRA_ONLY | ++ V4L2_VP9_FRAME_FLAG_ALLOW_HIGH_PREC_MV | ++ V4L2_VP9_FRAME_FLAG_REFRESH_FRAME_CTX | ++ V4L2_VP9_FRAME_FLAG_PARALLEL_DEC_MODE | ++ V4L2_VP9_FRAME_FLAG_X_SUBSAMPLING | ++ V4L2_VP9_FRAME_FLAG_Y_SUBSAMPLING | ++ V4L2_VP9_FRAME_FLAG_COLOR_RANGE_FULL_SWING)) ++ return -EINVAL; ++ ++ /* ++ * The refresh context and error resilient flags are mutually exclusive. ++ * Same goes for parallel decoding and error resilient modes. ++ */ ++ if (dec_params->flags & V4L2_VP9_FRAME_FLAG_ERROR_RESILIENT && ++ dec_params->flags & ++ (V4L2_VP9_FRAME_FLAG_REFRESH_FRAME_CTX | ++ V4L2_VP9_FRAME_FLAG_PARALLEL_DEC_MODE)) ++ return -EINVAL; ++ ++ if (dec_params->profile > V4L2_VP9_PROFILE_MAX) ++ return -EINVAL; ++ ++ if (dec_params->reset_frame_context > V4L2_VP9_RESET_FRAME_CTX_ALL) ++ return -EINVAL; ++ ++ if (dec_params->frame_context_idx >= V4L2_VP9_NUM_FRAME_CTX) ++ return -EINVAL; ++ ++ /* ++ * Profiles 0 and 1 only support 8-bit depth, profiles 2 and 3 only 10 ++ * and 12 bit depths. ++ */ ++ if ((dec_params->profile < 2 && dec_params->bit_depth != 8) || ++ (dec_params->profile >= 2 && ++ (dec_params->bit_depth != 10 && dec_params->bit_depth != 12))) ++ return -EINVAL; ++ ++ /* Profile 0 and 2 only accept YUV 4:2:0. */ ++ if ((dec_params->profile == 0 || dec_params->profile == 2) && ++ (!(dec_params->flags & V4L2_VP9_FRAME_FLAG_X_SUBSAMPLING) || ++ !(dec_params->flags & V4L2_VP9_FRAME_FLAG_Y_SUBSAMPLING))) ++ return -EINVAL; ++ ++ /* Profile 1 and 3 only accept YUV 4:2:2, 4:4:0 and 4:4:4. */ ++ if ((dec_params->profile == 1 || dec_params->profile == 3) && ++ ((dec_params->flags & V4L2_VP9_FRAME_FLAG_X_SUBSAMPLING) && ++ (dec_params->flags & V4L2_VP9_FRAME_FLAG_Y_SUBSAMPLING))) ++ return -EINVAL; ++ ++ if (dec_params->interpolation_filter > V4L2_VP9_INTERP_FILTER_SWITCHABLE) ++ return -EINVAL; ++ ++ /* ++ * According to the spec, tile_cols_log2 shall be less than or equal ++ * to 6. ++ */ ++ if (dec_params->tile_cols_log2 > 6) ++ return -EINVAL; ++ ++ if (dec_params->tx_mode > V4L2_VP9_TX_MODE_SELECT) ++ return -EINVAL; ++ ++ if (dec_params->reference_mode > V4L2_VP9_REF_MODE_SELECT) ++ return -EINVAL; ++ ++ ret = validate_vp9_lf_params(&dec_params->lf); ++ if (ret) ++ return ret; ++ ++ ret = validate_vp9_quant_params(&dec_params->quant); ++ if (ret) ++ return ret; ++ ++ ret = validate_vp9_seg_params(&dec_params->seg); ++ if (ret) ++ return ret; ++ ++ memset(dec_params->padding, 0, sizeof(dec_params->padding)); ++ return 0; ++} ++ + /* Validate a new control */ + + #define zero_padding(s) \ +@@ -1838,6 +2065,12 @@ static int std_validate_compound(const struct v4l2_ctrl *ctrl, u32 idx, + zero_padding(p_vp8_frame_header->coder_state); + break; + ++ case V4L2_CTRL_TYPE_VP9_FRAME_DECODE_PARAMS: ++ return validate_vp9_frame_decode_params(p); ++ ++ case V4L2_CTRL_TYPE_VP9_FRAME_CONTEXT: ++ break; ++ + case V4L2_CTRL_TYPE_HEVC_SPS: + p_hevc_sps = p; + +@@ -2584,6 +2817,12 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl, + case V4L2_CTRL_TYPE_VP8_FRAME_HEADER: + elem_size = sizeof(struct v4l2_ctrl_vp8_frame_header); + break; ++ case V4L2_CTRL_TYPE_VP9_FRAME_CONTEXT: ++ elem_size = sizeof(struct v4l2_ctrl_vp9_frame_ctx); ++ break; ++ case V4L2_CTRL_TYPE_VP9_FRAME_DECODE_PARAMS: ++ elem_size = sizeof(struct v4l2_ctrl_vp9_frame_decode_params); ++ break; + case V4L2_CTRL_TYPE_HEVC_SPS: + elem_size = sizeof(struct v4l2_ctrl_hevc_sps); + break; +diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c +index 53de49087938..22eab942c8d4 100644 +--- a/drivers/media/v4l2-core/v4l2-ioctl.c ++++ b/drivers/media/v4l2-core/v4l2-ioctl.c +@@ -1431,6 +1431,7 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt) + case V4L2_PIX_FMT_VP8: descr = "VP8"; break; + case V4L2_PIX_FMT_VP8_FRAME: descr = "VP8 Frame"; break; + case V4L2_PIX_FMT_VP9: descr = "VP9"; break; ++ case V4L2_PIX_FMT_VP9_FRAME: descr = "VP9 Frame"; break; + case V4L2_PIX_FMT_HEVC: descr = "HEVC"; break; /* aka H.265 */ + case V4L2_PIX_FMT_HEVC_SLICE: descr = "HEVC Parsed Slice Data"; break; + case V4L2_PIX_FMT_FWHT: descr = "FWHT"; break; /* used in vicodec */ +diff --git a/include/media/v4l2-ctrls.h b/include/media/v4l2-ctrls.h +index cb25f345e9ad..c427acc964b9 100644 +--- a/include/media/v4l2-ctrls.h ++++ b/include/media/v4l2-ctrls.h +@@ -21,6 +21,7 @@ + #include + #include + #include ++#include + #include + + /* forward references */ +diff --git a/include/media/vp9-ctrls.h b/include/media/vp9-ctrls.h +new file mode 100644 +index 000000000000..0cdea8a18b72 +--- /dev/null ++++ b/include/media/vp9-ctrls.h +@@ -0,0 +1,485 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * These are the VP9 state controls for use with stateless VP9 ++ * codec drivers. ++ * ++ * It turns out that these structs are not stable yet and will undergo ++ * more changes. So keep them private until they are stable and ready to ++ * become part of the official public API. ++ */ ++ ++#ifndef _VP9_CTRLS_H_ ++#define _VP9_CTRLS_H_ ++ ++#include ++ ++#define V4L2_PIX_FMT_VP9_FRAME v4l2_fourcc('V', 'P', '9', 'F') ++ ++#define V4L2_CID_MPEG_VIDEO_VP9_FRAME_CONTEXT(i) (V4L2_CID_MPEG_BASE + 4000 + (i)) ++#define V4L2_CID_MPEG_VIDEO_VP9_FRAME_DECODE_PARAMS (V4L2_CID_MPEG_BASE + 4004) ++#define V4L2_CTRL_TYPE_VP9_FRAME_CONTEXT 0x400 ++#define V4L2_CTRL_TYPE_VP9_FRAME_DECODE_PARAMS 0x404 ++ ++/** ++ * enum v4l2_vp9_loop_filter_flags - VP9 loop filter flags ++ * ++ * @V4L2_VP9_LOOP_FILTER_FLAG_DELTA_ENABLED: the filter level depends on ++ * the mode and reference frame used ++ * to predict a block ++ * @V4L2_VP9_LOOP_FILTER_FLAG_DELTA_UPDATE: the bitstream contains additional ++ * syntax elements that specify which ++ * mode and reference frame deltas ++ * are to be updated ++ * ++ * Those are the flags you should pass to &v4l2_vp9_loop_filter.flags. See ++ * section '7.2.8 Loop filter semantics' of the VP9 specification for more ++ * details. ++ */ ++enum v4l2_vp9_loop_filter_flags { ++ V4L2_VP9_LOOP_FILTER_FLAG_DELTA_ENABLED = 1 << 0, ++ V4L2_VP9_LOOP_FILTER_FLAG_DELTA_UPDATE = 1 << 1, ++}; ++ ++/** ++ * struct v4l2_vp9_loop_filter - VP9 loop filter parameters ++ * ++ * @flags: combination of V4L2_VP9_LOOP_FILTER_FLAG_* flags ++ * @level: indicates the loop filter strength ++ * @sharpness: indicates the sharpness level ++ * @ref_deltas: contains the adjustment needed for the filter level based on ++ * the chosen reference frame ++ * @mode_deltas: contains the adjustment needed for the filter level based on ++ * the chosen mode ++ * @level_lookup: level lookup table ++ * ++ * This structure contains all loop filter related parameters. See sections ++ * '7.2.8 Loop filter semantics' and '8.8.1 Loop filter frame init process' ++ * of the VP9 specification for more details. ++ */ ++struct v4l2_vp9_loop_filter { ++ __u8 flags; ++ __u8 level; ++ __u8 sharpness; ++ __s8 ref_deltas[4]; ++ __s8 mode_deltas[2]; ++ __u8 level_lookup[8][4][2]; ++}; ++ ++/** ++ * struct v4l2_vp9_quantization - VP9 quantization parameters ++ * ++ * @base_q_idx: indicates the base frame qindex ++ * @delta_q_y_dc: indicates the Y DC quantizer relative to base_q_idx ++ * @delta_q_uv_dc: indicates the UV DC quantizer relative to base_q_idx ++ * @delta_q_uv_ac indicates the UV AC quantizer relative to base_q_idx ++ * @padding: padding bytes to align things on 64 bits. Must be set to 0 ++ * ++ * Encodes the quantization parameters. See section '7.2.9 Quantization params ++ * syntax' of the VP9 specification for more details. ++ */ ++struct v4l2_vp9_quantization { ++ __u8 base_q_idx; ++ __s8 delta_q_y_dc; ++ __s8 delta_q_uv_dc; ++ __s8 delta_q_uv_ac; ++ __u8 padding[4]; ++}; ++ ++/** ++ * enum v4l2_vp9_segmentation_flags - VP9 segmentation flags ++ * ++ * @V4L2_VP9_SEGMENTATION_FLAG_ENABLED: indicates that this frame makes use of ++ * the segmentation tool ++ * @V4L2_VP9_SEGMENTATION_FLAG_UPDATE_MAP: indicates that the segmentation map ++ * should be updated during the ++ * decoding of this frame ++ * @V4L2_VP9_SEGMENTATION_FLAG_TEMPORAL_UPDATE: indicates that the updates to ++ * the segmentation map are coded ++ * relative to the existing ++ * segmentation map ++ * @V4L2_VP9_SEGMENTATION_FLAG_UPDATE_DATA: indicates that new parameters are ++ * about to be specified for each ++ * segment ++ * @V4L2_VP9_SEGMENTATION_FLAG_ABS_OR_DELTA_UPDATE: indicates that the ++ * segmentation parameters ++ * represent the actual values ++ * to be used ++ * ++ * Those are the flags you should pass to &v4l2_vp9_segmentation.flags. See ++ * section '7.2.10 Segmentation params syntax' of the VP9 specification for ++ * more details. ++ */ ++enum v4l2_vp9_segmentation_flags { ++ V4L2_VP9_SEGMENTATION_FLAG_ENABLED = 1 << 0, ++ V4L2_VP9_SEGMENTATION_FLAG_UPDATE_MAP = 1 << 1, ++ V4L2_VP9_SEGMENTATION_FLAG_TEMPORAL_UPDATE = 1 << 2, ++ V4L2_VP9_SEGMENTATION_FLAG_UPDATE_DATA = 1 << 3, ++ V4L2_VP9_SEGMENTATION_FLAG_ABS_OR_DELTA_UPDATE = 1 << 4, ++}; ++ ++#define V4L2_VP9_SEGMENT_FEATURE_ENABLED(id) (1 << (id)) ++#define V4L2_VP9_SEGMENT_FEATURE_ENABLED_MASK 0xf ++ ++/** ++ * enum v4l2_vp9_segment_feature - VP9 segment feature IDs ++ * ++ * @V4L2_VP9_SEGMENT_FEATURE_QP_DELTA: QP delta segment feature ++ * @V4L2_VP9_SEGMENT_FEATURE_LF: loop filter segment feature ++ * @V4L2_VP9_SEGMENT_FEATURE_REF_FRAME: reference frame segment feature ++ * @V4L2_VP9_SEGMENT_FEATURE_SKIP: skip segment feature ++ * @V4L2_VP9_SEGMENT_FEATURE_CNT: number of segment features ++ * ++ * Segment feature IDs. See section '7.2.10 Segmentation params syntax' of the ++ * VP9 specification for more details. ++ */ ++enum v4l2_vp9_segment_feature { ++ V4L2_VP9_SEGMENT_FEATURE_QP_DELTA, ++ V4L2_VP9_SEGMENT_FEATURE_LF, ++ V4L2_VP9_SEGMENT_FEATURE_REF_FRAME, ++ V4L2_VP9_SEGMENT_FEATURE_SKIP, ++ V4L2_VP9_SEGMENT_FEATURE_CNT, ++}; ++ ++/** ++ * struct v4l2_vp9_segmentation - VP9 segmentation parameters ++ * ++ * @flags: combination of V4L2_VP9_SEGMENTATION_FLAG_* flags ++ * @tree_probs: specifies the probability values to be used when ++ * decoding a Segment-ID. See '5.15. Segmentation map' ++ * section of the VP9 specification for more details. ++ * @pred_prob: specifies the probability values to be used when decoding a ++ * Predicted-Segment-ID. See '6.4.14. Get segment id syntax' ++ * section of :ref:`vp9` for more details.. ++ * @padding: padding used to make things aligned on 64 bits. Shall be zero ++ * filled ++ * @feature_enabled: bitmask defining which features are enabled in each ++ * segment ++ * @feature_data: data attached to each feature. Data entry is only valid if ++ * the feature is enabled ++ * ++ * Encodes the quantization parameters. See section '7.2.10 Segmentation ++ * params syntax' of the VP9 specification for more details. ++ */ ++struct v4l2_vp9_segmentation { ++ __u8 flags; ++ __u8 tree_probs[7]; ++ __u8 pred_probs[3]; ++ __u8 padding[5]; ++ __u8 feature_enabled[8]; ++ __s16 feature_data[8][4]; ++}; ++ ++/** ++ * enum v4l2_vp9_intra_prediction_mode - VP9 Intra prediction modes ++ * ++ * @V4L2_VP9_INTRA_PRED_DC: DC intra prediction ++ * @V4L2_VP9_INTRA_PRED_MODE_V: vertical intra prediction ++ * @V4L2_VP9_INTRA_PRED_MODE_H: horizontal intra prediction ++ * @V4L2_VP9_INTRA_PRED_MODE_D45: D45 intra prediction ++ * @V4L2_VP9_INTRA_PRED_MODE_D135: D135 intra prediction ++ * @V4L2_VP9_INTRA_PRED_MODE_D117: D117 intra prediction ++ * @V4L2_VP9_INTRA_PRED_MODE_D153: D153 intra prediction ++ * @V4L2_VP9_INTRA_PRED_MODE_D207: D207 intra prediction ++ * @V4L2_VP9_INTRA_PRED_MODE_D63: D63 intra prediction ++ * @V4L2_VP9_INTRA_PRED_MODE_TM: True Motion intra prediction ++ * ++ * See section '7.4.5 Intra frame mode info semantics' for more details. ++ */ ++enum v4l2_vp9_intra_prediction_mode { ++ V4L2_VP9_INTRA_PRED_MODE_DC, ++ V4L2_VP9_INTRA_PRED_MODE_V, ++ V4L2_VP9_INTRA_PRED_MODE_H, ++ V4L2_VP9_INTRA_PRED_MODE_D45, ++ V4L2_VP9_INTRA_PRED_MODE_D135, ++ V4L2_VP9_INTRA_PRED_MODE_D117, ++ V4L2_VP9_INTRA_PRED_MODE_D153, ++ V4L2_VP9_INTRA_PRED_MODE_D207, ++ V4L2_VP9_INTRA_PRED_MODE_D63, ++ V4L2_VP9_INTRA_PRED_MODE_TM, ++}; ++ ++/** ++ * struct v4l2_vp9_mv_probabilities - VP9 Motion vector probabilities ++ * @joint: motion vector joint probabilities ++ * @sign: motion vector sign probabilities ++ * @class: motion vector class probabilities ++ * @class0_bit: motion vector class0 bit probabilities ++ * @bits: motion vector bits probabilities ++ * @class0_fr: motion vector class0 fractional bit probabilities ++ * @fr: motion vector fractional bit probabilities ++ * @class0_hp: motion vector class0 high precision fractional bit probabilities ++ * @hp: motion vector high precision fractional bit probabilities ++ */ ++struct v4l2_vp9_mv_probabilities { ++ __u8 joint[3]; ++ __u8 sign[2]; ++ __u8 class[2][10]; ++ __u8 class0_bit[2]; ++ __u8 bits[2][10]; ++ __u8 class0_fr[2][2][3]; ++ __u8 fr[2][3]; ++ __u8 class0_hp[2]; ++ __u8 hp[2]; ++}; ++ ++/** ++ * struct v4l2_vp9_probabilities - VP9 Probabilities ++ * ++ * @tx8: TX 8x8 probabilities ++ * @tx16: TX 16x16 probabilities ++ * @tx32: TX 32x32 probabilities ++ * @coef: coefficient probabilities ++ * @skip: skip probabilities ++ * @inter_mode: inter mode probabilities ++ * @interp_filter: interpolation filter probabilities ++ * @is_inter: is inter-block probabilities ++ * @comp_mode: compound prediction mode probabilities ++ * @single_ref: single ref probabilities ++ * @comp_ref: compound ref probabilities ++ * @y_mode: Y prediction mode probabilities ++ * @uv_mode: UV prediction mode probabilities ++ * @partition: partition probabilities ++ * @mv: motion vector probabilities ++ * ++ * Structure containing most VP9 probabilities. See the VP9 specification ++ * for more details. ++ */ ++struct v4l2_vp9_probabilities { ++ __u8 tx8[2][1]; ++ __u8 tx16[2][2]; ++ __u8 tx32[2][3]; ++ __u8 coef[4][2][2][6][6][3]; ++ __u8 skip[3]; ++ __u8 inter_mode[7][3]; ++ __u8 interp_filter[4][2]; ++ __u8 is_inter[4]; ++ __u8 comp_mode[5]; ++ __u8 single_ref[5][2]; ++ __u8 comp_ref[5]; ++ __u8 y_mode[4][9]; ++ __u8 uv_mode[10][9]; ++ __u8 partition[16][3]; ++ ++ struct v4l2_vp9_mv_probabilities mv; ++}; ++ ++/** ++ * enum v4l2_vp9_reset_frame_context - Valid values for ++ * &v4l2_ctrl_vp9_frame_decode_params->reset_frame_context ++ * ++ * @V4L2_VP9_RESET_FRAME_CTX_NONE: don't reset any frame context ++ * @V4L2_VP9_RESET_FRAME_CTX_SPEC: reset the frame context pointed by ++ * &v4l2_ctrl_vp9_frame_decode_params.frame_context_idx ++ * @V4L2_VP9_RESET_FRAME_CTX_ALL: reset all frame contexts ++ * ++ * See section '7.2 Uncompressed header semantics' of the VP9 specification ++ * for more details. ++ */ ++enum v4l2_vp9_reset_frame_context { ++ V4L2_VP9_RESET_FRAME_CTX_NONE, ++ V4L2_VP9_RESET_FRAME_CTX_SPEC, ++ V4L2_VP9_RESET_FRAME_CTX_ALL, ++}; ++ ++/** ++ * enum v4l2_vp9_interpolation_filter - VP9 interpolation filter types ++ * ++ * @V4L2_VP9_INTERP_FILTER_8TAP: height tap filter ++ * @V4L2_VP9_INTERP_FILTER_8TAP_SMOOTH: height tap smooth filter ++ * @V4L2_VP9_INTERP_FILTER_8TAP_SHARP: height tap sharp filter ++ * @V4L2_VP9_INTERP_FILTER_BILINEAR: bilinear filter ++ * @V4L2_VP9_INTERP_FILTER_SWITCHABLE: filter selection is signaled at the ++ * block level ++ * ++ * See section '7.2.7 Interpolation filter semantics' of the VP9 specification ++ * for more details. ++ */ ++enum v4l2_vp9_interpolation_filter { ++ V4L2_VP9_INTERP_FILTER_8TAP, ++ V4L2_VP9_INTERP_FILTER_8TAP_SMOOTH, ++ V4L2_VP9_INTERP_FILTER_8TAP_SHARP, ++ V4L2_VP9_INTERP_FILTER_BILINEAR, ++ V4L2_VP9_INTERP_FILTER_SWITCHABLE, ++}; ++ ++/** ++ * enum v4l2_vp9_reference_mode - VP9 reference modes ++ * ++ * @V4L2_VP9_REF_MODE_SINGLE: indicates that all the inter blocks use only a ++ * single reference frame to generate motion ++ * compensated prediction ++ * @V4L2_VP9_REF_MODE_COMPOUND: requires all the inter blocks to use compound ++ * mode. Single reference frame prediction is not ++ * allowed ++ * @V4L2_VP9_REF_MODE_SELECT: allows each individual inter block to select ++ * between single and compound prediction modes ++ * ++ * See section '7.3.6 Frame reference mode semantics' of the VP9 specification ++ * for more details. ++ */ ++enum v4l2_vp9_reference_mode { ++ V4L2_VP9_REF_MODE_SINGLE, ++ V4L2_VP9_REF_MODE_COMPOUND, ++ V4L2_VP9_REF_MODE_SELECT, ++}; ++ ++/** ++ * enum v4l2_vp9_tx_mode - VP9 TX modes ++ * ++ * @V4L2_VP9_TX_MODE_ONLY_4X4: transform size is 4x4 ++ * @V4L2_VP9_TX_MODE_ALLOW_8X8: transform size can be up to 8x8 ++ * @V4L2_VP9_TX_MODE_ALLOW_16X16: transform size can be up to 16x16 ++ * @V4L2_VP9_TX_MODE_ALLOW_32X32: transform size can be up to 32x32 ++ * @V4L2_VP9_TX_MODE_SELECT: bitstream contains transform size for each block ++ * ++ * See section '7.3.1 Tx mode semantics' of the VP9 specification for more ++ * details. ++ */ ++enum v4l2_vp9_tx_mode { ++ V4L2_VP9_TX_MODE_ONLY_4X4, ++ V4L2_VP9_TX_MODE_ALLOW_8X8, ++ V4L2_VP9_TX_MODE_ALLOW_16X16, ++ V4L2_VP9_TX_MODE_ALLOW_32X32, ++ V4L2_VP9_TX_MODE_SELECT, ++}; ++ ++/** ++ * enum v4l2_vp9_ref_id - VP9 Reference frame IDs ++ * ++ * @V4L2_REF_ID_LAST: last reference frame ++ * @V4L2_REF_ID_GOLDEN: golden reference frame ++ * @V4L2_REF_ID_ALTREF: alternative reference frame ++ * @V4L2_REF_ID_CNT: number of reference frames ++ * ++ * See section '7.4.12 Ref frames semantics' of the VP9 specification for more ++ * details. ++ */ ++enum v4l2_vp9_ref_id { ++ V4L2_REF_ID_LAST, ++ V4L2_REF_ID_GOLDEN, ++ V4L2_REF_ID_ALTREF, ++ V4L2_REF_ID_CNT, ++}; ++ ++/** ++ * enum v4l2_vp9_frame_flags - VP9 frame flags ++ * @V4L2_VP9_FRAME_FLAG_KEY_FRAME: the frame is a key frame ++ * @V4L2_VP9_FRAME_FLAG_SHOW_FRAME: the frame should be displayed ++ * @V4L2_VP9_FRAME_FLAG_ERROR_RESILIENT: the decoding should be error resilient ++ * @V4L2_VP9_FRAME_FLAG_INTRA_ONLY: the frame does not reference other frames ++ * @V4L2_VP9_FRAME_FLAG_ALLOW_HIGH_PREC_MV: the frame might can high precision ++ * motion vectors ++ * @V4L2_VP9_FRAME_FLAG_REFRESH_FRAME_CTX: frame context should be updated ++ * after decoding ++ * @V4L2_VP9_FRAME_FLAG_PARALLEL_DEC_MODE: parallel decoding is used ++ * @V4L2_VP9_FRAME_FLAG_X_SUBSAMPLING: vertical subsampling is enabled ++ * @V4L2_VP9_FRAME_FLAG_Y_SUBSAMPLING: horizontal subsampling is enabled ++ * @V4L2_VP9_FRAME_FLAG_COLOR_RANGE_FULL_SWING: full UV range is used ++ * ++ * Check the VP9 specification for more details. ++ */ ++enum v4l2_vp9_frame_flags { ++ V4L2_VP9_FRAME_FLAG_KEY_FRAME = 1 << 0, ++ V4L2_VP9_FRAME_FLAG_SHOW_FRAME = 1 << 1, ++ V4L2_VP9_FRAME_FLAG_ERROR_RESILIENT = 1 << 2, ++ V4L2_VP9_FRAME_FLAG_INTRA_ONLY = 1 << 3, ++ V4L2_VP9_FRAME_FLAG_ALLOW_HIGH_PREC_MV = 1 << 4, ++ V4L2_VP9_FRAME_FLAG_REFRESH_FRAME_CTX = 1 << 5, ++ V4L2_VP9_FRAME_FLAG_PARALLEL_DEC_MODE = 1 << 6, ++ V4L2_VP9_FRAME_FLAG_X_SUBSAMPLING = 1 << 7, ++ V4L2_VP9_FRAME_FLAG_Y_SUBSAMPLING = 1 << 8, ++ V4L2_VP9_FRAME_FLAG_COLOR_RANGE_FULL_SWING = 1 << 9, ++}; ++ ++#define V4L2_VP9_PROFILE_MAX 3 ++ ++/** ++ * struct v4l2_ctrl_vp9_frame_decode_params - VP9 frame decoding control ++ * ++ * @flags: combination of V4L2_VP9_FRAME_FLAG_* flags ++ * @compressed_header_size: compressed header size in bytes ++ * @uncompressed_header_size: uncompressed header size in bytes ++ * @profile: VP9 profile. Can be 0, 1, 2 or 3 ++ * @reset_frame_context: specifies whether the frame context should be reset ++ * to default values. See &v4l2_vp9_reset_frame_context ++ * for more details ++ * @frame_context_idx: frame context that should be used/updated ++ * @bit_depth: bits per components. Can be 8, 10 or 12. Note that not all ++ * profiles support 10 and/or 12 bits depths ++ * @interpolation_filter: specifies the filter selection used for performing ++ * inter prediction. See &v4l2_vp9_interpolation_filter ++ * for more details ++ * @tile_cols_log2: specifies the base 2 logarithm of the width of each tile ++ * (where the width is measured in units of 8x8 blocks). ++ * Shall be less than or equal to 6 ++ * @tile_rows_log2: specifies the base 2 logarithm of the height of each tile ++ * (where the height is measured in units of 8x8 blocks) ++ * @tx_mode: specifies the TX mode. See &v4l2_vp9_tx_mode for more details ++ * @reference_mode: specifies the type of inter prediction to be used. See ++ * &v4l2_vp9_reference_mode for more details ++ * @padding: needed to make this struct 64 bit aligned. Shall be filled with ++ * zeros ++ * @frame_width_minus_1: add 1 to it and you'll get the frame width expressed ++ * in pixels ++ * @frame_height_minus_1: add 1 to it and you'll get the frame height expressed ++ * in pixels ++ * @frame_width_minus_1: add 1 to it and you'll get the expected render width ++ * expressed in pixels. This is not used during the ++ * decoding process but might be used by HW scalers to ++ * prepare a frame that's ready for scanout ++ * @frame_height_minus_1: add 1 to it and you'll get the expected render height ++ * expressed in pixels. This is not used during the ++ * decoding process but might be used by HW scalers to ++ * prepare a frame that's ready for scanout ++ * @refs: array of reference frames. See &v4l2_vp9_ref_id for more details ++ * @lf: loop filter parameters. See &v4l2_vp9_loop_filter for more details ++ * @quant: quantization parameters. See &v4l2_vp9_quantization for more details ++ * @seg: segmentation parameters. See &v4l2_vp9_segmentation for more details ++ * @probs: probabilities. See &v4l2_vp9_probabilities for more details ++ */ ++struct v4l2_ctrl_vp9_frame_decode_params { ++ __u32 flags; ++ __u16 compressed_header_size; ++ __u16 uncompressed_header_size; ++ __u8 profile; ++ __u8 reset_frame_context; ++ __u8 frame_context_idx; ++ __u8 bit_depth; ++ __u8 interpolation_filter; ++ __u8 tile_cols_log2; ++ __u8 tile_rows_log2; ++ __u8 tx_mode; ++ __u8 reference_mode; ++ __u8 padding[6]; ++ __u16 frame_width_minus_1; ++ __u16 frame_height_minus_1; ++ __u16 render_width_minus_1; ++ __u16 render_height_minus_1; ++ __u64 refs[V4L2_REF_ID_CNT]; ++ struct v4l2_vp9_loop_filter lf; ++ struct v4l2_vp9_quantization quant; ++ struct v4l2_vp9_segmentation seg; ++ struct v4l2_vp9_probabilities probs; ++}; ++ ++#define V4L2_VP9_NUM_FRAME_CTX 4 ++ ++/** ++ * struct v4l2_ctrl_vp9_frame_ctx - VP9 frame context control ++ * ++ * @probs: VP9 probabilities ++ * ++ * This control is accessed in both direction. The user should initialize the ++ * 4 contexts with default values just after starting the stream. Then before ++ * decoding a frame it should query the current frame context (the one passed ++ * through &v4l2_ctrl_vp9_frame_decode_params.frame_context_idx) to initialize ++ * &v4l2_ctrl_vp9_frame_decode_params.probs. The probs are then adjusted based ++ * on the bitstream info and passed to the kernel. The codec should update ++ * the frame context after the frame has been decoded, so that next time ++ * userspace query this context it contains the updated probabilities. ++ */ ++struct v4l2_ctrl_vp9_frame_ctx { ++ struct v4l2_vp9_probabilities probs; ++}; ++ ++#endif /* _VP9_CTRLS_H_ */ + +From 3e089d23e73a5eb2b070f875845ff423a492f3ba Mon Sep 17 00:00:00 2001 +From: Boris Brezillon +Date: Mon, 18 May 2020 14:40:11 -0300 +Subject: [PATCH] media: rkvdec: Add the VP9 backend + +The Rockchip VDEC supports VP9 profile 0 up to 4096x2304@30fps. Add +a backend for this new format. + +Signed-off-by: Boris Brezillon +Signed-off-by: Ezequiel Garcia +--- + drivers/staging/media/rkvdec/Makefile | 2 +- + drivers/staging/media/rkvdec/rkvdec-vp9.c | 1577 +++++++++++++++++++++ + drivers/staging/media/rkvdec/rkvdec.c | 54 + + drivers/staging/media/rkvdec/rkvdec.h | 6 + + 4 files changed, 1638 insertions(+), 1 deletion(-) + create mode 100644 drivers/staging/media/rkvdec/rkvdec-vp9.c + +diff --git a/drivers/staging/media/rkvdec/Makefile b/drivers/staging/media/rkvdec/Makefile +index c08fed0a39f9..cb86b429cfaa 100644 +--- a/drivers/staging/media/rkvdec/Makefile ++++ b/drivers/staging/media/rkvdec/Makefile +@@ -1,3 +1,3 @@ + obj-$(CONFIG_VIDEO_ROCKCHIP_VDEC) += rockchip-vdec.o + +-rockchip-vdec-y += rkvdec.o rkvdec-h264.o ++rockchip-vdec-y += rkvdec.o rkvdec-h264.o rkvdec-vp9.o +diff --git a/drivers/staging/media/rkvdec/rkvdec-vp9.c b/drivers/staging/media/rkvdec/rkvdec-vp9.c +new file mode 100644 +index 000000000000..37d0ea4e3570 +--- /dev/null ++++ b/drivers/staging/media/rkvdec/rkvdec-vp9.c +@@ -0,0 +1,1577 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Rockchip Video Decoder VP9 backend ++ * ++ * Copyright (C) 2019 Collabora, Ltd. ++ * Boris Brezillon ++ * ++ * Copyright (C) 2016 Rockchip Electronics Co., Ltd. ++ * Alpha Lin ++ */ ++ ++#include ++#include ++#include ++ ++#include "rkvdec.h" ++#include "rkvdec-regs.h" ++ ++#define RKVDEC_VP9_PROBE_SIZE 4864 ++#define RKVDEC_VP9_COUNT_SIZE 13232 ++#define RKVDEC_VP9_MAX_SEGMAP_SIZE 73728 ++ ++struct rkvdec_vp9_intra_mode_probs { ++ u8 y_mode[105]; ++ u8 uv_mode[23]; ++}; ++ ++struct rkvdec_vp9_intra_only_frame_probs { ++ u8 coef_intra[4][2][128]; ++ struct rkvdec_vp9_intra_mode_probs intra_mode[10]; ++}; ++ ++struct rkvdec_vp9_inter_frame_probs { ++ u8 y_mode[4][9]; ++ u8 comp_mode[5]; ++ u8 comp_ref[5]; ++ u8 single_ref[5][2]; ++ u8 inter_mode[7][3]; ++ u8 interp_filter[4][2]; ++ u8 padding0[11]; ++ u8 coef[2][4][2][128]; ++ u8 uv_mode_0_2[3][9]; ++ u8 padding1[5]; ++ u8 uv_mode_3_5[3][9]; ++ u8 padding2[5]; ++ u8 uv_mode_6_8[3][9]; ++ u8 padding3[5]; ++ u8 uv_mode_9[9]; ++ u8 padding4[7]; ++ u8 padding5[16]; ++ struct { ++ u8 joint[3]; ++ u8 sign[2]; ++ u8 class[2][10]; ++ u8 class0_bit[2]; ++ u8 bits[2][10]; ++ u8 class0_fr[2][2][3]; ++ u8 fr[2][3]; ++ u8 class0_hp[2]; ++ u8 hp[2]; ++ } mv; ++}; ++ ++struct rkvdec_vp9_probs { ++ u8 partition[16][3]; ++ u8 pred[3]; ++ u8 tree[7]; ++ u8 skip[3]; ++ u8 tx32[2][3]; ++ u8 tx16[2][2]; ++ u8 tx8[2][1]; ++ u8 is_inter[4]; ++ /* 128 bit alignment */ ++ u8 padding0[3]; ++ union { ++ struct rkvdec_vp9_inter_frame_probs inter; ++ struct rkvdec_vp9_intra_only_frame_probs intra_only; ++ }; ++}; ++ ++/* Data structure describing auxiliary buffer format. */ ++struct rkvdec_vp9_priv_tbl { ++ struct rkvdec_vp9_probs probs; ++ u8 segmap[2][RKVDEC_VP9_MAX_SEGMAP_SIZE]; ++}; ++ ++struct rkvdec_vp9_refs_counts { ++ u32 eob[2]; ++ u32 coeff[3]; ++}; ++ ++struct rkvdec_vp9_inter_frame_symbol_counts { ++ u32 partition[16][4]; ++ u32 skip[3][2]; ++ u32 inter[4][2]; ++ u32 tx32p[2][4]; ++ u32 tx16p[2][4]; ++ u32 tx8p[2][2]; ++ u32 y_mode[4][10]; ++ u32 uv_mode[10][10]; ++ u32 comp[5][2]; ++ u32 comp_ref[5][2]; ++ u32 single_ref[5][2][2]; ++ u32 mv_mode[7][4]; ++ u32 filter[4][3]; ++ u32 mv_joint[4]; ++ u32 sign[2][2]; ++ /* add 1 element for align */ ++ u32 classes[2][11 + 1]; ++ u32 class0[2][2]; ++ u32 bits[2][10][2]; ++ u32 class0_fp[2][2][4]; ++ u32 fp[2][4]; ++ u32 class0_hp[2][2]; ++ u32 hp[2][2]; ++ struct rkvdec_vp9_refs_counts ref_cnt[2][4][2][6][6]; ++}; ++ ++struct rkvdec_vp9_intra_frame_symbol_counts { ++ u32 partition[4][4][4]; ++ u32 skip[3][2]; ++ u32 intra[4][2]; ++ u32 tx32p[2][4]; ++ u32 tx16p[2][4]; ++ u32 tx8p[2][2]; ++ struct rkvdec_vp9_refs_counts ref_cnt[2][4][2][6][6]; ++}; ++ ++struct rkvdec_vp9_run { ++ struct rkvdec_run base; ++ const struct v4l2_ctrl_vp9_frame_decode_params *decode_params; ++}; ++ ++struct rkvdec_vp9_frame_info { ++ u32 valid : 1; ++ u32 segmapid : 1; ++ u32 frame_context_idx : 2; ++ u32 reference_mode : 2; ++ u32 tx_mode : 3; ++ u32 interpolation_filter : 3; ++ u32 flags; ++ u64 timestamp; ++ struct v4l2_vp9_segmentation seg; ++ struct v4l2_vp9_loop_filter lf; ++}; ++ ++struct rkvdec_vp9_ctx { ++ struct rkvdec_aux_buf priv_tbl; ++ struct rkvdec_aux_buf count_tbl; ++ struct v4l2_ctrl_vp9_frame_ctx frame_context; ++ struct rkvdec_vp9_frame_info cur; ++ struct rkvdec_vp9_frame_info last; ++}; ++ ++static u32 rkvdec_fastdiv(u32 dividend, u16 divisor) ++{ ++#define DIV_INV(d) (u32)(((1ULL << 32) + ((d) - 1)) / (d)) ++#define DIVS_INV(d0, d1, d2, d3, d4, d5, d6, d7, d8, d9) \ ++ DIV_INV(d0), DIV_INV(d1), DIV_INV(d2), DIV_INV(d3), \ ++ DIV_INV(d4), DIV_INV(d5), DIV_INV(d6), DIV_INV(d7), \ ++ DIV_INV(d8), DIV_INV(d9) ++ ++ static const u32 inv[] = { ++ DIV_INV(2), DIV_INV(3), DIV_INV(4), DIV_INV(5), ++ DIV_INV(6), DIV_INV(7), DIV_INV(8), DIV_INV(9), ++ DIVS_INV(10, 11, 12, 13, 14, 15, 16, 17, 18, 19), ++ DIVS_INV(20, 21, 22, 23, 24, 25, 26, 27, 28, 29), ++ DIVS_INV(30, 31, 32, 33, 34, 35, 36, 37, 38, 39), ++ DIVS_INV(40, 41, 42, 43, 44, 45, 46, 47, 48, 49), ++ DIVS_INV(50, 51, 52, 53, 54, 55, 56, 57, 58, 59), ++ DIVS_INV(60, 61, 62, 63, 64, 65, 66, 67, 68, 69), ++ DIVS_INV(70, 71, 72, 73, 74, 75, 76, 77, 78, 79), ++ DIVS_INV(80, 81, 82, 83, 84, 85, 86, 87, 88, 89), ++ DIVS_INV(90, 91, 92, 93, 94, 95, 96, 97, 98, 99), ++ DIVS_INV(100, 101, 102, 103, 104, 105, 106, 107, 108, 109), ++ DIVS_INV(110, 111, 112, 113, 114, 115, 116, 117, 118, 119), ++ DIVS_INV(120, 121, 122, 123, 124, 125, 126, 127, 128, 129), ++ DIVS_INV(130, 131, 132, 133, 134, 135, 136, 137, 138, 139), ++ DIVS_INV(140, 141, 142, 143, 144, 145, 146, 147, 148, 149), ++ DIVS_INV(150, 151, 152, 153, 154, 155, 156, 157, 158, 159), ++ DIVS_INV(160, 161, 162, 163, 164, 165, 166, 167, 168, 169), ++ DIVS_INV(170, 171, 172, 173, 174, 175, 176, 177, 178, 179), ++ DIVS_INV(180, 181, 182, 183, 184, 185, 186, 187, 188, 189), ++ DIVS_INV(190, 191, 192, 193, 194, 195, 196, 197, 198, 199), ++ DIVS_INV(200, 201, 202, 203, 204, 205, 206, 207, 208, 209), ++ DIVS_INV(210, 211, 212, 213, 214, 215, 216, 217, 218, 219), ++ DIVS_INV(220, 221, 222, 223, 224, 225, 226, 227, 228, 229), ++ DIVS_INV(230, 231, 232, 233, 234, 235, 236, 237, 238, 239), ++ DIVS_INV(240, 241, 242, 243, 244, 245, 246, 247, 248, 249), ++ DIV_INV(250), DIV_INV(251), DIV_INV(252), DIV_INV(253), ++ DIV_INV(254), DIV_INV(255), DIV_INV(256), ++ }; ++ ++ if (divisor == 0) ++ return 0; ++ else if (divisor == 1) ++ return dividend; ++ ++ if (WARN_ON(divisor - 2 >= ARRAY_SIZE(inv))) ++ return dividend; ++ ++ return ((u64)dividend * inv[divisor - 2]) >> 32; ++} ++ ++static const u8 vp9_kf_y_mode_prob[10][10][9] = { ++ { ++ /* above = dc */ ++ { 137, 30, 42, 148, 151, 207, 70, 52, 91 },/*left = dc */ ++ { 92, 45, 102, 136, 116, 180, 74, 90, 100 },/*left = v */ ++ { 73, 32, 19, 187, 222, 215, 46, 34, 100 },/*left = h */ ++ { 91, 30, 32, 116, 121, 186, 93, 86, 94 },/*left = d45 */ ++ { 72, 35, 36, 149, 68, 206, 68, 63, 105 },/*left = d135*/ ++ { 73, 31, 28, 138, 57, 124, 55, 122, 151 },/*left = d117*/ ++ { 67, 23, 21, 140, 126, 197, 40, 37, 171 },/*left = d153*/ ++ { 86, 27, 28, 128, 154, 212, 45, 43, 53 },/*left = d207*/ ++ { 74, 32, 27, 107, 86, 160, 63, 134, 102 },/*left = d63 */ ++ { 59, 67, 44, 140, 161, 202, 78, 67, 119 } /*left = tm */ ++ }, { /* above = v */ ++ { 63, 36, 126, 146, 123, 158, 60, 90, 96 },/*left = dc */ ++ { 43, 46, 168, 134, 107, 128, 69, 142, 92 },/*left = v */ ++ { 44, 29, 68, 159, 201, 177, 50, 57, 77 },/*left = h */ ++ { 58, 38, 76, 114, 97, 172, 78, 133, 92 },/*left = d45 */ ++ { 46, 41, 76, 140, 63, 184, 69, 112, 57 },/*left = d135*/ ++ { 38, 32, 85, 140, 46, 112, 54, 151, 133 },/*left = d117*/ ++ { 39, 27, 61, 131, 110, 175, 44, 75, 136 },/*left = d153*/ ++ { 52, 30, 74, 113, 130, 175, 51, 64, 58 },/*left = d207*/ ++ { 47, 35, 80, 100, 74, 143, 64, 163, 74 },/*left = d63 */ ++ { 36, 61, 116, 114, 128, 162, 80, 125, 82 } /*left = tm */ ++ }, { /* above = h */ ++ { 82, 26, 26, 171, 208, 204, 44, 32, 105 },/*left = dc */ ++ { 55, 44, 68, 166, 179, 192, 57, 57, 108 },/*left = v */ ++ { 42, 26, 11, 199, 241, 228, 23, 15, 85 },/*left = h */ ++ { 68, 42, 19, 131, 160, 199, 55, 52, 83 },/*left = d45 */ ++ { 58, 50, 25, 139, 115, 232, 39, 52, 118 },/*left = d135*/ ++ { 50, 35, 33, 153, 104, 162, 64, 59, 131 },/*left = d117*/ ++ { 44, 24, 16, 150, 177, 202, 33, 19, 156 },/*left = d153*/ ++ { 55, 27, 12, 153, 203, 218, 26, 27, 49 },/*left = d207*/ ++ { 53, 49, 21, 110, 116, 168, 59, 80, 76 },/*left = d63 */ ++ { 38, 72, 19, 168, 203, 212, 50, 50, 107 } /*left = tm */ ++ }, { /* above = d45 */ ++ { 103, 26, 36, 129, 132, 201, 83, 80, 93 },/*left = dc */ ++ { 59, 38, 83, 112, 103, 162, 98, 136, 90 },/*left = v */ ++ { 62, 30, 23, 158, 200, 207, 59, 57, 50 },/*left = h */ ++ { 67, 30, 29, 84, 86, 191, 102, 91, 59 },/*left = d45 */ ++ { 60, 32, 33, 112, 71, 220, 64, 89, 104 },/*left = d135*/ ++ { 53, 26, 34, 130, 56, 149, 84, 120, 103 },/*left = d117*/ ++ { 53, 21, 23, 133, 109, 210, 56, 77, 172 },/*left = d153*/ ++ { 77, 19, 29, 112, 142, 228, 55, 66, 36 },/*left = d207*/ ++ { 61, 29, 29, 93, 97, 165, 83, 175, 162 },/*left = d63 */ ++ { 47, 47, 43, 114, 137, 181, 100, 99, 95 } /*left = tm */ ++ }, { /* above = d135 */ ++ { 69, 23, 29, 128, 83, 199, 46, 44, 101 },/*left = dc */ ++ { 53, 40, 55, 139, 69, 183, 61, 80, 110 },/*left = v */ ++ { 40, 29, 19, 161, 180, 207, 43, 24, 91 },/*left = h */ ++ { 60, 34, 19, 105, 61, 198, 53, 64, 89 },/*left = d45 */ ++ { 52, 31, 22, 158, 40, 209, 58, 62, 89 },/*left = d135*/ ++ { 44, 31, 29, 147, 46, 158, 56, 102, 198 },/*left = d117*/ ++ { 35, 19, 12, 135, 87, 209, 41, 45, 167 },/*left = d153*/ ++ { 55, 25, 21, 118, 95, 215, 38, 39, 66 },/*left = d207*/ ++ { 51, 38, 25, 113, 58, 164, 70, 93, 97 },/*left = d63 */ ++ { 47, 54, 34, 146, 108, 203, 72, 103, 151 } /*left = tm */ ++ }, { /* above = d117 */ ++ { 64, 19, 37, 156, 66, 138, 49, 95, 133 },/*left = dc */ ++ { 46, 27, 80, 150, 55, 124, 55, 121, 135 },/*left = v */ ++ { 36, 23, 27, 165, 149, 166, 54, 64, 118 },/*left = h */ ++ { 53, 21, 36, 131, 63, 163, 60, 109, 81 },/*left = d45 */ ++ { 40, 26, 35, 154, 40, 185, 51, 97, 123 },/*left = d135*/ ++ { 35, 19, 34, 179, 19, 97, 48, 129, 124 },/*left = d117*/ ++ { 36, 20, 26, 136, 62, 164, 33, 77, 154 },/*left = d153*/ ++ { 45, 18, 32, 130, 90, 157, 40, 79, 91 },/*left = d207*/ ++ { 45, 26, 28, 129, 45, 129, 49, 147, 123 },/*left = d63 */ ++ { 38, 44, 51, 136, 74, 162, 57, 97, 121 } /*left = tm */ ++ }, { /* above = d153 */ ++ { 75, 17, 22, 136, 138, 185, 32, 34, 166 },/*left = dc */ ++ { 56, 39, 58, 133, 117, 173, 48, 53, 187 },/*left = v */ ++ { 35, 21, 12, 161, 212, 207, 20, 23, 145 },/*left = h */ ++ { 56, 29, 19, 117, 109, 181, 55, 68, 112 },/*left = d45 */ ++ { 47, 29, 17, 153, 64, 220, 59, 51, 114 },/*left = d135*/ ++ { 46, 16, 24, 136, 76, 147, 41, 64, 172 },/*left = d117*/ ++ { 34, 17, 11, 108, 152, 187, 13, 15, 209 },/*left = d153*/ ++ { 51, 24, 14, 115, 133, 209, 32, 26, 104 },/*left = d207*/ ++ { 55, 30, 18, 122, 79, 179, 44, 88, 116 },/*left = d63 */ ++ { 37, 49, 25, 129, 168, 164, 41, 54, 148 } /*left = tm */ ++ }, { /* above = d207 */ ++ { 82, 22, 32, 127, 143, 213, 39, 41, 70 },/*left = dc */ ++ { 62, 44, 61, 123, 105, 189, 48, 57, 64 },/*left = v */ ++ { 47, 25, 17, 175, 222, 220, 24, 30, 86 },/*left = h */ ++ { 68, 36, 17, 106, 102, 206, 59, 74, 74 },/*left = d45 */ ++ { 57, 39, 23, 151, 68, 216, 55, 63, 58 },/*left = d135*/ ++ { 49, 30, 35, 141, 70, 168, 82, 40, 115 },/*left = d117*/ ++ { 51, 25, 15, 136, 129, 202, 38, 35, 139 },/*left = d153*/ ++ { 68, 26, 16, 111, 141, 215, 29, 28, 28 },/*left = d207*/ ++ { 59, 39, 19, 114, 75, 180, 77, 104, 42 },/*left = d63 */ ++ { 40, 61, 26, 126, 152, 206, 61, 59, 93 } /*left = tm */ ++ }, { /* above = d63 */ ++ { 78, 23, 39, 111, 117, 170, 74, 124, 94 },/*left = dc */ ++ { 48, 34, 86, 101, 92, 146, 78, 179, 134 },/*left = v */ ++ { 47, 22, 24, 138, 187, 178, 68, 69, 59 },/*left = h */ ++ { 56, 25, 33, 105, 112, 187, 95, 177, 129 },/*left = d45 */ ++ { 48, 31, 27, 114, 63, 183, 82, 116, 56 },/*left = d135*/ ++ { 43, 28, 37, 121, 63, 123, 61, 192, 169 },/*left = d117*/ ++ { 42, 17, 24, 109, 97, 177, 56, 76, 122 },/*left = d153*/ ++ { 58, 18, 28, 105, 139, 182, 70, 92, 63 },/*left = d207*/ ++ { 46, 23, 32, 74, 86, 150, 67, 183, 88 },/*left = d63 */ ++ { 36, 38, 48, 92, 122, 165, 88, 137, 91 } /*left = tm */ ++ }, { /* above = tm */ ++ { 65, 70, 60, 155, 159, 199, 61, 60, 81 },/*left = dc */ ++ { 44, 78, 115, 132, 119, 173, 71, 112, 93 },/*left = v */ ++ { 39, 38, 21, 184, 227, 206, 42, 32, 64 },/*left = h */ ++ { 58, 47, 36, 124, 137, 193, 80, 82, 78 },/*left = d45 */ ++ { 49, 50, 35, 144, 95, 205, 63, 78, 59 },/*left = d135*/ ++ { 41, 53, 52, 148, 71, 142, 65, 128, 51 },/*left = d117*/ ++ { 40, 36, 28, 143, 143, 202, 40, 55, 137 },/*left = d153*/ ++ { 52, 34, 29, 129, 183, 227, 42, 35, 43 },/*left = d207*/ ++ { 42, 44, 44, 104, 105, 164, 64, 130, 80 },/*left = d63 */ ++ { 43, 81, 53, 140, 169, 204, 68, 84, 72 } /*left = tm */ ++ } ++}; ++ ++static const u8 kf_partition_probs[16][3] = { ++ /* 8x8 -> 4x4 */ ++ { 158, 97, 94 }, /* a/l both not split */ ++ { 93, 24, 99 }, /* a split, l not split */ ++ { 85, 119, 44 }, /* l split, a not split */ ++ { 62, 59, 67 }, /* a/l both split */ ++ /* 16x16 -> 8x8 */ ++ { 149, 53, 53 }, /* a/l both not split */ ++ { 94, 20, 48 }, /* a split, l not split */ ++ { 83, 53, 24 }, /* l split, a not split */ ++ { 52, 18, 18 }, /* a/l both split */ ++ /* 32x32 -> 16x16 */ ++ { 150, 40, 39 }, /* a/l both not split */ ++ { 78, 12, 26 }, /* a split, l not split */ ++ { 67, 33, 11 }, /* l split, a not split */ ++ { 24, 7, 5 }, /* a/l both split */ ++ /* 64x64 -> 32x32 */ ++ { 174, 35, 49 }, /* a/l both not split */ ++ { 68, 11, 27 }, /* a split, l not split */ ++ { 57, 15, 9 }, /* l split, a not split */ ++ { 12, 3, 3 }, /* a/l both split */ ++}; ++ ++static const u8 kf_uv_mode_prob[10][9] = { ++ { 144, 11, 54, 157, 195, 130, 46, 58, 108 }, /* y = dc */ ++ { 118, 15, 123, 148, 131, 101, 44, 93, 131 }, /* y = v */ ++ { 113, 12, 23, 188, 226, 142, 26, 32, 125 }, /* y = h */ ++ { 120, 11, 50, 123, 163, 135, 64, 77, 103 }, /* y = d45 */ ++ { 113, 9, 36, 155, 111, 157, 32, 44, 161 }, /* y = d135 */ ++ { 116, 9, 55, 176, 76, 96, 37, 61, 149 }, /* y = d117 */ ++ { 115, 9, 28, 141, 161, 167, 21, 25, 193 }, /* y = d153 */ ++ { 120, 12, 32, 145, 195, 142, 32, 38, 86 }, /* y = d207 */ ++ { 116, 12, 64, 120, 140, 125, 49, 115, 121 }, /* y = d63 */ ++ { 102, 19, 66, 162, 182, 122, 35, 59, 128 } /* y = tm */ ++}; ++ ++static void write_coeff_plane(const u8 coef[6][6][3], u8 *coeff_plane) ++{ ++ unsigned int idx = 0; ++ u8 byte_count = 0, p; ++ s32 k, m, n; ++ ++ for (k = 0; k < 6; k++) { ++ for (m = 0; m < 6; m++) { ++ for (n = 0; n < 3; n++) { ++ p = coef[k][m][n]; ++ coeff_plane[idx++] = p; ++ byte_count++; ++ if (byte_count == 27) { ++ idx += 5; ++ byte_count = 0; ++ } ++ } ++ } ++ } ++} ++ ++static void init_intra_only_probs(struct rkvdec_ctx *ctx, ++ const struct rkvdec_vp9_run *run) ++{ ++ const struct v4l2_ctrl_vp9_frame_decode_params *dec_params; ++ struct rkvdec_vp9_ctx *vp9_ctx = ctx->priv; ++ struct rkvdec_vp9_priv_tbl *tbl = vp9_ctx->priv_tbl.cpu; ++ struct rkvdec_vp9_intra_only_frame_probs *rkprobs; ++ const struct v4l2_vp9_probabilities *probs; ++ unsigned int i, j, k, m; ++ ++ rkprobs = &tbl->probs.intra_only; ++ dec_params = run->decode_params; ++ probs = &dec_params->probs; ++ ++ /* ++ * intra only 149 x 128 bits ,aligned to 152 x 128 bits coeff related ++ * prob 64 x 128 bits ++ */ ++ for (i = 0; i < ARRAY_SIZE(probs->coef); i++) { ++ for (j = 0; j < ARRAY_SIZE(probs->coef[0]); j++) ++ write_coeff_plane(probs->coef[i][j][0], ++ rkprobs->coef_intra[i][j]); ++ } ++ ++ /* intra mode prob 80 x 128 bits */ ++ for (i = 0; i < ARRAY_SIZE(vp9_kf_y_mode_prob); i++) { ++ u32 byte_count = 0; ++ int idx = 0; ++ ++ /* vp9_kf_y_mode_prob */ ++ for (j = 0; j < ARRAY_SIZE(vp9_kf_y_mode_prob[0]); j++) { ++ for (k = 0; k < ARRAY_SIZE(vp9_kf_y_mode_prob[0][0]); ++ k++) { ++ u8 val = vp9_kf_y_mode_prob[i][j][k]; ++ ++ rkprobs->intra_mode[i].y_mode[idx++] = val; ++ byte_count++; ++ if (byte_count == 27) { ++ byte_count = 0; ++ idx += 5; ++ } ++ } ++ } ++ ++ idx = 0; ++ if (i < 4) { ++ for (m = 0; m < (i < 3 ? 23 : 21); m++) { ++ const u8 *ptr = (const u8 *)kf_uv_mode_prob; ++ ++ rkprobs->intra_mode[i].uv_mode[idx++] = ptr[i * 23 + m]; ++ } ++ } ++ } ++} ++ ++static void init_inter_probs(struct rkvdec_ctx *ctx, ++ const struct rkvdec_vp9_run *run) ++{ ++ const struct v4l2_ctrl_vp9_frame_decode_params *dec_params; ++ struct rkvdec_vp9_ctx *vp9_ctx = ctx->priv; ++ struct rkvdec_vp9_priv_tbl *tbl = vp9_ctx->priv_tbl.cpu; ++ struct rkvdec_vp9_inter_frame_probs *rkprobs; ++ const struct v4l2_vp9_probabilities *probs; ++ unsigned int i, j, k; ++ ++ rkprobs = &tbl->probs.inter; ++ dec_params = run->decode_params; ++ probs = &dec_params->probs; ++ ++ /* ++ * inter probs ++ * 151 x 128 bits, aligned to 152 x 128 bits ++ * inter only ++ * intra_y_mode & inter_block info 6 x 128 bits ++ */ ++ ++ memcpy(rkprobs->y_mode, probs->y_mode, sizeof(rkprobs->y_mode)); ++ memcpy(rkprobs->comp_mode, probs->comp_mode, ++ sizeof(rkprobs->comp_mode)); ++ memcpy(rkprobs->comp_ref, probs->comp_ref, ++ sizeof(rkprobs->comp_ref)); ++ memcpy(rkprobs->single_ref, probs->single_ref, ++ sizeof(rkprobs->single_ref)); ++ memcpy(rkprobs->inter_mode, probs->inter_mode, ++ sizeof(rkprobs->inter_mode)); ++ memcpy(rkprobs->interp_filter, probs->interp_filter, ++ sizeof(rkprobs->interp_filter)); ++ ++ /* 128 x 128 bits coeff related */ ++ for (i = 0; i < ARRAY_SIZE(probs->coef); i++) { ++ for (j = 0; j < ARRAY_SIZE(probs->coef[0]); j++) { ++ for (k = 0; k < ARRAY_SIZE(probs->coef[0][0]); k++) ++ write_coeff_plane(probs->coef[i][j][k], ++ rkprobs->coef[k][i][j]); ++ } ++ } ++ ++ /* intra uv mode 6 x 128 */ ++ memcpy(rkprobs->uv_mode_0_2, &probs->uv_mode[0], ++ sizeof(rkprobs->uv_mode_0_2)); ++ memcpy(rkprobs->uv_mode_3_5, &probs->uv_mode[3], ++ sizeof(rkprobs->uv_mode_3_5)); ++ memcpy(rkprobs->uv_mode_6_8, &probs->uv_mode[6], ++ sizeof(rkprobs->uv_mode_6_8)); ++ memcpy(rkprobs->uv_mode_9, &probs->uv_mode[9], ++ sizeof(rkprobs->uv_mode_9)); ++ ++ /* mv related 6 x 128 */ ++ memcpy(rkprobs->mv.joint, probs->mv.joint, ++ sizeof(rkprobs->mv.joint)); ++ memcpy(rkprobs->mv.sign, probs->mv.sign, ++ sizeof(rkprobs->mv.sign)); ++ memcpy(rkprobs->mv.class, probs->mv.class, ++ sizeof(rkprobs->mv.class)); ++ memcpy(rkprobs->mv.class0_bit, probs->mv.class0_bit, ++ sizeof(rkprobs->mv.class0_bit)); ++ memcpy(rkprobs->mv.bits, probs->mv.bits, ++ sizeof(rkprobs->mv.bits)); ++ memcpy(rkprobs->mv.class0_fr, probs->mv.class0_fr, ++ sizeof(rkprobs->mv.class0_fr)); ++ memcpy(rkprobs->mv.fr, probs->mv.fr, ++ sizeof(rkprobs->mv.fr)); ++ memcpy(rkprobs->mv.class0_hp, probs->mv.class0_hp, ++ sizeof(rkprobs->mv.class0_hp)); ++ memcpy(rkprobs->mv.hp, probs->mv.hp, ++ sizeof(rkprobs->mv.hp)); ++} ++ ++static void init_probs(struct rkvdec_ctx *ctx, ++ const struct rkvdec_vp9_run *run) ++{ ++ const struct v4l2_ctrl_vp9_frame_decode_params *dec_params; ++ struct rkvdec_vp9_ctx *vp9_ctx = ctx->priv; ++ struct rkvdec_vp9_priv_tbl *tbl = vp9_ctx->priv_tbl.cpu; ++ struct rkvdec_vp9_probs *rkprobs = &tbl->probs; ++ const struct v4l2_vp9_segmentation *seg; ++ const struct v4l2_vp9_probabilities *probs; ++ bool intra_only; ++ ++ dec_params = run->decode_params; ++ probs = &dec_params->probs; ++ seg = &dec_params->seg; ++ ++ memset(rkprobs, 0, sizeof(*rkprobs)); ++ ++ intra_only = !!(dec_params->flags & ++ (V4L2_VP9_FRAME_FLAG_KEY_FRAME | ++ V4L2_VP9_FRAME_FLAG_INTRA_ONLY)); ++ ++ /* sb info 5 x 128 bit */ ++ memcpy(rkprobs->partition, ++ intra_only ? kf_partition_probs : probs->partition, ++ sizeof(rkprobs->partition)); ++ ++ memcpy(rkprobs->pred, seg->pred_probs, sizeof(rkprobs->pred)); ++ memcpy(rkprobs->tree, seg->tree_probs, sizeof(rkprobs->tree)); ++ memcpy(rkprobs->skip, probs->skip, sizeof(rkprobs->skip)); ++ memcpy(rkprobs->tx32, probs->tx32, sizeof(rkprobs->tx32)); ++ memcpy(rkprobs->tx16, probs->tx16, sizeof(rkprobs->tx16)); ++ memcpy(rkprobs->tx8, probs->tx8, sizeof(rkprobs->tx8)); ++ memcpy(rkprobs->is_inter, probs->is_inter, sizeof(rkprobs->is_inter)); ++ ++ if (intra_only) ++ init_intra_only_probs(ctx, run); ++ else ++ init_inter_probs(ctx, run); ++} ++ ++struct vp9d_ref_config { ++ u32 reg_frm_size; ++ u32 reg_hor_stride; ++ u32 reg_y_stride; ++ u32 reg_yuv_stride; ++ u32 reg_ref_base; ++}; ++ ++static struct vp9d_ref_config ref_config[3] = { ++ { ++ .reg_frm_size = RKVDEC_REG_VP9_FRAME_SIZE(0), ++ .reg_hor_stride = RKVDEC_VP9_HOR_VIRSTRIDE(0), ++ .reg_y_stride = RKVDEC_VP9_LAST_FRAME_YSTRIDE, ++ .reg_yuv_stride = RKVDEC_VP9_LAST_FRAME_YUVSTRIDE, ++ .reg_ref_base = RKVDEC_REG_VP9_LAST_FRAME_BASE, ++ }, ++ { ++ .reg_frm_size = RKVDEC_REG_VP9_FRAME_SIZE(1), ++ .reg_hor_stride = RKVDEC_VP9_HOR_VIRSTRIDE(1), ++ .reg_y_stride = RKVDEC_VP9_GOLDEN_FRAME_YSTRIDE, ++ .reg_yuv_stride = 0, ++ .reg_ref_base = RKVDEC_REG_VP9_GOLDEN_FRAME_BASE, ++ }, ++ { ++ .reg_frm_size = RKVDEC_REG_VP9_FRAME_SIZE(2), ++ .reg_hor_stride = RKVDEC_VP9_HOR_VIRSTRIDE(2), ++ .reg_y_stride = RKVDEC_VP9_ALTREF_FRAME_YSTRIDE, ++ .reg_yuv_stride = 0, ++ .reg_ref_base = RKVDEC_REG_VP9_ALTREF_FRAME_BASE, ++ } ++}; ++ ++static struct rkvdec_decoded_buffer * ++get_ref_buf(struct rkvdec_ctx *ctx, struct vb2_v4l2_buffer *dst, u64 timestamp) ++{ ++ struct v4l2_m2m_ctx *m2m_ctx = ctx->fh.m2m_ctx; ++ struct vb2_queue *cap_q = &m2m_ctx->cap_q_ctx.q; ++ int buf_idx; ++ ++ /* ++ * If a ref is unused or invalid, address of current destination ++ * buffer is returned. ++ */ ++ buf_idx = vb2_find_timestamp(cap_q, timestamp, 0); ++ if (buf_idx < 0) ++ return vb2_to_rkvdec_decoded_buf(&dst->vb2_buf); ++ ++ return vb2_to_rkvdec_decoded_buf(vb2_get_buffer(cap_q, buf_idx)); ++} ++ ++static dma_addr_t get_mv_base_addr(struct rkvdec_decoded_buffer *buf) ++{ ++ u32 aligned_pitch, aligned_height, yuv_len; ++ ++ aligned_height = round_up(buf->vp9.height, 64); ++ aligned_pitch = round_up(buf->vp9.width * buf->vp9.bit_depth, 512) / 8; ++ yuv_len = (aligned_height * aligned_pitch * 3) / 2; ++ ++ return vb2_dma_contig_plane_dma_addr(&buf->base.vb.vb2_buf, 0) + ++ yuv_len; ++} ++ ++static void ++config_ref_registers(struct rkvdec_ctx *ctx, ++ const struct rkvdec_vp9_run *run, ++ struct rkvdec_decoded_buffer **ref_bufs, ++ enum v4l2_vp9_ref_id id) ++{ ++ u32 aligned_pitch, aligned_height, y_len, yuv_len; ++ struct rkvdec_decoded_buffer *buf = ref_bufs[id]; ++ struct rkvdec_dev *rkvdec = ctx->dev; ++ ++ aligned_height = round_up(buf->vp9.height, 64); ++ writel_relaxed(RKVDEC_VP9_FRAMEWIDTH(buf->vp9.width) | ++ RKVDEC_VP9_FRAMEHEIGHT(buf->vp9.height), ++ rkvdec->regs + ref_config[id].reg_frm_size); ++ ++ writel_relaxed(vb2_dma_contig_plane_dma_addr(&buf->base.vb.vb2_buf, 0), ++ rkvdec->regs + ref_config[id].reg_ref_base); ++ ++ if (&buf->base.vb == run->base.bufs.dst) ++ return; ++ ++ aligned_pitch = round_up(buf->vp9.width * buf->vp9.bit_depth, 512) / 8; ++ y_len = aligned_height * aligned_pitch; ++ yuv_len = (y_len * 3) / 2; ++ ++ writel_relaxed(RKVDEC_HOR_Y_VIRSTRIDE(aligned_pitch / 16) | ++ RKVDEC_HOR_UV_VIRSTRIDE(aligned_pitch / 16), ++ rkvdec->regs + ref_config[id].reg_hor_stride); ++ writel_relaxed(RKVDEC_VP9_REF_YSTRIDE(y_len / 16), ++ rkvdec->regs + ref_config[id].reg_y_stride); ++ ++ if (!ref_config[id].reg_yuv_stride) ++ return; ++ ++ writel_relaxed(RKVDEC_VP9_REF_YUVSTRIDE(yuv_len / 16), ++ rkvdec->regs + ref_config[id].reg_yuv_stride); ++} ++ ++static bool seg_featured_enabled(const struct v4l2_vp9_segmentation *seg, ++ enum v4l2_vp9_segment_feature feature, ++ unsigned int segid) ++{ ++ u8 mask = V4L2_VP9_SEGMENT_FEATURE_ENABLED(feature); ++ ++ return !!(seg->feature_enabled[segid] & mask); ++} ++ ++static void ++config_seg_registers(struct rkvdec_ctx *ctx, ++ unsigned int segid) ++{ ++ struct rkvdec_vp9_ctx *vp9_ctx = ctx->priv; ++ const struct v4l2_vp9_segmentation *seg; ++ struct rkvdec_dev *rkvdec = ctx->dev; ++ s16 feature_val; ++ u8 feature_id; ++ u32 val = 0; ++ ++ seg = vp9_ctx->last.valid ? &vp9_ctx->last.seg : &vp9_ctx->cur.seg; ++ feature_id = V4L2_VP9_SEGMENT_FEATURE_QP_DELTA; ++ if (seg_featured_enabled(seg, feature_id, segid)) { ++ feature_val = seg->feature_data[segid][feature_id]; ++ val |= RKVDEC_SEGID_FRAME_QP_DELTA_EN(1) | ++ RKVDEC_SEGID_FRAME_QP_DELTA(feature_val); ++ } ++ ++ feature_id = V4L2_VP9_SEGMENT_FEATURE_LF; ++ if (seg_featured_enabled(seg, feature_id, segid)) { ++ feature_val = seg->feature_data[segid][feature_id]; ++ val |= RKVDEC_SEGID_FRAME_LOOPFILTER_VALUE_EN(1) | ++ RKVDEC_SEGID_FRAME_LOOPFILTER_VALUE(feature_val); ++ } ++ ++ feature_id = V4L2_VP9_SEGMENT_FEATURE_REF_FRAME; ++ if (seg_featured_enabled(seg, feature_id, segid)) { ++ feature_val = seg->feature_data[segid][feature_id]; ++ val |= RKVDEC_SEGID_REFERINFO_EN(1) | ++ RKVDEC_SEGID_REFERINFO(feature_val); ++ } ++ ++ feature_id = V4L2_VP9_SEGMENT_FEATURE_SKIP; ++ if (seg_featured_enabled(seg, feature_id, segid)) ++ val |= RKVDEC_SEGID_FRAME_SKIP_EN(1); ++ ++ if (!segid && ++ (seg->flags & V4L2_VP9_SEGMENTATION_FLAG_ABS_OR_DELTA_UPDATE)) ++ val |= RKVDEC_SEGID_ABS_DELTA(1); ++ ++ writel_relaxed(val, rkvdec->regs + RKVDEC_VP9_SEGID_GRP(segid)); ++} ++ ++static void ++update_dec_buf_info(struct rkvdec_decoded_buffer *buf, ++ const struct v4l2_ctrl_vp9_frame_decode_params *dec_params) ++{ ++ buf->vp9.width = dec_params->frame_width_minus_1 + 1; ++ buf->vp9.height = dec_params->frame_height_minus_1 + 1; ++ buf->vp9.bit_depth = dec_params->bit_depth; ++} ++ ++static void ++update_ctx_cur_info(struct rkvdec_vp9_ctx *vp9_ctx, ++ struct rkvdec_decoded_buffer *buf, ++ const struct v4l2_ctrl_vp9_frame_decode_params *dec_params) ++{ ++ vp9_ctx->cur.valid = true; ++ vp9_ctx->cur.frame_context_idx = dec_params->frame_context_idx; ++ vp9_ctx->cur.reference_mode = dec_params->reference_mode; ++ vp9_ctx->cur.tx_mode = dec_params->tx_mode; ++ vp9_ctx->cur.interpolation_filter = dec_params->interpolation_filter; ++ vp9_ctx->cur.flags = dec_params->flags; ++ vp9_ctx->cur.timestamp = buf->base.vb.vb2_buf.timestamp; ++ vp9_ctx->cur.seg = dec_params->seg; ++ vp9_ctx->cur.lf = dec_params->lf; ++} ++ ++static void ++update_ctx_last_info(struct rkvdec_vp9_ctx *vp9_ctx) ++{ ++ vp9_ctx->last = vp9_ctx->cur; ++} ++ ++static void config_registers(struct rkvdec_ctx *ctx, ++ const struct rkvdec_vp9_run *run) ++{ ++ u32 y_len, uv_len, yuv_len, bit_depth, aligned_height, aligned_pitch; ++ const struct v4l2_ctrl_vp9_frame_decode_params *dec_params; ++ struct rkvdec_decoded_buffer *ref_bufs[V4L2_REF_ID_CNT]; ++ struct rkvdec_decoded_buffer *dst, *last, *mv_ref; ++ struct rkvdec_vp9_ctx *vp9_ctx = ctx->priv; ++ u32 val, stream_len, last_frame_info = 0; ++ const struct v4l2_vp9_segmentation *seg; ++ struct rkvdec_dev *rkvdec = ctx->dev; ++ dma_addr_t addr; ++ bool intra_only; ++ unsigned int i; ++ ++ dec_params = run->decode_params; ++ dst = vb2_to_rkvdec_decoded_buf(&run->base.bufs.dst->vb2_buf); ++ for (i = 0; i < ARRAY_SIZE(ref_bufs); i++) ++ ref_bufs[i] = get_ref_buf(ctx, &dst->base.vb, ++ dec_params->refs[i]); ++ ++ if (vp9_ctx->last.valid) ++ last = get_ref_buf(ctx, &dst->base.vb, vp9_ctx->last.timestamp); ++ else ++ last = dst; ++ ++ update_dec_buf_info(dst, dec_params); ++ update_ctx_cur_info(vp9_ctx, dst, dec_params); ++ seg = &dec_params->seg; ++ ++ intra_only = !!(dec_params->flags & ++ (V4L2_VP9_FRAME_FLAG_KEY_FRAME | ++ V4L2_VP9_FRAME_FLAG_INTRA_ONLY)); ++ ++ writel_relaxed(RKVDEC_MODE(RKVDEC_MODE_VP9), ++ rkvdec->regs + RKVDEC_REG_SYSCTRL); ++ ++ bit_depth = dec_params->bit_depth; ++ aligned_height = round_up(ctx->decoded_fmt.fmt.pix_mp.height, 64); ++ ++ aligned_pitch = round_up(ctx->decoded_fmt.fmt.pix_mp.width * ++ bit_depth, ++ 512) / 8; ++ y_len = aligned_height * aligned_pitch; ++ uv_len = y_len / 2; ++ yuv_len = y_len + uv_len; ++ ++ writel_relaxed(RKVDEC_Y_HOR_VIRSTRIDE(aligned_pitch / 16) | ++ RKVDEC_UV_HOR_VIRSTRIDE(aligned_pitch / 16), ++ rkvdec->regs + RKVDEC_REG_PICPAR); ++ writel_relaxed(RKVDEC_Y_VIRSTRIDE(y_len / 16), ++ rkvdec->regs + RKVDEC_REG_Y_VIRSTRIDE); ++ writel_relaxed(RKVDEC_YUV_VIRSTRIDE(yuv_len / 16), ++ rkvdec->regs + RKVDEC_REG_YUV_VIRSTRIDE); ++ ++ stream_len = vb2_get_plane_payload(&run->base.bufs.src->vb2_buf, 0); ++ writel_relaxed(RKVDEC_STRM_LEN(stream_len), ++ rkvdec->regs + RKVDEC_REG_STRM_LEN); ++ ++ /* ++ * Reset count buffer, because decoder only output intra related syntax ++ * counts when decoding intra frame, but update entropy need to update ++ * all the probabilities. ++ */ ++ if (intra_only) ++ memset(vp9_ctx->count_tbl.cpu, 0, vp9_ctx->count_tbl.size); ++ ++ vp9_ctx->cur.segmapid = vp9_ctx->last.segmapid; ++ if (!intra_only && ++ !(dec_params->flags & V4L2_VP9_FRAME_FLAG_ERROR_RESILIENT) && ++ (!(seg->flags & V4L2_VP9_SEGMENTATION_FLAG_ENABLED) || ++ (seg->flags & V4L2_VP9_SEGMENTATION_FLAG_UPDATE_MAP))) ++ vp9_ctx->cur.segmapid++; ++ ++ for (i = 0; i < ARRAY_SIZE(ref_bufs); i++) ++ config_ref_registers(ctx, run, ref_bufs, i); ++ ++ for (i = 0; i < 8; i++) ++ config_seg_registers(ctx, i); ++ ++ writel_relaxed(RKVDEC_VP9_TX_MODE(dec_params->tx_mode) | ++ RKVDEC_VP9_FRAME_REF_MODE(dec_params->reference_mode), ++ rkvdec->regs + RKVDEC_VP9_CPRHEADER_CONFIG); ++ ++ if (!intra_only) { ++ const struct v4l2_vp9_loop_filter *lf; ++ s8 delta; ++ ++ if (vp9_ctx->last.valid) ++ lf = &vp9_ctx->last.lf; ++ else ++ lf = &vp9_ctx->cur.lf; ++ ++ val = 0; ++ for (i = 0; i < ARRAY_SIZE(lf->ref_deltas); i++) { ++ delta = lf->ref_deltas[i]; ++ val |= RKVDEC_REF_DELTAS_LASTFRAME(i, delta); ++ } ++ ++ writel_relaxed(val, ++ rkvdec->regs + RKVDEC_VP9_REF_DELTAS_LASTFRAME); ++ ++ for (i = 0; i < ARRAY_SIZE(lf->mode_deltas); i++) { ++ delta = lf->mode_deltas[i]; ++ last_frame_info |= RKVDEC_MODE_DELTAS_LASTFRAME(i, ++ delta); ++ } ++ } ++ ++ if (vp9_ctx->last.valid && !intra_only && ++ vp9_ctx->last.seg.flags & V4L2_VP9_SEGMENTATION_FLAG_ENABLED) ++ last_frame_info |= RKVDEC_SEG_EN_LASTFRAME; ++ ++ if (vp9_ctx->last.valid && ++ vp9_ctx->last.flags & V4L2_VP9_FRAME_FLAG_SHOW_FRAME) ++ last_frame_info |= RKVDEC_LAST_SHOW_FRAME; ++ ++ if (vp9_ctx->last.valid && ++ vp9_ctx->last.flags & ++ (V4L2_VP9_FRAME_FLAG_KEY_FRAME | V4L2_VP9_FRAME_FLAG_INTRA_ONLY)) ++ last_frame_info |= RKVDEC_LAST_INTRA_ONLY; ++ ++ if (vp9_ctx->last.valid && ++ last->vp9.width == dst->vp9.width && ++ last->vp9.height == dst->vp9.height) ++ last_frame_info |= RKVDEC_LAST_WIDHHEIGHT_EQCUR; ++ ++ writel_relaxed(last_frame_info, ++ rkvdec->regs + RKVDEC_VP9_INFO_LASTFRAME); ++ ++ writel_relaxed(stream_len - dec_params->compressed_header_size - ++ dec_params->uncompressed_header_size, ++ rkvdec->regs + RKVDEC_VP9_LASTTILE_SIZE); ++ ++ for (i = 0; !intra_only && i < ARRAY_SIZE(ref_bufs); i++) { ++ u32 refw = ref_bufs[i]->vp9.width; ++ u32 refh = ref_bufs[i]->vp9.height; ++ u32 hscale, vscale; ++ ++ hscale = (refw << 14) / dst->vp9.width; ++ vscale = (refh << 14) / dst->vp9.height; ++ writel_relaxed(RKVDEC_VP9_REF_HOR_SCALE(hscale) | ++ RKVDEC_VP9_REF_VER_SCALE(vscale), ++ rkvdec->regs + RKVDEC_VP9_REF_SCALE(i)); ++ } ++ ++ addr = vb2_dma_contig_plane_dma_addr(&dst->base.vb.vb2_buf, 0); ++ writel_relaxed(addr, rkvdec->regs + RKVDEC_REG_DECOUT_BASE); ++ addr = vb2_dma_contig_plane_dma_addr(&run->base.bufs.src->vb2_buf, 0); ++ writel_relaxed(addr, rkvdec->regs + RKVDEC_REG_STRM_RLC_BASE); ++ writel_relaxed(vp9_ctx->priv_tbl.dma + ++ offsetof(struct rkvdec_vp9_priv_tbl, probs), ++ rkvdec->regs + RKVDEC_REG_CABACTBL_PROB_BASE); ++ writel_relaxed(vp9_ctx->count_tbl.dma, ++ rkvdec->regs + RKVDEC_REG_VP9COUNT_BASE); ++ ++ writel_relaxed(vp9_ctx->priv_tbl.dma + ++ offsetof(struct rkvdec_vp9_priv_tbl, segmap) + ++ (RKVDEC_VP9_MAX_SEGMAP_SIZE * vp9_ctx->cur.segmapid), ++ rkvdec->regs + RKVDEC_REG_VP9_SEGIDCUR_BASE); ++ writel_relaxed(vp9_ctx->priv_tbl.dma + ++ offsetof(struct rkvdec_vp9_priv_tbl, segmap) + ++ (RKVDEC_VP9_MAX_SEGMAP_SIZE * (!vp9_ctx->cur.segmapid)), ++ rkvdec->regs + RKVDEC_REG_VP9_SEGIDLAST_BASE); ++ ++ if (!intra_only && ++ !(dec_params->flags & V4L2_VP9_FRAME_FLAG_ERROR_RESILIENT) && ++ vp9_ctx->last.valid) ++ mv_ref = last; ++ else ++ mv_ref = dst; ++ ++ writel_relaxed(get_mv_base_addr(mv_ref), ++ rkvdec->regs + RKVDEC_VP9_REF_COLMV_BASE); ++ ++ writel_relaxed(ctx->decoded_fmt.fmt.pix_mp.width | ++ (ctx->decoded_fmt.fmt.pix_mp.height << 16), ++ rkvdec->regs + RKVDEC_REG_PERFORMANCE_CYCLE); ++} ++ ++static int ++validate_dec_params(struct rkvdec_ctx *ctx, ++ const struct v4l2_ctrl_vp9_frame_decode_params *dec_params) ++{ ++ unsigned int aligned_width, aligned_height; ++ ++ /* We only support profile 0. */ ++ if (dec_params->profile != 0) { ++ dev_err(ctx->dev->dev, "unsupported profile %d\n", ++ dec_params->profile); ++ return -EINVAL; ++ } ++ ++ aligned_width = round_up(dec_params->frame_width_minus_1 + 1, 64); ++ aligned_height = round_up(dec_params->frame_height_minus_1 + 1, 64); ++ ++ /* ++ * Userspace should update the capture/decoded format when the ++ * resolution changes. ++ */ ++ if (aligned_width != ctx->decoded_fmt.fmt.pix_mp.width || ++ aligned_height != ctx->decoded_fmt.fmt.pix_mp.height) { ++ dev_err(ctx->dev->dev, ++ "unexpected bitstream resolution %dx%d\n", ++ dec_params->frame_width_minus_1 + 1, ++ dec_params->frame_height_minus_1 +1); ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static int rkvdec_vp9_run_preamble(struct rkvdec_ctx *ctx, ++ struct rkvdec_vp9_run *run) ++{ ++ const struct v4l2_ctrl_vp9_frame_decode_params *dec_params; ++ const struct v4l2_ctrl_vp9_frame_ctx *fctx = NULL; ++ struct rkvdec_vp9_ctx *vp9_ctx = ctx->priv; ++ struct v4l2_ctrl *ctrl; ++ u8 frm_ctx; ++ int ret; ++ ++ rkvdec_run_preamble(ctx, &run->base); ++ ++ ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl, ++ V4L2_CID_MPEG_VIDEO_VP9_FRAME_DECODE_PARAMS); ++ WARN_ON(!ctrl); ++ ++ dec_params = ctrl ? ctrl->p_cur.p : NULL; ++ if (WARN_ON(!dec_params)) ++ return -EINVAL; ++ ++ ret = validate_dec_params(ctx, dec_params); ++ if (ret) ++ return ret; ++ ++ run->decode_params = dec_params; ++ ++ /* No need to load the frame context if we don't need to update it. */ ++ if (!(dec_params->flags & V4L2_VP9_FRAME_FLAG_REFRESH_FRAME_CTX)) ++ return 0; ++ ++ /* ++ * When a refresh context is requested in parallel mode, we should just ++ * update the context with the probs passed in the decode parameters. ++ */ ++ if (dec_params->flags & V4L2_VP9_FRAME_FLAG_PARALLEL_DEC_MODE) { ++ vp9_ctx->frame_context.probs = dec_params->probs; ++ return 0; ++ } ++ ++ frm_ctx = run->decode_params->frame_context_idx; ++ ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl, ++ V4L2_CID_MPEG_VIDEO_VP9_FRAME_CONTEXT(frm_ctx)); ++ if (WARN_ON(!ctrl)) ++ return 0; ++ ++ fctx = ctrl->p_cur.p; ++ vp9_ctx->frame_context = *fctx; ++ ++ /* ++ * For intra-only frames, we must update the context TX and skip probs ++ * with the value passed in the decode params. ++ */ ++ if (dec_params->flags & ++ (V4L2_VP9_FRAME_FLAG_KEY_FRAME | V4L2_VP9_FRAME_FLAG_INTRA_ONLY)) { ++ struct v4l2_vp9_probabilities *probs; ++ ++ probs = &vp9_ctx->frame_context.probs; ++ memcpy(probs->skip, dec_params->probs.skip, ++ sizeof(probs->skip)); ++ memcpy(probs->tx8, dec_params->probs.tx8, ++ sizeof(probs->tx8)); ++ memcpy(probs->tx16, dec_params->probs.tx16, ++ sizeof(probs->tx16)); ++ memcpy(probs->tx32, dec_params->probs.tx32, ++ sizeof(probs->tx32)); ++ } ++ ++ return 0; ++} ++ ++static int rkvdec_vp9_run(struct rkvdec_ctx *ctx) ++{ ++ struct rkvdec_dev *rkvdec = ctx->dev; ++ struct rkvdec_vp9_run run = { }; ++ int ret; ++ ++ ret = rkvdec_vp9_run_preamble(ctx, &run); ++ if (ret) { ++ rkvdec_run_postamble(ctx, &run.base); ++ return ret; ++ } ++ ++ /* Prepare probs. */ ++ init_probs(ctx, &run); ++ ++ /* Configure hardware registers. */ ++ config_registers(ctx, &run); ++ ++ rkvdec_run_postamble(ctx, &run.base); ++ ++ schedule_delayed_work(&rkvdec->watchdog_work, msecs_to_jiffies(2000)); ++ ++ writel(1, rkvdec->regs + RKVDEC_REG_PREF_LUMA_CACHE_COMMAND); ++ writel(1, rkvdec->regs + RKVDEC_REG_PREF_CHR_CACHE_COMMAND); ++ ++ writel(0xe, rkvdec->regs + RKVDEC_REG_STRMD_ERR_EN); ++ /* Start decoding! */ ++ writel(RKVDEC_INTERRUPT_DEC_E | RKVDEC_CONFIG_DEC_CLK_GATE_E | ++ RKVDEC_TIMEOUT_E | RKVDEC_BUF_EMPTY_E, ++ rkvdec->regs + RKVDEC_REG_INTERRUPT); ++ ++ return 0; ++} ++ ++static u8 adapt_prob(u8 p1, u32 ct0, u32 ct1, u16 max_count, u32 update_factor) ++{ ++ u32 ct = ct0 + ct1, p2; ++ u32 lo = 1; ++ u32 hi = 255; ++ ++ if (!ct) ++ return p1; ++ ++ p2 = ((ct0 << 8) + (ct >> 1)) / ct; ++ p2 = clamp(p2, lo, hi); ++ ct = min_t(u32, ct, max_count); ++ ++ if (WARN_ON(max_count >= 257)) ++ return p1; ++ ++ update_factor = rkvdec_fastdiv(update_factor * ct, max_count); ++ ++ return p1 + (((p2 - p1) * update_factor + 128) >> 8); ++} ++ ++#define BAND_6(band) ((band) == 0 ? 3 : 6) ++ ++static void adapt_coeff(u8 coef[6][6][3], ++ const struct rkvdec_vp9_refs_counts ref_cnt[6][6], ++ u32 uf) ++{ ++ s32 l, m, n; ++ ++ for (l = 0; l < 6; l++) { ++ for (m = 0; m < BAND_6(l); m++) { ++ u8 *p = coef[l][m]; ++ const u32 n0 = ref_cnt[l][m].coeff[0]; ++ const u32 n1 = ref_cnt[l][m].coeff[1]; ++ const u32 n2 = ref_cnt[l][m].coeff[2]; ++ const u32 neob = ref_cnt[l][m].eob[1]; ++ const u32 eob_count = ref_cnt[l][m].eob[0]; ++ const u32 branch_ct[3][2] = { ++ { neob, eob_count - neob }, ++ { n0, n1 + n2 }, ++ { n1, n2 } ++ }; ++ ++ for (n = 0; n < 3; n++) ++ p[n] = adapt_prob(p[n], branch_ct[n][0], ++ branch_ct[n][1], 24, uf); ++ } ++ } ++} ++ ++static void ++adapt_coef_probs(struct v4l2_vp9_probabilities *probs, ++ const struct rkvdec_vp9_refs_counts ref_cnt[2][4][2][6][6], ++ unsigned int uf) ++{ ++ unsigned int i, j, k; ++ ++ for (i = 0; i < ARRAY_SIZE(probs->coef); i++) { ++ for (j = 0; j < ARRAY_SIZE(probs->coef[0]); j++) { ++ for (k = 0; k < ARRAY_SIZE(probs->coef[0][0]); ++ k++) { ++ adapt_coeff(probs->coef[i][j][k], ++ ref_cnt[k][i][j], ++ uf); ++ } ++ } ++ } ++} ++ ++static void adapt_intra_frame_probs(struct rkvdec_ctx *ctx) ++{ ++ struct rkvdec_vp9_ctx *vp9_ctx = ctx->priv; ++ struct v4l2_vp9_probabilities *probs = &vp9_ctx->frame_context.probs; ++ const struct rkvdec_vp9_intra_frame_symbol_counts *sym_cnts; ++ ++ sym_cnts = vp9_ctx->count_tbl.cpu; ++ adapt_coef_probs(probs, sym_cnts->ref_cnt, 112); ++} ++ ++static void ++adapt_skip_probs(struct v4l2_vp9_probabilities *probs, ++ const struct rkvdec_vp9_inter_frame_symbol_counts *sym_cnts) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < ARRAY_SIZE(probs->skip); i++) ++ probs->skip[i] = adapt_prob(probs->skip[i], ++ sym_cnts->skip[i][0], ++ sym_cnts->skip[i][1], ++ 20, 128); ++} ++ ++static void ++adapt_is_inter_probs(struct v4l2_vp9_probabilities *probs, ++ const struct rkvdec_vp9_inter_frame_symbol_counts *sym_cnts) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < ARRAY_SIZE(probs->is_inter); i++) ++ probs->is_inter[i] = adapt_prob(probs->is_inter[i], ++ sym_cnts->inter[i][0], ++ sym_cnts->inter[i][1], ++ 20, 128); ++} ++ ++static void ++adapt_comp_mode_probs(struct v4l2_vp9_probabilities *probs, ++ const struct rkvdec_vp9_inter_frame_symbol_counts *sym_cnts) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < ARRAY_SIZE(probs->comp_mode); i++) ++ probs->comp_mode[i] = adapt_prob(probs->comp_mode[i], ++ sym_cnts->comp[i][0], ++ sym_cnts->comp[i][1], ++ 20, 128); ++} ++ ++static void ++adapt_comp_ref_probs(struct v4l2_vp9_probabilities *probs, ++ const struct rkvdec_vp9_inter_frame_symbol_counts *sym_cnts) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < ARRAY_SIZE(probs->comp_ref); i++) ++ probs->comp_ref[i] = adapt_prob(probs->comp_ref[i], ++ sym_cnts->comp_ref[i][0], ++ sym_cnts->comp_ref[i][1], ++ 20, 128); ++} ++ ++static void ++adapt_single_ref_probs(struct v4l2_vp9_probabilities *probs, ++ const struct rkvdec_vp9_inter_frame_symbol_counts *sym_cnts) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < ARRAY_SIZE(probs->single_ref); i++) { ++ u8 *p = probs->single_ref[i]; ++ ++ p[0] = adapt_prob(p[0], sym_cnts->single_ref[i][0][0], ++ sym_cnts->single_ref[i][0][1], 20, 128); ++ p[1] = adapt_prob(p[1], sym_cnts->single_ref[i][1][0], ++ sym_cnts->single_ref[i][1][1], 20, 128); ++ } ++} ++ ++static void ++adapt_partition_probs(struct v4l2_vp9_probabilities *probs, ++ const struct rkvdec_vp9_inter_frame_symbol_counts *sym_cnts) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < ARRAY_SIZE(probs->partition); i++) { ++ const u32 *c = sym_cnts->partition[i]; ++ u8 *p = probs->partition[i]; ++ ++ p[0] = adapt_prob(p[0], c[0], c[1] + c[2] + c[3], 20, 128); ++ p[1] = adapt_prob(p[1], c[1], c[2] + c[3], 20, 128); ++ p[2] = adapt_prob(p[2], c[2], c[3], 20, 128); ++ } ++} ++ ++static void ++adapt_tx_probs(struct v4l2_vp9_probabilities *probs, ++ const struct rkvdec_vp9_inter_frame_symbol_counts *sym_cnts) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < ARRAY_SIZE(probs->tx8); i++) { ++ u8 *p16x16 = probs->tx16[i]; ++ u8 *p32x32 = probs->tx32[i]; ++ const u32 *c16 = sym_cnts->tx16p[i]; ++ const u32 *c32 = sym_cnts->tx32p[i]; ++ const u32 *c8 = sym_cnts->tx8p[i]; ++ u8 *p8x8 = probs->tx8[i]; ++ ++ p8x8[0] = adapt_prob(p8x8[0], c8[0], c8[1], 20, 128); ++ p16x16[0] = adapt_prob(p16x16[0], c16[0], c16[1] + c16[2], ++ 20, 128); ++ p16x16[1] = adapt_prob(p16x16[1], c16[1], c16[2], 20, 128); ++ p32x32[0] = adapt_prob(p32x32[0], c32[0], ++ c32[1] + c32[2] + c32[3], 20, 128); ++ p32x32[1] = adapt_prob(p32x32[1], c32[1], c32[2] + c32[3], ++ 20, 128); ++ p32x32[2] = adapt_prob(p32x32[2], c32[2], c32[3], 20, 128); ++ } ++} ++ ++static void ++adapt_interp_filter_probs(struct v4l2_vp9_probabilities *probs, ++ const struct rkvdec_vp9_inter_frame_symbol_counts *sym_cnts) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < ARRAY_SIZE(probs->interp_filter); i++) { ++ u8 *p = probs->interp_filter[i]; ++ const u32 *c = sym_cnts->filter[i]; ++ ++ p[0] = adapt_prob(p[0], c[0], c[1] + c[2], 20, 128); ++ p[1] = adapt_prob(p[1], c[1], c[2], 20, 128); ++ } ++} ++ ++static void ++adapt_inter_mode_probs(struct v4l2_vp9_probabilities *probs, ++ const struct rkvdec_vp9_inter_frame_symbol_counts *sym_cnts) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < ARRAY_SIZE(probs->inter_mode); i++) { ++ const u32 *c = sym_cnts->mv_mode[i]; ++ u8 *p = probs->inter_mode[i]; ++ ++ p[0] = adapt_prob(p[0], c[2], c[1] + c[0] + c[3], 20, 128); ++ p[1] = adapt_prob(p[1], c[0], c[1] + c[3], 20, 128); ++ p[2] = adapt_prob(p[2], c[1], c[3], 20, 128); ++ } ++} ++ ++static void ++adapt_mv_probs(struct v4l2_vp9_probabilities *probs, ++ const struct rkvdec_vp9_inter_frame_symbol_counts *sym_cnts, ++ bool high_prec_mv) ++{ ++ const u32 *c = sym_cnts->mv_joint; ++ u8 *p = probs->mv.joint; ++ unsigned int i, j; ++ u32 sum; ++ ++ p[0] = adapt_prob(p[0], c[0], c[1] + c[2] + c[3], 20, 128); ++ p[1] = adapt_prob(p[1], c[1], c[2] + c[3], 20, 128); ++ p[2] = adapt_prob(p[2], c[2], c[3], 20, 128); ++ ++ for (i = 0; i < ARRAY_SIZE(probs->mv.sign); i++) { ++ p = probs->mv.sign; ++ ++ p[i] = adapt_prob(p[i], sym_cnts->sign[i][0], ++ sym_cnts->sign[i][1], 20, 128); ++ ++ p = probs->mv.class[i]; ++ c = sym_cnts->classes[i]; ++ sum = c[1] + c[2] + c[3] + c[4] + c[5] + c[6] + c[7] + c[8] + ++ c[9] + c[10]; ++ p[0] = adapt_prob(p[0], c[0], sum, 20, 128); ++ sum -= c[1]; ++ p[1] = adapt_prob(p[1], c[1], sum, 20, 128); ++ sum -= c[2] + c[3]; ++ p[2] = adapt_prob(p[2], c[2] + c[3], sum, 20, 128); ++ p[3] = adapt_prob(p[3], c[2], c[3], 20, 128); ++ sum -= c[4] + c[5]; ++ p[4] = adapt_prob(p[4], c[4] + c[5], sum, 20, 128); ++ p[5] = adapt_prob(p[5], c[4], c[5], 20, 128); ++ sum -= c[6]; ++ p[6] = adapt_prob(p[6], c[6], sum, 20, 128); ++ p[7] = adapt_prob(p[7], c[7] + c[8], c[9] + c[10], 20, 128); ++ p[8] = adapt_prob(p[8], c[7], c[8], 20, 128); ++ p[9] = adapt_prob(p[9], c[9], c[10], 20, 128); ++ ++ p = probs->mv.class0_bit; ++ p[i] = adapt_prob(p[i], ++ sym_cnts->class0[i][0], ++ sym_cnts->class0[i][1], 20, 128); ++ ++ p = probs->mv.bits[i]; ++ for (j = 0; j < 10; j++) ++ p[j] = adapt_prob(p[j], sym_cnts->bits[i][j][0], ++ sym_cnts->bits[i][j][1], 20, 128); ++ ++ for (j = 0; j < 2; j++) { ++ p = probs->mv.class0_fr[i][j]; ++ c = sym_cnts->class0_fp[i][j]; ++ p[0] = adapt_prob(p[0], c[0], c[1] + c[2] + c[3], ++ 20, 128); ++ p[1] = adapt_prob(p[1], c[1], c[2] + c[3], 20, 128); ++ p[2] = adapt_prob(p[2], c[2], c[3], 20, 128); ++ } ++ ++ p = probs->mv.fr[i]; ++ c = sym_cnts->fp[i]; ++ p[0] = adapt_prob(p[0], c[0], c[1] + c[2] + c[3], 20, 128); ++ p[1] = adapt_prob(p[1], c[1], c[2] + c[3], 20, 128); ++ p[2] = adapt_prob(p[2], c[2], c[3], 20, 128); ++ ++ if (!high_prec_mv) ++ continue; ++ ++ p = probs->mv.class0_hp; ++ p[i] = adapt_prob(p[i], sym_cnts->class0_hp[i][0], ++ sym_cnts->class0_hp[i][1], 20, 128); ++ ++ p = probs->mv.hp; ++ p[i] = adapt_prob(p[i], sym_cnts->hp[i][0], ++ sym_cnts->hp[i][1], 20, 128); ++ } ++} ++ ++static void ++adapt_intra_mode_probs(u8 *p, const u32 *c) ++{ ++ u32 sum = 0, s2; ++ unsigned int i; ++ ++ for (i = V4L2_VP9_INTRA_PRED_MODE_V; i <= V4L2_VP9_INTRA_PRED_MODE_TM; ++ i++) ++ sum += c[i]; ++ ++ p[0] = adapt_prob(p[0], c[V4L2_VP9_INTRA_PRED_MODE_DC], sum, 20, 128); ++ sum -= c[V4L2_VP9_INTRA_PRED_MODE_TM]; ++ p[1] = adapt_prob(p[1], c[V4L2_VP9_INTRA_PRED_MODE_TM], sum, 20, 128); ++ sum -= c[V4L2_VP9_INTRA_PRED_MODE_V]; ++ p[2] = adapt_prob(p[2], c[V4L2_VP9_INTRA_PRED_MODE_V], sum, 20, 128); ++ s2 = c[V4L2_VP9_INTRA_PRED_MODE_H] + c[V4L2_VP9_INTRA_PRED_MODE_D135] + ++ c[V4L2_VP9_INTRA_PRED_MODE_D117]; ++ sum -= s2; ++ p[3] = adapt_prob(p[3], s2, sum, 20, 128); ++ s2 -= c[V4L2_VP9_INTRA_PRED_MODE_H]; ++ p[4] = adapt_prob(p[4], c[V4L2_VP9_INTRA_PRED_MODE_H], s2, 20, 128); ++ p[5] = adapt_prob(p[5], c[V4L2_VP9_INTRA_PRED_MODE_D135], ++ c[V4L2_VP9_INTRA_PRED_MODE_D117], 20, 128); ++ sum -= c[V4L2_VP9_INTRA_PRED_MODE_D45]; ++ p[6] = adapt_prob(p[6], c[V4L2_VP9_INTRA_PRED_MODE_D45], ++ sum, 20, 128); ++ sum -= c[V4L2_VP9_INTRA_PRED_MODE_D63]; ++ p[7] = adapt_prob(p[7], c[V4L2_VP9_INTRA_PRED_MODE_D63], sum, ++ 20, 128); ++ p[8] = adapt_prob(p[8], c[V4L2_VP9_INTRA_PRED_MODE_D153], ++ c[V4L2_VP9_INTRA_PRED_MODE_D207], 20, 128); ++} ++ ++static void ++adapt_y_intra_mode_probs(struct v4l2_vp9_probabilities *probs, ++ const struct rkvdec_vp9_inter_frame_symbol_counts *sym_cnts) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < ARRAY_SIZE(probs->y_mode); i++) ++ adapt_intra_mode_probs(probs->y_mode[i], sym_cnts->y_mode[i]); ++} ++ ++static void ++adapt_uv_intra_mode_probs(struct v4l2_vp9_probabilities *probs, ++ const struct rkvdec_vp9_inter_frame_symbol_counts *sym_cnts) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < ARRAY_SIZE(probs->uv_mode); i++) ++ adapt_intra_mode_probs(probs->uv_mode[i], ++ sym_cnts->uv_mode[i]); ++} ++ ++static void ++adapt_inter_frame_probs(struct rkvdec_ctx *ctx) ++{ ++ struct rkvdec_vp9_ctx *vp9_ctx = ctx->priv; ++ struct v4l2_vp9_probabilities *probs = &vp9_ctx->frame_context.probs; ++ const struct rkvdec_vp9_inter_frame_symbol_counts *sym_cnts; ++ ++ sym_cnts = vp9_ctx->count_tbl.cpu; ++ /* coefficients */ ++ if (vp9_ctx->last.valid && ++ !(vp9_ctx->last.flags & V4L2_VP9_FRAME_FLAG_KEY_FRAME)) ++ adapt_coef_probs(probs, sym_cnts->ref_cnt, 112); ++ else ++ adapt_coef_probs(probs, sym_cnts->ref_cnt, 128); ++ ++ /* skip flag */ ++ adapt_skip_probs(probs, sym_cnts); ++ ++ /* intra/inter flag */ ++ adapt_is_inter_probs(probs, sym_cnts); ++ ++ /* comppred flag */ ++ adapt_comp_mode_probs(probs, sym_cnts); ++ ++ /* reference frames */ ++ adapt_comp_ref_probs(probs, sym_cnts); ++ ++ if (vp9_ctx->cur.reference_mode != V4L2_VP9_REF_MODE_COMPOUND) ++ adapt_single_ref_probs(probs, sym_cnts); ++ ++ /* block partitioning */ ++ adapt_partition_probs(probs, sym_cnts); ++ ++ /* tx size */ ++ if (vp9_ctx->cur.tx_mode == V4L2_VP9_TX_MODE_SELECT) ++ adapt_tx_probs(probs, sym_cnts); ++ ++ /* interpolation filter */ ++ if (vp9_ctx->cur.interpolation_filter == V4L2_VP9_INTERP_FILTER_SWITCHABLE) ++ adapt_interp_filter_probs(probs, sym_cnts); ++ ++ /* inter modes */ ++ adapt_inter_mode_probs(probs, sym_cnts); ++ ++ /* mv probs */ ++ adapt_mv_probs(probs, sym_cnts, ++ !!(vp9_ctx->cur.flags & ++ V4L2_VP9_FRAME_FLAG_ALLOW_HIGH_PREC_MV)); ++ ++ /* y intra modes */ ++ adapt_y_intra_mode_probs(probs, sym_cnts); ++ ++ /* uv intra modes */ ++ adapt_uv_intra_mode_probs(probs, sym_cnts); ++} ++ ++static void adapt_probs(struct rkvdec_ctx *ctx) ++{ ++ struct rkvdec_vp9_ctx *vp9_ctx = ctx->priv; ++ bool intra_only; ++ ++ intra_only = !!(vp9_ctx->cur.flags & ++ (V4L2_VP9_FRAME_FLAG_KEY_FRAME | ++ V4L2_VP9_FRAME_FLAG_INTRA_ONLY)); ++ ++ if (intra_only) ++ adapt_intra_frame_probs(ctx); ++ else ++ adapt_inter_frame_probs(ctx); ++} ++ ++static void rkvdec_vp9_done(struct rkvdec_ctx *ctx, ++ struct vb2_v4l2_buffer *src_buf, ++ struct vb2_v4l2_buffer *dst_buf, ++ enum vb2_buffer_state result) ++{ ++ struct rkvdec_vp9_ctx *vp9_ctx = ctx->priv; ++ struct v4l2_ctrl *ctrl; ++ unsigned int fctx_idx; ++ ++ if (result == VB2_BUF_STATE_ERROR) ++ goto out_update_last; ++ ++ if (!(vp9_ctx->cur.flags & V4L2_VP9_FRAME_FLAG_REFRESH_FRAME_CTX)) ++ goto out_update_last; ++ ++ fctx_idx = vp9_ctx->cur.frame_context_idx; ++ ++ if (!(vp9_ctx->cur.flags & ++ (V4L2_VP9_FRAME_FLAG_ERROR_RESILIENT | ++ V4L2_VP9_FRAME_FLAG_PARALLEL_DEC_MODE))) ++ adapt_probs(ctx); ++ ++ ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl, ++ V4L2_CID_MPEG_VIDEO_VP9_FRAME_CONTEXT(fctx_idx)); ++ if (WARN_ON(!ctrl)) ++ goto out_update_last; ++ ++ v4l2_ctrl_s_ctrl_compound(ctrl, V4L2_CTRL_TYPE_VP9_FRAME_CONTEXT, ++ &vp9_ctx->frame_context); ++ ++out_update_last: ++ update_ctx_last_info(vp9_ctx); ++} ++ ++static int rkvdec_vp9_start(struct rkvdec_ctx *ctx) ++{ ++ struct rkvdec_dev *rkvdec = ctx->dev; ++ struct rkvdec_vp9_priv_tbl *priv_tbl; ++ struct rkvdec_vp9_ctx *vp9_ctx; ++ u8 *count_tbl; ++ int ret; ++ ++ vp9_ctx = kzalloc(sizeof(*vp9_ctx), GFP_KERNEL); ++ if (!vp9_ctx) ++ return -ENOMEM; ++ ++ ctx->priv = vp9_ctx; ++ ++ priv_tbl = dma_alloc_coherent(rkvdec->dev, sizeof(*priv_tbl), ++ &vp9_ctx->priv_tbl.dma, GFP_KERNEL); ++ if (!priv_tbl) { ++ ret = -ENOMEM; ++ goto err_free_ctx; ++ } ++ ++ vp9_ctx->priv_tbl.size = sizeof(*priv_tbl); ++ vp9_ctx->priv_tbl.cpu = priv_tbl; ++ memset(priv_tbl, 0, sizeof(*priv_tbl)); ++ ++ count_tbl = dma_alloc_coherent(rkvdec->dev, RKVDEC_VP9_COUNT_SIZE, ++ &vp9_ctx->count_tbl.dma, GFP_KERNEL); ++ if (!count_tbl) { ++ ret = -ENOMEM; ++ goto err_free_priv_tbl; ++ } ++ ++ vp9_ctx->count_tbl.size = RKVDEC_VP9_COUNT_SIZE; ++ vp9_ctx->count_tbl.cpu = count_tbl; ++ memset(count_tbl, 0, sizeof(*count_tbl)); ++ ++ return 0; ++ ++err_free_priv_tbl: ++ dma_free_coherent(rkvdec->dev, vp9_ctx->priv_tbl.size, ++ vp9_ctx->priv_tbl.cpu, vp9_ctx->priv_tbl.dma); ++ ++err_free_ctx: ++ kfree(vp9_ctx); ++ return ret; ++} ++ ++static void rkvdec_vp9_stop(struct rkvdec_ctx *ctx) ++{ ++ struct rkvdec_vp9_ctx *vp9_ctx = ctx->priv; ++ struct rkvdec_dev *rkvdec = ctx->dev; ++ ++ dma_free_coherent(rkvdec->dev, vp9_ctx->count_tbl.size, ++ vp9_ctx->count_tbl.cpu, vp9_ctx->count_tbl.dma); ++ dma_free_coherent(rkvdec->dev, vp9_ctx->priv_tbl.size, ++ vp9_ctx->priv_tbl.cpu, vp9_ctx->priv_tbl.dma); ++ kfree(vp9_ctx); ++} ++ ++static int rkvdec_vp9_adjust_fmt(struct rkvdec_ctx *ctx, ++ struct v4l2_format *f) ++{ ++ struct v4l2_pix_format_mplane *fmt = &f->fmt.pix_mp; ++ ++ fmt->num_planes = 1; ++ if (!fmt->plane_fmt[0].sizeimage) ++ fmt->plane_fmt[0].sizeimage = fmt->width * fmt->height * 2; ++ return 0; ++} ++ ++const struct rkvdec_coded_fmt_ops rkvdec_vp9_fmt_ops = { ++ .adjust_fmt = rkvdec_vp9_adjust_fmt, ++ .start = rkvdec_vp9_start, ++ .stop = rkvdec_vp9_stop, ++ .run = rkvdec_vp9_run, ++ .done = rkvdec_vp9_done, ++}; +diff --git a/drivers/staging/media/rkvdec/rkvdec.c b/drivers/staging/media/rkvdec/rkvdec.c +index 91f8a1bb6176..f0f28f6a68cf 100644 +--- a/drivers/staging/media/rkvdec/rkvdec.c ++++ b/drivers/staging/media/rkvdec/rkvdec.c +@@ -159,6 +159,45 @@ static const u32 rkvdec_h264_decoded_fmts[] = { + V4L2_PIX_FMT_NV20, + }; + ++static const struct rkvdec_ctrl_desc rkvdec_vp9_ctrl_descs[] = { ++ { ++ .per_request = true, ++ .mandatory = true, ++ .cfg.id = V4L2_CID_MPEG_VIDEO_VP9_FRAME_DECODE_PARAMS, ++ }, ++ { ++ .mandatory = true, ++ .cfg.id = V4L2_CID_MPEG_VIDEO_VP9_FRAME_CONTEXT(0), ++ }, ++ { ++ .mandatory = true, ++ .cfg.id = V4L2_CID_MPEG_VIDEO_VP9_FRAME_CONTEXT(1), ++ }, ++ { ++ .mandatory = true, ++ .cfg.id = V4L2_CID_MPEG_VIDEO_VP9_FRAME_CONTEXT(2), ++ }, ++ { ++ .mandatory = true, ++ .cfg.id = V4L2_CID_MPEG_VIDEO_VP9_FRAME_CONTEXT(3), ++ }, ++ { ++ .cfg.id = V4L2_CID_MPEG_VIDEO_VP9_PROFILE, ++ .cfg.min = V4L2_MPEG_VIDEO_VP9_PROFILE_0, ++ .cfg.max = V4L2_MPEG_VIDEO_VP9_PROFILE_0, ++ .cfg.def = V4L2_MPEG_VIDEO_VP9_PROFILE_0, ++ }, ++}; ++ ++static const struct rkvdec_ctrls rkvdec_vp9_ctrls = { ++ .ctrls = rkvdec_vp9_ctrl_descs, ++ .num_ctrls = ARRAY_SIZE(rkvdec_vp9_ctrl_descs), ++}; ++ ++static const u32 rkvdec_vp9_decoded_fmts[] = { ++ V4L2_PIX_FMT_NV12, ++}; ++ + static const struct rkvdec_coded_fmt_desc rkvdec_coded_fmts[] = { + { + .fourcc = V4L2_PIX_FMT_H264_SLICE, +@@ -174,6 +213,21 @@ static const struct rkvdec_coded_fmt_desc rkvdec_coded_fmts[] = { + .ops = &rkvdec_h264_fmt_ops, + .num_decoded_fmts = ARRAY_SIZE(rkvdec_h264_decoded_fmts), + .decoded_fmts = rkvdec_h264_decoded_fmts, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_VP9_FRAME, ++ .frmsize = { ++ .min_width = 64, ++ .max_width = 4096, ++ .step_width = 64, ++ .min_height = 64, ++ .max_height = 2304, ++ .step_height = 64, ++ }, ++ .ctrls = &rkvdec_vp9_ctrls, ++ .ops = &rkvdec_vp9_fmt_ops, ++ .num_decoded_fmts = ARRAY_SIZE(rkvdec_vp9_decoded_fmts), ++ .decoded_fmts = rkvdec_vp9_decoded_fmts, + } + }; + +diff --git a/drivers/staging/media/rkvdec/rkvdec.h b/drivers/staging/media/rkvdec/rkvdec.h +index e95c52e3168a..5f66f07acac5 100644 +--- a/drivers/staging/media/rkvdec/rkvdec.h ++++ b/drivers/staging/media/rkvdec/rkvdec.h +@@ -51,6 +51,10 @@ struct rkvdec_vp9_decoded_buffer_info { + struct rkvdec_decoded_buffer { + /* Must be the first field in this struct. */ + struct v4l2_m2m_buffer base; ++ ++ union { ++ struct rkvdec_vp9_decoded_buffer_info vp9; ++ }; + }; + + static inline struct rkvdec_decoded_buffer * +@@ -119,4 +123,6 @@ void rkvdec_run_preamble(struct rkvdec_ctx *ctx, struct rkvdec_run *run); + void rkvdec_run_postamble(struct rkvdec_ctx *ctx, struct rkvdec_run *run); + + extern const struct rkvdec_coded_fmt_ops rkvdec_h264_fmt_ops; ++extern const struct rkvdec_coded_fmt_ops rkvdec_vp9_fmt_ops; ++ + #endif /* RKVDEC_H_ */ diff --git a/patch/kernel/rk322x-dev/01-linux-0015-fromlist-rga-for-rk322x.patch.disabled b/patch/kernel/rk322x-dev/01-linux-0015-fromlist-rga-for-rk322x.patch.disabled deleted file mode 100644 index be186ba1c..000000000 --- a/patch/kernel/rk322x-dev/01-linux-0015-fromlist-rga-for-rk322x.patch.disabled +++ /dev/null @@ -1,53 +0,0 @@ -Add a node to define the presence of RGA, a 2D raster -graphic acceleration unit. - -Signed-off-by: Justin Swartz ---- - arch/arm/boot/dts/rk322x.dtsi | 11 +++++++++++ - 1 file changed, 11 insertions(+) - -diff --git a/arch/arm/boot/dts/rk322x.dtsi b/arch/arm/boot/dts/rk322x.dtsi -index 340ed6ccb..29d50bebc 100644 ---- a/arch/arm/boot/dts/rk322x.dtsi -+++ b/arch/arm/boot/dts/rk322x.dtsi -@@ -621,6 +621,17 @@ - status = "disabled"; - }; - -+ rga: rga@20060000 { -+ compatible = "rockchip,rk3228-rga", "rockchip,rk3288-rga"; -+ reg = <0x20060000 0x1000>; -+ interrupts = ; -+ clocks = <&cru ACLK_RGA>, <&cru HCLK_RGA>, <&cru SCLK_RGA>; -+ clock-names = "aclk", "hclk", "sclk"; -+ resets = <&cru SRST_RGA>, <&cru SRST_RGA_A>, <&cru SRST_RGA_H>; -+ reset-names = "core", "axi", "ahb"; -+ status = "disabled"; -+ }; -+ - iep_mmu: iommu@20070800 { - compatible = "rockchip,iommu"; - reg = <0x20070800 0x100>; - -Enable RGA for Mecer Xtreme Mini S6. - -Signed-off-by: Justin Swartz ---- - arch/arm/boot/dts/rk3229-xms6.dts | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/arch/arm/boot/dts/rk3229-xms6.dts b/arch/arm/boot/dts/rk3229-xms6.dts -index 679fc2b00..894f64a4a 100644 ---- a/arch/arm/boot/dts/rk3229-xms6.dts -+++ b/arch/arm/boot/dts/rk3229-xms6.dts -@@ -202,6 +202,10 @@ - status = "okay"; - }; - -+&rga { -+ status = "okay"; -+}; -+ - &sdmmc { - cap-mmc-highspeed; - disable-wp; diff --git a/patch/kernel/rk322x-dev/01-linux-0021-drm-from-5.9.patch b/patch/kernel/rk322x-dev/01-linux-0021-drm-from-5.9.patch new file mode 100644 index 000000000..d97f0818a --- /dev/null +++ b/patch/kernel/rk322x-dev/01-linux-0021-drm-from-5.9.patch @@ -0,0 +1,3500 @@ +From 761a6a88e4fc8d732b6d4319d0bf6f0206d280de Mon Sep 17 00:00:00 2001 +From: Emil Velikov +Date: Tue, 5 May 2020 16:16:13 +0100 +Subject: [PATCH] drm/rockchip: vop: call vop_cfg_done() under reg_lock +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The function vop_cfg_done() is a simple VOP_REG_SET(). As such it should +be done under a reg_lock. A quick look through the driver shows that all +other instances (apart from driver init) have the lock. Do the same here + +Cc: Sandy Huang +Cc: Heiko Stübner +Signed-off-by: Emil Velikov +Reviewed-by: Sandy Huang +Link: https://patchwork.freedesktop.org/patch/msgid/20200505151613.2932456-1-emil.l.velikov@gmail.com +(cherry picked from commit 5fa63f0773323b1d028f2da5c94b8f3e38619b69) +--- + drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +index 33463b79a37b..1d76455ca933 100644 +--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c ++++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +@@ -645,10 +645,10 @@ static int vop_enable(struct drm_crtc *crtc, struct drm_crtc_state *old_state) + s->enable_afbc = false; + } + +- spin_unlock(&vop->reg_lock); +- + vop_cfg_done(vop); + ++ spin_unlock(&vop->reg_lock); ++ + /* + * At here, vop clock & iommu is enable, R/W vop regs would be safe. + */ + +From 7e1b1997341632ffac3e1ab8fdac8923929403c9 Mon Sep 17 00:00:00 2001 +From: Bernard Zhao +Date: Mon, 27 Apr 2020 01:05:23 -0700 +Subject: [PATCH] drivers: video: hdmi: cleanup coding style in video a bit + +Eliminate the magic numbers, add vendor infoframe size macro +like other hdmi modules. + +Signed-off-by: Bernard Zhao +Cc: Uma Shankar +Cc: Ville Syrjala +Cc: Shashank Sharma +Cc: Laurent Pinchart +Cc: Daniel Vetter +Cc: opensource.kernel@vivo.com +[b.zolnierkie: add "hdmi" to the patch summary] +[b.zolnierkie: fix "vender" -> vendor" typo in the patch description] +Signed-off-by: Bartlomiej Zolnierkiewicz +Link: https://patchwork.freedesktop.org/patch/msgid/20200427080530.3234-1-bernard@vivo.com +(cherry picked from commit d43be2554b58621a21cb5f54b32db2263b3008b6) +--- + drivers/video/hdmi.c | 2 +- + include/linux/hdmi.h | 1 + + 2 files changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/video/hdmi.c b/drivers/video/hdmi.c +index e70792b3e367..b7a1d6fae90d 100644 +--- a/drivers/video/hdmi.c ++++ b/drivers/video/hdmi.c +@@ -495,7 +495,7 @@ int hdmi_vendor_infoframe_init(struct hdmi_vendor_infoframe *frame) + * value + */ + frame->s3d_struct = HDMI_3D_STRUCTURE_INVALID; +- frame->length = 4; ++ frame->length = HDMI_VENDOR_INFOFRAME_SIZE; + + return 0; + } +diff --git a/include/linux/hdmi.h b/include/linux/hdmi.h +index 50c31f1a0a2d..9850d59d6f1c 100644 +--- a/include/linux/hdmi.h ++++ b/include/linux/hdmi.h +@@ -57,6 +57,7 @@ enum hdmi_infoframe_type { + #define HDMI_SPD_INFOFRAME_SIZE 25 + #define HDMI_AUDIO_INFOFRAME_SIZE 10 + #define HDMI_DRM_INFOFRAME_SIZE 26 ++#define HDMI_VENDOR_INFOFRAME_SIZE 4 + + #define HDMI_INFOFRAME_SIZE(type) \ + (HDMI_INFOFRAME_HEADER_SIZE + HDMI_ ## type ## _INFOFRAME_SIZE) + +From 86ce9313bd2561a632b4f3a03bdb894b92b988bb Mon Sep 17 00:00:00 2001 +From: Paul Kocialkowski +Date: Thu, 16 Apr 2020 16:05:26 +0200 +Subject: [PATCH] drm/rockchip: Add per-pixel alpha support for the PX30 VOP + +Compared to its predecessors, the PX30 VOP has a different register layout +for enabling per-pixel alpha. Instead of src_alpha_ctl and dst_alpha_ctl, +there is a single alpha control register. This register takes some fields +from src_alpha_ctl, but with a different layout. + +Add support for the required fields to the PX30 VOP window descriptions, +which makes per-pixel-alpha formats behave correctly. + +Signed-off-by: Paul Kocialkowski +Signed-off-by: Heiko Stuebner +Link: https://patchwork.freedesktop.org/patch/msgid/20200416140526.262533-1-paul.kocialkowski@bootlin.com +(cherry picked from commit 2aae8ed1f390a42ec752e4403ffca877fb3260e1) +--- + drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 4 ++++ + drivers/gpu/drm/rockchip/rockchip_drm_vop.h | 3 +++ + drivers/gpu/drm/rockchip/rockchip_vop_reg.c | 9 +++++++++ + 3 files changed, 16 insertions(+) + +diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +index 1d76455ca933..c80f7d9fd13f 100644 +--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c ++++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +@@ -1007,6 +1007,10 @@ static void vop_plane_atomic_update(struct drm_plane *plane, + SRC_ALPHA_CAL_M0(ALPHA_NO_SATURATION) | + SRC_FACTOR_M0(ALPHA_ONE); + VOP_WIN_SET(vop, win, src_alpha_ctl, val); ++ ++ VOP_WIN_SET(vop, win, alpha_pre_mul, ALPHA_SRC_PRE_MUL); ++ VOP_WIN_SET(vop, win, alpha_mode, ALPHA_PER_PIX); ++ VOP_WIN_SET(vop, win, alpha_en, 1); + } else { + VOP_WIN_SET(vop, win, src_alpha_ctl, SRC_ALPHA_EN(0)); + } +diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h +index d03bdb531ef2..4a2099cb582e 100644 +--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h ++++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h +@@ -167,6 +167,9 @@ struct vop_win_phy { + + struct vop_reg dst_alpha_ctl; + struct vop_reg src_alpha_ctl; ++ struct vop_reg alpha_pre_mul; ++ struct vop_reg alpha_mode; ++ struct vop_reg alpha_en; + struct vop_reg channel; + }; + +diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c +index 2413deded22c..80053d91a301 100644 +--- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c ++++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c +@@ -264,6 +264,9 @@ static const struct vop_win_phy px30_win0_data = { + .uv_mst = VOP_REG(PX30_WIN0_CBR_MST0, 0xffffffff, 0), + .yrgb_vir = VOP_REG(PX30_WIN0_VIR, 0x1fff, 0), + .uv_vir = VOP_REG(PX30_WIN0_VIR, 0x1fff, 16), ++ .alpha_pre_mul = VOP_REG(PX30_WIN0_ALPHA_CTRL, 0x1, 2), ++ .alpha_mode = VOP_REG(PX30_WIN0_ALPHA_CTRL, 0x1, 1), ++ .alpha_en = VOP_REG(PX30_WIN0_ALPHA_CTRL, 0x1, 0), + }; + + static const struct vop_win_phy px30_win1_data = { +@@ -277,6 +280,9 @@ static const struct vop_win_phy px30_win1_data = { + .dsp_st = VOP_REG(PX30_WIN1_DSP_ST, 0xffffffff, 0), + .yrgb_mst = VOP_REG(PX30_WIN1_MST, 0xffffffff, 0), + .yrgb_vir = VOP_REG(PX30_WIN1_VIR, 0x1fff, 0), ++ .alpha_pre_mul = VOP_REG(PX30_WIN1_ALPHA_CTRL, 0x1, 2), ++ .alpha_mode = VOP_REG(PX30_WIN1_ALPHA_CTRL, 0x1, 1), ++ .alpha_en = VOP_REG(PX30_WIN1_ALPHA_CTRL, 0x1, 0), + }; + + static const struct vop_win_phy px30_win2_data = { +@@ -291,6 +297,9 @@ static const struct vop_win_phy px30_win2_data = { + .dsp_st = VOP_REG(PX30_WIN2_DSP_ST0, 0x1fff1fff, 0), + .yrgb_mst = VOP_REG(PX30_WIN2_MST0, 0xffffffff, 0), + .yrgb_vir = VOP_REG(PX30_WIN2_VIR0_1, 0x1fff, 0), ++ .alpha_pre_mul = VOP_REG(PX30_WIN2_ALPHA_CTRL, 0x1, 2), ++ .alpha_mode = VOP_REG(PX30_WIN2_ALPHA_CTRL, 0x1, 1), ++ .alpha_en = VOP_REG(PX30_WIN2_ALPHA_CTRL, 0x1, 0), + }; + + static const struct vop_win_data px30_vop_big_win_data[] = { + +From 022f13fb762722cc81f51f2615131fd4b4cd72e6 Mon Sep 17 00:00:00 2001 +From: Krzysztof Kozlowski +Date: Wed, 27 May 2020 22:05:44 +0200 +Subject: [PATCH] drm/panfrost: Reduce the amount of logs on deferred probe + +There is no point to print deferred probe (and its failures to get +resources) as an error. Also there is no need to print regulator errors +twice. + +In case of multiple probe tries this would pollute the dmesg. + +Signed-off-by: Krzysztof Kozlowski +Reviewed-by: Steven Price +Signed-off-by: Steven Price +Link: https://patchwork.freedesktop.org/patch/msgid/20200527200544.7849-1-krzk@kernel.org +(cherry picked from commit e63adeccc0bbba34a7b988b8898bebbd5bbb6461) +--- + drivers/gpu/drm/panfrost/panfrost_device.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/gpu/drm/panfrost/panfrost_device.c b/drivers/gpu/drm/panfrost/panfrost_device.c +index 8136babd3ba9..b172087eee6a 100644 +--- a/drivers/gpu/drm/panfrost/panfrost_device.c ++++ b/drivers/gpu/drm/panfrost/panfrost_device.c +@@ -101,7 +101,9 @@ static int panfrost_regulator_init(struct panfrost_device *pfdev) + pfdev->comp->num_supplies, + pfdev->regulators); + if (ret < 0) { +- dev_err(pfdev->dev, "failed to get regulators: %d\n", ret); ++ if (ret != -EPROBE_DEFER) ++ dev_err(pfdev->dev, "failed to get regulators: %d\n", ++ ret); + return ret; + } + +@@ -213,10 +215,8 @@ int panfrost_device_init(struct panfrost_device *pfdev) + } + + err = panfrost_regulator_init(pfdev); +- if (err) { +- dev_err(pfdev->dev, "regulator init failed %d\n", err); ++ if (err) + goto err_out0; +- } + + err = panfrost_reset_init(pfdev); + if (err) { + +From 9bda1bca65f6067e191b056e6884ba7a9a0c4c09 Mon Sep 17 00:00:00 2001 +From: Dinghao Liu +Date: Fri, 22 May 2020 21:41:09 +0800 +Subject: [PATCH] drm/panfrost: Fix runtime PM imbalance on error + +The caller expects panfrost_job_hw_submit() to increase +runtime PM usage counter. The refcount decrement on the +error branch of WARN_ON() will break the counter balance +and needs to be removed. + +Signed-off-by: Dinghao Liu +Reviewed-by: Steven Price +Signed-off-by: Steven Price +Link: https://patchwork.freedesktop.org/patch/msgid/20200522134109.27204-1-dinghao.liu@zju.edu.cn +(cherry picked from commit 64092598c4566dc80a71ca57396dc36fdbf3da4b) +--- + drivers/gpu/drm/panfrost/panfrost_job.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/drivers/gpu/drm/panfrost/panfrost_job.c b/drivers/gpu/drm/panfrost/panfrost_job.c +index f9519afca29d..c6242fe34840 100644 +--- a/drivers/gpu/drm/panfrost/panfrost_job.c ++++ b/drivers/gpu/drm/panfrost/panfrost_job.c +@@ -152,7 +152,6 @@ static void panfrost_job_hw_submit(struct panfrost_job *job, int js) + return; + + if (WARN_ON(job_read(pfdev, JS_COMMAND_NEXT(js)))) { +- pm_runtime_put_sync_autosuspend(pfdev->dev); + return; + } + + +From 3c403361c554bd46a9ddb2b0d794785916327a83 Mon Sep 17 00:00:00 2001 +From: Ben Davis +Date: Mon, 1 Jun 2020 17:28:17 +0100 +Subject: [PATCH] drm: drm_fourcc: add NV15, Q410, Q401 YUV formats + +DRM_FORMAT_NV15 is a 2 plane format suitable for linear and 16x16 +block-linear memory layouts (DRM_FORMAT_MOD_SAMSUNG_16_16_TILE). The +format is similar to P010 with 4:2:0 sub-sampling but has no padding +between components. Instead, luminance and chrominance samples are +grouped into 4s so that each group is packed into an integer number +of bytes: + +YYYY = UVUV = 4 * 10 bits = 40 bits = 5 bytes + +The '15' suffix refers to the optimum effective bits per pixel which is +achieved when the total number of luminance samples is a multiple of 8. + +Q410 and Q401 are both 3 plane non-subsampled formats with 16 bits per +component, but only 10 bits are used and 6 are padded. 'Q' is chosen +as the first letter to denote 3 plane YUV444, (and is the next letter +along from P which is usually 2 plane). + +V2: Updated block_w of NV15 to {4, 2, 0} +V3: Updated commit message to include specific modifier name + +NV15: +Tested-by: Jonas Karlman + +Reviewed-by: Brian Starkey +Signed-off-by: Ben Davis +Signed-off-by: Liviu Dudau +Link: https://patchwork.freedesktop.org/patch/msgid/20200601162817.18230-1-ben.davis@arm.com +(cherry picked from commit 94b292b277343190175d39172c903c0c5fb814f1) +--- + drivers/gpu/drm/drm_fourcc.c | 12 ++++++++++++ + include/uapi/drm/drm_fourcc.h | 22 ++++++++++++++++++++++ + 2 files changed, 34 insertions(+) + +diff --git a/drivers/gpu/drm/drm_fourcc.c b/drivers/gpu/drm/drm_fourcc.c +index b234bfaeda06..722c7ebe4e88 100644 +--- a/drivers/gpu/drm/drm_fourcc.c ++++ b/drivers/gpu/drm/drm_fourcc.c +@@ -274,6 +274,18 @@ const struct drm_format_info *__drm_format_info(u32 format) + { .format = DRM_FORMAT_YUV420_10BIT, .depth = 0, + .num_planes = 1, .cpp = { 0, 0, 0 }, .hsub = 2, .vsub = 2, + .is_yuv = true }, ++ { .format = DRM_FORMAT_NV15, .depth = 0, ++ .num_planes = 2, .char_per_block = { 5, 5, 0 }, ++ .block_w = { 4, 2, 0 }, .block_h = { 1, 1, 0 }, .hsub = 2, ++ .vsub = 2, .is_yuv = true }, ++ { .format = DRM_FORMAT_Q410, .depth = 0, ++ .num_planes = 3, .char_per_block = { 2, 2, 2 }, ++ .block_w = { 1, 1, 1 }, .block_h = { 1, 1, 1 }, .hsub = 0, ++ .vsub = 0, .is_yuv = true }, ++ { .format = DRM_FORMAT_Q401, .depth = 0, ++ .num_planes = 3, .char_per_block = { 2, 2, 2 }, ++ .block_w = { 1, 1, 1 }, .block_h = { 1, 1, 1 }, .hsub = 0, ++ .vsub = 0, .is_yuv = true }, + }; + + unsigned int i; +diff --git a/include/uapi/drm/drm_fourcc.h b/include/uapi/drm/drm_fourcc.h +index 490143500a50..8ba2d9153a94 100644 +--- a/include/uapi/drm/drm_fourcc.h ++++ b/include/uapi/drm/drm_fourcc.h +@@ -236,6 +236,12 @@ extern "C" { + #define DRM_FORMAT_NV61 fourcc_code('N', 'V', '6', '1') /* 2x1 subsampled Cb:Cr plane */ + #define DRM_FORMAT_NV24 fourcc_code('N', 'V', '2', '4') /* non-subsampled Cr:Cb plane */ + #define DRM_FORMAT_NV42 fourcc_code('N', 'V', '4', '2') /* non-subsampled Cb:Cr plane */ ++/* ++ * 2 plane YCbCr ++ * index 0 = Y plane, [39:0] Y3:Y2:Y1:Y0 little endian ++ * index 1 = Cr:Cb plane, [39:0] Cr1:Cb1:Cr0:Cb0 little endian ++ */ ++#define DRM_FORMAT_NV15 fourcc_code('N', 'V', '1', '5') /* 2x2 subsampled Cr:Cb plane */ + + /* + * 2 plane YCbCr MSB aligned +@@ -265,6 +271,22 @@ extern "C" { + */ + #define DRM_FORMAT_P016 fourcc_code('P', '0', '1', '6') /* 2x2 subsampled Cr:Cb plane 16 bits per channel */ + ++/* 3 plane non-subsampled (444) YCbCr ++ * 16 bits per component, but only 10 bits are used and 6 bits are padded ++ * index 0: Y plane, [15:0] Y:x [10:6] little endian ++ * index 1: Cb plane, [15:0] Cb:x [10:6] little endian ++ * index 2: Cr plane, [15:0] Cr:x [10:6] little endian ++ */ ++#define DRM_FORMAT_Q410 fourcc_code('Q', '4', '1', '0') ++ ++/* 3 plane non-subsampled (444) YCrCb ++ * 16 bits per component, but only 10 bits are used and 6 bits are padded ++ * index 0: Y plane, [15:0] Y:x [10:6] little endian ++ * index 1: Cr plane, [15:0] Cr:x [10:6] little endian ++ * index 2: Cb plane, [15:0] Cb:x [10:6] little endian ++ */ ++#define DRM_FORMAT_Q401 fourcc_code('Q', '4', '0', '1') ++ + /* + * 3 plane YCbCr + * index 0: Y plane, [7:0] Y + +From 7e57394c63258ac63d5c74cbd2a700916c31d4f6 Mon Sep 17 00:00:00 2001 +From: Ben Davis +Date: Thu, 30 Apr 2020 09:32:20 +0100 +Subject: [PATCH] drm: drm_fourcc: Add uncompressed AFBC modifier + +AFBC has a mode that guarantees use of AFBC with an uncompressed +payloads, we add a new modifier to support this mode. + +V2: updated modifier comment + +Signed-off-by: Ben Davis +Acked-by: Liviu Dudau +Signed-off-by: Liviu Dudau +Link: https://patchwork.freedesktop.org/patch/msgid/20200430083220.17347-1-ben.davis@arm.com +(cherry picked from commit 79ce058032c391b12af928b1e30abf92482a270f) +--- + include/uapi/drm/drm_fourcc.h | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +diff --git a/include/uapi/drm/drm_fourcc.h b/include/uapi/drm/drm_fourcc.h +index 8ba2d9153a94..993c1b342315 100644 +--- a/include/uapi/drm/drm_fourcc.h ++++ b/include/uapi/drm/drm_fourcc.h +@@ -914,6 +914,18 @@ drm_fourcc_canonicalize_nvidia_format_mod(__u64 modifier) + */ + #define AFBC_FORMAT_MOD_BCH (1ULL << 11) + ++/* AFBC uncompressed storage mode ++ * ++ * Indicates that the buffer is using AFBC uncompressed storage mode. ++ * In this mode all superblock payloads in the buffer use the uncompressed ++ * storage mode, which is usually only used for data which cannot be compressed. ++ * The buffer layout is the same as for AFBC buffers without USM set, this only ++ * affects the storage mode of the individual superblocks. Note that even a ++ * buffer without USM set may use uncompressed storage mode for some or all ++ * superblocks, USM just guarantees it for all. ++ */ ++#define AFBC_FORMAT_MOD_USM (1ULL << 12) ++ + /* + * Arm 16x16 Block U-Interleaved modifier + * + +From 32b33df85c3c84ce2a145f2d68305116fbec91fd Mon Sep 17 00:00:00 2001 +From: Laurent Pinchart +Date: Tue, 26 May 2020 04:14:47 +0300 +Subject: [PATCH] drm: edid: Constify connector argument to infoframe functions + +The drm_hdmi_avi_infoframe_from_display_mode(), +drm_hdmi_vendor_infoframe_from_display_mode() and +drm_hdmi_avi_infoframe_quant_range() functions take a drm_connector that +they don't modify. Mark it as const. + +Signed-off-by: Laurent Pinchart +Acked-by: Sam Ravnborg +Signed-off-by: Sam Ravnborg +Link: https://patchwork.freedesktop.org/patch/msgid/20200526011505.31884-10-laurent.pinchart+renesas@ideasonboard.com +(cherry picked from commit 192a3aa0e4e20e1087baa29183c5d64d48716fa9) +--- + drivers/gpu/drm/drm_edid.c | 12 ++++++------ + include/drm/drm_edid.h | 6 +++--- + 2 files changed, 9 insertions(+), 9 deletions(-) + +diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c +index fed653f13c26..b3f659759adb 100644 +--- a/drivers/gpu/drm/drm_edid.c ++++ b/drivers/gpu/drm/drm_edid.c +@@ -5366,7 +5366,7 @@ void drm_set_preferred_mode(struct drm_connector *connector, + } + EXPORT_SYMBOL(drm_set_preferred_mode); + +-static bool is_hdmi2_sink(struct drm_connector *connector) ++static bool is_hdmi2_sink(const struct drm_connector *connector) + { + /* + * FIXME: sil-sii8620 doesn't have a connector around when +@@ -5451,7 +5451,7 @@ drm_hdmi_infoframe_set_hdr_metadata(struct hdmi_drm_infoframe *frame, + } + EXPORT_SYMBOL(drm_hdmi_infoframe_set_hdr_metadata); + +-static u8 drm_mode_hdmi_vic(struct drm_connector *connector, ++static u8 drm_mode_hdmi_vic(const struct drm_connector *connector, + const struct drm_display_mode *mode) + { + bool has_hdmi_infoframe = connector ? +@@ -5467,7 +5467,7 @@ static u8 drm_mode_hdmi_vic(struct drm_connector *connector, + return drm_match_hdmi_mode(mode); + } + +-static u8 drm_mode_cea_vic(struct drm_connector *connector, ++static u8 drm_mode_cea_vic(const struct drm_connector *connector, + const struct drm_display_mode *mode) + { + u8 vic; +@@ -5505,7 +5505,7 @@ static u8 drm_mode_cea_vic(struct drm_connector *connector, + */ + int + drm_hdmi_avi_infoframe_from_display_mode(struct hdmi_avi_infoframe *frame, +- struct drm_connector *connector, ++ const struct drm_connector *connector, + const struct drm_display_mode *mode) + { + enum hdmi_picture_aspect picture_aspect; +@@ -5652,7 +5652,7 @@ EXPORT_SYMBOL(drm_hdmi_avi_infoframe_colorspace); + */ + void + drm_hdmi_avi_infoframe_quant_range(struct hdmi_avi_infoframe *frame, +- struct drm_connector *connector, ++ const struct drm_connector *connector, + const struct drm_display_mode *mode, + enum hdmi_quantization_range rgb_quant_range) + { +@@ -5756,7 +5756,7 @@ s3d_structure_from_display_mode(const struct drm_display_mode *mode) + */ + int + drm_hdmi_vendor_infoframe_from_display_mode(struct hdmi_vendor_infoframe *frame, +- struct drm_connector *connector, ++ const struct drm_connector *connector, + const struct drm_display_mode *mode) + { + /* +diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h +index 34b15e3d070c..43254319ab19 100644 +--- a/include/drm/drm_edid.h ++++ b/include/drm/drm_edid.h +@@ -361,11 +361,11 @@ drm_load_edid_firmware(struct drm_connector *connector) + + int + drm_hdmi_avi_infoframe_from_display_mode(struct hdmi_avi_infoframe *frame, +- struct drm_connector *connector, ++ const struct drm_connector *connector, + const struct drm_display_mode *mode); + int + drm_hdmi_vendor_infoframe_from_display_mode(struct hdmi_vendor_infoframe *frame, +- struct drm_connector *connector, ++ const struct drm_connector *connector, + const struct drm_display_mode *mode); + + void +@@ -378,7 +378,7 @@ drm_hdmi_avi_infoframe_bars(struct hdmi_avi_infoframe *frame, + + void + drm_hdmi_avi_infoframe_quant_range(struct hdmi_avi_infoframe *frame, +- struct drm_connector *connector, ++ const struct drm_connector *connector, + const struct drm_display_mode *mode, + enum hdmi_quantization_range rgb_quant_range); + + +From 23fe85a8775eb3c926be0f3d2bc99b70a6d0bb07 Mon Sep 17 00:00:00 2001 +From: Laurent Pinchart +Date: Tue, 26 May 2020 04:14:48 +0300 +Subject: [PATCH] drm: bridge: Pass drm_display_info to drm_bridge_funcs + .mode_valid() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +When validating a mode, bridges may need to do so in the context of a +display, as specified by drm_display_info. An example is the meson +dw-hdmi bridge that needs to consider the YUV 4:2:0 output format to +perform clock calculations. + +Bridges that need the display info currently retrieve it from the +drm_connector created by the bridge. This gets in the way of moving +connector creation out of bridge drivers. To make this possible, pass +the drm_display_info to drm_bridge_funcs .mode_valid(). + +Changes to the bridge drivers have been performed with the following +coccinelle semantic patch and have been compile-tested. + +@ rule1 @ +identifier funcs; +identifier fn; +@@ + struct drm_bridge_funcs funcs = { + ..., + .mode_valid = fn + }; + +@ depends on rule1 @ +identifier rule1.fn; +identifier bridge; +identifier mode; +@@ + enum drm_mode_status fn( + struct drm_bridge *bridge, ++ const struct drm_display_info *info, + const struct drm_display_mode *mode + ) + { + ... + } + +Signed-off-by: Laurent Pinchart +Reviewed-by: Neil Armstrong +Reviewed-by: Boris Brezillon +Reviewed-by: Guido Günther # for the nwl-dsi part: +Signed-off-by: Sam Ravnborg +Link: https://patchwork.freedesktop.org/patch/msgid/20200526011505.31884-11-laurent.pinchart+renesas@ideasonboard.com +(cherry picked from commit 12c683e12cd8e2dcf7b7143bebceae484d17727a) +--- + drivers/gpu/drm/bridge/analogix/analogix-anx6345.c | 1 + + drivers/gpu/drm/bridge/analogix/analogix-anx78xx.c | 1 + + drivers/gpu/drm/bridge/cdns-dsi.c | 1 + + drivers/gpu/drm/bridge/chrontel-ch7033.c | 1 + + drivers/gpu/drm/bridge/nwl-dsi.c | 1 + + drivers/gpu/drm/bridge/sii9234.c | 1 + + drivers/gpu/drm/bridge/sil-sii8620.c | 1 + + drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 1 + + drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c | 1 + + drivers/gpu/drm/bridge/tc358767.c | 1 + + drivers/gpu/drm/bridge/tc358768.c | 1 + + drivers/gpu/drm/bridge/thc63lvd1024.c | 1 + + drivers/gpu/drm/bridge/ti-tfp410.c | 1 + + drivers/gpu/drm/drm_atomic_helper.c | 3 ++- + drivers/gpu/drm/drm_bridge.c | 4 +++- + drivers/gpu/drm/drm_probe_helper.c | 4 +++- + drivers/gpu/drm/i2c/tda998x_drv.c | 1 + + drivers/gpu/drm/omapdrm/dss/dpi.c | 1 + + drivers/gpu/drm/omapdrm/dss/sdi.c | 1 + + drivers/gpu/drm/omapdrm/dss/venc.c | 1 + + include/drm/drm_bridge.h | 3 +++ + 21 files changed, 28 insertions(+), 3 deletions(-) + +diff --git a/drivers/gpu/drm/bridge/analogix/analogix-anx6345.c b/drivers/gpu/drm/bridge/analogix/analogix-anx6345.c +index 9af39ec958db..f082b4ed4878 100644 +--- a/drivers/gpu/drm/bridge/analogix/analogix-anx6345.c ++++ b/drivers/gpu/drm/bridge/analogix/analogix-anx6345.c +@@ -588,6 +588,7 @@ static int anx6345_bridge_attach(struct drm_bridge *bridge, + + static enum drm_mode_status + anx6345_bridge_mode_valid(struct drm_bridge *bridge, ++ const struct drm_display_info *info, + const struct drm_display_mode *mode) + { + if (mode->flags & DRM_MODE_FLAG_INTERLACE) +diff --git a/drivers/gpu/drm/bridge/analogix/analogix-anx78xx.c b/drivers/gpu/drm/bridge/analogix/analogix-anx78xx.c +index 0d5a5ad0c9ee..81debd02c169 100644 +--- a/drivers/gpu/drm/bridge/analogix/analogix-anx78xx.c ++++ b/drivers/gpu/drm/bridge/analogix/analogix-anx78xx.c +@@ -944,6 +944,7 @@ static int anx78xx_bridge_attach(struct drm_bridge *bridge, + + static enum drm_mode_status + anx78xx_bridge_mode_valid(struct drm_bridge *bridge, ++ const struct drm_display_info *info, + const struct drm_display_mode *mode) + { + if (mode->flags & DRM_MODE_FLAG_INTERLACE) +diff --git a/drivers/gpu/drm/bridge/cdns-dsi.c b/drivers/gpu/drm/bridge/cdns-dsi.c +index 69c3892caee5..76373e31df92 100644 +--- a/drivers/gpu/drm/bridge/cdns-dsi.c ++++ b/drivers/gpu/drm/bridge/cdns-dsi.c +@@ -663,6 +663,7 @@ static int cdns_dsi_bridge_attach(struct drm_bridge *bridge, + + static enum drm_mode_status + cdns_dsi_bridge_mode_valid(struct drm_bridge *bridge, ++ const struct drm_display_info *info, + const struct drm_display_mode *mode) + { + struct cdns_dsi_input *input = bridge_to_cdns_dsi_input(bridge); +diff --git a/drivers/gpu/drm/bridge/chrontel-ch7033.c b/drivers/gpu/drm/bridge/chrontel-ch7033.c +index f8675d82974b..486f405c2e16 100644 +--- a/drivers/gpu/drm/bridge/chrontel-ch7033.c ++++ b/drivers/gpu/drm/bridge/chrontel-ch7033.c +@@ -317,6 +317,7 @@ static void ch7033_bridge_detach(struct drm_bridge *bridge) + } + + static enum drm_mode_status ch7033_bridge_mode_valid(struct drm_bridge *bridge, ++ const struct drm_display_info *info, + const struct drm_display_mode *mode) + { + if (mode->clock > 165000) +diff --git a/drivers/gpu/drm/bridge/nwl-dsi.c b/drivers/gpu/drm/bridge/nwl-dsi.c +index c7bc194bbce3..ce94f797d090 100644 +--- a/drivers/gpu/drm/bridge/nwl-dsi.c ++++ b/drivers/gpu/drm/bridge/nwl-dsi.c +@@ -818,6 +818,7 @@ static bool nwl_dsi_bridge_mode_fixup(struct drm_bridge *bridge, + + static enum drm_mode_status + nwl_dsi_bridge_mode_valid(struct drm_bridge *bridge, ++ const struct drm_display_info *info, + const struct drm_display_mode *mode) + { + struct nwl_dsi *dsi = bridge_to_dsi(bridge); +diff --git a/drivers/gpu/drm/bridge/sii9234.c b/drivers/gpu/drm/bridge/sii9234.c +index b1258f0ed205..15c98a7bd81c 100644 +--- a/drivers/gpu/drm/bridge/sii9234.c ++++ b/drivers/gpu/drm/bridge/sii9234.c +@@ -873,6 +873,7 @@ static inline struct sii9234 *bridge_to_sii9234(struct drm_bridge *bridge) + } + + static enum drm_mode_status sii9234_mode_valid(struct drm_bridge *bridge, ++ const struct drm_display_info *info, + const struct drm_display_mode *mode) + { + if (mode->clock > MHL1_MAX_CLK) +diff --git a/drivers/gpu/drm/bridge/sil-sii8620.c b/drivers/gpu/drm/bridge/sil-sii8620.c +index ca98133411aa..95f3d8cfe9ec 100644 +--- a/drivers/gpu/drm/bridge/sil-sii8620.c ++++ b/drivers/gpu/drm/bridge/sil-sii8620.c +@@ -2244,6 +2244,7 @@ static int sii8620_is_packing_required(struct sii8620 *ctx, + } + + static enum drm_mode_status sii8620_mode_valid(struct drm_bridge *bridge, ++ const struct drm_display_info *info, + const struct drm_display_mode *mode) + { + struct sii8620 *ctx = bridge_to_sii8620(bridge); +diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +index 30681398cfb0..b535354150db 100644 +--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c ++++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +@@ -2767,6 +2767,7 @@ static void dw_hdmi_bridge_detach(struct drm_bridge *bridge) + + static enum drm_mode_status + dw_hdmi_bridge_mode_valid(struct drm_bridge *bridge, ++ const struct drm_display_info *info, + const struct drm_display_mode *mode) + { + struct dw_hdmi *hdmi = bridge->driver_private; +diff --git a/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c b/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c +index 5ef0f154aa7b..c223fb9a04cb 100644 +--- a/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c ++++ b/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c +@@ -924,6 +924,7 @@ static void dw_mipi_dsi_bridge_enable(struct drm_bridge *bridge) + + static enum drm_mode_status + dw_mipi_dsi_bridge_mode_valid(struct drm_bridge *bridge, ++ const struct drm_display_info *info, + const struct drm_display_mode *mode) + { + struct dw_mipi_dsi *dsi = bridge_to_dsi(bridge); +diff --git a/drivers/gpu/drm/bridge/tc358767.c b/drivers/gpu/drm/bridge/tc358767.c +index e4c0ea03ae3a..c2777b226c75 100644 +--- a/drivers/gpu/drm/bridge/tc358767.c ++++ b/drivers/gpu/drm/bridge/tc358767.c +@@ -1306,6 +1306,7 @@ static bool tc_bridge_mode_fixup(struct drm_bridge *bridge, + } + + static enum drm_mode_status tc_mode_valid(struct drm_bridge *bridge, ++ const struct drm_display_info *info, + const struct drm_display_mode *mode) + { + struct tc_data *tc = bridge_to_tc(bridge); +diff --git a/drivers/gpu/drm/bridge/tc358768.c b/drivers/gpu/drm/bridge/tc358768.c +index 6650fe4cfc20..4a463fadf743 100644 +--- a/drivers/gpu/drm/bridge/tc358768.c ++++ b/drivers/gpu/drm/bridge/tc358768.c +@@ -529,6 +529,7 @@ static int tc358768_bridge_attach(struct drm_bridge *bridge, + + static enum drm_mode_status + tc358768_bridge_mode_valid(struct drm_bridge *bridge, ++ const struct drm_display_info *info, + const struct drm_display_mode *mode) + { + struct tc358768_priv *priv = bridge_to_tc358768(bridge); +diff --git a/drivers/gpu/drm/bridge/thc63lvd1024.c b/drivers/gpu/drm/bridge/thc63lvd1024.c +index 97d8129760e9..86b06975bfdd 100644 +--- a/drivers/gpu/drm/bridge/thc63lvd1024.c ++++ b/drivers/gpu/drm/bridge/thc63lvd1024.c +@@ -51,6 +51,7 @@ static int thc63_attach(struct drm_bridge *bridge, + } + + static enum drm_mode_status thc63_mode_valid(struct drm_bridge *bridge, ++ const struct drm_display_info *info, + const struct drm_display_mode *mode) + { + struct thc63_dev *thc63 = to_thc63(bridge); +diff --git a/drivers/gpu/drm/bridge/ti-tfp410.c b/drivers/gpu/drm/bridge/ti-tfp410.c +index e3eb6364c0f7..30230c552aeb 100644 +--- a/drivers/gpu/drm/bridge/ti-tfp410.c ++++ b/drivers/gpu/drm/bridge/ti-tfp410.c +@@ -188,6 +188,7 @@ static void tfp410_disable(struct drm_bridge *bridge) + } + + static enum drm_mode_status tfp410_mode_valid(struct drm_bridge *bridge, ++ const struct drm_display_info *info, + const struct drm_display_mode *mode) + { + if (mode->clock < 25000) +diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c +index b78e142a5620..ab9078eaa912 100644 +--- a/drivers/gpu/drm/drm_atomic_helper.c ++++ b/drivers/gpu/drm/drm_atomic_helper.c +@@ -507,7 +507,8 @@ static enum drm_mode_status mode_valid_path(struct drm_connector *connector, + } + + bridge = drm_bridge_chain_get_first_bridge(encoder); +- ret = drm_bridge_chain_mode_valid(bridge, mode); ++ ret = drm_bridge_chain_mode_valid(bridge, &connector->display_info, ++ mode); + if (ret != MODE_OK) { + DRM_DEBUG_ATOMIC("[BRIDGE] mode_valid() failed\n"); + return ret; +diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c +index afdec8e5fc68..8e31af64e8fe 100644 +--- a/drivers/gpu/drm/drm_bridge.c ++++ b/drivers/gpu/drm/drm_bridge.c +@@ -377,6 +377,7 @@ EXPORT_SYMBOL(drm_bridge_chain_mode_fixup); + * drm_bridge_chain_mode_valid - validate the mode against all bridges in the + * encoder chain. + * @bridge: bridge control structure ++ * @info: display info against which the mode shall be validated + * @mode: desired mode to be validated + * + * Calls &drm_bridge_funcs.mode_valid for all the bridges in the encoder +@@ -390,6 +391,7 @@ EXPORT_SYMBOL(drm_bridge_chain_mode_fixup); + */ + enum drm_mode_status + drm_bridge_chain_mode_valid(struct drm_bridge *bridge, ++ const struct drm_display_info *info, + const struct drm_display_mode *mode) + { + struct drm_encoder *encoder; +@@ -404,7 +406,7 @@ drm_bridge_chain_mode_valid(struct drm_bridge *bridge, + if (!bridge->funcs->mode_valid) + continue; + +- ret = bridge->funcs->mode_valid(bridge, mode); ++ ret = bridge->funcs->mode_valid(bridge, info, mode); + if (ret != MODE_OK) + return ret; + } +diff --git a/drivers/gpu/drm/drm_probe_helper.c b/drivers/gpu/drm/drm_probe_helper.c +index 576b4b7dcd89..f5d141e0400f 100644 +--- a/drivers/gpu/drm/drm_probe_helper.c ++++ b/drivers/gpu/drm/drm_probe_helper.c +@@ -114,7 +114,9 @@ drm_mode_validate_pipeline(struct drm_display_mode *mode, + } + + bridge = drm_bridge_chain_get_first_bridge(encoder); +- ret = drm_bridge_chain_mode_valid(bridge, mode); ++ ret = drm_bridge_chain_mode_valid(bridge, ++ &connector->display_info, ++ mode); + if (ret != MODE_OK) { + /* There is also no point in continuing for crtc check + * here. */ +diff --git a/drivers/gpu/drm/i2c/tda998x_drv.c b/drivers/gpu/drm/i2c/tda998x_drv.c +index 9517f522dcb9..50fd119a5276 100644 +--- a/drivers/gpu/drm/i2c/tda998x_drv.c ++++ b/drivers/gpu/drm/i2c/tda998x_drv.c +@@ -1379,6 +1379,7 @@ static void tda998x_bridge_detach(struct drm_bridge *bridge) + } + + static enum drm_mode_status tda998x_bridge_mode_valid(struct drm_bridge *bridge, ++ const struct drm_display_info *info, + const struct drm_display_mode *mode) + { + /* TDA19988 dotclock can go up to 165MHz */ +diff --git a/drivers/gpu/drm/omapdrm/dss/dpi.c b/drivers/gpu/drm/omapdrm/dss/dpi.c +index 5110acb0c6c1..1d2992daef40 100644 +--- a/drivers/gpu/drm/omapdrm/dss/dpi.c ++++ b/drivers/gpu/drm/omapdrm/dss/dpi.c +@@ -434,6 +434,7 @@ static int dpi_bridge_attach(struct drm_bridge *bridge, + + static enum drm_mode_status + dpi_bridge_mode_valid(struct drm_bridge *bridge, ++ const struct drm_display_info *info, + const struct drm_display_mode *mode) + { + struct dpi_data *dpi = drm_bridge_to_dpi(bridge); +diff --git a/drivers/gpu/drm/omapdrm/dss/sdi.c b/drivers/gpu/drm/omapdrm/dss/sdi.c +index 417a8740ad0a..033fd30074b0 100644 +--- a/drivers/gpu/drm/omapdrm/dss/sdi.c ++++ b/drivers/gpu/drm/omapdrm/dss/sdi.c +@@ -140,6 +140,7 @@ static int sdi_bridge_attach(struct drm_bridge *bridge, + + static enum drm_mode_status + sdi_bridge_mode_valid(struct drm_bridge *bridge, ++ const struct drm_display_info *info, + const struct drm_display_mode *mode) + { + struct sdi_device *sdi = drm_bridge_to_sdi(bridge); +diff --git a/drivers/gpu/drm/omapdrm/dss/venc.c b/drivers/gpu/drm/omapdrm/dss/venc.c +index 01ee6c50b663..e0817934ee16 100644 +--- a/drivers/gpu/drm/omapdrm/dss/venc.c ++++ b/drivers/gpu/drm/omapdrm/dss/venc.c +@@ -548,6 +548,7 @@ static int venc_bridge_attach(struct drm_bridge *bridge, + + static enum drm_mode_status + venc_bridge_mode_valid(struct drm_bridge *bridge, ++ const struct drm_display_info *info, + const struct drm_display_mode *mode) + { + switch (venc_get_videomode(mode)) { +diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h +index ea2aa5ebae34..e3d7f36d8c39 100644 +--- a/include/drm/drm_bridge.h ++++ b/include/drm/drm_bridge.h +@@ -35,6 +35,7 @@ + struct drm_bridge; + struct drm_bridge_timings; + struct drm_connector; ++struct drm_display_info; + struct drm_panel; + struct edid; + struct i2c_adapter; +@@ -112,6 +113,7 @@ struct drm_bridge_funcs { + * drm_mode_status Enum + */ + enum drm_mode_status (*mode_valid)(struct drm_bridge *bridge, ++ const struct drm_display_info *info, + const struct drm_display_mode *mode); + + /** +@@ -836,6 +838,7 @@ bool drm_bridge_chain_mode_fixup(struct drm_bridge *bridge, + struct drm_display_mode *adjusted_mode); + enum drm_mode_status + drm_bridge_chain_mode_valid(struct drm_bridge *bridge, ++ const struct drm_display_info *info, + const struct drm_display_mode *mode); + void drm_bridge_chain_disable(struct drm_bridge *bridge); + void drm_bridge_chain_post_disable(struct drm_bridge *bridge); + +From a9ae85591e16f342fc822ce27a514f2879ac4c06 Mon Sep 17 00:00:00 2001 +From: Laurent Pinchart +Date: Tue, 26 May 2020 04:14:49 +0300 +Subject: [PATCH] drm: bridge: dw-hdmi: Pass private data pointer to + .mode_valid() + +Platform glue drivers for dw_hdmi may need to access device-specific +data from their .mode_valid() implementation. They currently have no +clean way to do so, and one driver hacks around it by accessing the +dev_private data of the drm_device retrieved from the connector. + +Add a priv_data void pointer to the dw_hdmi_plat_data structure, and +pass it to the .mode_valid() function. + +Signed-off-by: Laurent Pinchart +Reviewed-by: Neil Armstrong +Signed-off-by: Sam Ravnborg +Link: https://patchwork.freedesktop.org/patch/msgid/20200526011505.31884-12-laurent.pinchart+renesas@ideasonboard.com +(cherry picked from commit 96591a4b93fb8b335941783dd6e7ded9d6d49f09) +--- + drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 6 ++++-- + drivers/gpu/drm/imx/dw_hdmi-imx.c | 6 ++++-- + drivers/gpu/drm/meson/meson_dw_hdmi.c | 3 ++- + drivers/gpu/drm/rcar-du/rcar_dw_hdmi.c | 3 ++- + drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 3 ++- + drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c | 6 ++++-- + drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h | 3 ++- + include/drm/bridge/dw_hdmi.h | 14 ++++++++++++-- + 8 files changed, 32 insertions(+), 12 deletions(-) + +diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +index b535354150db..2b3f203cf467 100644 +--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c ++++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +@@ -2771,6 +2771,7 @@ dw_hdmi_bridge_mode_valid(struct drm_bridge *bridge, + const struct drm_display_mode *mode) + { + struct dw_hdmi *hdmi = bridge->driver_private; ++ const struct dw_hdmi_plat_data *pdata = hdmi->plat_data; + struct drm_connector *connector = &hdmi->connector; + enum drm_mode_status mode_status = MODE_OK; + +@@ -2778,8 +2779,9 @@ dw_hdmi_bridge_mode_valid(struct drm_bridge *bridge, + if (mode->flags & DRM_MODE_FLAG_DBLCLK) + return MODE_BAD; + +- if (hdmi->plat_data->mode_valid) +- mode_status = hdmi->plat_data->mode_valid(connector, mode); ++ if (pdata->mode_valid) ++ mode_status = pdata->mode_valid(hdmi, pdata->priv_data, ++ connector, mode); + + return mode_status; + } +diff --git a/drivers/gpu/drm/imx/dw_hdmi-imx.c b/drivers/gpu/drm/imx/dw_hdmi-imx.c +index 87869b9997a6..ff4fde0eb5f6 100644 +--- a/drivers/gpu/drm/imx/dw_hdmi-imx.c ++++ b/drivers/gpu/drm/imx/dw_hdmi-imx.c +@@ -145,7 +145,8 @@ static const struct drm_encoder_helper_funcs dw_hdmi_imx_encoder_helper_funcs = + }; + + static enum drm_mode_status +-imx6q_hdmi_mode_valid(struct drm_connector *con, ++imx6q_hdmi_mode_valid(struct dw_hdmi *hdmi, void *data, ++ struct drm_connector *con, + const struct drm_display_mode *mode) + { + if (mode->clock < 13500) +@@ -158,7 +159,8 @@ imx6q_hdmi_mode_valid(struct drm_connector *con, + } + + static enum drm_mode_status +-imx6dl_hdmi_mode_valid(struct drm_connector *con, ++imx6dl_hdmi_mode_valid(struct dw_hdmi *hdmi, void *data, ++ struct drm_connector *con, + const struct drm_display_mode *mode) + { + if (mode->clock < 13500) +diff --git a/drivers/gpu/drm/meson/meson_dw_hdmi.c b/drivers/gpu/drm/meson/meson_dw_hdmi.c +index 24a12c453095..fc594213c0e0 100644 +--- a/drivers/gpu/drm/meson/meson_dw_hdmi.c ++++ b/drivers/gpu/drm/meson/meson_dw_hdmi.c +@@ -630,7 +630,8 @@ static irqreturn_t dw_hdmi_top_thread_irq(int irq, void *dev_id) + } + + static enum drm_mode_status +-dw_hdmi_mode_valid(struct drm_connector *connector, ++dw_hdmi_mode_valid(struct dw_hdmi *hdmi, void *data, ++ struct drm_connector *connector, + const struct drm_display_mode *mode) + { + struct meson_drm *priv = connector->dev->dev_private; +diff --git a/drivers/gpu/drm/rcar-du/rcar_dw_hdmi.c b/drivers/gpu/drm/rcar-du/rcar_dw_hdmi.c +index 452461dc96f2..4d837a4d302d 100644 +--- a/drivers/gpu/drm/rcar-du/rcar_dw_hdmi.c ++++ b/drivers/gpu/drm/rcar-du/rcar_dw_hdmi.c +@@ -38,7 +38,8 @@ static const struct rcar_hdmi_phy_params rcar_hdmi_phy_params[] = { + }; + + static enum drm_mode_status +-rcar_hdmi_mode_valid(struct drm_connector *connector, ++rcar_hdmi_mode_valid(struct dw_hdmi *hdmi, void *data, ++ struct drm_connector *connector, + const struct drm_display_mode *mode) + { + /* +diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +index 121aa8a63a76..d08f86783a28 100644 +--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c ++++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +@@ -220,7 +220,8 @@ static int rockchip_hdmi_parse_dt(struct rockchip_hdmi *hdmi) + } + + static enum drm_mode_status +-dw_hdmi_rockchip_mode_valid(struct drm_connector *connector, ++dw_hdmi_rockchip_mode_valid(struct dw_hdmi *hdmi, void *data, ++ struct drm_connector *connector, + const struct drm_display_mode *mode) + { + const struct dw_hdmi_mpll_config *mpll_cfg = rockchip_mpll_cfg; +diff --git a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c +index 972682bb8000..0a3637442ba6 100644 +--- a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c ++++ b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c +@@ -31,7 +31,8 @@ sun8i_dw_hdmi_encoder_helper_funcs = { + }; + + static enum drm_mode_status +-sun8i_dw_hdmi_mode_valid_a83t(struct drm_connector *connector, ++sun8i_dw_hdmi_mode_valid_a83t(struct dw_hdmi *hdmi, void *data, ++ struct drm_connector *connector, + const struct drm_display_mode *mode) + { + if (mode->clock > 297000) +@@ -41,7 +42,8 @@ sun8i_dw_hdmi_mode_valid_a83t(struct drm_connector *connector, + } + + static enum drm_mode_status +-sun8i_dw_hdmi_mode_valid_h6(struct drm_connector *connector, ++sun8i_dw_hdmi_mode_valid_h6(struct dw_hdmi *hdmi, void *data, ++ struct drm_connector *connector, + const struct drm_display_mode *mode) + { + /* +diff --git a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h +index 8e64945167e9..8587b8d2590e 100644 +--- a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h ++++ b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h +@@ -176,7 +176,8 @@ struct sun8i_hdmi_phy { + }; + + struct sun8i_dw_hdmi_quirks { +- enum drm_mode_status (*mode_valid)(struct drm_connector *connector, ++ enum drm_mode_status (*mode_valid)(struct dw_hdmi *hdmi, void *data, ++ struct drm_connector *connector, + const struct drm_display_mode *mode); + unsigned int set_rate : 1; + unsigned int use_drm_infoframe : 1; +diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h +index 0b34a12c4a1c..66a811f75b91 100644 +--- a/include/drm/bridge/dw_hdmi.h ++++ b/include/drm/bridge/dw_hdmi.h +@@ -124,13 +124,23 @@ struct dw_hdmi_phy_ops { + + struct dw_hdmi_plat_data { + struct regmap *regm; +- enum drm_mode_status (*mode_valid)(struct drm_connector *connector, +- const struct drm_display_mode *mode); ++ + unsigned long input_bus_format; + unsigned long input_bus_encoding; + bool use_drm_infoframe; + bool ycbcr_420_allowed; + ++ /* ++ * Private data passed to all the .mode_valid() and .configure_phy() ++ * callback functions. ++ */ ++ void *priv_data; ++ ++ /* Platform-specific mode validation (optional). */ ++ enum drm_mode_status (*mode_valid)(struct dw_hdmi *hdmi, void *data, ++ struct drm_connector *connector, ++ const struct drm_display_mode *mode); ++ + /* Vendor PHY support */ + const struct dw_hdmi_phy_ops *phy_ops; + const char *phy_name; + +From 5a367989e0577a22f143fd9a0ae8bc3c5e187144 Mon Sep 17 00:00:00 2001 +From: Laurent Pinchart +Date: Tue, 26 May 2020 04:14:50 +0300 +Subject: [PATCH] drm: bridge: dw-hdmi: Pass private data pointer to + .configure_phy() + +The .configure_phy() operation takes a dw_hdmi_plat_data pointer as a +context argument. This differs from .mode_valid() that takes a custom +private context pointer, causing possible confusion. Make the +dw_hdmi_plat_data operations more consistent by passing the private +context pointer to .configure_phy() as well. + +Signed-off-by: Laurent Pinchart +Reviewed-by: Neil Armstrong +Signed-off-by: Sam Ravnborg +Link: https://patchwork.freedesktop.org/patch/msgid/20200526011505.31884-13-laurent.pinchart+renesas@ideasonboard.com +(cherry picked from commit 49da7e5d84e3b520355c0b6148d6dc9e5415a13e) +--- + drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 2 +- + drivers/gpu/drm/rcar-du/rcar_dw_hdmi.c | 3 +-- + include/drm/bridge/dw_hdmi.h | 3 +-- + 3 files changed, 3 insertions(+), 5 deletions(-) + +diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +index 2b3f203cf467..6edb60e6c784 100644 +--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c ++++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +@@ -1514,7 +1514,7 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi) + + /* Write to the PHY as configured by the platform */ + if (pdata->configure_phy) +- ret = pdata->configure_phy(hdmi, pdata, mpixelclock); ++ ret = pdata->configure_phy(hdmi, pdata->priv_data, mpixelclock); + else + ret = phy->configure(hdmi, pdata, mpixelclock); + if (ret) { +diff --git a/drivers/gpu/drm/rcar-du/rcar_dw_hdmi.c b/drivers/gpu/drm/rcar-du/rcar_dw_hdmi.c +index 4d837a4d302d..d0dffe55a7cb 100644 +--- a/drivers/gpu/drm/rcar-du/rcar_dw_hdmi.c ++++ b/drivers/gpu/drm/rcar-du/rcar_dw_hdmi.c +@@ -52,8 +52,7 @@ rcar_hdmi_mode_valid(struct dw_hdmi *hdmi, void *data, + return MODE_OK; + } + +-static int rcar_hdmi_phy_configure(struct dw_hdmi *hdmi, +- const struct dw_hdmi_plat_data *pdata, ++static int rcar_hdmi_phy_configure(struct dw_hdmi *hdmi, void *data, + unsigned long mpixelclock) + { + const struct rcar_hdmi_phy_params *params = rcar_hdmi_phy_params; +diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h +index 66a811f75b91..09348c9cbd11 100644 +--- a/include/drm/bridge/dw_hdmi.h ++++ b/include/drm/bridge/dw_hdmi.h +@@ -151,8 +151,7 @@ struct dw_hdmi_plat_data { + const struct dw_hdmi_mpll_config *mpll_cfg; + const struct dw_hdmi_curr_ctrl *cur_ctr; + const struct dw_hdmi_phy_config *phy_config; +- int (*configure_phy)(struct dw_hdmi *hdmi, +- const struct dw_hdmi_plat_data *pdata, ++ int (*configure_phy)(struct dw_hdmi *hdmi, void *data, + unsigned long mpixelclock); + }; + + +From 93a10000d40b44c93674ca8b596019e0b3908541 Mon Sep 17 00:00:00 2001 +From: Laurent Pinchart +Date: Tue, 26 May 2020 04:14:51 +0300 +Subject: [PATCH] drm: bridge: dw-hdmi: Remove unused field from + dw_hdmi_plat_data + +The input_bus_format field of struct dw_hdmi_plat_data is unused. Remove +it. + +Signed-off-by: Laurent Pinchart +Reviewed-by: Neil Armstrong +Signed-off-by: Sam Ravnborg +Link: https://patchwork.freedesktop.org/patch/msgid/20200526011505.31884-14-laurent.pinchart+renesas@ideasonboard.com +(cherry picked from commit 29fc89719d396e81176974ce37e0cc81e23869d8) +--- + drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 5 +---- + include/drm/bridge/dw_hdmi.h | 1 - + 2 files changed, 1 insertion(+), 5 deletions(-) + +diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +index 6edb60e6c784..adc5a95a06e9 100644 +--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c ++++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +@@ -2137,10 +2137,7 @@ static int dw_hdmi_setup(struct dw_hdmi *hdmi, struct drm_display_mode *mode) + hdmi->hdmi_data.video_mode.mpixelrepetitionoutput = 0; + hdmi->hdmi_data.video_mode.mpixelrepetitioninput = 0; + +- if (hdmi->plat_data->input_bus_format) +- hdmi->hdmi_data.enc_in_bus_format = +- hdmi->plat_data->input_bus_format; +- else if (hdmi->hdmi_data.enc_in_bus_format == MEDIA_BUS_FMT_FIXED) ++ if (hdmi->hdmi_data.enc_in_bus_format == MEDIA_BUS_FMT_FIXED) + hdmi->hdmi_data.enc_in_bus_format = MEDIA_BUS_FMT_RGB888_1X24; + + /* TOFIX: Get input encoding from plat data or fallback to none */ +diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h +index 09348c9cbd11..5dfa9d83e2d3 100644 +--- a/include/drm/bridge/dw_hdmi.h ++++ b/include/drm/bridge/dw_hdmi.h +@@ -125,7 +125,6 @@ struct dw_hdmi_phy_ops { + struct dw_hdmi_plat_data { + struct regmap *regm; + +- unsigned long input_bus_format; + unsigned long input_bus_encoding; + bool use_drm_infoframe; + bool ycbcr_420_allowed; + +From 69d79aec4b09b3dce733fedcef1c5f129220e745 Mon Sep 17 00:00:00 2001 +From: Laurent Pinchart +Date: Tue, 26 May 2020 04:14:52 +0300 +Subject: [PATCH] drm: meson: dw-hdmi: Use dw_hdmi context to replace hack + +The meson-dw-hdmi driver needs to access its own context from the +.mode_valid() operation. It currently gets it from the dev_private field +of the drm_device retrieved from the connector, which is a hack. Use the +private data passed to the .mode_valid() operation instead. + +Signed-off-by: Laurent Pinchart +Reviewed-by: Neil Armstrong +Signed-off-by: Sam Ravnborg +Link: https://patchwork.freedesktop.org/patch/msgid/20200526011505.31884-15-laurent.pinchart+renesas@ideasonboard.com +(cherry picked from commit 9bc78d6dc818701e47c5ebd0879877a512f039f0) +--- + drivers/gpu/drm/meson/meson_dw_hdmi.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/drivers/gpu/drm/meson/meson_dw_hdmi.c b/drivers/gpu/drm/meson/meson_dw_hdmi.c +index fc594213c0e0..607bd9f495b1 100644 +--- a/drivers/gpu/drm/meson/meson_dw_hdmi.c ++++ b/drivers/gpu/drm/meson/meson_dw_hdmi.c +@@ -634,7 +634,8 @@ dw_hdmi_mode_valid(struct dw_hdmi *hdmi, void *data, + struct drm_connector *connector, + const struct drm_display_mode *mode) + { +- struct meson_drm *priv = connector->dev->dev_private; ++ struct meson_dw_hdmi *dw_hdmi = data; ++ struct meson_drm *priv = dw_hdmi->priv; + bool is_hdmi2_sink = connector->display_info.hdmi.scdc.supported; + unsigned int phy_freq; + unsigned int vclk_freq; +@@ -693,7 +694,7 @@ dw_hdmi_mode_valid(struct dw_hdmi *hdmi, void *data, + if (mode->flags & DRM_MODE_FLAG_DBLCLK) + venc_freq /= 2; + +- dev_dbg(connector->dev->dev, "%s: vclk:%d phy=%d venc=%d hdmi=%d\n", ++ dev_dbg(dw_hdmi->dev, "%s: vclk:%d phy=%d venc=%d hdmi=%d\n", + __func__, phy_freq, vclk_freq, venc_freq, hdmi_freq); + + return meson_vclk_vic_supported_freq(priv, phy_freq, vclk_freq); +@@ -1066,6 +1067,7 @@ static int meson_dw_hdmi_bind(struct device *dev, struct device *master, + + /* Bridge / Connector */ + ++ dw_plat_data->priv_data = meson_dw_hdmi; + dw_plat_data->mode_valid = dw_hdmi_mode_valid; + dw_plat_data->phy_ops = &meson_dw_hdmi_phy_ops; + dw_plat_data->phy_name = "meson_dw_hdmi_phy"; + +From 76b17d37e5f17f622d947792abcf4477a27b609e Mon Sep 17 00:00:00 2001 +From: Laurent Pinchart +Date: Tue, 26 May 2020 04:14:53 +0300 +Subject: [PATCH] drm: bridge: dw-hdmi: Pass drm_display_info to .mode_valid() + +Replace the drm_connector pointer passed to the .mode_valid() function +with a const drm_display_info pointer, as that's all the function should +need. Use the display info passed to the bridge .mode_valid() operation +instead of retrieving it from the connector, to prepare for make +connector creation optional. + +Signed-off-by: Laurent Pinchart +Reviewed-by: Neil Armstrong +Signed-off-by: Sam Ravnborg +Link: https://patchwork.freedesktop.org/patch/msgid/20200526011505.31884-16-laurent.pinchart+renesas@ideasonboard.com +(cherry picked from commit af05bba0fbe2c07fe500f697080d78d050be2fbf) +--- + drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 5 ++--- + drivers/gpu/drm/imx/dw_hdmi-imx.c | 4 ++-- + drivers/gpu/drm/meson/meson_dw_hdmi.c | 20 ++++++++++---------- + drivers/gpu/drm/rcar-du/rcar_dw_hdmi.c | 2 +- + drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 2 +- + drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c | 4 ++-- + drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h | 2 +- + include/drm/bridge/dw_hdmi.h | 4 ++-- + 8 files changed, 21 insertions(+), 22 deletions(-) + +diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +index adc5a95a06e9..23650e69604c 100644 +--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c ++++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +@@ -2769,7 +2769,6 @@ dw_hdmi_bridge_mode_valid(struct drm_bridge *bridge, + { + struct dw_hdmi *hdmi = bridge->driver_private; + const struct dw_hdmi_plat_data *pdata = hdmi->plat_data; +- struct drm_connector *connector = &hdmi->connector; + enum drm_mode_status mode_status = MODE_OK; + + /* We don't support double-clocked modes */ +@@ -2777,8 +2776,8 @@ dw_hdmi_bridge_mode_valid(struct drm_bridge *bridge, + return MODE_BAD; + + if (pdata->mode_valid) +- mode_status = pdata->mode_valid(hdmi, pdata->priv_data, +- connector, mode); ++ mode_status = pdata->mode_valid(hdmi, pdata->priv_data, info, ++ mode); + + return mode_status; + } +diff --git a/drivers/gpu/drm/imx/dw_hdmi-imx.c b/drivers/gpu/drm/imx/dw_hdmi-imx.c +index ff4fde0eb5f6..71d84c7a5378 100644 +--- a/drivers/gpu/drm/imx/dw_hdmi-imx.c ++++ b/drivers/gpu/drm/imx/dw_hdmi-imx.c +@@ -146,7 +146,7 @@ static const struct drm_encoder_helper_funcs dw_hdmi_imx_encoder_helper_funcs = + + static enum drm_mode_status + imx6q_hdmi_mode_valid(struct dw_hdmi *hdmi, void *data, +- struct drm_connector *con, ++ const struct drm_display_info *info, + const struct drm_display_mode *mode) + { + if (mode->clock < 13500) +@@ -160,7 +160,7 @@ imx6q_hdmi_mode_valid(struct dw_hdmi *hdmi, void *data, + + static enum drm_mode_status + imx6dl_hdmi_mode_valid(struct dw_hdmi *hdmi, void *data, +- struct drm_connector *con, ++ const struct drm_display_info *info, + const struct drm_display_mode *mode) + { + if (mode->clock < 13500) +diff --git a/drivers/gpu/drm/meson/meson_dw_hdmi.c b/drivers/gpu/drm/meson/meson_dw_hdmi.c +index 607bd9f495b1..50b950f5ca3c 100644 +--- a/drivers/gpu/drm/meson/meson_dw_hdmi.c ++++ b/drivers/gpu/drm/meson/meson_dw_hdmi.c +@@ -631,12 +631,12 @@ static irqreturn_t dw_hdmi_top_thread_irq(int irq, void *dev_id) + + static enum drm_mode_status + dw_hdmi_mode_valid(struct dw_hdmi *hdmi, void *data, +- struct drm_connector *connector, ++ const struct drm_display_info *display_info, + const struct drm_display_mode *mode) + { + struct meson_dw_hdmi *dw_hdmi = data; + struct meson_drm *priv = dw_hdmi->priv; +- bool is_hdmi2_sink = connector->display_info.hdmi.scdc.supported; ++ bool is_hdmi2_sink = display_info->hdmi.scdc.supported; + unsigned int phy_freq; + unsigned int vclk_freq; + unsigned int venc_freq; +@@ -647,10 +647,10 @@ dw_hdmi_mode_valid(struct dw_hdmi *hdmi, void *data, + DRM_DEBUG_DRIVER("Modeline " DRM_MODE_FMT "\n", DRM_MODE_ARG(mode)); + + /* If sink does not support 540MHz, reject the non-420 HDMI2 modes */ +- if (connector->display_info.max_tmds_clock && +- mode->clock > connector->display_info.max_tmds_clock && +- !drm_mode_is_420_only(&connector->display_info, mode) && +- !drm_mode_is_420_also(&connector->display_info, mode)) ++ if (display_info->max_tmds_clock && ++ mode->clock > display_info->max_tmds_clock && ++ !drm_mode_is_420_only(display_info, mode) && ++ !drm_mode_is_420_also(display_info, mode)) + return MODE_BAD; + + /* Check against non-VIC supported modes */ +@@ -667,9 +667,9 @@ dw_hdmi_mode_valid(struct dw_hdmi *hdmi, void *data, + vclk_freq = mode->clock; + + /* For 420, pixel clock is half unlike venc clock */ +- if (drm_mode_is_420_only(&connector->display_info, mode) || ++ if (drm_mode_is_420_only(display_info, mode) || + (!is_hdmi2_sink && +- drm_mode_is_420_also(&connector->display_info, mode))) ++ drm_mode_is_420_also(display_info, mode))) + vclk_freq /= 2; + + /* TMDS clock is pixel_clock * 10 */ +@@ -684,9 +684,9 @@ dw_hdmi_mode_valid(struct dw_hdmi *hdmi, void *data, + + /* VENC double pixels for 1080i, 720p and YUV420 modes */ + if (meson_venc_hdmi_venc_repeat(vic) || +- drm_mode_is_420_only(&connector->display_info, mode) || ++ drm_mode_is_420_only(display_info, mode) || + (!is_hdmi2_sink && +- drm_mode_is_420_also(&connector->display_info, mode))) ++ drm_mode_is_420_also(display_info, mode))) + venc_freq *= 2; + + vclk_freq = max(venc_freq, hdmi_freq); +diff --git a/drivers/gpu/drm/rcar-du/rcar_dw_hdmi.c b/drivers/gpu/drm/rcar-du/rcar_dw_hdmi.c +index d0dffe55a7cb..7b8ec8310699 100644 +--- a/drivers/gpu/drm/rcar-du/rcar_dw_hdmi.c ++++ b/drivers/gpu/drm/rcar-du/rcar_dw_hdmi.c +@@ -39,7 +39,7 @@ static const struct rcar_hdmi_phy_params rcar_hdmi_phy_params[] = { + + static enum drm_mode_status + rcar_hdmi_mode_valid(struct dw_hdmi *hdmi, void *data, +- struct drm_connector *connector, ++ const struct drm_display_info *info, + const struct drm_display_mode *mode) + { + /* +diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +index d08f86783a28..d286751bb333 100644 +--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c ++++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +@@ -221,7 +221,7 @@ static int rockchip_hdmi_parse_dt(struct rockchip_hdmi *hdmi) + + static enum drm_mode_status + dw_hdmi_rockchip_mode_valid(struct dw_hdmi *hdmi, void *data, +- struct drm_connector *connector, ++ const struct drm_display_info *info, + const struct drm_display_mode *mode) + { + const struct dw_hdmi_mpll_config *mpll_cfg = rockchip_mpll_cfg; +diff --git a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c +index 0a3637442ba6..d4c08043dd81 100644 +--- a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c ++++ b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c +@@ -32,7 +32,7 @@ sun8i_dw_hdmi_encoder_helper_funcs = { + + static enum drm_mode_status + sun8i_dw_hdmi_mode_valid_a83t(struct dw_hdmi *hdmi, void *data, +- struct drm_connector *connector, ++ const struct drm_display_info *info, + const struct drm_display_mode *mode) + { + if (mode->clock > 297000) +@@ -43,7 +43,7 @@ sun8i_dw_hdmi_mode_valid_a83t(struct dw_hdmi *hdmi, void *data, + + static enum drm_mode_status + sun8i_dw_hdmi_mode_valid_h6(struct dw_hdmi *hdmi, void *data, +- struct drm_connector *connector, ++ const struct drm_display_info *info, + const struct drm_display_mode *mode) + { + /* +diff --git a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h +index 8587b8d2590e..d983746fa194 100644 +--- a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h ++++ b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h +@@ -177,7 +177,7 @@ struct sun8i_hdmi_phy { + + struct sun8i_dw_hdmi_quirks { + enum drm_mode_status (*mode_valid)(struct dw_hdmi *hdmi, void *data, +- struct drm_connector *connector, ++ const struct drm_display_info *info, + const struct drm_display_mode *mode); + unsigned int set_rate : 1; + unsigned int use_drm_infoframe : 1; +diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h +index 5dfa9d83e2d3..fec293b21c2e 100644 +--- a/include/drm/bridge/dw_hdmi.h ++++ b/include/drm/bridge/dw_hdmi.h +@@ -8,7 +8,7 @@ + + #include + +-struct drm_connector; ++struct drm_display_info; + struct drm_display_mode; + struct drm_encoder; + struct dw_hdmi; +@@ -137,7 +137,7 @@ struct dw_hdmi_plat_data { + + /* Platform-specific mode validation (optional). */ + enum drm_mode_status (*mode_valid)(struct dw_hdmi *hdmi, void *data, +- struct drm_connector *connector, ++ const struct drm_display_info *info, + const struct drm_display_mode *mode); + + /* Vendor PHY support */ + +From 799196d6da0801a31a7129bbdae2aa760714b187 Mon Sep 17 00:00:00 2001 +From: Laurent Pinchart +Date: Tue, 26 May 2020 04:14:54 +0300 +Subject: [PATCH] drm: bridge: dw-hdmi: Constify mode argument to + dw_hdmi_phy_ops .init() + +The PHY .init() must not modify the mode it receives. Make the pointer +const to enfore that. + +Signed-off-by: Laurent Pinchart +Reviewed-by: Neil Armstrong +Signed-off-by: Sam Ravnborg +Link: https://patchwork.freedesktop.org/patch/msgid/20200526011505.31884-17-laurent.pinchart+renesas@ideasonboard.com +(cherry picked from commit 35a395f1134bbbd2984dcca28c04f09fbbb8b0a4) +--- + drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 2 +- + drivers/gpu/drm/meson/meson_dw_hdmi.c | 4 ++-- + drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 2 +- + drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c | 2 +- + include/drm/bridge/dw_hdmi.h | 2 +- + 5 files changed, 6 insertions(+), 6 deletions(-) + +diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +index 23650e69604c..6e6a3d95e68e 100644 +--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c ++++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +@@ -1531,7 +1531,7 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi) + } + + static int dw_hdmi_phy_init(struct dw_hdmi *hdmi, void *data, +- struct drm_display_mode *mode) ++ const struct drm_display_mode *mode) + { + int i, ret; + +diff --git a/drivers/gpu/drm/meson/meson_dw_hdmi.c b/drivers/gpu/drm/meson/meson_dw_hdmi.c +index 50b950f5ca3c..a1217df5fe5a 100644 +--- a/drivers/gpu/drm/meson/meson_dw_hdmi.c ++++ b/drivers/gpu/drm/meson/meson_dw_hdmi.c +@@ -297,7 +297,7 @@ static inline void dw_hdmi_dwc_write_bits(struct meson_dw_hdmi *dw_hdmi, + + /* Setup PHY bandwidth modes */ + static void meson_hdmi_phy_setup_mode(struct meson_dw_hdmi *dw_hdmi, +- struct drm_display_mode *mode) ++ const struct drm_display_mode *mode) + { + struct meson_drm *priv = dw_hdmi->priv; + unsigned int pixel_clock = mode->clock; +@@ -427,7 +427,7 @@ static void dw_hdmi_set_vclk(struct meson_dw_hdmi *dw_hdmi, + } + + static int dw_hdmi_phy_init(struct dw_hdmi *hdmi, void *data, +- struct drm_display_mode *mode) ++ const struct drm_display_mode *mode) + { + struct meson_dw_hdmi *dw_hdmi = (struct meson_dw_hdmi *)data; + struct meson_drm *priv = dw_hdmi->priv; +diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +index d286751bb333..10e210f6455d 100644 +--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c ++++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +@@ -312,7 +312,7 @@ static const struct drm_encoder_helper_funcs dw_hdmi_rockchip_encoder_helper_fun + }; + + static int dw_hdmi_rockchip_genphy_init(struct dw_hdmi *dw_hdmi, void *data, +- struct drm_display_mode *mode) ++ const struct drm_display_mode *mode) + { + struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data; + +diff --git a/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c b/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c +index 43643ad31730..8e078cacf063 100644 +--- a/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c ++++ b/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c +@@ -341,7 +341,7 @@ static int sun8i_hdmi_phy_config_h3(struct dw_hdmi *hdmi, + } + + static int sun8i_hdmi_phy_config(struct dw_hdmi *hdmi, void *data, +- struct drm_display_mode *mode) ++ const struct drm_display_mode *mode) + { + struct sun8i_hdmi_phy *phy = (struct sun8i_hdmi_phy *)data; + u32 val = 0; +diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h +index fec293b21c2e..f930d218cc6b 100644 +--- a/include/drm/bridge/dw_hdmi.h ++++ b/include/drm/bridge/dw_hdmi.h +@@ -114,7 +114,7 @@ struct dw_hdmi_phy_config { + + struct dw_hdmi_phy_ops { + int (*init)(struct dw_hdmi *hdmi, void *data, +- struct drm_display_mode *mode); ++ const struct drm_display_mode *mode); + void (*disable)(struct dw_hdmi *hdmi, void *data); + enum drm_connector_status (*read_hpd)(struct dw_hdmi *hdmi, void *data); + void (*update_hpd)(struct dw_hdmi *hdmi, void *data, + +From 39e51f084a6c1b5a94151803063f5d2ec44c2389 Mon Sep 17 00:00:00 2001 +From: Laurent Pinchart +Date: Tue, 26 May 2020 04:14:55 +0300 +Subject: [PATCH] drm: bridge: dw-hdmi: Constify mode argument to internal + functions + +Several internal functions take a drm_display_mode argument to configure +the HDMI encoder or the HDMI PHY. They must not modify the mode, make +the pointer const to enforce that. + +Signed-off-by: Laurent Pinchart +Reviewed-by: Neil Armstrong +Signed-off-by: Sam Ravnborg +Link: https://patchwork.freedesktop.org/patch/msgid/20200526011505.31884-18-laurent.pinchart+renesas@ideasonboard.com +(cherry picked from commit 9fbfa320b435e6f25499a63f7bb74b4fc5341b30) +--- + drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +index 6e6a3d95e68e..5b5f07a23400 100644 +--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c ++++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +@@ -1628,7 +1628,8 @@ static void hdmi_tx_hdcp_config(struct dw_hdmi *hdmi) + HDMI_A_HDCPCFG1_ENCRYPTIONDISABLE_MASK, HDMI_A_HDCPCFG1); + } + +-static void hdmi_config_AVI(struct dw_hdmi *hdmi, struct drm_display_mode *mode) ++static void hdmi_config_AVI(struct dw_hdmi *hdmi, ++ const struct drm_display_mode *mode) + { + struct hdmi_avi_infoframe frame; + u8 val; +@@ -1756,7 +1757,7 @@ static void hdmi_config_AVI(struct dw_hdmi *hdmi, struct drm_display_mode *mode) + } + + static void hdmi_config_vendor_specific_infoframe(struct dw_hdmi *hdmi, +- struct drm_display_mode *mode) ++ const struct drm_display_mode *mode) + { + struct hdmi_vendor_infoframe frame; + u8 buffer[10]; +@@ -2112,7 +2113,8 @@ static void hdmi_disable_overflow_interrupts(struct dw_hdmi *hdmi) + HDMI_IH_MUTE_FC_STAT2); + } + +-static int dw_hdmi_setup(struct dw_hdmi *hdmi, struct drm_display_mode *mode) ++static int dw_hdmi_setup(struct dw_hdmi *hdmi, ++ const struct drm_display_mode *mode) + { + int ret; + + +From 9dd65c0f564ebe5257c3d5322e40200ac254570b Mon Sep 17 00:00:00 2001 +From: Laurent Pinchart +Date: Tue, 26 May 2020 04:14:56 +0300 +Subject: [PATCH] drm: bridge: dw-hdmi: Pass drm_display_info to + dw_hdmi_support_scdc() + +To prepare for making connector creation optional in the driver, pass +the drm_display_info explicitly to dw_hdmi_support_scdc(). The pointer +is passed to the callers where required, particularly to the +dw_hdmi_phy_ops .init() function. + +Signed-off-by: Laurent Pinchart +Reviewed-by: Neil Armstrong +Signed-off-by: Sam Ravnborg +Link: https://patchwork.freedesktop.org/patch/msgid/20200526011505.31884-19-laurent.pinchart+renesas@ideasonboard.com +(cherry picked from commit 7be390d4c0a125266c558c30a3687d931c3b6101) +--- + drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 32 ++++++++++++--------- + drivers/gpu/drm/meson/meson_dw_hdmi.c | 3 +- + drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 1 + + drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c | 1 + + include/drm/bridge/dw_hdmi.h | 4 ++- + 5 files changed, 26 insertions(+), 15 deletions(-) + +diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +index 5b5f07a23400..a18794cce0d8 100644 +--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c ++++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +@@ -1241,10 +1241,9 @@ void dw_hdmi_phy_i2c_write(struct dw_hdmi *hdmi, unsigned short data, + EXPORT_SYMBOL_GPL(dw_hdmi_phy_i2c_write); + + /* Filter out invalid setups to avoid configuring SCDC and scrambling */ +-static bool dw_hdmi_support_scdc(struct dw_hdmi *hdmi) ++static bool dw_hdmi_support_scdc(struct dw_hdmi *hdmi, ++ const struct drm_display_info *display) + { +- struct drm_display_info *display = &hdmi->connector.display_info; +- + /* Completely disable SCDC support for older controllers */ + if (hdmi->version < 0x200a) + return false; +@@ -1282,12 +1281,13 @@ static bool dw_hdmi_support_scdc(struct dw_hdmi *hdmi) + * helper should called right before enabling the TMDS Clock and Data in + * the PHY configuration callback. + */ +-void dw_hdmi_set_high_tmds_clock_ratio(struct dw_hdmi *hdmi) ++void dw_hdmi_set_high_tmds_clock_ratio(struct dw_hdmi *hdmi, ++ const struct drm_display_info *display) + { + unsigned long mtmdsclock = hdmi->hdmi_data.video_mode.mtmdsclock; + + /* Control for TMDS Bit Period/TMDS Clock-Period Ratio */ +- if (dw_hdmi_support_scdc(hdmi)) { ++ if (dw_hdmi_support_scdc(hdmi, display)) { + if (mtmdsclock > HDMI14_MAX_TMDSCLK) + drm_scdc_set_high_tmds_clock_ratio(hdmi->ddc, 1); + else +@@ -1490,7 +1490,8 @@ static int hdmi_phy_configure_dwc_hdmi_3d_tx(struct dw_hdmi *hdmi, + return 0; + } + +-static int hdmi_phy_configure(struct dw_hdmi *hdmi) ++static int hdmi_phy_configure(struct dw_hdmi *hdmi, ++ const struct drm_display_info *display) + { + const struct dw_hdmi_phy_data *phy = hdmi->phy.data; + const struct dw_hdmi_plat_data *pdata = hdmi->plat_data; +@@ -1500,7 +1501,7 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi) + + dw_hdmi_phy_power_off(hdmi); + +- dw_hdmi_set_high_tmds_clock_ratio(hdmi); ++ dw_hdmi_set_high_tmds_clock_ratio(hdmi, display); + + /* Leave low power consumption mode by asserting SVSRET. */ + if (phy->has_svsret) +@@ -1531,6 +1532,7 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi) + } + + static int dw_hdmi_phy_init(struct dw_hdmi *hdmi, void *data, ++ const struct drm_display_info *display, + const struct drm_display_mode *mode) + { + int i, ret; +@@ -1540,7 +1542,7 @@ static int dw_hdmi_phy_init(struct dw_hdmi *hdmi, void *data, + dw_hdmi_phy_sel_data_en_pol(hdmi, 1); + dw_hdmi_phy_sel_interface_control(hdmi, 0); + +- ret = hdmi_phy_configure(hdmi); ++ ret = hdmi_phy_configure(hdmi, display); + if (ret) + return ret; + } +@@ -1846,10 +1848,11 @@ static void hdmi_config_drm_infoframe(struct dw_hdmi *hdmi) + } + + static void hdmi_av_composer(struct dw_hdmi *hdmi, ++ const struct drm_display_info *display, + const struct drm_display_mode *mode) + { + u8 inv_val, bytes; +- struct drm_hdmi_info *hdmi_info = &hdmi->connector.display_info.hdmi; ++ const struct drm_hdmi_info *hdmi_info = &display->hdmi; + struct hdmi_vmode *vmode = &hdmi->hdmi_data.video_mode; + int hblank, vblank, h_de_hs, v_de_vs, hsync_len, vsync_len; + unsigned int vdisplay, hdisplay; +@@ -1882,7 +1885,7 @@ static void hdmi_av_composer(struct dw_hdmi *hdmi, + + /* Set up HDMI_FC_INVIDCONF */ + inv_val = (hdmi->hdmi_data.hdcp_enable || +- (dw_hdmi_support_scdc(hdmi) && ++ (dw_hdmi_support_scdc(hdmi, display) && + (vmode->mtmdsclock > HDMI14_MAX_TMDSCLK || + hdmi_info->scdc.scrambling.low_rates)) ? + HDMI_FC_INVIDCONF_HDCP_KEEPOUT_ACTIVE : +@@ -1950,7 +1953,7 @@ static void hdmi_av_composer(struct dw_hdmi *hdmi, + } + + /* Scrambling Control */ +- if (dw_hdmi_support_scdc(hdmi)) { ++ if (dw_hdmi_support_scdc(hdmi, display)) { + if (vmode->mtmdsclock > HDMI14_MAX_TMDSCLK || + hdmi_info->scdc.scrambling.low_rates) { + /* +@@ -2116,6 +2119,7 @@ static void hdmi_disable_overflow_interrupts(struct dw_hdmi *hdmi) + static int dw_hdmi_setup(struct dw_hdmi *hdmi, + const struct drm_display_mode *mode) + { ++ struct drm_connector *connector = &hdmi->connector; + int ret; + + hdmi_disable_overflow_interrupts(hdmi); +@@ -2161,10 +2165,12 @@ static int dw_hdmi_setup(struct dw_hdmi *hdmi, + hdmi->hdmi_data.video_mode.mdataenablepolarity = true; + + /* HDMI Initialization Step B.1 */ +- hdmi_av_composer(hdmi, mode); ++ hdmi_av_composer(hdmi, &connector->display_info, mode); + + /* HDMI Initializateion Step B.2 */ +- ret = hdmi->phy.ops->init(hdmi, hdmi->phy.data, &hdmi->previous_mode); ++ ret = hdmi->phy.ops->init(hdmi, hdmi->phy.data, ++ &connector->display_info, ++ &hdmi->previous_mode); + if (ret) + return ret; + hdmi->phy.enabled = true; +diff --git a/drivers/gpu/drm/meson/meson_dw_hdmi.c b/drivers/gpu/drm/meson/meson_dw_hdmi.c +index a1217df5fe5a..29a8ff41595d 100644 +--- a/drivers/gpu/drm/meson/meson_dw_hdmi.c ++++ b/drivers/gpu/drm/meson/meson_dw_hdmi.c +@@ -427,6 +427,7 @@ static void dw_hdmi_set_vclk(struct meson_dw_hdmi *dw_hdmi, + } + + static int dw_hdmi_phy_init(struct dw_hdmi *hdmi, void *data, ++ const struct drm_display_info *display, + const struct drm_display_mode *mode) + { + struct meson_dw_hdmi *dw_hdmi = (struct meson_dw_hdmi *)data; +@@ -496,7 +497,7 @@ static int dw_hdmi_phy_init(struct dw_hdmi *hdmi, void *data, + /* Disable clock, fifo, fifo_wr */ + regmap_update_bits(priv->hhi, HHI_HDMI_PHY_CNTL1, 0xf, 0); + +- dw_hdmi_set_high_tmds_clock_ratio(hdmi); ++ dw_hdmi_set_high_tmds_clock_ratio(hdmi, display); + + msleep(100); + +diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +index 10e210f6455d..23de359a1dec 100644 +--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c ++++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +@@ -312,6 +312,7 @@ static const struct drm_encoder_helper_funcs dw_hdmi_rockchip_encoder_helper_fun + }; + + static int dw_hdmi_rockchip_genphy_init(struct dw_hdmi *dw_hdmi, void *data, ++ const struct drm_display_info *display, + const struct drm_display_mode *mode) + { + struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data; +diff --git a/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c b/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c +index 8e078cacf063..156d00e5165b 100644 +--- a/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c ++++ b/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c +@@ -341,6 +341,7 @@ static int sun8i_hdmi_phy_config_h3(struct dw_hdmi *hdmi, + } + + static int sun8i_hdmi_phy_config(struct dw_hdmi *hdmi, void *data, ++ const struct drm_display_info *display, + const struct drm_display_mode *mode) + { + struct sun8i_hdmi_phy *phy = (struct sun8i_hdmi_phy *)data; +diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h +index f930d218cc6b..ea34ca146b82 100644 +--- a/include/drm/bridge/dw_hdmi.h ++++ b/include/drm/bridge/dw_hdmi.h +@@ -114,6 +114,7 @@ struct dw_hdmi_phy_config { + + struct dw_hdmi_phy_ops { + int (*init)(struct dw_hdmi *hdmi, void *data, ++ const struct drm_display_info *display, + const struct drm_display_mode *mode); + void (*disable)(struct dw_hdmi *hdmi, void *data); + enum drm_connector_status (*read_hpd)(struct dw_hdmi *hdmi, void *data); +@@ -174,7 +175,8 @@ void dw_hdmi_set_channel_status(struct dw_hdmi *hdmi, u8 *channel_status); + void dw_hdmi_set_channel_allocation(struct dw_hdmi *hdmi, unsigned int ca); + void dw_hdmi_audio_enable(struct dw_hdmi *hdmi); + void dw_hdmi_audio_disable(struct dw_hdmi *hdmi); +-void dw_hdmi_set_high_tmds_clock_ratio(struct dw_hdmi *hdmi); ++void dw_hdmi_set_high_tmds_clock_ratio(struct dw_hdmi *hdmi, ++ const struct drm_display_info *display); + + /* PHY configuration */ + void dw_hdmi_phy_i2c_set_addr(struct dw_hdmi *hdmi, u8 address); + +From 57c01c57d5aff20753b3c418abb52b3b317c0166 Mon Sep 17 00:00:00 2001 +From: Laurent Pinchart +Date: Tue, 26 May 2020 04:14:57 +0300 +Subject: [PATCH] drm: bridge: dw-hdmi: Split connector creation to a separate + function + +Isolate all the code related to connector creation to a new +dw_hdmi_connector_create() function, to prepare for making connector +creation optional. + +Signed-off-by: Laurent Pinchart +Reviewed-by: Neil Armstrong +Signed-off-by: Sam Ravnborg +Link: https://patchwork.freedesktop.org/patch/msgid/20200526011505.31884-20-laurent.pinchart+renesas@ideasonboard.com +(cherry picked from commit 3f588fda4b80dbd7dafa08b0e16fd72a42676e3c) +--- + drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 107 +++++++++++++--------- + 1 file changed, 62 insertions(+), 45 deletions(-) + +diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +index a18794cce0d8..35d38b644912 100644 +--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c ++++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +@@ -2317,6 +2317,10 @@ static void dw_hdmi_update_phy_mask(struct dw_hdmi *hdmi) + hdmi->rxsense); + } + ++/* ----------------------------------------------------------------------------- ++ * DRM Connector Operations ++ */ ++ + static enum drm_connector_status + dw_hdmi_connector_detect(struct drm_connector *connector, bool force) + { +@@ -2438,6 +2442,59 @@ static const struct drm_connector_helper_funcs dw_hdmi_connector_helper_funcs = + .atomic_check = dw_hdmi_connector_atomic_check, + }; + ++static int dw_hdmi_connector_create(struct dw_hdmi *hdmi) ++{ ++ struct drm_connector *connector = &hdmi->connector; ++ struct cec_connector_info conn_info; ++ struct cec_notifier *notifier; ++ ++ if (hdmi->version >= 0x200a) ++ connector->ycbcr_420_allowed = ++ hdmi->plat_data->ycbcr_420_allowed; ++ else ++ connector->ycbcr_420_allowed = false; ++ ++ connector->interlace_allowed = 1; ++ connector->polled = DRM_CONNECTOR_POLL_HPD; ++ ++ drm_connector_helper_add(connector, &dw_hdmi_connector_helper_funcs); ++ ++ drm_connector_init_with_ddc(hdmi->bridge.dev, connector, ++ &dw_hdmi_connector_funcs, ++ DRM_MODE_CONNECTOR_HDMIA, ++ hdmi->ddc); ++ ++ /* ++ * drm_connector_attach_max_bpc_property() requires the ++ * connector to have a state. ++ */ ++ drm_atomic_helper_connector_reset(connector); ++ ++ drm_connector_attach_max_bpc_property(connector, 8, 16); ++ ++ if (hdmi->version >= 0x200a && hdmi->plat_data->use_drm_infoframe) ++ drm_object_attach_property(&connector->base, ++ connector->dev->mode_config.hdr_output_metadata_property, 0); ++ ++ drm_connector_attach_encoder(connector, hdmi->bridge.encoder); ++ ++ cec_fill_conn_info_from_drm(&conn_info, connector); ++ ++ notifier = cec_notifier_conn_register(hdmi->dev, NULL, &conn_info); ++ if (!notifier) ++ return -ENOMEM; ++ ++ mutex_lock(&hdmi->cec_notifier_mutex); ++ hdmi->cec_notifier = notifier; ++ mutex_unlock(&hdmi->cec_notifier_mutex); ++ ++ return 0; ++} ++ ++/* ----------------------------------------------------------------------------- ++ * DRM Bridge Operations ++ */ ++ + /* + * Possible output formats : + * - MEDIA_BUS_FMT_UYYVYY16_0_5X48, +@@ -2713,51 +2770,13 @@ static int dw_hdmi_bridge_attach(struct drm_bridge *bridge, + enum drm_bridge_attach_flags flags) + { + struct dw_hdmi *hdmi = bridge->driver_private; +- struct drm_encoder *encoder = bridge->encoder; +- struct drm_connector *connector = &hdmi->connector; +- struct cec_connector_info conn_info; +- struct cec_notifier *notifier; + + if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR) { + DRM_ERROR("Fix bridge driver to make connector optional!"); + return -EINVAL; + } + +- connector->interlace_allowed = 1; +- connector->polled = DRM_CONNECTOR_POLL_HPD; +- +- drm_connector_helper_add(connector, &dw_hdmi_connector_helper_funcs); +- +- drm_connector_init_with_ddc(bridge->dev, connector, +- &dw_hdmi_connector_funcs, +- DRM_MODE_CONNECTOR_HDMIA, +- hdmi->ddc); +- +- /* +- * drm_connector_attach_max_bpc_property() requires the +- * connector to have a state. +- */ +- drm_atomic_helper_connector_reset(connector); +- +- drm_connector_attach_max_bpc_property(connector, 8, 16); +- +- if (hdmi->version >= 0x200a && hdmi->plat_data->use_drm_infoframe) +- drm_object_attach_property(&connector->base, +- connector->dev->mode_config.hdr_output_metadata_property, 0); +- +- drm_connector_attach_encoder(connector, encoder); +- +- cec_fill_conn_info_from_drm(&conn_info, connector); +- +- notifier = cec_notifier_conn_register(hdmi->dev, NULL, &conn_info); +- if (!notifier) +- return -ENOMEM; +- +- mutex_lock(&hdmi->cec_notifier_mutex); +- hdmi->cec_notifier = notifier; +- mutex_unlock(&hdmi->cec_notifier_mutex); +- +- return 0; ++ return dw_hdmi_connector_create(hdmi); + } + + static void dw_hdmi_bridge_detach(struct drm_bridge *bridge) +@@ -2841,6 +2860,10 @@ static const struct drm_bridge_funcs dw_hdmi_bridge_funcs = { + .mode_valid = dw_hdmi_bridge_mode_valid, + }; + ++/* ----------------------------------------------------------------------------- ++ * IRQ Handling ++ */ ++ + static irqreturn_t dw_hdmi_i2c_irq(struct dw_hdmi *hdmi) + { + struct dw_hdmi_i2c *i2c = hdmi->i2c; +@@ -3303,12 +3326,6 @@ __dw_hdmi_probe(struct platform_device *pdev, + hdmi->bridge.of_node = pdev->dev.of_node; + #endif + +- if (hdmi->version >= 0x200a) +- hdmi->connector.ycbcr_420_allowed = +- hdmi->plat_data->ycbcr_420_allowed; +- else +- hdmi->connector.ycbcr_420_allowed = false; +- + memset(&pdevinfo, 0, sizeof(pdevinfo)); + pdevinfo.parent = dev; + pdevinfo.id = PLATFORM_DEVID_AUTO; + +From a3b8c4bc7907f025862b25aca04c9edc999a44e5 Mon Sep 17 00:00:00 2001 +From: Laurent Pinchart +Date: Tue, 26 May 2020 04:14:58 +0300 +Subject: [PATCH] drm: bridge: dw-hdmi: Store current connector in struct + dw_hdmi + +Store the connector that the bridge is currently wired to in the dw_hdmi +structure. This is currently identical to the connector field, but will +differ once the driver supports disabling connector creation. + +Signed-off-by: Laurent Pinchart +Reviewed-by: Neil Armstrong +Signed-off-by: Sam Ravnborg +Link: https://patchwork.freedesktop.org/patch/msgid/20200526011505.31884-21-laurent.pinchart+renesas@ideasonboard.com +(cherry picked from commit ca7b6b7176ffea4d07afbd98ede7a94fb0f68fa1) +--- + drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 18 ++++++++++++++---- + 1 file changed, 14 insertions(+), 4 deletions(-) + +diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +index 35d38b644912..16bffedb4715 100644 +--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c ++++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +@@ -181,6 +181,7 @@ struct dw_hdmi { + + struct mutex mutex; /* for state below and previous_mode */ + enum drm_connector_force force; /* mutex-protected force state */ ++ struct drm_connector *curr_conn;/* current connector (only valid when !disabled) */ + bool disabled; /* DRM has disabled our bridge */ + bool bridge_is_on; /* indicates the bridge is on */ + bool rxsense; /* rxsense state */ +@@ -2823,23 +2824,32 @@ static void dw_hdmi_bridge_mode_set(struct drm_bridge *bridge, + mutex_unlock(&hdmi->mutex); + } + +-static void dw_hdmi_bridge_disable(struct drm_bridge *bridge) ++static void dw_hdmi_bridge_atomic_disable(struct drm_bridge *bridge, ++ struct drm_bridge_state *old_state) + { + struct dw_hdmi *hdmi = bridge->driver_private; + + mutex_lock(&hdmi->mutex); + hdmi->disabled = true; ++ hdmi->curr_conn = NULL; + dw_hdmi_update_power(hdmi); + dw_hdmi_update_phy_mask(hdmi); + mutex_unlock(&hdmi->mutex); + } + +-static void dw_hdmi_bridge_enable(struct drm_bridge *bridge) ++static void dw_hdmi_bridge_atomic_enable(struct drm_bridge *bridge, ++ struct drm_bridge_state *old_state) + { + struct dw_hdmi *hdmi = bridge->driver_private; ++ struct drm_atomic_state *state = old_state->base.state; ++ struct drm_connector *connector; ++ ++ connector = drm_atomic_get_new_connector_for_encoder(state, ++ bridge->encoder); + + mutex_lock(&hdmi->mutex); + hdmi->disabled = false; ++ hdmi->curr_conn = connector; + dw_hdmi_update_power(hdmi); + dw_hdmi_update_phy_mask(hdmi); + mutex_unlock(&hdmi->mutex); +@@ -2854,8 +2864,8 @@ static const struct drm_bridge_funcs dw_hdmi_bridge_funcs = { + .atomic_check = dw_hdmi_bridge_atomic_check, + .atomic_get_output_bus_fmts = dw_hdmi_bridge_atomic_get_output_bus_fmts, + .atomic_get_input_bus_fmts = dw_hdmi_bridge_atomic_get_input_bus_fmts, +- .enable = dw_hdmi_bridge_enable, +- .disable = dw_hdmi_bridge_disable, ++ .atomic_enable = dw_hdmi_bridge_atomic_enable, ++ .atomic_disable = dw_hdmi_bridge_atomic_disable, + .mode_set = dw_hdmi_bridge_mode_set, + .mode_valid = dw_hdmi_bridge_mode_valid, + }; + +From 30b1907401f2475b4b7e8341269a36ef3a45a6bb Mon Sep 17 00:00:00 2001 +From: Laurent Pinchart +Date: Tue, 26 May 2020 04:14:59 +0300 +Subject: [PATCH] drm: bridge: dw-hdmi: Pass drm_connector to internal + functions as needed + +To prepare for making connector creation optional in the driver, pass +the drm_connector explicitly to the internal functions that require it. +The functions that still access the connector from the dw_hdmi structure +are dw_hdmi_connector_create() and __dw_hdmi_probe(). The former access +is expected, as that's where the internal connector is created. The +latter will be addressed separately. + +Signed-off-by: Laurent Pinchart +Reviewed-by: Neil Armstrong +Signed-off-by: Sam Ravnborg +Link: https://patchwork.freedesktop.org/patch/msgid/20200526011505.31884-22-laurent.pinchart+renesas@ideasonboard.com +(cherry picked from commit 81980037fb275d9db1bbb0239682d707e8dd62a0) +--- + drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 31 +++++++++++++---------- + 1 file changed, 18 insertions(+), 13 deletions(-) + +diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +index 16bffedb4715..b69c14b9de62 100644 +--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c ++++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +@@ -1632,18 +1632,17 @@ static void hdmi_tx_hdcp_config(struct dw_hdmi *hdmi) + } + + static void hdmi_config_AVI(struct dw_hdmi *hdmi, ++ const struct drm_connector *connector, + const struct drm_display_mode *mode) + { + struct hdmi_avi_infoframe frame; + u8 val; + + /* Initialise info frame from DRM mode */ +- drm_hdmi_avi_infoframe_from_display_mode(&frame, +- &hdmi->connector, mode); ++ drm_hdmi_avi_infoframe_from_display_mode(&frame, connector, mode); + + if (hdmi_bus_fmt_is_rgb(hdmi->hdmi_data.enc_out_bus_format)) { +- drm_hdmi_avi_infoframe_quant_range(&frame, &hdmi->connector, +- mode, ++ drm_hdmi_avi_infoframe_quant_range(&frame, connector, mode, + hdmi->hdmi_data.rgb_limited_range ? + HDMI_QUANTIZATION_RANGE_LIMITED : + HDMI_QUANTIZATION_RANGE_FULL); +@@ -1760,14 +1759,14 @@ static void hdmi_config_AVI(struct dw_hdmi *hdmi, + } + + static void hdmi_config_vendor_specific_infoframe(struct dw_hdmi *hdmi, ++ const struct drm_connector *connector, + const struct drm_display_mode *mode) + { + struct hdmi_vendor_infoframe frame; + u8 buffer[10]; + ssize_t err; + +- err = drm_hdmi_vendor_infoframe_from_display_mode(&frame, +- &hdmi->connector, ++ err = drm_hdmi_vendor_infoframe_from_display_mode(&frame, connector, + mode); + if (err < 0) + /* +@@ -1813,9 +1812,10 @@ static void hdmi_config_vendor_specific_infoframe(struct dw_hdmi *hdmi, + HDMI_FC_DATAUTO0_VSD_MASK); + } + +-static void hdmi_config_drm_infoframe(struct dw_hdmi *hdmi) ++static void hdmi_config_drm_infoframe(struct dw_hdmi *hdmi, ++ const struct drm_connector *connector) + { +- const struct drm_connector_state *conn_state = hdmi->connector.state; ++ const struct drm_connector_state *conn_state = connector->state; + struct hdmi_drm_infoframe frame; + u8 buffer[30]; + ssize_t err; +@@ -2118,9 +2118,9 @@ static void hdmi_disable_overflow_interrupts(struct dw_hdmi *hdmi) + } + + static int dw_hdmi_setup(struct dw_hdmi *hdmi, ++ const struct drm_connector *connector, + const struct drm_display_mode *mode) + { +- struct drm_connector *connector = &hdmi->connector; + int ret; + + hdmi_disable_overflow_interrupts(hdmi); +@@ -2192,9 +2192,9 @@ static int dw_hdmi_setup(struct dw_hdmi *hdmi, + dev_dbg(hdmi->dev, "%s HDMI mode\n", __func__); + + /* HDMI Initialization Step F - Configure AVI InfoFrame */ +- hdmi_config_AVI(hdmi, mode); +- hdmi_config_vendor_specific_infoframe(hdmi, mode); +- hdmi_config_drm_infoframe(hdmi); ++ hdmi_config_AVI(hdmi, connector, mode); ++ hdmi_config_vendor_specific_infoframe(hdmi, connector, mode); ++ hdmi_config_drm_infoframe(hdmi, connector); + } else { + dev_dbg(hdmi->dev, "%s DVI mode\n", __func__); + } +@@ -2263,7 +2263,12 @@ static void initialize_hdmi_ih_mutes(struct dw_hdmi *hdmi) + static void dw_hdmi_poweron(struct dw_hdmi *hdmi) + { + hdmi->bridge_is_on = true; +- dw_hdmi_setup(hdmi, &hdmi->previous_mode); ++ ++ /* ++ * The curr_conn field is guaranteed to be valid here, as this function ++ * is only be called when !hdmi->disabled. ++ */ ++ dw_hdmi_setup(hdmi, hdmi->curr_conn, &hdmi->previous_mode); + } + + static void dw_hdmi_poweroff(struct dw_hdmi *hdmi) + +From 26ccb66a87e10784ccfc8366494769888f21ebf2 Mon Sep 17 00:00:00 2001 +From: Laurent Pinchart +Date: Tue, 26 May 2020 04:15:00 +0300 +Subject: [PATCH] drm: bridge: dw-hdmi: Make connector creation optional + +Implement the drm_bridge_funcs .detect() and .get_edid() operations, and +call drm_bridge_hpd_notify() notify to report HPD. This provides the +necessary API to support disabling connector creation, do so by +accepting DRM_BRIDGE_ATTACH_NO_CONNECTOR in dw_hdmi_bridge_attach(). + +Signed-off-by: Laurent Pinchart +Reviewed-by: Neil Armstrong +Signed-off-by: Sam Ravnborg +Link: https://patchwork.freedesktop.org/patch/msgid/20200526011505.31884-23-laurent.pinchart+renesas@ideasonboard.com +(cherry picked from commit ec971aaa6775cff555b4f58777ceab1d9a8370e0) +--- + drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 104 +++++++++++++++------- + 1 file changed, 74 insertions(+), 30 deletions(-) + +diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +index b69c14b9de62..6148a022569a 100644 +--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c ++++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +@@ -2323,15 +2323,8 @@ static void dw_hdmi_update_phy_mask(struct dw_hdmi *hdmi) + hdmi->rxsense); + } + +-/* ----------------------------------------------------------------------------- +- * DRM Connector Operations +- */ +- +-static enum drm_connector_status +-dw_hdmi_connector_detect(struct drm_connector *connector, bool force) ++static enum drm_connector_status dw_hdmi_detect(struct dw_hdmi *hdmi) + { +- struct dw_hdmi *hdmi = container_of(connector, struct dw_hdmi, +- connector); + enum drm_connector_status result; + + mutex_lock(&hdmi->mutex); +@@ -2354,31 +2347,57 @@ dw_hdmi_connector_detect(struct drm_connector *connector, bool force) + return result; + } + +-static int dw_hdmi_connector_get_modes(struct drm_connector *connector) ++static struct edid *dw_hdmi_get_edid(struct dw_hdmi *hdmi, ++ struct drm_connector *connector) + { +- struct dw_hdmi *hdmi = container_of(connector, struct dw_hdmi, +- connector); + struct edid *edid; +- int ret = 0; + + if (!hdmi->ddc) +- return 0; ++ return NULL; + + edid = drm_get_edid(connector, hdmi->ddc); +- if (edid) { +- dev_dbg(hdmi->dev, "got edid: width[%d] x height[%d]\n", +- edid->width_cm, edid->height_cm); +- +- hdmi->sink_is_hdmi = drm_detect_hdmi_monitor(edid); +- hdmi->sink_has_audio = drm_detect_monitor_audio(edid); +- drm_connector_update_edid_property(connector, edid); +- cec_notifier_set_phys_addr_from_edid(hdmi->cec_notifier, edid); +- ret = drm_add_edid_modes(connector, edid); +- kfree(edid); +- } else { ++ if (!edid) { + dev_dbg(hdmi->dev, "failed to get edid\n"); ++ return NULL; + } + ++ dev_dbg(hdmi->dev, "got edid: width[%d] x height[%d]\n", ++ edid->width_cm, edid->height_cm); ++ ++ hdmi->sink_is_hdmi = drm_detect_hdmi_monitor(edid); ++ hdmi->sink_has_audio = drm_detect_monitor_audio(edid); ++ ++ return edid; ++} ++ ++/* ----------------------------------------------------------------------------- ++ * DRM Connector Operations ++ */ ++ ++static enum drm_connector_status ++dw_hdmi_connector_detect(struct drm_connector *connector, bool force) ++{ ++ struct dw_hdmi *hdmi = container_of(connector, struct dw_hdmi, ++ connector); ++ return dw_hdmi_detect(hdmi); ++} ++ ++static int dw_hdmi_connector_get_modes(struct drm_connector *connector) ++{ ++ struct dw_hdmi *hdmi = container_of(connector, struct dw_hdmi, ++ connector); ++ struct edid *edid; ++ int ret; ++ ++ edid = dw_hdmi_get_edid(hdmi, connector); ++ if (!edid) ++ return 0; ++ ++ drm_connector_update_edid_property(connector, edid); ++ cec_notifier_set_phys_addr_from_edid(hdmi->cec_notifier, edid); ++ ret = drm_add_edid_modes(connector, edid); ++ kfree(edid); ++ + return ret; + } + +@@ -2777,10 +2796,8 @@ static int dw_hdmi_bridge_attach(struct drm_bridge *bridge, + { + struct dw_hdmi *hdmi = bridge->driver_private; + +- if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR) { +- DRM_ERROR("Fix bridge driver to make connector optional!"); +- return -EINVAL; +- } ++ if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR) ++ return 0; + + return dw_hdmi_connector_create(hdmi); + } +@@ -2860,6 +2877,21 @@ static void dw_hdmi_bridge_atomic_enable(struct drm_bridge *bridge, + mutex_unlock(&hdmi->mutex); + } + ++static enum drm_connector_status dw_hdmi_bridge_detect(struct drm_bridge *bridge) ++{ ++ struct dw_hdmi *hdmi = bridge->driver_private; ++ ++ return dw_hdmi_detect(hdmi); ++} ++ ++static struct edid *dw_hdmi_bridge_get_edid(struct drm_bridge *bridge, ++ struct drm_connector *connector) ++{ ++ struct dw_hdmi *hdmi = bridge->driver_private; ++ ++ return dw_hdmi_get_edid(hdmi, connector); ++} ++ + static const struct drm_bridge_funcs dw_hdmi_bridge_funcs = { + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, +@@ -2873,6 +2905,8 @@ static const struct drm_bridge_funcs dw_hdmi_bridge_funcs = { + .atomic_disable = dw_hdmi_bridge_atomic_disable, + .mode_set = dw_hdmi_bridge_mode_set, + .mode_valid = dw_hdmi_bridge_mode_valid, ++ .detect = dw_hdmi_bridge_detect, ++ .get_edid = dw_hdmi_bridge_get_edid, + }; + + /* ----------------------------------------------------------------------------- +@@ -2988,10 +3022,18 @@ static irqreturn_t dw_hdmi_irq(int irq, void *dev_id) + } + + if (intr_stat & HDMI_IH_PHY_STAT0_HPD) { ++ enum drm_connector_status status = phy_int_pol & HDMI_PHY_HPD ++ ? connector_status_connected ++ : connector_status_disconnected; ++ + dev_dbg(hdmi->dev, "EVENT=%s\n", +- phy_int_pol & HDMI_PHY_HPD ? "plugin" : "plugout"); +- if (hdmi->bridge.dev) ++ status == connector_status_connected ? ++ "plugin" : "plugout"); ++ ++ if (hdmi->bridge.dev) { + drm_helper_hpd_irq_event(hdmi->bridge.dev); ++ drm_bridge_hpd_notify(&hdmi->bridge, status); ++ } + } + + hdmi_writeb(hdmi, intr_stat, HDMI_IH_PHY_STAT0); +@@ -3337,6 +3379,8 @@ __dw_hdmi_probe(struct platform_device *pdev, + + hdmi->bridge.driver_private = hdmi; + hdmi->bridge.funcs = &dw_hdmi_bridge_funcs; ++ hdmi->bridge.ops = DRM_BRIDGE_OP_DETECT | DRM_BRIDGE_OP_EDID ++ | DRM_BRIDGE_OP_HPD; + #ifdef CONFIG_OF + hdmi->bridge.of_node = pdev->dev.of_node; + #endif + +From 5631b3347b2c688d45a5804cc706702553873c3f Mon Sep 17 00:00:00 2001 +From: Stanislav Lisovskiy +Date: Tue, 30 Jun 2020 05:56:58 +0530 +Subject: [PATCH] drm: Add helper to compare edids. + +Many drivers would benefit from using +drm helper to compare edid, rather +than bothering with own implementation. + +v2: Added documentation for this function. + +Signed-off-by: Stanislav Lisovskiy +Signed-off-by: Maarten Lankhorst +Link: https://patchwork.freedesktop.org/patch/msgid/20200630002700.5451-2-kunal1.joshi@intel.com +(cherry picked from commit 536faa450e17f32fddb1a2124e3df71a966122cd) +--- + drivers/gpu/drm/drm_edid.c | 33 +++++++++++++++++++++++++++++++++ + include/drm/drm_edid.h | 9 +++++++++ + 2 files changed, 42 insertions(+) + +diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c +index b3f659759adb..aa0644d8272a 100644 +--- a/drivers/gpu/drm/drm_edid.c ++++ b/drivers/gpu/drm/drm_edid.c +@@ -1615,6 +1615,39 @@ static bool drm_edid_is_zero(const u8 *in_edid, int length) + return true; + } + ++/** ++ * drm_edid_are_equal - compare two edid blobs. ++ * @edid1: pointer to first blob ++ * @edid2: pointer to second blob ++ * This helper can be used during probing to determine if ++ * edid had changed. ++ */ ++bool drm_edid_are_equal(const struct edid *edid1, const struct edid *edid2) ++{ ++ int edid1_len, edid2_len; ++ bool edid1_present = edid1 != NULL; ++ bool edid2_present = edid2 != NULL; ++ ++ if (edid1_present != edid2_present) ++ return false; ++ ++ if (edid1) { ++ ++ edid1_len = EDID_LENGTH * (1 + edid1->extensions); ++ edid2_len = EDID_LENGTH * (1 + edid2->extensions); ++ ++ if (edid1_len != edid2_len) ++ return false; ++ ++ if (memcmp(edid1, edid2, edid1_len)) ++ return false; ++ } ++ ++ return true; ++} ++EXPORT_SYMBOL(drm_edid_are_equal); ++ ++ + /** + * drm_edid_block_valid - Sanity check the EDID block (base or extension) + * @raw_edid: pointer to raw EDID block +diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h +index 43254319ab19..cfa4f5af49af 100644 +--- a/include/drm/drm_edid.h ++++ b/include/drm/drm_edid.h +@@ -359,6 +359,15 @@ drm_load_edid_firmware(struct drm_connector *connector) + } + #endif + ++/** ++ * drm_edid_are_equal - compare two edid blobs. ++ * @edid1: pointer to first blob ++ * @edid2: pointer to second blob ++ * This helper can be used during probing to determine if ++ * edid had changed. ++ */ ++bool drm_edid_are_equal(const struct edid *edid1, const struct edid *edid2); ++ + int + drm_hdmi_avi_infoframe_from_display_mode(struct hdmi_avi_infoframe *frame, + const struct drm_connector *connector, + +From 00fb1055155719f429be43ff1864959cea9a56e2 Mon Sep 17 00:00:00 2001 +From: Stanislav Lisovskiy +Date: Tue, 30 Jun 2020 05:56:59 +0530 +Subject: [PATCH] drm: Introduce epoch counter to drm_connector + +This counter will be used by drm_helper_probe_detect caller to determine +if anything had changed(including edid, connection status and etc). +Hardware specific driver detect hooks are responsible for updating this +counter when some change is detected to notify the drm part, +which can trigger for example hotplug event. + +Also now call drm_connector_update_edid_property +right after we get edid always to make sure there is a +unified way to handle edid change, without having to +change tons of source code as currently +drm_connector_update_edid_property is called only in +certain cases like reprobing and not right after edid is +actually updated. + +v2: Added documentation for the new counter. Rename change_counter to + epoch_counter. + +Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=105540 + +Signed-off-by: Stanislav Lisovskiy +Signed-off-by: Maarten Lankhorst +Link: https://patchwork.freedesktop.org/patch/msgid/20200630002700.5451-3-kunal1.joshi@intel.com +(cherry picked from commit 5186421cbfe250002308d4d759674214b385752f) +--- + drivers/gpu/drm/drm_connector.c | 16 +++++++++++++ + drivers/gpu/drm/drm_edid.c | 8 ++++--- + drivers/gpu/drm/drm_probe_helper.c | 38 ++++++++++++++++++++++++++---- + include/drm/drm_connector.h | 2 ++ + 4 files changed, 56 insertions(+), 8 deletions(-) + +diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c +index d877ddc6dc57..c6d7fc45aeac 100644 +--- a/drivers/gpu/drm/drm_connector.c ++++ b/drivers/gpu/drm/drm_connector.c +@@ -269,6 +269,7 @@ int drm_connector_init(struct drm_device *dev, + INIT_LIST_HEAD(&connector->modes); + mutex_init(&connector->mutex); + connector->edid_blob_ptr = NULL; ++ connector->epoch_counter = 0; + connector->tile_blob_ptr = NULL; + connector->status = connector_status_unknown; + connector->display_info.panel_orientation = +@@ -1954,6 +1955,7 @@ int drm_connector_update_edid_property(struct drm_connector *connector, + struct drm_device *dev = connector->dev; + size_t size = 0; + int ret; ++ const struct edid *old_edid; + + /* ignore requests to set edid when overridden */ + if (connector->override_edid) +@@ -1977,6 +1979,20 @@ int drm_connector_update_edid_property(struct drm_connector *connector, + + drm_update_tile_info(connector, edid); + ++ if (connector->edid_blob_ptr) { ++ old_edid = (const struct edid *)connector->edid_blob_ptr->data; ++ if (old_edid) { ++ if (!drm_edid_are_equal(edid, old_edid)) { ++ DRM_DEBUG_KMS("[CONNECTOR:%d:%s] Edid was changed.\n", ++ connector->base.id, connector->name); ++ ++ connector->epoch_counter += 1; ++ DRM_DEBUG_KMS("Updating change counter to %llu\n", ++ connector->epoch_counter); ++ } ++ } ++ } ++ + drm_object_property_set_value(&connector->base, + dev->mode_config.non_desktop_property, + connector->display_info.non_desktop); +diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c +index aa0644d8272a..ddb9a093ad0d 100644 +--- a/drivers/gpu/drm/drm_edid.c ++++ b/drivers/gpu/drm/drm_edid.c +@@ -1632,7 +1632,6 @@ bool drm_edid_are_equal(const struct edid *edid1, const struct edid *edid2) + return false; + + if (edid1) { +- + edid1_len = EDID_LENGTH * (1 + edid1->extensions); + edid2_len = EDID_LENGTH * (1 + edid2->extensions); + +@@ -1647,7 +1646,6 @@ bool drm_edid_are_equal(const struct edid *edid1, const struct edid *edid2) + } + EXPORT_SYMBOL(drm_edid_are_equal); + +- + /** + * drm_edid_block_valid - Sanity check the EDID block (base or extension) + * @raw_edid: pointer to raw EDID block +@@ -2050,13 +2048,17 @@ EXPORT_SYMBOL(drm_probe_ddc); + struct edid *drm_get_edid(struct drm_connector *connector, + struct i2c_adapter *adapter) + { ++ struct edid *edid; ++ + if (connector->force == DRM_FORCE_OFF) + return NULL; + + if (connector->force == DRM_FORCE_UNSPECIFIED && !drm_probe_ddc(adapter)) + return NULL; + +- return drm_do_get_edid(connector, drm_do_probe_ddc_edid, adapter); ++ edid = drm_do_get_edid(connector, drm_do_probe_ddc_edid, adapter); ++ drm_connector_update_edid_property(connector, edid); ++ return edid; + } + EXPORT_SYMBOL(drm_get_edid); + +diff --git a/drivers/gpu/drm/drm_probe_helper.c b/drivers/gpu/drm/drm_probe_helper.c +index f5d141e0400f..6d3a1dbfcba5 100644 +--- a/drivers/gpu/drm/drm_probe_helper.c ++++ b/drivers/gpu/drm/drm_probe_helper.c +@@ -290,6 +290,9 @@ drm_helper_probe_detect_ctx(struct drm_connector *connector, bool force) + if (WARN_ON(ret < 0)) + ret = connector_status_unknown; + ++ if (ret != connector->status) ++ connector->epoch_counter += 1; ++ + drm_modeset_drop_locks(&ctx); + drm_modeset_acquire_fini(&ctx); + +@@ -323,11 +326,16 @@ drm_helper_probe_detect(struct drm_connector *connector, + return ret; + + if (funcs->detect_ctx) +- return funcs->detect_ctx(connector, ctx, force); ++ ret = funcs->detect_ctx(connector, ctx, force); + else if (connector->funcs->detect) +- return connector->funcs->detect(connector, force); ++ ret = connector->funcs->detect(connector, force); + else +- return connector_status_connected; ++ ret = connector_status_connected; ++ ++ if (ret != connector->status) ++ connector->epoch_counter += 1; ++ ++ return ret; + } + EXPORT_SYMBOL(drm_helper_probe_detect); + +@@ -780,6 +788,7 @@ bool drm_helper_hpd_irq_event(struct drm_device *dev) + struct drm_connector_list_iter conn_iter; + enum drm_connector_status old_status; + bool changed = false; ++ u64 old_epoch_counter; + + if (!dev->mode_config.poll_enabled) + return false; +@@ -793,20 +802,39 @@ bool drm_helper_hpd_irq_event(struct drm_device *dev) + + old_status = connector->status; + ++ old_epoch_counter = connector->epoch_counter; ++ ++ DRM_DEBUG_KMS("[CONNECTOR:%d:%s] Old epoch counter %llu\n", connector->base.id, ++ connector->name, ++ old_epoch_counter); ++ + connector->status = drm_helper_probe_detect(connector, NULL, false); + DRM_DEBUG_KMS("[CONNECTOR:%d:%s] status updated from %s to %s\n", + connector->base.id, + connector->name, + drm_get_connector_status_name(old_status), + drm_get_connector_status_name(connector->status)); +- if (old_status != connector->status) ++ ++ DRM_DEBUG_KMS("[CONNECTOR:%d:%s] New epoch counter %llu\n", ++ connector->base.id, ++ connector->name, ++ connector->epoch_counter); ++ ++ /* ++ * Check if epoch counter had changed, meaning that we need ++ * to send a uevent. ++ */ ++ if (old_epoch_counter != connector->epoch_counter) + changed = true; ++ + } + drm_connector_list_iter_end(&conn_iter); + mutex_unlock(&dev->mode_config.mutex); + +- if (changed) ++ if (changed) { + drm_kms_helper_hotplug_event(dev); ++ DRM_DEBUG_KMS("Sent hotplug event\n"); ++ } + + return changed; + } +diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h +index fd543d1db9b2..6a451b86c454 100644 +--- a/include/drm/drm_connector.h ++++ b/include/drm/drm_connector.h +@@ -1329,6 +1329,8 @@ struct drm_connector { + enum drm_connector_force force; + /** @override_edid: has the EDID been overwritten through debugfs for testing? */ + bool override_edid; ++ /** @epoch_counter: used to detect any other changes in connector, besides status */ ++ u64 epoch_counter; + + /** + * @possible_encoders: Bit mask of encoders that can drive this + +From 0402c6b6ec3351cdf475a0a7b4196cea5e213bd0 Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Fri, 3 Jul 2020 10:07:23 +0200 +Subject: [PATCH] drm/fourcc: Add modifier definitions for describing Amlogic + Video Framebuffer Compression + +Amlogic uses a proprietary lossless image compression protocol and format +for their hardware video codec accelerators, either video decoders or +video input encoders. + +It considerably reduces memory bandwidth while writing and reading +frames in memory. + +The underlying storage is considered to be 3 components, 8bit or 10-bit +per component, YCbCr 420, single plane : +- DRM_FORMAT_YUV420_8BIT +- DRM_FORMAT_YUV420_10BIT + +This modifier will be notably added to DMA-BUF frames imported from the V4L2 +Amlogic VDEC decoder. + +This introduces the basic layout composed of: +- a body content organized in 64x32 superblocks with 4096 bytes per + superblock in default mode. +- a 32 bytes per 128x64 header block + +This layout is tranferrable between Amlogic SoCs supporting this modifier. + +The Memory Saving option exist changing the layout superblock size to save memory when +using 8bit components pixels size. + +Finally is also adds the Scatter Memory layout, meaning the header contains IOMMU +references to the compressed frames content to optimize memory access +and layout. + +In this mode, only the header memory address is needed, thus the content +memory organization is tied to the current producer execution and cannot +be saved/dumped neither transferrable between Amlogic SoCs supporting this +modifier. + +Signed-off-by: Neil Armstrong +Tested-by: Kevin Hilman +Reviewed-by: Kevin Hilman +Acked-by: Daniel Vetter +Link: https://patchwork.freedesktop.org/patch/msgid/20200703080728.25207-2-narmstrong@baylibre.com +(cherry picked from commit d6528ec883096e7ccdb08257bcc45670bc878519) +--- + include/uapi/drm/drm_fourcc.h | 81 +++++++++++++++++++++++++++++++++++ + 1 file changed, 81 insertions(+) + +diff --git a/include/uapi/drm/drm_fourcc.h b/include/uapi/drm/drm_fourcc.h +index 993c1b342315..cbf92fdf2712 100644 +--- a/include/uapi/drm/drm_fourcc.h ++++ b/include/uapi/drm/drm_fourcc.h +@@ -331,6 +331,7 @@ extern "C" { + #define DRM_FORMAT_MOD_VENDOR_BROADCOM 0x07 + #define DRM_FORMAT_MOD_VENDOR_ARM 0x08 + #define DRM_FORMAT_MOD_VENDOR_ALLWINNER 0x09 ++#define DRM_FORMAT_MOD_VENDOR_AMLOGIC 0x0a + + /* add more to the end as needed */ + +@@ -950,6 +951,86 @@ drm_fourcc_canonicalize_nvidia_format_mod(__u64 modifier) + */ + #define DRM_FORMAT_MOD_ALLWINNER_TILED fourcc_mod_code(ALLWINNER, 1) + ++/* ++ * Amlogic Video Framebuffer Compression modifiers ++ * ++ * Amlogic uses a proprietary lossless image compression protocol and format ++ * for their hardware video codec accelerators, either video decoders or ++ * video input encoders. ++ * ++ * It considerably reduces memory bandwidth while writing and reading ++ * frames in memory. ++ * ++ * The underlying storage is considered to be 3 components, 8bit or 10-bit ++ * per component YCbCr 420, single plane : ++ * - DRM_FORMAT_YUV420_8BIT ++ * - DRM_FORMAT_YUV420_10BIT ++ * ++ * The first 8 bits of the mode defines the layout, then the following 8 bits ++ * defines the options changing the layout. ++ * ++ * Not all combinations are valid, and different SoCs may support different ++ * combinations of layout and options. ++ */ ++#define __fourcc_mod_amlogic_layout_mask 0xf ++#define __fourcc_mod_amlogic_options_shift 8 ++#define __fourcc_mod_amlogic_options_mask 0xf ++ ++#define DRM_FORMAT_MOD_AMLOGIC_FBC(__layout, __options) \ ++ fourcc_mod_code(AMLOGIC, \ ++ ((__layout) & __fourcc_mod_amlogic_layout_mask) | \ ++ ((__options) & __fourcc_mod_amlogic_options_mask \ ++ << __fourcc_mod_amlogic_options_shift)) ++ ++/* Amlogic FBC Layouts */ ++ ++/* ++ * Amlogic FBC Basic Layout ++ * ++ * The basic layout is composed of: ++ * - a body content organized in 64x32 superblocks with 4096 bytes per ++ * superblock in default mode. ++ * - a 32 bytes per 128x64 header block ++ * ++ * This layout is transferrable between Amlogic SoCs supporting this modifier. ++ */ ++#define AMLOGIC_FBC_LAYOUT_BASIC (1ULL) ++ ++/* ++ * Amlogic FBC Scatter Memory layout ++ * ++ * Indicates the header contains IOMMU references to the compressed ++ * frames content to optimize memory access and layout. ++ * ++ * In this mode, only the header memory address is needed, thus the ++ * content memory organization is tied to the current producer ++ * execution and cannot be saved/dumped neither transferrable between ++ * Amlogic SoCs supporting this modifier. ++ * ++ * Due to the nature of the layout, these buffers are not expected to ++ * be accessible by the user-space clients, but only accessible by the ++ * hardware producers and consumers. ++ * ++ * The user-space clients should expect a failure while trying to mmap ++ * the DMA-BUF handle returned by the producer. ++ */ ++#define AMLOGIC_FBC_LAYOUT_SCATTER (2ULL) ++ ++/* Amlogic FBC Layout Options Bit Mask */ ++ ++/* ++ * Amlogic FBC Memory Saving mode ++ * ++ * Indicates the storage is packed when pixel size is multiple of word ++ * boudaries, i.e. 8bit should be stored in this mode to save allocation ++ * memory. ++ * ++ * This mode reduces body layout to 3072 bytes per 64x32 superblock with ++ * the basic layout and 3200 bytes per 64x32 superblock combined with ++ * the scatter layout. ++ */ ++#define AMLOGIC_FBC_OPTION_MEM_SAVING (1ULL << 0) ++ + #if defined(__cplusplus) + } + #endif + +From bca1f53e15b80ac4fa24a073f96e8f99d994ca8a Mon Sep 17 00:00:00 2001 +From: Brian Starkey +Date: Fri, 26 Jun 2020 17:48:00 +0100 +Subject: [PATCH] drm: drm_fourcc: Add generic alias for 16_16_TILE modifier + +In cases such as DRM_FORMAT_MOD_SAMSUNG_16_16_TILE, the modifier +describes a generic pixel re-ordering which can be applicable to +multiple vendors. + +Define an alias: DRM_FORMAT_MOD_GENERIC_16_16_TILE, which can be +used to describe this layout in a vendor-neutral way, and add a +comment about the expected usage of such "generic" modifiers. + +Changes in v2: + - Move note about future cases to comment (Daniel) + +Signed-off-by: Brian Starkey +Reviewed-by: Daniel Vetter +Signed-off-by: Liviu Dudau +Link: https://patchwork.freedesktop.org/patch/msgid/20200626164800.11595-1-brian.starkey@arm.com +(cherry picked from commit 9ac2b63791ef63935c71e2a7f5444a1118c4d084) +--- + include/uapi/drm/drm_fourcc.h | 25 +++++++++++++++++++++++++ + 1 file changed, 25 insertions(+) + +diff --git a/include/uapi/drm/drm_fourcc.h b/include/uapi/drm/drm_fourcc.h +index cbf92fdf2712..4bee7de5f306 100644 +--- a/include/uapi/drm/drm_fourcc.h ++++ b/include/uapi/drm/drm_fourcc.h +@@ -346,8 +346,33 @@ extern "C" { + * When adding a new token please document the layout with a code comment, + * similar to the fourcc codes above. drm_fourcc.h is considered the + * authoritative source for all of these. ++ * ++ * Generic modifier names: ++ * ++ * DRM_FORMAT_MOD_GENERIC_* definitions are used to provide vendor-neutral names ++ * for layouts which are common across multiple vendors. To preserve ++ * compatibility, in cases where a vendor-specific definition already exists and ++ * a generic name for it is desired, the common name is a purely symbolic alias ++ * and must use the same numerical value as the original definition. ++ * ++ * Note that generic names should only be used for modifiers which describe ++ * generic layouts (such as pixel re-ordering), which may have ++ * independently-developed support across multiple vendors. ++ * ++ * In future cases where a generic layout is identified before merging with a ++ * vendor-specific modifier, a new 'GENERIC' vendor or modifier using vendor ++ * 'NONE' could be considered. This should only be for obvious, exceptional ++ * cases to avoid polluting the 'GENERIC' namespace with modifiers which only ++ * apply to a single vendor. ++ * ++ * Generic names should not be used for cases where multiple hardware vendors ++ * have implementations of the same standardised compression scheme (such as ++ * AFBC). In those cases, all implementations should use the same format ++ * modifier(s), reflecting the vendor of the standard. + */ + ++#define DRM_FORMAT_MOD_GENERIC_16_16_TILE DRM_FORMAT_MOD_SAMSUNG_16_16_TILE ++ + /* + * Invalid Modifier + * + +From 01f7cea4ef8c373df777713ceef5599a3efa88cb Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= +Date: Wed, 27 May 2020 16:03:08 +0300 +Subject: [PATCH] drm/edid: Allow looking for ext blocks starting from a + specified index +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Apparently EDIDs with multiple DispID ext blocks is a thing, so prepare +for iterating through multiple ext blocks of the same type by +passing the starting ext block index to drm_find_edid_extension(). Well +also have drm_find_edid_extension() update the index to point to the +next ext block on success. Thus we should be able to call +drm_find_edid_extension() in loop. + +Signed-off-by: Ville Syrjälä +Link: https://patchwork.freedesktop.org/patch/msgid/20200527130310.27099-1-ville.syrjala@linux.intel.com +Reviewed-by: José Roberto de Souza +(cherry picked from commit 8873cfa384055d0348c03161420b1e9b6c1dc5d0) +--- + drivers/gpu/drm/drm_edid.c | 30 +++++++++++++++++++++--------- + 1 file changed, 21 insertions(+), 9 deletions(-) + +diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c +index ddb9a093ad0d..06cb75b9fc44 100644 +--- a/drivers/gpu/drm/drm_edid.c ++++ b/drivers/gpu/drm/drm_edid.c +@@ -3226,7 +3226,8 @@ add_detailed_modes(struct drm_connector *connector, struct edid *edid, + /* + * Search EDID for CEA extension block. + */ +-static u8 *drm_find_edid_extension(const struct edid *edid, int ext_id) ++static u8 *drm_find_edid_extension(const struct edid *edid, ++ int ext_id, int *ext_index) + { + u8 *edid_ext = NULL; + int i; +@@ -3236,23 +3237,26 @@ static u8 *drm_find_edid_extension(const struct edid *edid, int ext_id) + return NULL; + + /* Find CEA extension */ +- for (i = 0; i < edid->extensions; i++) { ++ for (i = *ext_index; i < edid->extensions; i++) { + edid_ext = (u8 *)edid + EDID_LENGTH * (i + 1); + if (edid_ext[0] == ext_id) + break; + } + +- if (i == edid->extensions) ++ if (i >= edid->extensions) + return NULL; + ++ *ext_index = i + 1; ++ + return edid_ext; + } + + + static u8 *drm_find_displayid_extension(const struct edid *edid, +- int *length, int *idx) ++ int *length, int *idx, ++ int *ext_index) + { +- u8 *displayid = drm_find_edid_extension(edid, DISPLAYID_EXT); ++ u8 *displayid = drm_find_edid_extension(edid, DISPLAYID_EXT, ext_index); + struct displayid_hdr *base; + int ret; + +@@ -3279,14 +3283,18 @@ static u8 *drm_find_cea_extension(const struct edid *edid) + struct displayid_block *block; + u8 *cea; + u8 *displayid; ++ int ext_index; + + /* Look for a top level CEA extension block */ +- cea = drm_find_edid_extension(edid, CEA_EXT); ++ ext_index = 0; ++ cea = drm_find_edid_extension(edid, CEA_EXT, &ext_index); + if (cea) + return cea; + + /* CEA blocks can also be found embedded in a DisplayID block */ +- displayid = drm_find_displayid_extension(edid, &length, &idx); ++ ext_index = 0; ++ displayid = drm_find_displayid_extension(edid, &length, &idx, ++ &ext_index); + if (!displayid) + return NULL; + +@@ -5236,8 +5244,10 @@ static int add_displayid_detailed_modes(struct drm_connector *connector, + int length, idx; + struct displayid_block *block; + int num_modes = 0; ++ int ext_index = 0; + +- displayid = drm_find_displayid_extension(edid, &length, &idx); ++ displayid = drm_find_displayid_extension(edid, &length, &idx, ++ &ext_index); + if (!displayid) + return 0; + +@@ -5911,11 +5921,13 @@ void drm_update_tile_info(struct drm_connector *connector, + const struct edid *edid) + { + const void *displayid = NULL; ++ int ext_index = 0; + int length, idx; + int ret; + + connector->has_tile = false; +- displayid = drm_find_displayid_extension(edid, &length, &idx); ++ displayid = drm_find_displayid_extension(edid, &length, &idx, ++ &ext_index); + if (!displayid) { + /* drop reference to any tile group we had */ + goto out_drop_ref; + +From 181edc12e551c8194591969ee528ed6041e4ada4 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= +Date: Wed, 27 May 2020 16:03:09 +0300 +Subject: [PATCH] drm/edid: Iterate through all DispID ext blocks +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Apparently there are EDIDs in the wild with multiple DispID extension +blocks. Iterate through them all. + +In one particular case the tile information is specicied in the +second DispID ext block, and since the current parser only looks +at the first DispID ext block we don't notice that we're dealing +with a tiled display. + +While at it change a few functions to return void since we have +no use for the errno. + +References: https://gitlab.freedesktop.org/drm/intel/-/issues/27 +Signed-off-by: Ville Syrjälä +Link: https://patchwork.freedesktop.org/patch/msgid/20200527130310.27099-2-ville.syrjala@linux.intel.com +Reviewed-by: José Roberto de Souza +(cherry picked from commit 7f261afdcfae363192e3eef52dd34855cc149c15) +--- + drivers/gpu/drm/drm_edid.c | 84 +++++++++++++++++--------------------- + 1 file changed, 38 insertions(+), 46 deletions(-) + +diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c +index 06cb75b9fc44..fcd739af570f 100644 +--- a/drivers/gpu/drm/drm_edid.c ++++ b/drivers/gpu/drm/drm_edid.c +@@ -3286,6 +3286,7 @@ static u8 *drm_find_cea_extension(const struct edid *edid) + int ext_index; + + /* Look for a top level CEA extension block */ ++ /* FIXME: make callers iterate through multiple CEA ext blocks? */ + ext_index = 0; + cea = drm_find_edid_extension(edid, CEA_EXT, &ext_index); + if (cea) +@@ -3293,20 +3294,20 @@ static u8 *drm_find_cea_extension(const struct edid *edid) + + /* CEA blocks can also be found embedded in a DisplayID block */ + ext_index = 0; +- displayid = drm_find_displayid_extension(edid, &length, &idx, +- &ext_index); +- if (!displayid) +- return NULL; ++ for (;;) { ++ displayid = drm_find_displayid_extension(edid, &length, &idx, ++ &ext_index); ++ if (!displayid) ++ return NULL; + +- idx += sizeof(struct displayid_hdr); +- for_each_displayid_db(displayid, block, idx, length) { +- if (block->tag == DATA_BLOCK_CTA) { +- cea = (u8 *)block; +- break; ++ idx += sizeof(struct displayid_hdr); ++ for_each_displayid_db(displayid, block, idx, length) { ++ if (block->tag == DATA_BLOCK_CTA) ++ return (u8 *)block; + } + } + +- return cea; ++ return NULL; + } + + static __always_inline const struct drm_display_mode *cea_mode_for_vic(u8 vic) +@@ -5246,19 +5247,22 @@ static int add_displayid_detailed_modes(struct drm_connector *connector, + int num_modes = 0; + int ext_index = 0; + +- displayid = drm_find_displayid_extension(edid, &length, &idx, +- &ext_index); +- if (!displayid) +- return 0; +- +- idx += sizeof(struct displayid_hdr); +- for_each_displayid_db(displayid, block, idx, length) { +- switch (block->tag) { +- case DATA_BLOCK_TYPE_1_DETAILED_TIMING: +- num_modes += add_displayid_detailed_1_modes(connector, block); ++ for (;;) { ++ displayid = drm_find_displayid_extension(edid, &length, &idx, ++ &ext_index); ++ if (!displayid) + break; ++ ++ idx += sizeof(struct displayid_hdr); ++ for_each_displayid_db(displayid, block, idx, length) { ++ switch (block->tag) { ++ case DATA_BLOCK_TYPE_1_DETAILED_TIMING: ++ num_modes += add_displayid_detailed_1_modes(connector, block); ++ break; ++ } + } + } ++ + return num_modes; + } + +@@ -5838,8 +5842,8 @@ drm_hdmi_vendor_infoframe_from_display_mode(struct hdmi_vendor_infoframe *frame, + } + EXPORT_SYMBOL(drm_hdmi_vendor_infoframe_from_display_mode); + +-static int drm_parse_tiled_block(struct drm_connector *connector, +- const struct displayid_block *block) ++static void drm_parse_tiled_block(struct drm_connector *connector, ++ const struct displayid_block *block) + { + const struct displayid_tiled_block *tile = (struct displayid_tiled_block *)block; + u16 w, h; +@@ -5877,7 +5881,7 @@ static int drm_parse_tiled_block(struct drm_connector *connector, + tg = drm_mode_create_tile_group(connector->dev, tile->topology_id); + } + if (!tg) +- return -ENOMEM; ++ return; + + if (connector->tile_group != tg) { + /* if we haven't got a pointer, +@@ -5889,14 +5893,12 @@ static int drm_parse_tiled_block(struct drm_connector *connector, + } else + /* if same tile group, then release the ref we just took. */ + drm_mode_put_tile_group(connector->dev, tg); +- return 0; + } + +-static int drm_displayid_parse_tiled(struct drm_connector *connector, +- const u8 *displayid, int length, int idx) ++static void drm_displayid_parse_tiled(struct drm_connector *connector, ++ const u8 *displayid, int length, int idx) + { + const struct displayid_block *block; +- int ret; + + idx += sizeof(struct displayid_hdr); + for_each_displayid_db(displayid, block, idx, length) { +@@ -5905,16 +5907,13 @@ static int drm_displayid_parse_tiled(struct drm_connector *connector, + + switch (block->tag) { + case DATA_BLOCK_TILED_DISPLAY: +- ret = drm_parse_tiled_block(connector, block); +- if (ret) +- return ret; ++ drm_parse_tiled_block(connector, block); + break; + default: + DRM_DEBUG_KMS("found DisplayID tag 0x%x, unhandled\n", block->tag); + break; + } + } +- return 0; + } + + void drm_update_tile_info(struct drm_connector *connector, +@@ -5923,26 +5922,19 @@ void drm_update_tile_info(struct drm_connector *connector, + const void *displayid = NULL; + int ext_index = 0; + int length, idx; +- int ret; + + connector->has_tile = false; +- displayid = drm_find_displayid_extension(edid, &length, &idx, +- &ext_index); +- if (!displayid) { +- /* drop reference to any tile group we had */ +- goto out_drop_ref; ++ for (;;) { ++ displayid = drm_find_displayid_extension(edid, &length, &idx, ++ &ext_index); ++ if (!displayid) ++ break; ++ ++ drm_displayid_parse_tiled(connector, displayid, length, idx); + } + +- ret = drm_displayid_parse_tiled(connector, displayid, length, idx); +- if (ret < 0) +- goto out_drop_ref; +- if (!connector->has_tile) +- goto out_drop_ref; +- return; +-out_drop_ref: +- if (connector->tile_group) { ++ if (!connector->has_tile && connector->tile_group) { + drm_mode_put_tile_group(connector->dev, connector->tile_group); + connector->tile_group = NULL; + } +- return; + } + +From c4a01f31ea528f8a1057b720eed47d502b19a3fb Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= +Date: Wed, 27 May 2020 16:03:10 +0300 +Subject: [PATCH] drm/edid: Clean up some curly braces +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Drop some pointless curly braces, and add some across the +else when the if has them too. + +Signed-off-by: Ville Syrjälä +Link: https://patchwork.freedesktop.org/patch/msgid/20200527130310.27099-3-ville.syrjala@linux.intel.com +Reviewed-by: José Roberto de Souza +(cherry picked from commit 392f9fcb159bf95ec3c7de340a880f4778167275) +--- + drivers/gpu/drm/drm_edid.c | 9 ++++----- + 1 file changed, 4 insertions(+), 5 deletions(-) + +diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c +index fcd739af570f..c28e7678014d 100644 +--- a/drivers/gpu/drm/drm_edid.c ++++ b/drivers/gpu/drm/drm_edid.c +@@ -5877,22 +5877,21 @@ static void drm_parse_tiled_block(struct drm_connector *connector, + DRM_DEBUG_KMS("vend %c%c%c\n", tile->topology_id[0], tile->topology_id[1], tile->topology_id[2]); + + tg = drm_mode_get_tile_group(connector->dev, tile->topology_id); +- if (!tg) { ++ if (!tg) + tg = drm_mode_create_tile_group(connector->dev, tile->topology_id); +- } + if (!tg) + return; + + if (connector->tile_group != tg) { + /* if we haven't got a pointer, + take the reference, drop ref to old tile group */ +- if (connector->tile_group) { ++ if (connector->tile_group) + drm_mode_put_tile_group(connector->dev, connector->tile_group); +- } + connector->tile_group = tg; +- } else ++ } else { + /* if same tile group, then release the ref we just took. */ + drm_mode_put_tile_group(connector->dev, tg); ++ } + } + + static void drm_displayid_parse_tiled(struct drm_connector *connector, + +From 7a5d301a5077083f45d826c49248882eacec778d Mon Sep 17 00:00:00 2001 +From: Liu Ying +Date: Thu, 9 Jul 2020 10:02:35 +0800 +Subject: [PATCH] drm/bridge: dw-hdmi: Don't cleanup i2c adapter and ddc ptr in + __dw_hdmi_probe() bailout path + +It's unnecessary to cleanup the i2c adapter and the ddc pointer in +the bailout path of __dw_hdmi_probe(), since the adapter is not +added and the ddc pointer is not set. + +Fixes: a23d6265f033 ("drm: bridge: dw-hdmi: Extract PHY interrupt setup to a function") +Cc: Andrzej Hajda +Cc: Neil Armstrong +Cc: Laurent Pinchart +Cc: Jonas Karlman +Cc: Jernej Skrabec +Cc: David Airlie +Cc: Daniel Vetter +Cc: Boris Brezillon +Cc: Jerome Brunet +Cc: Cheng-Yi Chiang +Cc: Dariusz Marcinkiewicz +Cc: Archit Taneja +Cc: Jose Abreu +Cc: dri-devel@lists.freedesktop.org +Cc: NXP Linux Team +Signed-off-by: Liu Ying +Reviewed-by: Laurent Pinchart +Signed-off-by: Sam Ravnborg +Link: https://patchwork.freedesktop.org/patch/msgid/1594260156-8316-1-git-send-email-victor.liu@nxp.com +(cherry picked from commit 2ae53e79f2dec41949d7b089c0b6d7edce292d10) +--- + drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 5 ----- + 1 file changed, 5 deletions(-) + +diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +index 6148a022569a..137b6ebfed19 100644 +--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c ++++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +@@ -3441,11 +3441,6 @@ __dw_hdmi_probe(struct platform_device *pdev, + return hdmi; + + err_iahb: +- if (hdmi->i2c) { +- i2c_del_adapter(&hdmi->i2c->adap); +- hdmi->ddc = NULL; +- } +- + clk_disable_unprepare(hdmi->iahb_clk); + if (hdmi->cec_clk) + clk_disable_unprepare(hdmi->cec_clk); + +From fe98962cfe32f385bed8c1fea444aeb887b472e6 Mon Sep 17 00:00:00 2001 +From: Liu Ying +Date: Thu, 9 Jul 2020 10:02:36 +0800 +Subject: [PATCH] drm/bridge: dw-hdmi: Always add the bridge in the global + bridge list + +It doesn't hurt to add the bridge in the global bridge list also for +platform specific dw-hdmi drivers which are based on the component +framework. This can be achieved by moving the drm_bridge_add() function +call from dw_hdmi_probe() to __dw_hdmi_probe(). A counterpart movement +for drm_bridge_remove() is also needed then. Moreover, since drm_bridge_add() +initializes &bridge->hpd_mutex, this may help those platform specific +dw-hdmi drivers(based on the component framework) avoid accessing the +uninitialized mutex in drm_bridge_hpd_notify() which is called in +dw_hdmi_irq(). Putting drm_bridge_add() in __dw_hdmi_probe() just before +it returns successfully should bring no logic change for platforms based +on the DRM bridge API, which is a good choice from safety point of view. +Also, __dw_hdmi_probe() is renamed to dw_hdmi_probe() since dw_hdmi_probe() +does nothing else but calling __dw_hdmi_probe(). Similar renaming applies +to the __dw_hdmi_remove()/dw_hdmi_remove() pair. + +Fixes: ec971aaa6775 ("drm: bridge: dw-hdmi: Make connector creation optional") +Cc: Andrzej Hajda +Cc: Neil Armstrong +Cc: Laurent Pinchart +Cc: Jonas Karlman +Cc: Jernej Skrabec +Cc: David Airlie +Cc: Daniel Vetter +Cc: Boris Brezillon +Cc: Jerome Brunet +Cc: Cheng-Yi Chiang +Cc: Dariusz Marcinkiewicz +Cc: Archit Taneja +Cc: Jose Abreu +Cc: Sam Ravnborg +Cc: dri-devel@lists.freedesktop.org +Cc: NXP Linux Team +Signed-off-by: Liu Ying +Signed-off-by: Sam Ravnborg +Link: https://patchwork.freedesktop.org/patch/msgid/1594260156-8316-2-git-send-email-victor.liu@nxp.com +(cherry picked from commit 0bf4f5b5d3972df7014df302b95b58b8de1a1e94) +--- + drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 44 +++++++---------------- + 1 file changed, 13 insertions(+), 31 deletions(-) + +diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +index 137b6ebfed19..748df1cacd2b 100644 +--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c ++++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +@@ -3179,9 +3179,11 @@ static void dw_hdmi_init_hw(struct dw_hdmi *hdmi) + hdmi->phy.ops->setup_hpd(hdmi, hdmi->phy.data); + } + +-static struct dw_hdmi * +-__dw_hdmi_probe(struct platform_device *pdev, +- const struct dw_hdmi_plat_data *plat_data) ++/* ----------------------------------------------------------------------------- ++ * Probe/remove API, used from platforms based on the DRM bridge API. ++ */ ++struct dw_hdmi *dw_hdmi_probe(struct platform_device *pdev, ++ const struct dw_hdmi_plat_data *plat_data) + { + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; +@@ -3438,6 +3440,8 @@ __dw_hdmi_probe(struct platform_device *pdev, + hdmi->cec = platform_device_register_full(&pdevinfo); + } + ++ drm_bridge_add(&hdmi->bridge); ++ + return hdmi; + + err_iahb: +@@ -3451,9 +3455,12 @@ __dw_hdmi_probe(struct platform_device *pdev, + + return ERR_PTR(ret); + } ++EXPORT_SYMBOL_GPL(dw_hdmi_probe); + +-static void __dw_hdmi_remove(struct dw_hdmi *hdmi) ++void dw_hdmi_remove(struct dw_hdmi *hdmi) + { ++ drm_bridge_remove(&hdmi->bridge); ++ + if (hdmi->audio && !IS_ERR(hdmi->audio)) + platform_device_unregister(hdmi->audio); + if (!IS_ERR(hdmi->cec)) +@@ -3472,31 +3479,6 @@ static void __dw_hdmi_remove(struct dw_hdmi *hdmi) + else + i2c_put_adapter(hdmi->ddc); + } +- +-/* ----------------------------------------------------------------------------- +- * Probe/remove API, used from platforms based on the DRM bridge API. +- */ +-struct dw_hdmi *dw_hdmi_probe(struct platform_device *pdev, +- const struct dw_hdmi_plat_data *plat_data) +-{ +- struct dw_hdmi *hdmi; +- +- hdmi = __dw_hdmi_probe(pdev, plat_data); +- if (IS_ERR(hdmi)) +- return hdmi; +- +- drm_bridge_add(&hdmi->bridge); +- +- return hdmi; +-} +-EXPORT_SYMBOL_GPL(dw_hdmi_probe); +- +-void dw_hdmi_remove(struct dw_hdmi *hdmi) +-{ +- drm_bridge_remove(&hdmi->bridge); +- +- __dw_hdmi_remove(hdmi); +-} + EXPORT_SYMBOL_GPL(dw_hdmi_remove); + + /* ----------------------------------------------------------------------------- +@@ -3509,7 +3491,7 @@ struct dw_hdmi *dw_hdmi_bind(struct platform_device *pdev, + struct dw_hdmi *hdmi; + int ret; + +- hdmi = __dw_hdmi_probe(pdev, plat_data); ++ hdmi = dw_hdmi_probe(pdev, plat_data); + if (IS_ERR(hdmi)) + return hdmi; + +@@ -3526,7 +3508,7 @@ EXPORT_SYMBOL_GPL(dw_hdmi_bind); + + void dw_hdmi_unbind(struct dw_hdmi *hdmi) + { +- __dw_hdmi_remove(hdmi); ++ dw_hdmi_remove(hdmi); + } + EXPORT_SYMBOL_GPL(dw_hdmi_unbind); + + +From d046fd09e47e5ea681fa9a0ba441eb493a8b5b14 Mon Sep 17 00:00:00 2001 +From: Andrey Lebedev +Date: Fri, 19 Jun 2020 10:58:59 +0300 +Subject: [PATCH] drm/lima: Expose job_hang_limit module parameter + +Some pp or gp jobs can be successfully repeated even after they time outs. +Introduce lima module parameter to specify number of times a job can hang +before being dropped. + +Signed-off-by: Andrey Lebedev +Signed-off-by: Qiang Yu +Link: https://patchwork.freedesktop.org/patch/msgid/20200619075900.3030696-1-andrey.lebedev@gmail.com +(cherry picked from commit de48984486d942d4f23e2b29374639f21042bdaa) +--- + drivers/gpu/drm/lima/lima_drv.c | 4 ++++ + drivers/gpu/drm/lima/lima_drv.h | 1 + + drivers/gpu/drm/lima/lima_sched.c | 5 +++-- + 3 files changed, 8 insertions(+), 2 deletions(-) + +diff --git a/drivers/gpu/drm/lima/lima_drv.c b/drivers/gpu/drm/lima/lima_drv.c +index a831565af813..ab460121fd52 100644 +--- a/drivers/gpu/drm/lima/lima_drv.c ++++ b/drivers/gpu/drm/lima/lima_drv.c +@@ -19,6 +19,7 @@ + int lima_sched_timeout_ms; + uint lima_heap_init_nr_pages = 8; + uint lima_max_error_tasks; ++uint lima_job_hang_limit; + + MODULE_PARM_DESC(sched_timeout_ms, "task run timeout in ms"); + module_param_named(sched_timeout_ms, lima_sched_timeout_ms, int, 0444); +@@ -29,6 +30,9 @@ module_param_named(heap_init_nr_pages, lima_heap_init_nr_pages, uint, 0444); + MODULE_PARM_DESC(max_error_tasks, "max number of error tasks to save"); + module_param_named(max_error_tasks, lima_max_error_tasks, uint, 0644); + ++MODULE_PARM_DESC(job_hang_limit, "number of times to allow a job to hang before dropping it (default 0)"); ++module_param_named(job_hang_limit, lima_job_hang_limit, uint, 0444); ++ + static int lima_ioctl_get_param(struct drm_device *dev, void *data, struct drm_file *file) + { + struct drm_lima_get_param *args = data; +diff --git a/drivers/gpu/drm/lima/lima_drv.h b/drivers/gpu/drm/lima/lima_drv.h +index fdbd4077c768..c738d288547b 100644 +--- a/drivers/gpu/drm/lima/lima_drv.h ++++ b/drivers/gpu/drm/lima/lima_drv.h +@@ -11,6 +11,7 @@ + extern int lima_sched_timeout_ms; + extern uint lima_heap_init_nr_pages; + extern uint lima_max_error_tasks; ++extern uint lima_job_hang_limit; + + struct lima_vm; + struct lima_bo; +diff --git a/drivers/gpu/drm/lima/lima_sched.c b/drivers/gpu/drm/lima/lima_sched.c +index e6cefda00279..1602985dfa04 100644 +--- a/drivers/gpu/drm/lima/lima_sched.c ++++ b/drivers/gpu/drm/lima/lima_sched.c +@@ -503,8 +503,9 @@ int lima_sched_pipe_init(struct lima_sched_pipe *pipe, const char *name) + + INIT_WORK(&pipe->recover_work, lima_sched_recover_work); + +- return drm_sched_init(&pipe->base, &lima_sched_ops, 1, 0, +- msecs_to_jiffies(timeout), name); ++ return drm_sched_init(&pipe->base, &lima_sched_ops, 1, ++ lima_job_hang_limit, msecs_to_jiffies(timeout), ++ name); + } + + void lima_sched_pipe_fini(struct lima_sched_pipe *pipe) diff --git a/patch/kernel/rk322x-dev/01-linux-0022-drm-from-next.patch b/patch/kernel/rk322x-dev/01-linux-0022-drm-from-next.patch new file mode 100644 index 000000000..4cf8cdbe7 --- /dev/null +++ b/patch/kernel/rk322x-dev/01-linux-0022-drm-from-next.patch @@ -0,0 +1,1276 @@ +From 055013808487a12514bd6a10d5f1be4267d3cf4a Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Thu, 23 Jul 2020 11:05:50 +0200 +Subject: [PATCH] drm/fourcc: fix Amlogic Video Framebuffer Compression macro + +Fix the Amlogic Video Framebuffer Compression modifier macro to +correctly add the layout options, a pair of parenthesis was missing. + +Fixes: d6528ec88309 ("drm/fourcc: Add modifier definitions for describing Amlogic Video Framebuffer Compression") +Signed-off-by: Neil Armstrong +Acked-by: Sam Ravnborg +Link: https://patchwork.freedesktop.org/patch/msgid/20200723090551.27529-1-narmstrong@baylibre.com +(cherry picked from commit da3a9e9a6aa96ef589c153078f66e0646bf06b55) +--- + include/uapi/drm/drm_fourcc.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/include/uapi/drm/drm_fourcc.h b/include/uapi/drm/drm_fourcc.h +index 4bee7de5f306..82f327801267 100644 +--- a/include/uapi/drm/drm_fourcc.h ++++ b/include/uapi/drm/drm_fourcc.h +@@ -1004,7 +1004,7 @@ drm_fourcc_canonicalize_nvidia_format_mod(__u64 modifier) + #define DRM_FORMAT_MOD_AMLOGIC_FBC(__layout, __options) \ + fourcc_mod_code(AMLOGIC, \ + ((__layout) & __fourcc_mod_amlogic_layout_mask) | \ +- ((__options) & __fourcc_mod_amlogic_options_mask \ ++ (((__options) & __fourcc_mod_amlogic_options_mask) \ + << __fourcc_mod_amlogic_options_shift)) + + /* Amlogic FBC Layouts */ + +From 9df4c74d07ec7d3141b2a243b49de48f3e36932b Mon Sep 17 00:00:00 2001 +From: Tomeu Vizoso +Date: Thu, 11 Jun 2020 10:58:43 +0200 +Subject: [PATCH] drm/panfrost: Make sure GPU is powered on when reading + GPU_LATEST_FLUSH_ID + +Bifrost devices do support the flush reduction feature, so on first job +submit we were trying to read the register while still powered off. + +If the GPU is powered off, the feature doesn't bring any benefit, so +don't try to read. + +Tested-by: Heiko Stuebner +Reviewed-by: Steven Price +Signed-off-by: Tomeu Vizoso +Signed-off-by: Rob Herring +Link: https://patchwork.freedesktop.org/patch/msgid/20200611085900.49740-1-tomeu.vizoso@collabora.com +(cherry picked from commit 3a74265c54f883c847ed8554129baefb3e04f135) +--- + drivers/gpu/drm/panfrost/panfrost_gpu.c | 14 ++++++++++++-- + 1 file changed, 12 insertions(+), 2 deletions(-) + +diff --git a/drivers/gpu/drm/panfrost/panfrost_gpu.c b/drivers/gpu/drm/panfrost/panfrost_gpu.c +index f2c1ddc41a9b..e0f190e43813 100644 +--- a/drivers/gpu/drm/panfrost/panfrost_gpu.c ++++ b/drivers/gpu/drm/panfrost/panfrost_gpu.c +@@ -10,6 +10,7 @@ + #include + #include + #include ++#include + + #include "panfrost_device.h" + #include "panfrost_features.h" +@@ -368,7 +369,16 @@ void panfrost_gpu_fini(struct panfrost_device *pfdev) + + u32 panfrost_gpu_get_latest_flush_id(struct panfrost_device *pfdev) + { +- if (panfrost_has_hw_feature(pfdev, HW_FEATURE_FLUSH_REDUCTION)) +- return gpu_read(pfdev, GPU_LATEST_FLUSH_ID); ++ u32 flush_id; ++ ++ if (panfrost_has_hw_feature(pfdev, HW_FEATURE_FLUSH_REDUCTION)) { ++ /* Flush reduction only makes sense when the GPU is kept powered on between jobs */ ++ if (pm_runtime_get_if_in_use(pfdev->dev)) { ++ flush_id = gpu_read(pfdev, GPU_LATEST_FLUSH_ID); ++ pm_runtime_put(pfdev->dev); ++ return flush_id; ++ } ++ } ++ + return 0; + } + +From 956be03f3fc751937bbb07a4e4201a2a73aa87f1 Mon Sep 17 00:00:00 2001 +From: Tomeu Vizoso +Date: Thu, 11 Jun 2020 10:58:44 +0200 +Subject: [PATCH] drm/panfrost: Add compatible string for bifrost + +Mesa now supports some Bifrost devices, so enable it. + +Tested-by: Heiko Stuebner +Reviewed-by: Steven Price +Reviewed-by: Heiko Stuebner +Signed-off-by: Tomeu Vizoso +Signed-off-by: Rob Herring +Link: https://patchwork.freedesktop.org/patch/msgid/20200611085900.49740-2-tomeu.vizoso@collabora.com +(cherry picked from commit 72ef7fe96fd20d3d0e538e165b393819f99870ad) +--- + drivers/gpu/drm/panfrost/panfrost_drv.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/gpu/drm/panfrost/panfrost_drv.c b/drivers/gpu/drm/panfrost/panfrost_drv.c +index 882fecc33fdb..8ff8e140f91e 100644 +--- a/drivers/gpu/drm/panfrost/panfrost_drv.c ++++ b/drivers/gpu/drm/panfrost/panfrost_drv.c +@@ -677,6 +677,7 @@ static const struct of_device_id dt_match[] = { + { .compatible = "arm,mali-t830", .data = &default_data, }, + { .compatible = "arm,mali-t860", .data = &default_data, }, + { .compatible = "arm,mali-t880", .data = &default_data, }, ++ { .compatible = "arm,mali-bifrost", .data = &default_data, }, + {} + }; + MODULE_DEVICE_TABLE(of, dt_match); + +From 1404f107a58a28fb71227550469c4785fa58081c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Cl=C3=A9ment=20P=C3=A9ron?= +Date: Fri, 10 Jul 2020 11:53:56 +0200 +Subject: [PATCH] drm/panfrost: avoid static declaration +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This declaration can be avoided so change it. + +Reviewed-by: Steven Price +Reviewed-by: Alyssa Rosenzweig +Signed-off-by: Clément Péron +Signed-off-by: Rob Herring +Link: https://patchwork.freedesktop.org/patch/msgid/20200710095409.407087-2-peron.clem@gmail.com +(cherry picked from commit 862cc626210e34501b4d7a7795c41a67785987e5) +--- + drivers/gpu/drm/panfrost/panfrost_devfreq.c | 38 ++++++++++----------- + 1 file changed, 18 insertions(+), 20 deletions(-) + +diff --git a/drivers/gpu/drm/panfrost/panfrost_devfreq.c b/drivers/gpu/drm/panfrost/panfrost_devfreq.c +index 413987038fbf..1b560b903ea6 100644 +--- a/drivers/gpu/drm/panfrost/panfrost_devfreq.c ++++ b/drivers/gpu/drm/panfrost/panfrost_devfreq.c +@@ -14,7 +14,24 @@ + #include "panfrost_gpu.h" + #include "panfrost_regs.h" + +-static void panfrost_devfreq_update_utilization(struct panfrost_device *pfdev); ++static void panfrost_devfreq_update_utilization(struct panfrost_device *pfdev) ++{ ++ ktime_t now; ++ ktime_t last; ++ ++ if (!pfdev->devfreq.devfreq) ++ return; ++ ++ now = ktime_get(); ++ last = pfdev->devfreq.time_last_update; ++ ++ if (atomic_read(&pfdev->devfreq.busy_count) > 0) ++ pfdev->devfreq.busy_time += ktime_sub(now, last); ++ else ++ pfdev->devfreq.idle_time += ktime_sub(now, last); ++ ++ pfdev->devfreq.time_last_update = now; ++} + + static int panfrost_devfreq_target(struct device *dev, unsigned long *freq, + u32 flags) +@@ -139,25 +156,6 @@ void panfrost_devfreq_suspend(struct panfrost_device *pfdev) + devfreq_suspend_device(pfdev->devfreq.devfreq); + } + +-static void panfrost_devfreq_update_utilization(struct panfrost_device *pfdev) +-{ +- ktime_t now; +- ktime_t last; +- +- if (!pfdev->devfreq.devfreq) +- return; +- +- now = ktime_get(); +- last = pfdev->devfreq.time_last_update; +- +- if (atomic_read(&pfdev->devfreq.busy_count) > 0) +- pfdev->devfreq.busy_time += ktime_sub(now, last); +- else +- pfdev->devfreq.idle_time += ktime_sub(now, last); +- +- pfdev->devfreq.time_last_update = now; +-} +- + void panfrost_devfreq_record_busy(struct panfrost_device *pfdev) + { + panfrost_devfreq_update_utilization(pfdev); + +From 42e45c3c4195d8e7ebe5bf970c7da55fc9c0d157 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Cl=C3=A9ment=20P=C3=A9ron?= +Date: Fri, 10 Jul 2020 11:53:57 +0200 +Subject: [PATCH] drm/panfrost: clean headers in devfreq +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Don't include not required headers and sort them. + +Reviewed-by: Steven Price +Reviewed-by: Alyssa Rosenzweig +Signed-off-by: Clément Péron +Signed-off-by: Rob Herring +Link: https://patchwork.freedesktop.org/patch/msgid/20200710095409.407087-3-peron.clem@gmail.com +(cherry picked from commit 9713e942a539c55b5e0bc64ba83b736bda1087fe) +--- + drivers/gpu/drm/panfrost/panfrost_devfreq.c | 8 ++------ + 1 file changed, 2 insertions(+), 6 deletions(-) + +diff --git a/drivers/gpu/drm/panfrost/panfrost_devfreq.c b/drivers/gpu/drm/panfrost/panfrost_devfreq.c +index 1b560b903ea6..df7b71da9a84 100644 +--- a/drivers/gpu/drm/panfrost/panfrost_devfreq.c ++++ b/drivers/gpu/drm/panfrost/panfrost_devfreq.c +@@ -1,18 +1,14 @@ + // SPDX-License-Identifier: GPL-2.0 + /* Copyright 2019 Collabora ltd. */ ++ ++#include + #include + #include + #include + #include +-#include +-#include + + #include "panfrost_device.h" + #include "panfrost_devfreq.h" +-#include "panfrost_features.h" +-#include "panfrost_issues.h" +-#include "panfrost_gpu.h" +-#include "panfrost_regs.h" + + static void panfrost_devfreq_update_utilization(struct panfrost_device *pfdev) + { + +From 99fda3d26b30e5f30d45fc6197da6335a2806e73 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Cl=C3=A9ment=20P=C3=A9ron?= +Date: Fri, 10 Jul 2020 11:53:58 +0200 +Subject: [PATCH] drm/panfrost: don't use pfdevfreq.busy_count to know if hw is + idle +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This use devfreq variable that will be lock with spinlock in future +patches. We should either introduce a function to access this one +but as devfreq is optional let's just remove it. + +Reviewed-by: Steven Price +Reviewed-by: Alyssa Rosenzweig +Signed-off-by: Clément Péron +Signed-off-by: Rob Herring +Link: https://patchwork.freedesktop.org/patch/msgid/20200710095409.407087-4-peron.clem@gmail.com +(cherry picked from commit eb9dd67249b55fd1fa3d7359be387ea2079247a6) +--- + drivers/gpu/drm/panfrost/panfrost_job.c | 4 ---- + 1 file changed, 4 deletions(-) + +diff --git a/drivers/gpu/drm/panfrost/panfrost_job.c b/drivers/gpu/drm/panfrost/panfrost_job.c +index c6242fe34840..aec05be1ba7a 100644 +--- a/drivers/gpu/drm/panfrost/panfrost_job.c ++++ b/drivers/gpu/drm/panfrost/panfrost_job.c +@@ -581,10 +581,6 @@ int panfrost_job_is_idle(struct panfrost_device *pfdev) + struct panfrost_job_slot *js = pfdev->js; + int i; + +- /* Check whether the hardware is idle */ +- if (atomic_read(&pfdev->devfreq.busy_count)) +- return false; +- + for (i = 0; i < NUM_JOB_SLOTS; i++) { + /* If there are any jobs in the HW queue, we're not idle */ + if (atomic_read(&js->queue[i].sched.hw_rq_count)) + +From ca3fb7080e5fbaf5894bed7e119e8f4e49545449 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Cl=C3=A9ment=20P=C3=A9ron?= +Date: Fri, 10 Jul 2020 11:53:59 +0200 +Subject: [PATCH] drm/panfrost: introduce panfrost_devfreq struct +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Introduce a proper panfrost_devfreq to deal with devfreq variables. + +Reviewed-by: Steven Price +Reviewed-by: Alyssa Rosenzweig +Signed-off-by: Clément Péron +Signed-off-by: Rob Herring +Link: https://patchwork.freedesktop.org/patch/msgid/20200710095409.407087-5-peron.clem@gmail.com +(cherry picked from commit 9bfacfc82f903b066b0b63460d5b7943705048a4) +--- + drivers/gpu/drm/panfrost/panfrost_devfreq.c | 76 ++++++++++++--------- + drivers/gpu/drm/panfrost/panfrost_devfreq.h | 20 +++++- + drivers/gpu/drm/panfrost/panfrost_device.h | 11 +-- + drivers/gpu/drm/panfrost/panfrost_job.c | 6 +- + 4 files changed, 66 insertions(+), 47 deletions(-) + +diff --git a/drivers/gpu/drm/panfrost/panfrost_devfreq.c b/drivers/gpu/drm/panfrost/panfrost_devfreq.c +index df7b71da9a84..962550363391 100644 +--- a/drivers/gpu/drm/panfrost/panfrost_devfreq.c ++++ b/drivers/gpu/drm/panfrost/panfrost_devfreq.c +@@ -10,23 +10,23 @@ + #include "panfrost_device.h" + #include "panfrost_devfreq.h" + +-static void panfrost_devfreq_update_utilization(struct panfrost_device *pfdev) ++static void panfrost_devfreq_update_utilization(struct panfrost_devfreq *pfdevfreq) + { + ktime_t now; + ktime_t last; + +- if (!pfdev->devfreq.devfreq) ++ if (!pfdevfreq->devfreq) + return; + + now = ktime_get(); +- last = pfdev->devfreq.time_last_update; ++ last = pfdevfreq->time_last_update; + +- if (atomic_read(&pfdev->devfreq.busy_count) > 0) +- pfdev->devfreq.busy_time += ktime_sub(now, last); ++ if (atomic_read(&pfdevfreq->busy_count) > 0) ++ pfdevfreq->busy_time += ktime_sub(now, last); + else +- pfdev->devfreq.idle_time += ktime_sub(now, last); ++ pfdevfreq->idle_time += ktime_sub(now, last); + +- pfdev->devfreq.time_last_update = now; ++ pfdevfreq->time_last_update = now; + } + + static int panfrost_devfreq_target(struct device *dev, unsigned long *freq, +@@ -47,30 +47,31 @@ static int panfrost_devfreq_target(struct device *dev, unsigned long *freq, + return 0; + } + +-static void panfrost_devfreq_reset(struct panfrost_device *pfdev) ++static void panfrost_devfreq_reset(struct panfrost_devfreq *pfdevfreq) + { +- pfdev->devfreq.busy_time = 0; +- pfdev->devfreq.idle_time = 0; +- pfdev->devfreq.time_last_update = ktime_get(); ++ pfdevfreq->busy_time = 0; ++ pfdevfreq->idle_time = 0; ++ pfdevfreq->time_last_update = ktime_get(); + } + + static int panfrost_devfreq_get_dev_status(struct device *dev, + struct devfreq_dev_status *status) + { + struct panfrost_device *pfdev = dev_get_drvdata(dev); ++ struct panfrost_devfreq *pfdevfreq = &pfdev->pfdevfreq; + +- panfrost_devfreq_update_utilization(pfdev); ++ panfrost_devfreq_update_utilization(pfdevfreq); + + status->current_frequency = clk_get_rate(pfdev->clock); +- status->total_time = ktime_to_ns(ktime_add(pfdev->devfreq.busy_time, +- pfdev->devfreq.idle_time)); ++ status->total_time = ktime_to_ns(ktime_add(pfdevfreq->busy_time, ++ pfdevfreq->idle_time)); + +- status->busy_time = ktime_to_ns(pfdev->devfreq.busy_time); ++ status->busy_time = ktime_to_ns(pfdevfreq->busy_time); + +- panfrost_devfreq_reset(pfdev); ++ panfrost_devfreq_reset(pfdevfreq); + +- dev_dbg(pfdev->dev, "busy %lu total %lu %lu %% freq %lu MHz\n", status->busy_time, +- status->total_time, ++ dev_dbg(pfdev->dev, "busy %lu total %lu %lu %% freq %lu MHz\n", ++ status->busy_time, status->total_time, + status->busy_time / (status->total_time / 100), + status->current_frequency / 1000 / 1000); + +@@ -91,6 +92,7 @@ int panfrost_devfreq_init(struct panfrost_device *pfdev) + struct device *dev = &pfdev->pdev->dev; + struct devfreq *devfreq; + struct thermal_cooling_device *cooling; ++ struct panfrost_devfreq *pfdevfreq = &pfdev->pfdevfreq; + + ret = dev_pm_opp_of_add_table(dev); + if (ret == -ENODEV) /* Optional, continue without devfreq */ +@@ -98,7 +100,7 @@ int panfrost_devfreq_init(struct panfrost_device *pfdev) + else if (ret) + return ret; + +- panfrost_devfreq_reset(pfdev); ++ panfrost_devfreq_reset(pfdevfreq); + + cur_freq = clk_get_rate(pfdev->clock); + +@@ -116,53 +118,59 @@ int panfrost_devfreq_init(struct panfrost_device *pfdev) + dev_pm_opp_of_remove_table(dev); + return PTR_ERR(devfreq); + } +- pfdev->devfreq.devfreq = devfreq; ++ pfdevfreq->devfreq = devfreq; + + cooling = of_devfreq_cooling_register(dev->of_node, devfreq); + if (IS_ERR(cooling)) + DRM_DEV_INFO(dev, "Failed to register cooling device\n"); + else +- pfdev->devfreq.cooling = cooling; ++ pfdevfreq->cooling = cooling; + + return 0; + } + + void panfrost_devfreq_fini(struct panfrost_device *pfdev) + { +- if (pfdev->devfreq.cooling) +- devfreq_cooling_unregister(pfdev->devfreq.cooling); ++ struct panfrost_devfreq *pfdevfreq = &pfdev->pfdevfreq; ++ ++ if (pfdevfreq->cooling) ++ devfreq_cooling_unregister(pfdevfreq->cooling); + dev_pm_opp_of_remove_table(&pfdev->pdev->dev); + } + + void panfrost_devfreq_resume(struct panfrost_device *pfdev) + { +- if (!pfdev->devfreq.devfreq) ++ struct panfrost_devfreq *pfdevfreq = &pfdev->pfdevfreq; ++ ++ if (!pfdevfreq->devfreq) + return; + +- panfrost_devfreq_reset(pfdev); ++ panfrost_devfreq_reset(pfdevfreq); + +- devfreq_resume_device(pfdev->devfreq.devfreq); ++ devfreq_resume_device(pfdevfreq->devfreq); + } + + void panfrost_devfreq_suspend(struct panfrost_device *pfdev) + { +- if (!pfdev->devfreq.devfreq) ++ struct panfrost_devfreq *pfdevfreq = &pfdev->pfdevfreq; ++ ++ if (!pfdevfreq->devfreq) + return; + +- devfreq_suspend_device(pfdev->devfreq.devfreq); ++ devfreq_suspend_device(pfdevfreq->devfreq); + } + +-void panfrost_devfreq_record_busy(struct panfrost_device *pfdev) ++void panfrost_devfreq_record_busy(struct panfrost_devfreq *pfdevfreq) + { +- panfrost_devfreq_update_utilization(pfdev); +- atomic_inc(&pfdev->devfreq.busy_count); ++ panfrost_devfreq_update_utilization(pfdevfreq); ++ atomic_inc(&pfdevfreq->busy_count); + } + +-void panfrost_devfreq_record_idle(struct panfrost_device *pfdev) ++void panfrost_devfreq_record_idle(struct panfrost_devfreq *pfdevfreq) + { + int count; + +- panfrost_devfreq_update_utilization(pfdev); +- count = atomic_dec_if_positive(&pfdev->devfreq.busy_count); ++ panfrost_devfreq_update_utilization(pfdevfreq); ++ count = atomic_dec_if_positive(&pfdevfreq->busy_count); + WARN_ON(count < 0); + } +diff --git a/drivers/gpu/drm/panfrost/panfrost_devfreq.h b/drivers/gpu/drm/panfrost/panfrost_devfreq.h +index 0611beffc8d0..0697f8d5aa34 100644 +--- a/drivers/gpu/drm/panfrost/panfrost_devfreq.h ++++ b/drivers/gpu/drm/panfrost/panfrost_devfreq.h +@@ -4,13 +4,29 @@ + #ifndef __PANFROST_DEVFREQ_H__ + #define __PANFROST_DEVFREQ_H__ + ++#include ++ ++struct devfreq; ++struct thermal_cooling_device; ++ ++struct panfrost_device; ++ ++struct panfrost_devfreq { ++ struct devfreq *devfreq; ++ struct thermal_cooling_device *cooling; ++ ktime_t busy_time; ++ ktime_t idle_time; ++ ktime_t time_last_update; ++ atomic_t busy_count; ++}; ++ + int panfrost_devfreq_init(struct panfrost_device *pfdev); + void panfrost_devfreq_fini(struct panfrost_device *pfdev); + + void panfrost_devfreq_resume(struct panfrost_device *pfdev); + void panfrost_devfreq_suspend(struct panfrost_device *pfdev); + +-void panfrost_devfreq_record_busy(struct panfrost_device *pfdev); +-void panfrost_devfreq_record_idle(struct panfrost_device *pfdev); ++void panfrost_devfreq_record_busy(struct panfrost_devfreq *devfreq); ++void panfrost_devfreq_record_idle(struct panfrost_devfreq *devfreq); + + #endif /* __PANFROST_DEVFREQ_H__ */ +diff --git a/drivers/gpu/drm/panfrost/panfrost_device.h b/drivers/gpu/drm/panfrost/panfrost_device.h +index c30c719a8059..2efa59c9d1c5 100644 +--- a/drivers/gpu/drm/panfrost/panfrost_device.h ++++ b/drivers/gpu/drm/panfrost/panfrost_device.h +@@ -13,6 +13,8 @@ + #include + #include + ++#include "panfrost_devfreq.h" ++ + struct panfrost_device; + struct panfrost_mmu; + struct panfrost_job_slot; +@@ -107,14 +109,7 @@ struct panfrost_device { + struct list_head shrinker_list; + struct shrinker shrinker; + +- struct { +- struct devfreq *devfreq; +- struct thermal_cooling_device *cooling; +- ktime_t busy_time; +- ktime_t idle_time; +- ktime_t time_last_update; +- atomic_t busy_count; +- } devfreq; ++ struct panfrost_devfreq pfdevfreq; + }; + + struct panfrost_mmu { +diff --git a/drivers/gpu/drm/panfrost/panfrost_job.c b/drivers/gpu/drm/panfrost/panfrost_job.c +index aec05be1ba7a..2f297d962e64 100644 +--- a/drivers/gpu/drm/panfrost/panfrost_job.c ++++ b/drivers/gpu/drm/panfrost/panfrost_job.c +@@ -145,7 +145,7 @@ static void panfrost_job_hw_submit(struct panfrost_job *job, int js) + u64 jc_head = job->jc; + int ret; + +- panfrost_devfreq_record_busy(pfdev); ++ panfrost_devfreq_record_busy(&pfdev->pfdevfreq); + + ret = pm_runtime_get_sync(pfdev->dev); + if (ret < 0) +@@ -410,7 +410,7 @@ static void panfrost_job_timedout(struct drm_sched_job *sched_job) + for (i = 0; i < NUM_JOB_SLOTS; i++) { + if (pfdev->jobs[i]) { + pm_runtime_put_noidle(pfdev->dev); +- panfrost_devfreq_record_idle(pfdev); ++ panfrost_devfreq_record_idle(&pfdev->pfdevfreq); + pfdev->jobs[i] = NULL; + } + } +@@ -478,7 +478,7 @@ static irqreturn_t panfrost_job_irq_handler(int irq, void *data) + pfdev->jobs[j] = NULL; + + panfrost_mmu_as_put(pfdev, &job->file_priv->mmu); +- panfrost_devfreq_record_idle(pfdev); ++ panfrost_devfreq_record_idle(&pfdev->pfdevfreq); + + dma_fence_signal_locked(job->done_fence); + pm_runtime_put_autosuspend(pfdev->dev); + +From 950ed8f4f8c6ab02e5f1c7b107e5af9a896c90dc Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Cl=C3=A9ment=20P=C3=A9ron?= +Date: Fri, 10 Jul 2020 11:54:00 +0200 +Subject: [PATCH] drm/panfrost: use spinlock instead of atomic +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Convert busy_count to a simple int protected by spinlock. + +Reviewed-by: Steven Price +Reviewed-by: Alyssa Rosenzweig +Signed-off-by: Clément Péron +Signed-off-by: Rob Herring +Link: https://patchwork.freedesktop.org/patch/msgid/20200710095409.407087-6-peron.clem@gmail.com +(cherry picked from commit ed85df3f60740bb4be23fbc2db283d59b361a834) +--- + drivers/gpu/drm/panfrost/panfrost_devfreq.c | 43 +++++++++++++++------ + drivers/gpu/drm/panfrost/panfrost_devfreq.h | 9 ++++- + 2 files changed, 40 insertions(+), 12 deletions(-) + +diff --git a/drivers/gpu/drm/panfrost/panfrost_devfreq.c b/drivers/gpu/drm/panfrost/panfrost_devfreq.c +index 962550363391..78753cfb59fb 100644 +--- a/drivers/gpu/drm/panfrost/panfrost_devfreq.c ++++ b/drivers/gpu/drm/panfrost/panfrost_devfreq.c +@@ -12,16 +12,12 @@ + + static void panfrost_devfreq_update_utilization(struct panfrost_devfreq *pfdevfreq) + { +- ktime_t now; +- ktime_t last; +- +- if (!pfdevfreq->devfreq) +- return; ++ ktime_t now, last; + + now = ktime_get(); + last = pfdevfreq->time_last_update; + +- if (atomic_read(&pfdevfreq->busy_count) > 0) ++ if (pfdevfreq->busy_count > 0) + pfdevfreq->busy_time += ktime_sub(now, last); + else + pfdevfreq->idle_time += ktime_sub(now, last); +@@ -59,10 +55,14 @@ static int panfrost_devfreq_get_dev_status(struct device *dev, + { + struct panfrost_device *pfdev = dev_get_drvdata(dev); + struct panfrost_devfreq *pfdevfreq = &pfdev->pfdevfreq; ++ unsigned long irqflags; ++ ++ status->current_frequency = clk_get_rate(pfdev->clock); ++ ++ spin_lock_irqsave(&pfdevfreq->lock, irqflags); + + panfrost_devfreq_update_utilization(pfdevfreq); + +- status->current_frequency = clk_get_rate(pfdev->clock); + status->total_time = ktime_to_ns(ktime_add(pfdevfreq->busy_time, + pfdevfreq->idle_time)); + +@@ -70,6 +70,8 @@ static int panfrost_devfreq_get_dev_status(struct device *dev, + + panfrost_devfreq_reset(pfdevfreq); + ++ spin_unlock_irqrestore(&pfdevfreq->lock, irqflags); ++ + dev_dbg(pfdev->dev, "busy %lu total %lu %lu %% freq %lu MHz\n", + status->busy_time, status->total_time, + status->busy_time / (status->total_time / 100), +@@ -100,6 +102,8 @@ int panfrost_devfreq_init(struct panfrost_device *pfdev) + else if (ret) + return ret; + ++ spin_lock_init(&pfdevfreq->lock); ++ + panfrost_devfreq_reset(pfdevfreq); + + cur_freq = clk_get_rate(pfdev->clock); +@@ -162,15 +166,32 @@ void panfrost_devfreq_suspend(struct panfrost_device *pfdev) + + void panfrost_devfreq_record_busy(struct panfrost_devfreq *pfdevfreq) + { ++ unsigned long irqflags; ++ ++ if (!pfdevfreq->devfreq) ++ return; ++ ++ spin_lock_irqsave(&pfdevfreq->lock, irqflags); ++ + panfrost_devfreq_update_utilization(pfdevfreq); +- atomic_inc(&pfdevfreq->busy_count); ++ ++ pfdevfreq->busy_count++; ++ ++ spin_unlock_irqrestore(&pfdevfreq->lock, irqflags); + } + + void panfrost_devfreq_record_idle(struct panfrost_devfreq *pfdevfreq) + { +- int count; ++ unsigned long irqflags; ++ ++ if (!pfdevfreq->devfreq) ++ return; ++ ++ spin_lock_irqsave(&pfdevfreq->lock, irqflags); + + panfrost_devfreq_update_utilization(pfdevfreq); +- count = atomic_dec_if_positive(&pfdevfreq->busy_count); +- WARN_ON(count < 0); ++ ++ WARN_ON(--pfdevfreq->busy_count < 0); ++ ++ spin_unlock_irqrestore(&pfdevfreq->lock, irqflags); + } +diff --git a/drivers/gpu/drm/panfrost/panfrost_devfreq.h b/drivers/gpu/drm/panfrost/panfrost_devfreq.h +index 0697f8d5aa34..3392df1020be 100644 +--- a/drivers/gpu/drm/panfrost/panfrost_devfreq.h ++++ b/drivers/gpu/drm/panfrost/panfrost_devfreq.h +@@ -4,6 +4,7 @@ + #ifndef __PANFROST_DEVFREQ_H__ + #define __PANFROST_DEVFREQ_H__ + ++#include + #include + + struct devfreq; +@@ -14,10 +15,16 @@ struct panfrost_device; + struct panfrost_devfreq { + struct devfreq *devfreq; + struct thermal_cooling_device *cooling; ++ + ktime_t busy_time; + ktime_t idle_time; + ktime_t time_last_update; +- atomic_t busy_count; ++ int busy_count; ++ /* ++ * Protect busy_time, idle_time, time_last_update and busy_count ++ * because these can be updated concurrently between multiple jobs. ++ */ ++ spinlock_t lock; + }; + + int panfrost_devfreq_init(struct panfrost_device *pfdev); + +From ac548872c7b7887d34b549efa3b8334b2cc862ed Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Cl=C3=A9ment=20P=C3=A9ron?= +Date: Fri, 10 Jul 2020 11:54:01 +0200 +Subject: [PATCH] drm/panfrost: properly handle error in probe +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Introduce a boolean to know if opp table has been added. + +With this, we can call panfrost_devfreq_fini() in case of error +and release what has been initialised. + +Reviewed-by: Steven Price +Reviewed-by: Alyssa Rosenzweig +Signed-off-by: Clément Péron +Signed-off-by: Rob Herring +Link: https://patchwork.freedesktop.org/patch/msgid/20200710095409.407087-7-peron.clem@gmail.com +(cherry picked from commit 81f2fbe62cb54b6cf3d91078c4d49451ba7b9877) +--- + drivers/gpu/drm/panfrost/panfrost_devfreq.c | 25 ++++++++++++++++----- + drivers/gpu/drm/panfrost/panfrost_devfreq.h | 1 + + 2 files changed, 20 insertions(+), 6 deletions(-) + +diff --git a/drivers/gpu/drm/panfrost/panfrost_devfreq.c b/drivers/gpu/drm/panfrost/panfrost_devfreq.c +index 78753cfb59fb..d9007f44b772 100644 +--- a/drivers/gpu/drm/panfrost/panfrost_devfreq.c ++++ b/drivers/gpu/drm/panfrost/panfrost_devfreq.c +@@ -101,6 +101,7 @@ int panfrost_devfreq_init(struct panfrost_device *pfdev) + return 0; + else if (ret) + return ret; ++ pfdevfreq->opp_of_table_added = true; + + spin_lock_init(&pfdevfreq->lock); + +@@ -109,8 +110,10 @@ int panfrost_devfreq_init(struct panfrost_device *pfdev) + cur_freq = clk_get_rate(pfdev->clock); + + opp = devfreq_recommended_opp(dev, &cur_freq, 0); +- if (IS_ERR(opp)) +- return PTR_ERR(opp); ++ if (IS_ERR(opp)) { ++ ret = PTR_ERR(opp); ++ goto err_fini; ++ } + + panfrost_devfreq_profile.initial_freq = cur_freq; + dev_pm_opp_put(opp); +@@ -119,8 +122,8 @@ int panfrost_devfreq_init(struct panfrost_device *pfdev) + DEVFREQ_GOV_SIMPLE_ONDEMAND, NULL); + if (IS_ERR(devfreq)) { + DRM_DEV_ERROR(dev, "Couldn't initialize GPU devfreq\n"); +- dev_pm_opp_of_remove_table(dev); +- return PTR_ERR(devfreq); ++ ret = PTR_ERR(devfreq); ++ goto err_fini; + } + pfdevfreq->devfreq = devfreq; + +@@ -131,15 +134,25 @@ int panfrost_devfreq_init(struct panfrost_device *pfdev) + pfdevfreq->cooling = cooling; + + return 0; ++ ++err_fini: ++ panfrost_devfreq_fini(pfdev); ++ return ret; + } + + void panfrost_devfreq_fini(struct panfrost_device *pfdev) + { + struct panfrost_devfreq *pfdevfreq = &pfdev->pfdevfreq; + +- if (pfdevfreq->cooling) ++ if (pfdevfreq->cooling) { + devfreq_cooling_unregister(pfdevfreq->cooling); +- dev_pm_opp_of_remove_table(&pfdev->pdev->dev); ++ pfdevfreq->cooling = NULL; ++ } ++ ++ if (pfdevfreq->opp_of_table_added) { ++ dev_pm_opp_of_remove_table(&pfdev->pdev->dev); ++ pfdevfreq->opp_of_table_added = false; ++ } + } + + void panfrost_devfreq_resume(struct panfrost_device *pfdev) +diff --git a/drivers/gpu/drm/panfrost/panfrost_devfreq.h b/drivers/gpu/drm/panfrost/panfrost_devfreq.h +index 3392df1020be..210269944687 100644 +--- a/drivers/gpu/drm/panfrost/panfrost_devfreq.h ++++ b/drivers/gpu/drm/panfrost/panfrost_devfreq.h +@@ -15,6 +15,7 @@ struct panfrost_device; + struct panfrost_devfreq { + struct devfreq *devfreq; + struct thermal_cooling_device *cooling; ++ bool opp_of_table_added; + + ktime_t busy_time; + ktime_t idle_time; + +From 96a752deaead8b45cd188cde09cb873fd8dfd4b6 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Cl=C3=A9ment=20P=C3=A9ron?= +Date: Fri, 10 Jul 2020 11:54:02 +0200 +Subject: [PATCH] drm/panfrost: rename error labels in device_init +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Rename goto labels in device_init it will be easier to maintain. + +Reviewed-by: Alyssa Rosenzweig +Reviewed-by: Steven Price +Signed-off-by: Clément Péron +Signed-off-by: Rob Herring +Link: https://patchwork.freedesktop.org/patch/msgid/20200710095409.407087-8-peron.clem@gmail.com +(cherry picked from commit d3c335da0200be9287cdf5755d19f62ce1670a8d) +--- + drivers/gpu/drm/panfrost/panfrost_device.c | 30 +++++++++++----------- + 1 file changed, 15 insertions(+), 15 deletions(-) + +diff --git a/drivers/gpu/drm/panfrost/panfrost_device.c b/drivers/gpu/drm/panfrost/panfrost_device.c +index b172087eee6a..9f89984f652a 100644 +--- a/drivers/gpu/drm/panfrost/panfrost_device.c ++++ b/drivers/gpu/drm/panfrost/panfrost_device.c +@@ -216,56 +216,56 @@ int panfrost_device_init(struct panfrost_device *pfdev) + + err = panfrost_regulator_init(pfdev); + if (err) +- goto err_out0; ++ goto out_clk; + + err = panfrost_reset_init(pfdev); + if (err) { + dev_err(pfdev->dev, "reset init failed %d\n", err); +- goto err_out1; ++ goto out_regulator; + } + + err = panfrost_pm_domain_init(pfdev); + if (err) +- goto err_out2; ++ goto out_reset; + + res = platform_get_resource(pfdev->pdev, IORESOURCE_MEM, 0); + pfdev->iomem = devm_ioremap_resource(pfdev->dev, res); + if (IS_ERR(pfdev->iomem)) { + dev_err(pfdev->dev, "failed to ioremap iomem\n"); + err = PTR_ERR(pfdev->iomem); +- goto err_out3; ++ goto out_pm_domain; + } + + err = panfrost_gpu_init(pfdev); + if (err) +- goto err_out3; ++ goto out_pm_domain; + + err = panfrost_mmu_init(pfdev); + if (err) +- goto err_out4; ++ goto out_gpu; + + err = panfrost_job_init(pfdev); + if (err) +- goto err_out5; ++ goto out_mmu; + + err = panfrost_perfcnt_init(pfdev); + if (err) +- goto err_out6; ++ goto out_job; + + return 0; +-err_out6: ++out_job: + panfrost_job_fini(pfdev); +-err_out5: ++out_mmu: + panfrost_mmu_fini(pfdev); +-err_out4: ++out_gpu: + panfrost_gpu_fini(pfdev); +-err_out3: ++out_pm_domain: + panfrost_pm_domain_fini(pfdev); +-err_out2: ++out_reset: + panfrost_reset_fini(pfdev); +-err_out1: ++out_regulator: + panfrost_regulator_fini(pfdev); +-err_out0: ++out_clk: + panfrost_clk_fini(pfdev); + return err; + } + +From 9c803e01258f241d49e1162ca6db5b29a98ba57d Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Cl=C3=A9ment=20P=C3=A9ron?= +Date: Fri, 10 Jul 2020 11:54:03 +0200 +Subject: [PATCH] drm/panfrost: move devfreq_init()/fini() in device +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Later we will introduce devfreq probing regulator if they +are present. As regulator should be probe only one time we +need to get this logic in the device_init(). + +panfrost_device is already taking care of devfreq_resume() +and devfreq_suspend(), so it's not totally illogic to move +the devfreq_init() and devfreq_fini() here. + +Reviewed-by: Alyssa Rosenzweig +Reviewed-by: Steven Price +Signed-off-by: Clément Péron +Signed-off-by: Rob Herring +Link: https://patchwork.freedesktop.org/patch/msgid/20200710095409.407087-9-peron.clem@gmail.com +(cherry picked from commit 25e247bbf85af3ad721dfeb2e2caf405f43b7e66) +--- + drivers/gpu/drm/panfrost/panfrost_device.c | 12 +++++++++++- + drivers/gpu/drm/panfrost/panfrost_drv.c | 15 ++------------- + 2 files changed, 13 insertions(+), 14 deletions(-) + +diff --git a/drivers/gpu/drm/panfrost/panfrost_device.c b/drivers/gpu/drm/panfrost/panfrost_device.c +index 9f89984f652a..36b5c8fea3eb 100644 +--- a/drivers/gpu/drm/panfrost/panfrost_device.c ++++ b/drivers/gpu/drm/panfrost/panfrost_device.c +@@ -214,9 +214,16 @@ int panfrost_device_init(struct panfrost_device *pfdev) + return err; + } + ++ err = panfrost_devfreq_init(pfdev); ++ if (err) { ++ if (err != -EPROBE_DEFER) ++ dev_err(pfdev->dev, "devfreq init failed %d\n", err); ++ goto out_clk; ++ } ++ + err = panfrost_regulator_init(pfdev); + if (err) +- goto out_clk; ++ goto out_devfreq; + + err = panfrost_reset_init(pfdev); + if (err) { +@@ -265,6 +272,8 @@ int panfrost_device_init(struct panfrost_device *pfdev) + panfrost_reset_fini(pfdev); + out_regulator: + panfrost_regulator_fini(pfdev); ++out_devfreq: ++ panfrost_devfreq_fini(pfdev); + out_clk: + panfrost_clk_fini(pfdev); + return err; +@@ -278,6 +287,7 @@ void panfrost_device_fini(struct panfrost_device *pfdev) + panfrost_gpu_fini(pfdev); + panfrost_pm_domain_fini(pfdev); + panfrost_reset_fini(pfdev); ++ panfrost_devfreq_fini(pfdev); + panfrost_regulator_fini(pfdev); + panfrost_clk_fini(pfdev); + } +diff --git a/drivers/gpu/drm/panfrost/panfrost_drv.c b/drivers/gpu/drm/panfrost/panfrost_drv.c +index 8ff8e140f91e..ed8bcdd6b211 100644 +--- a/drivers/gpu/drm/panfrost/panfrost_drv.c ++++ b/drivers/gpu/drm/panfrost/panfrost_drv.c +@@ -14,7 +14,6 @@ + #include + + #include "panfrost_device.h" +-#include "panfrost_devfreq.h" + #include "panfrost_gem.h" + #include "panfrost_mmu.h" + #include "panfrost_job.h" +@@ -606,13 +605,6 @@ static int panfrost_probe(struct platform_device *pdev) + goto err_out0; + } + +- err = panfrost_devfreq_init(pfdev); +- if (err) { +- if (err != -EPROBE_DEFER) +- dev_err(&pdev->dev, "Fatal error during devfreq init\n"); +- goto err_out1; +- } +- + pm_runtime_set_active(pfdev->dev); + pm_runtime_mark_last_busy(pfdev->dev); + pm_runtime_enable(pfdev->dev); +@@ -625,16 +617,14 @@ static int panfrost_probe(struct platform_device *pdev) + */ + err = drm_dev_register(ddev, 0); + if (err < 0) +- goto err_out2; ++ goto err_out1; + + panfrost_gem_shrinker_init(ddev); + + return 0; + +-err_out2: +- pm_runtime_disable(pfdev->dev); +- panfrost_devfreq_fini(pfdev); + err_out1: ++ pm_runtime_disable(pfdev->dev); + panfrost_device_fini(pfdev); + err_out0: + drm_dev_put(ddev); +@@ -650,7 +640,6 @@ static int panfrost_remove(struct platform_device *pdev) + panfrost_gem_shrinker_cleanup(ddev); + + pm_runtime_get_sync(pfdev->dev); +- panfrost_devfreq_fini(pfdev); + panfrost_device_fini(pfdev); + pm_runtime_put_sync_suspend(pfdev->dev); + pm_runtime_disable(pfdev->dev); + +From d858649520907e147d85147efb8cfdb280ee5852 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Cl=C3=A9ment=20P=C3=A9ron?= +Date: Fri, 10 Jul 2020 11:54:04 +0200 +Subject: [PATCH] drm/panfrost: dynamically alloc regulators +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +We will later introduce regulators managed by OPP. + +Only alloc regulators when it's needed. This also help use +to release the regulators only when they are allocated. + +Reviewed-by: Steven Price +Reviewed-by: Alyssa Rosenzweig +Signed-off-by: Clément Péron +Signed-off-by: Rob Herring +Link: https://patchwork.freedesktop.org/patch/msgid/20200710095409.407087-10-peron.clem@gmail.com +(cherry picked from commit 512f21227fd3d2dbe7aad57a995b9732229c9b56) +--- + drivers/gpu/drm/panfrost/panfrost_device.c | 14 +++++++++----- + drivers/gpu/drm/panfrost/panfrost_device.h | 3 +-- + 2 files changed, 10 insertions(+), 7 deletions(-) + +diff --git a/drivers/gpu/drm/panfrost/panfrost_device.c b/drivers/gpu/drm/panfrost/panfrost_device.c +index 36b5c8fea3eb..f1474b961def 100644 +--- a/drivers/gpu/drm/panfrost/panfrost_device.c ++++ b/drivers/gpu/drm/panfrost/panfrost_device.c +@@ -90,9 +90,11 @@ static int panfrost_regulator_init(struct panfrost_device *pfdev) + { + int ret, i; + +- if (WARN(pfdev->comp->num_supplies > ARRAY_SIZE(pfdev->regulators), +- "Too many supplies in compatible structure.\n")) +- return -EINVAL; ++ pfdev->regulators = devm_kcalloc(pfdev->dev, pfdev->comp->num_supplies, ++ sizeof(*pfdev->regulators), ++ GFP_KERNEL); ++ if (!pfdev->regulators) ++ return -ENOMEM; + + for (i = 0; i < pfdev->comp->num_supplies; i++) + pfdev->regulators[i].supply = pfdev->comp->supply_names[i]; +@@ -119,8 +121,10 @@ static int panfrost_regulator_init(struct panfrost_device *pfdev) + + static void panfrost_regulator_fini(struct panfrost_device *pfdev) + { +- regulator_bulk_disable(pfdev->comp->num_supplies, +- pfdev->regulators); ++ if (!pfdev->regulators) ++ return; ++ ++ regulator_bulk_disable(pfdev->comp->num_supplies, pfdev->regulators); + } + + static void panfrost_pm_domain_fini(struct panfrost_device *pfdev) +diff --git a/drivers/gpu/drm/panfrost/panfrost_device.h b/drivers/gpu/drm/panfrost/panfrost_device.h +index 2efa59c9d1c5..953f7536a773 100644 +--- a/drivers/gpu/drm/panfrost/panfrost_device.h ++++ b/drivers/gpu/drm/panfrost/panfrost_device.h +@@ -22,7 +22,6 @@ struct panfrost_job; + struct panfrost_perfcnt; + + #define NUM_JOB_SLOTS 3 +-#define MAX_REGULATORS 2 + #define MAX_PM_DOMAINS 3 + + struct panfrost_features { +@@ -81,7 +80,7 @@ struct panfrost_device { + void __iomem *iomem; + struct clk *clock; + struct clk *bus_clock; +- struct regulator_bulk_data regulators[MAX_REGULATORS]; ++ struct regulator_bulk_data *regulators; + struct reset_control *rstc; + /* pm_domains for devices with more than one. */ + struct device *pm_domain_devs[MAX_PM_DOMAINS]; + +From 1ee7aed7c3c6736b33828d488a6d29bd8f0e0e84 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Cl=C3=A9ment=20P=C3=A9ron?= +Date: Fri, 10 Jul 2020 11:54:05 +0200 +Subject: [PATCH] drm/panfrost: add regulators to devfreq +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Some OPP tables specify voltage for each frequency. Devfreq can +handle these regulators but they should be get only 1 time to avoid +issue and know who is in charge. + +If OPP table is probe don't init regulator. + +Reviewed-by: Steven Price +Reviewed-by: Alyssa Rosenzweig +Signed-off-by: Clément Péron +Signed-off-by: Rob Herring +Link: https://patchwork.freedesktop.org/patch/msgid/20200710095409.407087-11-peron.clem@gmail.com +(cherry picked from commit fd587ff01d59554144e2fd20f4113638a45c7c4e) +--- + drivers/gpu/drm/panfrost/panfrost_devfreq.c | 29 ++++++++++++++++++--- + drivers/gpu/drm/panfrost/panfrost_devfreq.h | 2 ++ + drivers/gpu/drm/panfrost/panfrost_device.c | 9 ++++--- + 3 files changed, 33 insertions(+), 7 deletions(-) + +diff --git a/drivers/gpu/drm/panfrost/panfrost_devfreq.c b/drivers/gpu/drm/panfrost/panfrost_devfreq.c +index d9007f44b772..8ab025d0035f 100644 +--- a/drivers/gpu/drm/panfrost/panfrost_devfreq.c ++++ b/drivers/gpu/drm/panfrost/panfrost_devfreq.c +@@ -93,14 +93,30 @@ int panfrost_devfreq_init(struct panfrost_device *pfdev) + unsigned long cur_freq; + struct device *dev = &pfdev->pdev->dev; + struct devfreq *devfreq; ++ struct opp_table *opp_table; + struct thermal_cooling_device *cooling; + struct panfrost_devfreq *pfdevfreq = &pfdev->pfdevfreq; + ++ opp_table = dev_pm_opp_set_regulators(dev, pfdev->comp->supply_names, ++ pfdev->comp->num_supplies); ++ if (IS_ERR(opp_table)) { ++ ret = PTR_ERR(opp_table); ++ /* Continue if the optional regulator is missing */ ++ if (ret != -ENODEV) { ++ DRM_DEV_ERROR(dev, "Couldn't set OPP regulators\n"); ++ goto err_fini; ++ } ++ } else { ++ pfdevfreq->regulators_opp_table = opp_table; ++ } ++ + ret = dev_pm_opp_of_add_table(dev); +- if (ret == -ENODEV) /* Optional, continue without devfreq */ +- return 0; +- else if (ret) +- return ret; ++ if (ret) { ++ /* Optional, continue without devfreq */ ++ if (ret == -ENODEV) ++ ret = 0; ++ goto err_fini; ++ } + pfdevfreq->opp_of_table_added = true; + + spin_lock_init(&pfdevfreq->lock); +@@ -153,6 +169,11 @@ void panfrost_devfreq_fini(struct panfrost_device *pfdev) + dev_pm_opp_of_remove_table(&pfdev->pdev->dev); + pfdevfreq->opp_of_table_added = false; + } ++ ++ if (pfdevfreq->regulators_opp_table) { ++ dev_pm_opp_put_regulators(pfdevfreq->regulators_opp_table); ++ pfdevfreq->regulators_opp_table = NULL; ++ } + } + + void panfrost_devfreq_resume(struct panfrost_device *pfdev) +diff --git a/drivers/gpu/drm/panfrost/panfrost_devfreq.h b/drivers/gpu/drm/panfrost/panfrost_devfreq.h +index 210269944687..db6ea48e21f9 100644 +--- a/drivers/gpu/drm/panfrost/panfrost_devfreq.h ++++ b/drivers/gpu/drm/panfrost/panfrost_devfreq.h +@@ -8,12 +8,14 @@ + #include + + struct devfreq; ++struct opp_table; + struct thermal_cooling_device; + + struct panfrost_device; + + struct panfrost_devfreq { + struct devfreq *devfreq; ++ struct opp_table *regulators_opp_table; + struct thermal_cooling_device *cooling; + bool opp_of_table_added; + +diff --git a/drivers/gpu/drm/panfrost/panfrost_device.c b/drivers/gpu/drm/panfrost/panfrost_device.c +index f1474b961def..e6896733838a 100644 +--- a/drivers/gpu/drm/panfrost/panfrost_device.c ++++ b/drivers/gpu/drm/panfrost/panfrost_device.c +@@ -225,9 +225,12 @@ int panfrost_device_init(struct panfrost_device *pfdev) + goto out_clk; + } + +- err = panfrost_regulator_init(pfdev); +- if (err) +- goto out_devfreq; ++ /* OPP will handle regulators */ ++ if (!pfdev->pfdevfreq.opp_of_table_added) { ++ err = panfrost_regulator_init(pfdev); ++ if (err) ++ goto out_devfreq; ++ } + + err = panfrost_reset_init(pfdev); + if (err) { + +From 94b3398f3b4d5e963f284bd39515bfdf84530c6c Mon Sep 17 00:00:00 2001 +From: Navid Emamdoost +Date: Sun, 14 Jun 2020 01:36:19 -0500 +Subject: [PATCH] drm/panfrost: perfcnt: fix ref count leak in + panfrost_perfcnt_enable_locked + +in panfrost_perfcnt_enable_locked, pm_runtime_get_sync is called which +increments the counter even in case of failure, leading to incorrect +ref count. In case of failure, decrement the ref count before returning. + +Acked-by: Alyssa Rosenzweig +Signed-off-by: Navid Emamdoost +Signed-off-by: Rob Herring +Link: https://patchwork.freedesktop.org/patch/msgid/20200614063619.44944-1-navid.emamdoost@gmail.com +(cherry picked from commit 9df0e0c1889677175037445d5ad1654d54176369) +--- + drivers/gpu/drm/panfrost/panfrost_perfcnt.c | 10 +++++++--- + 1 file changed, 7 insertions(+), 3 deletions(-) + +diff --git a/drivers/gpu/drm/panfrost/panfrost_perfcnt.c b/drivers/gpu/drm/panfrost/panfrost_perfcnt.c +index 6913578d5aa7..6169644d4469 100644 +--- a/drivers/gpu/drm/panfrost/panfrost_perfcnt.c ++++ b/drivers/gpu/drm/panfrost/panfrost_perfcnt.c +@@ -83,11 +83,13 @@ static int panfrost_perfcnt_enable_locked(struct panfrost_device *pfdev, + + ret = pm_runtime_get_sync(pfdev->dev); + if (ret < 0) +- return ret; ++ goto err_put_pm; + + bo = drm_gem_shmem_create(pfdev->ddev, perfcnt->bosize); +- if (IS_ERR(bo)) +- return PTR_ERR(bo); ++ if (IS_ERR(bo)) { ++ ret = PTR_ERR(bo); ++ goto err_put_pm; ++ } + + /* Map the perfcnt buf in the address space attached to file_priv. */ + ret = panfrost_gem_open(&bo->base, file_priv); +@@ -168,6 +170,8 @@ static int panfrost_perfcnt_enable_locked(struct panfrost_device *pfdev, + panfrost_gem_close(&bo->base, file_priv); + err_put_bo: + drm_gem_object_put_unlocked(&bo->base); ++err_put_pm: ++ pm_runtime_put(pfdev->dev); + return ret; + } + diff --git a/patch/kernel/rk322x-dev/01-linux-1000-clk-rockchip-rk3228-fixup.patch b/patch/kernel/rk322x-dev/01-linux-1000-clk-rockchip-rk3228-fixup.patch deleted file mode 100644 index 21826f856..000000000 --- a/patch/kernel/rk322x-dev/01-linux-1000-clk-rockchip-rk3228-fixup.patch +++ /dev/null @@ -1,98 +0,0 @@ -diff --git a/drivers/clk/rockchip/clk-rk3228.c b/drivers/clk/rockchip/clk-rk3228.c -index 0127d702720c..6ef71ec239ae 100644 ---- a/drivers/clk/rockchip/clk-rk3228.c -+++ b/drivers/clk/rockchip/clk-rk3228.c -@@ -353,7 +353,7 @@ static struct rockchip_clk_branch rk3228_clk_branches[] __initdata = { - RK2928_CLKGATE_CON(10), 12, GFLAGS), - - COMPOSITE(SCLK_WIFI, "sclk_wifi", mux_pll_src_cpll_gpll_usb480m_p, 0, -- RK2928_CLKSEL_CON(23), 5, 2, MFLAGS, 0, 6, DFLAGS, -+ RK2928_CLKSEL_CON(23), 5, 2, MFLAGS, 0, 5, DFLAGS, - RK2928_CLKGATE_CON(2), 15, GFLAGS), - - COMPOSITE(SCLK_SDMMC, "sclk_sdmmc", mux_mmc_src_p, 0, --- -2.17.1 - - -From 3acbbe5eb438e8b1061a803881579030d3c2b424 Mon Sep 17 00:00:00 2001 -From: Chen Lei -Date: Tue, 25 Dec 2018 18:29:04 +0800 -Subject: [PATCH] clk: rockchip: rk322x: fix wrong mmc phase shift for rk3228 - -mmc sample shift should be 1 for rk3228, or it will fail -if we enable mmc tuning for rk3228. - -Change-Id: I301c2a7d33de8d519d7c288aef03a82531016373 -Signed-off-by: Chen Lei ---- - drivers/clk/rockchip/clk-rk3228.c | 6 +++--- - 1 file changed, 3 insertions(+), 3 deletions(-) - -diff --git a/drivers/clk/rockchip/clk-rk3228.c b/drivers/clk/rockchip/clk-rk3228.c -index 6ef71ec239ae..27adfca1a095 100644 ---- a/drivers/clk/rockchip/clk-rk3228.c -+++ b/drivers/clk/rockchip/clk-rk3228.c -@@ -610,13 +610,13 @@ static struct rockchip_clk_branch rk3228_clk_branches[] __initdata = { - - /* PD_MMC */ - MMC(SCLK_SDMMC_DRV, "sdmmc_drv", "sclk_sdmmc", RK3228_SDMMC_CON0, 1), -- MMC(SCLK_SDMMC_SAMPLE, "sdmmc_sample", "sclk_sdmmc", RK3228_SDMMC_CON1, 0), -+ MMC(SCLK_SDMMC_SAMPLE, "sdmmc_sample", "sclk_sdmmc", RK3228_SDMMC_CON1, 1), - - MMC(SCLK_SDIO_DRV, "sdio_drv", "sclk_sdio", RK3228_SDIO_CON0, 1), -- MMC(SCLK_SDIO_SAMPLE, "sdio_sample", "sclk_sdio", RK3228_SDIO_CON1, 0), -+ MMC(SCLK_SDIO_SAMPLE, "sdio_sample", "sclk_sdio", RK3228_SDIO_CON1, 1), - - MMC(SCLK_EMMC_DRV, "emmc_drv", "sclk_emmc", RK3228_EMMC_CON0, 1), -- MMC(SCLK_EMMC_SAMPLE, "emmc_sample", "sclk_emmc", RK3228_EMMC_CON1, 0), -+ MMC(SCLK_EMMC_SAMPLE, "emmc_sample", "sclk_emmc", RK3228_EMMC_CON1, 1), - }; - - static const char *const rk3228_critical_clocks[] __initconst = { --- -2.17.1 - - -From a692001c1249473bdfe975ef53d2bdb8a4df736d Mon Sep 17 00:00:00 2001 -From: Finley Xiao -Date: Mon, 5 Feb 2018 10:04:15 +0800 -Subject: [PATCH] clk: rockchip: rk3228: Fix armclk parent - -Change-Id: I09830d96b37cca600f1782b9013b25e043467f97 -Signed-off-by: Finley Xiao ---- - drivers/clk/rockchip/clk-rk3228.c | 8 +++++++- - 1 file changed, 7 insertions(+), 1 deletion(-) - -diff --git a/drivers/clk/rockchip/clk-rk3228.c b/drivers/clk/rockchip/clk-rk3228.c -index 58292f80ad66..fba513de94eb 100644 ---- a/drivers/clk/rockchip/clk-rk3228.c -+++ b/drivers/clk/rockchip/clk-rk3228.c -@@ -170,7 +170,7 @@ static struct rockchip_pll_clock rk3228_pll_clks[] __initdata = { - [cpll] = PLL(pll_rk3036, PLL_CPLL, "cpll", mux_pll_p, 0, RK2928_PLL_CON(6), - RK2928_MODE_CON, 8, 8, 0, NULL), - [gpll] = PLL(pll_rk3036, PLL_GPLL, "gpll", mux_pll_p, 0, RK2928_PLL_CON(9), -- RK2928_MODE_CON, 12, 9, ROCKCHIP_PLL_SYNC_RATE, rk3228_pll_rates), -+ RK2928_MODE_CON, 12, 9, 0, rk3228_pll_rates), - }; - - #define MFLAGS CLK_MUX_HIWORD_MASK --- -2.17.1 - - -From f57d5061e7357a8f7a181517530658a223ba415b Mon Sep 17 00:00:00 2001 -From: Finley Xiao -Date: Thu, 22 Jun 2017 19:53:46 +0800 -Subject: [PATCH] clk: rockchip: rk3228: fix gpu gate-register - -Fix a typo making the aclk_gpu and aclk_gpu_noc access a wrong register to -handle its gate. - -Change-Id: Ie0bac8014363af7c0409b8a56eacf2e858818843 -Signed-off-by: Finley Xiao ---- - drivers/clk/rockchip/clk-rk3228.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - diff --git a/patch/kernel/rk322x-dev/01-linux-1000-export-mm_trace_rss_stat.patch b/patch/kernel/rk322x-dev/01-linux-1000-export-mm_trace_rss_stat.patch new file mode 100644 index 000000000..03be01030 --- /dev/null +++ b/patch/kernel/rk322x-dev/01-linux-1000-export-mm_trace_rss_stat.patch @@ -0,0 +1,12 @@ +diff --git a/mm/memory.c b/mm/memory.c +index 606da18..8429abc 100644 +--- a/mm/memory.c ++++ b/mm/memory.c +@@ -158,6 +158,7 @@ + { + trace_rss_stat(mm, member, count); + } ++EXPORT_SYMBOL(mm_trace_rss_stat); + + #if defined(SPLIT_RSS_COUNTING) + diff --git a/patch/kernel/rk322x-dev/01-linux-1001-clk-rockchip-rk3228-more-fixes.patch b/patch/kernel/rk322x-dev/01-linux-1001-clk-rockchip-rk3228-more-fixes.patch deleted file mode 100644 index 024940cd3..000000000 --- a/patch/kernel/rk322x-dev/01-linux-1001-clk-rockchip-rk3228-more-fixes.patch +++ /dev/null @@ -1,219 +0,0 @@ -diff --git a/drivers/clk/rockchip/clk-rk3228.c b/drivers/clk/rockchip/clk-rk3228.c -index 448b202bf4f3..828d0003a18e 100644 ---- a/drivers/clk/rockchip/clk-rk3228.c -+++ b/drivers/clk/rockchip/clk-rk3228.c -@@ -510,12 +510,12 @@ static struct rockchip_clk_branch rk3228_clk_branches[] __initdata = { - - /* PD_VOP */ - GATE(ACLK_RGA, "aclk_rga", "aclk_rga_pre", 0, RK2928_CLKGATE_CON(13), 0, GFLAGS), -- GATE(0, "aclk_rga_noc", "aclk_rga_pre", 0, RK2928_CLKGATE_CON(13), 11, GFLAGS), -+ GATE(0, "aclk_rga_noc", "aclk_rga_pre", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(13), 11, GFLAGS), - GATE(ACLK_IEP, "aclk_iep", "aclk_iep_pre", 0, RK2928_CLKGATE_CON(13), 2, GFLAGS), -- GATE(0, "aclk_iep_noc", "aclk_iep_pre", 0, RK2928_CLKGATE_CON(13), 9, GFLAGS), -+ GATE(0, "aclk_iep_noc", "aclk_iep_pre", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(13), 9, GFLAGS), - - GATE(ACLK_VOP, "aclk_vop", "aclk_vop_pre", 0, RK2928_CLKGATE_CON(13), 5, GFLAGS), -- GATE(0, "aclk_vop_noc", "aclk_vop_pre", 0, RK2928_CLKGATE_CON(13), 12, GFLAGS), -+ GATE(0, "aclk_vop_noc", "aclk_vop_pre", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(13), 12, GFLAGS), - - GATE(ACLK_HDCP, "aclk_hdcp", "aclk_hdcp_pre", 0, RK2928_CLKGATE_CON(14), 10, GFLAGS), - GATE(0, "aclk_hdcp_noc", "aclk_hdcp_pre", 0, RK2928_CLKGATE_CON(13), 10, GFLAGS), -@@ -523,13 +523,13 @@ static struct rockchip_clk_branch rk3228_clk_branches[] __initdata = { - GATE(HCLK_RGA, "hclk_rga", "hclk_vio_pre", 0, RK2928_CLKGATE_CON(13), 1, GFLAGS), - GATE(HCLK_IEP, "hclk_iep", "hclk_vio_pre", 0, RK2928_CLKGATE_CON(13), 3, GFLAGS), - GATE(HCLK_VOP, "hclk_vop", "hclk_vio_pre", 0, RK2928_CLKGATE_CON(13), 6, GFLAGS), -- GATE(0, "hclk_vio_ahb_arbi", "hclk_vio_pre", 0, RK2928_CLKGATE_CON(13), 7, GFLAGS), -- GATE(0, "hclk_vio_noc", "hclk_vio_pre", 0, RK2928_CLKGATE_CON(13), 8, GFLAGS), -- GATE(0, "hclk_vop_noc", "hclk_vio_pre", 0, RK2928_CLKGATE_CON(13), 13, GFLAGS), -- GATE(HCLK_VIO_H2P, "hclk_vio_h2p", "hclk_vio_pre", 0, RK2928_CLKGATE_CON(14), 7, GFLAGS), -+ GATE(0, "hclk_vio_ahb_arbi", "hclk_vio_pre", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(13), 7, GFLAGS), -+ GATE(0, "hclk_vio_noc", "hclk_vio_pre", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(13), 8, GFLAGS), -+ GATE(0, "hclk_vop_noc", "hclk_vio_pre", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(13), 13, GFLAGS), -+ GATE(HCLK_VIO_H2P, "hclk_vio_h2p", "hclk_vio_pre", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(14), 7, GFLAGS), - GATE(HCLK_HDCP_MMU, "hclk_hdcp_mmu", "hclk_vio_pre", 0, RK2928_CLKGATE_CON(14), 12, GFLAGS), - GATE(PCLK_HDMI_CTRL, "pclk_hdmi_ctrl", "hclk_vio_pre", 0, RK2928_CLKGATE_CON(14), 6, GFLAGS), -- GATE(PCLK_VIO_H2P, "pclk_vio_h2p", "hclk_vio_pre", 0, RK2928_CLKGATE_CON(14), 8, GFLAGS), -+ GATE(PCLK_VIO_H2P, "pclk_vio_h2p", "hclk_vio_pre", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(14), 8, GFLAGS), - GATE(PCLK_HDCP, "pclk_hdcp", "hclk_vio_pre", 0, RK2928_CLKGATE_CON(14), 11, GFLAGS), - - /* PD_PERI */ -@@ -541,13 +541,13 @@ static struct rockchip_clk_branch rk3228_clk_branches[] __initdata = { - GATE(HCLK_EMMC, "hclk_emmc", "hclk_peri", 0, RK2928_CLKGATE_CON(11), 2, GFLAGS), - GATE(HCLK_NANDC, "hclk_nandc", "hclk_peri", 0, RK2928_CLKGATE_CON(11), 3, GFLAGS), - GATE(HCLK_HOST0, "hclk_host0", "hclk_peri", 0, RK2928_CLKGATE_CON(11), 6, GFLAGS), -- GATE(0, "hclk_host0_arb", "hclk_peri", 0, RK2928_CLKGATE_CON(11), 7, GFLAGS), -+ GATE(0, "hclk_host0_arb", "hclk_peri", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(11), 7, GFLAGS), - GATE(HCLK_HOST1, "hclk_host1", "hclk_peri", 0, RK2928_CLKGATE_CON(11), 8, GFLAGS), -- GATE(0, "hclk_host1_arb", "hclk_peri", 0, RK2928_CLKGATE_CON(11), 9, GFLAGS), -+ GATE(0, "hclk_host1_arb", "hclk_peri", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(11), 9, GFLAGS), - GATE(HCLK_HOST2, "hclk_host2", "hclk_peri", 0, RK2928_CLKGATE_CON(11), 10, GFLAGS), - GATE(HCLK_OTG, "hclk_otg", "hclk_peri", 0, RK2928_CLKGATE_CON(11), 12, GFLAGS), -- GATE(0, "hclk_otg_pmu", "hclk_peri", 0, RK2928_CLKGATE_CON(11), 13, GFLAGS), -- GATE(0, "hclk_host2_arb", "hclk_peri", 0, RK2928_CLKGATE_CON(11), 14, GFLAGS), -+ GATE(0, "hclk_otg_pmu", "hclk_peri", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(11), 13, GFLAGS), -+ GATE(0, "hclk_host2_arb", "hclk_peri", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(11), 14, GFLAGS), - GATE(0, "hclk_peri_noc", "hclk_peri", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(12), 1, GFLAGS), - - GATE(PCLK_GMAC, "pclk_gmac", "pclk_peri", 0, RK2928_CLKGATE_CON(11), 5, GFLAGS), -@@ -555,15 +555,15 @@ static struct rockchip_clk_branch rk3228_clk_branches[] __initdata = { - - /* PD_GPU */ - GATE(ACLK_GPU, "aclk_gpu", "aclk_gpu_pre", 0, RK2928_CLKGATE_CON(7), 14, GFLAGS), -- GATE(0, "aclk_gpu_noc", "aclk_gpu_pre", 0, RK2928_CLKGATE_CON(7), 15, GFLAGS), -+ GATE(0, "aclk_gpu_noc", "aclk_gpu_pre", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(7), 15, GFLAGS), - - /* PD_BUS */ -- GATE(0, "sclk_initmem_mbist", "aclk_cpu", 0, RK2928_CLKGATE_CON(8), 1, GFLAGS), -- GATE(0, "aclk_initmem", "aclk_cpu", 0, RK2928_CLKGATE_CON(8), 0, GFLAGS), -+ GATE(0, "sclk_initmem_mbist", "aclk_cpu", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(8), 1, GFLAGS), -+ GATE(0, "aclk_initmem", "aclk_cpu", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(8), 0, GFLAGS), - GATE(ACLK_DMAC, "aclk_dmac_bus", "aclk_cpu", 0, RK2928_CLKGATE_CON(8), 2, GFLAGS), - GATE(0, "aclk_bus_noc", "aclk_cpu", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(10), 1, GFLAGS), - -- GATE(0, "hclk_rom", "hclk_cpu", 0, RK2928_CLKGATE_CON(8), 3, GFLAGS), -+ GATE(0, "hclk_rom", "hclk_cpu", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(8), 3, GFLAGS), - GATE(HCLK_I2S0_8CH, "hclk_i2s0_8ch", "hclk_cpu", 0, RK2928_CLKGATE_CON(8), 7, GFLAGS), - GATE(HCLK_I2S1_8CH, "hclk_i2s1_8ch", "hclk_cpu", 0, RK2928_CLKGATE_CON(8), 8, GFLAGS), - GATE(HCLK_I2S2_2CH, "hclk_i2s2_2ch", "hclk_cpu", 0, RK2928_CLKGATE_CON(8), 9, GFLAGS), -@@ -572,9 +572,9 @@ static struct rockchip_clk_branch rk3228_clk_branches[] __initdata = { - GATE(HCLK_M_CRYPTO, "hclk_crypto_mst", "hclk_cpu", 0, RK2928_CLKGATE_CON(8), 11, GFLAGS), - GATE(HCLK_S_CRYPTO, "hclk_crypto_slv", "hclk_cpu", 0, RK2928_CLKGATE_CON(8), 12, GFLAGS), - -- GATE(0, "pclk_ddrupctl", "pclk_ddr_pre", 0, RK2928_CLKGATE_CON(8), 4, GFLAGS), -- GATE(0, "pclk_ddrmon", "pclk_ddr_pre", 0, RK2928_CLKGATE_CON(8), 6, GFLAGS), -- GATE(0, "pclk_msch_noc", "pclk_ddr_pre", 0, RK2928_CLKGATE_CON(10), 2, GFLAGS), -+ GATE(0, "pclk_ddrupctl", "pclk_ddr_pre", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(8), 4, GFLAGS), -+ GATE(0, "pclk_ddrmon", "pclk_ddr_pre", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(8), 6, GFLAGS), -+ GATE(0, "pclk_msch_noc", "pclk_ddr_pre", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(10), 2, GFLAGS), - - GATE(PCLK_EFUSE_1024, "pclk_efuse_1024", "pclk_cpu", 0, RK2928_CLKGATE_CON(8), 13, GFLAGS), - GATE(PCLK_EFUSE_256, "pclk_efuse_256", "pclk_cpu", 0, RK2928_CLKGATE_CON(8), 14, GFLAGS), -@@ -583,7 +583,7 @@ static struct rockchip_clk_branch rk3228_clk_branches[] __initdata = { - GATE(PCLK_I2C2, "pclk_i2c2", "pclk_cpu", 0, RK2928_CLKGATE_CON(9), 1, GFLAGS), - GATE(PCLK_I2C3, "pclk_i2c3", "pclk_cpu", 0, RK2928_CLKGATE_CON(9), 2, GFLAGS), - GATE(PCLK_TIMER, "pclk_timer0", "pclk_cpu", 0, RK2928_CLKGATE_CON(9), 4, GFLAGS), -- GATE(0, "pclk_stimer", "pclk_cpu", 0, RK2928_CLKGATE_CON(9), 5, GFLAGS), -+ GATE(0, "pclk_stimer", "pclk_cpu", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(9), 5, GFLAGS), - GATE(PCLK_SPI0, "pclk_spi0", "pclk_cpu", 0, RK2928_CLKGATE_CON(9), 6, GFLAGS), - GATE(PCLK_PWM, "pclk_rk_pwm", "pclk_cpu", 0, RK2928_CLKGATE_CON(9), 7, GFLAGS), - GATE(PCLK_GPIO0, "pclk_gpio0", "pclk_cpu", 0, RK2928_CLKGATE_CON(9), 8, GFLAGS), -@@ -597,22 +597,22 @@ static struct rockchip_clk_branch rk3228_clk_branches[] __initdata = { - GATE(PCLK_GRF, "pclk_grf", "pclk_cpu", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(10), 0, GFLAGS), - GATE(0, "pclk_cru", "pclk_cpu", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(10), 1, GFLAGS), - GATE(0, "pclk_sgrf", "pclk_cpu", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(10), 2, GFLAGS), -- GATE(0, "pclk_sim", "pclk_cpu", 0, RK2928_CLKGATE_CON(10), 3, GFLAGS), -+ GATE(0, "pclk_sim", "pclk_cpu", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(10), 3, GFLAGS), - -- GATE(0, "pclk_ddrphy", "pclk_phy_pre", 0, RK2928_CLKGATE_CON(10), 3, GFLAGS), -- GATE(0, "pclk_acodecphy", "pclk_phy_pre", 0, RK2928_CLKGATE_CON(10), 5, GFLAGS), -+ GATE(0, "pclk_ddrphy", "pclk_phy_pre", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(10), 3, GFLAGS), -+ GATE(PCLK_ACODECPHY, "pclk_acodecphy", "pclk_phy_pre", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(10), 5, GFLAGS), - GATE(PCLK_HDMI_PHY, "pclk_hdmiphy", "pclk_phy_pre", 0, RK2928_CLKGATE_CON(10), 7, GFLAGS), -- GATE(0, "pclk_vdacphy", "pclk_phy_pre", 0, RK2928_CLKGATE_CON(10), 8, GFLAGS), -- GATE(0, "pclk_phy_noc", "pclk_phy_pre", 0, RK2928_CLKGATE_CON(10), 9, GFLAGS), -+ GATE(0, "pclk_vdacphy", "pclk_phy_pre", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(10), 8, GFLAGS), -+ GATE(0, "pclk_phy_noc", "pclk_phy_pre", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(10), 9, GFLAGS), - - GATE(ACLK_VPU, "aclk_vpu", "aclk_vpu_pre", 0, RK2928_CLKGATE_CON(15), 0, GFLAGS), -- GATE(0, "aclk_vpu_noc", "aclk_vpu_pre", 0, RK2928_CLKGATE_CON(15), 4, GFLAGS), -+ GATE(0, "aclk_vpu_noc", "aclk_vpu_pre", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(15), 4, GFLAGS), - GATE(ACLK_RKVDEC, "aclk_rkvdec", "aclk_rkvdec_pre", 0, RK2928_CLKGATE_CON(15), 2, GFLAGS), -- GATE(0, "aclk_rkvdec_noc", "aclk_rkvdec_pre", 0, RK2928_CLKGATE_CON(15), 6, GFLAGS), -+ GATE(0, "aclk_rkvdec_noc", "aclk_rkvdec_pre", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(15), 6, GFLAGS), - GATE(HCLK_VPU, "hclk_vpu", "hclk_vpu_pre", 0, RK2928_CLKGATE_CON(15), 1, GFLAGS), -- GATE(0, "hclk_vpu_noc", "hclk_vpu_pre", 0, RK2928_CLKGATE_CON(15), 5, GFLAGS), -+ GATE(0, "hclk_vpu_noc", "hclk_vpu_pre", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(15), 5, GFLAGS), - GATE(HCLK_RKVDEC, "hclk_rkvdec", "hclk_rkvdec_pre", 0, RK2928_CLKGATE_CON(15), 3, GFLAGS), -- GATE(0, "hclk_rkvdec_noc", "hclk_rkvdec_pre", 0, RK2928_CLKGATE_CON(15), 7, GFLAGS), -+ GATE(0, "hclk_rkvdec_noc", "hclk_rkvdec_pre", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(15), 7, GFLAGS), - - /* PD_MMC */ - MMC(SCLK_SDMMC_DRV, "sdmmc_drv", "sclk_sdmmc", RK3228_SDMMC_CON0, 1), -@@ -656,25 +656,34 @@ static const char *const rk3228_critical_clocks[] __initconst = { - "pclk_phy_noc", - "aclk_vpu_noc", - "aclk_rkvdec_noc", -+ "aclk_rkvdec", - "hclk_vpu_noc", - "hclk_rkvdec_noc", -+ "hclk_rkvdec", - }; - -+static void __iomem *rk3228_cru_base; -+ -+static void rk3228_clk_shutdown(void) -+{ -+ writel_relaxed(0x11010000, rk3228_cru_base + RK3228_MODE_CON); -+} -+ - static void __init rk3228_clk_init(struct device_node *np) - { - struct rockchip_clk_provider *ctx; -- void __iomem *reg_base; - -- reg_base = of_iomap(np, 0); -- if (!reg_base) { -+ rk3228_cru_base = of_iomap(np, 0); -+ -+ if (!rk3228_cru_base) { - pr_err("%s: could not map cru region\n", __func__); - return; - } - -- ctx = rockchip_clk_init(np, reg_base, CLK_NR_CLKS); -+ ctx = rockchip_clk_init(np, rk3228_cru_base, CLK_NR_CLKS); - if (IS_ERR(ctx)) { - pr_err("%s: rockchip clk init failed\n", __func__); -- iounmap(reg_base); -+ iounmap(rk3228_cru_base); - return; - } - -@@ -691,10 +700,10 @@ static void __init rk3228_clk_init(struct device_node *np) - &rk3228_cpuclk_data, rk3228_cpuclk_rates, - ARRAY_SIZE(rk3228_cpuclk_rates)); - -- rockchip_register_softrst(np, 9, reg_base + RK2928_SOFTRST_CON(0), -+ rockchip_register_softrst(np, 9, rk3228_cru_base + RK2928_SOFTRST_CON(0), - ROCKCHIP_SOFTRST_HIWORD_MASK); - -- rockchip_register_restart_notifier(ctx, RK3228_GLB_SRST_FST, NULL); -+ rockchip_register_restart_notifier(ctx, RK3228_GLB_SRST_FST, rk3228_clk_shutdown); - - rockchip_clk_of_add_provider(np, ctx); - } -diff --git a/drivers/clk/rockchip/clk.h b/drivers/clk/rockchip/clk.h -index 2271a84124b0..f2f80f224f30 100644 ---- a/drivers/clk/rockchip/clk.h -+++ b/drivers/clk/rockchip/clk.h -@@ -134,6 +134,7 @@ struct clk; - #define RK3308_EMMC_CON0 0x490 - #define RK3308_EMMC_CON1 0x494 - -+#define RK3228_MODE_CON 0x40 - #define RK3328_PLL_CON(x) RK2928_PLL_CON(x) - #define RK3328_CLKSEL_CON(x) ((x) * 0x4 + 0x100) - #define RK3328_CLKGATE_CON(x) ((x) * 0x4 + 0x200) -diff --git a/include/dt-bindings/clock/rk3228-cru.h b/include/dt-bindings/clock/rk3228-cru.h -index de550ea56eeb..16e1feae5ce4 100644 ---- a/include/dt-bindings/clock/rk3228-cru.h -+++ b/include/dt-bindings/clock/rk3228-cru.h -@@ -65,6 +65,7 @@ - #define SCLK_OTGPHY0 142 - #define SCLK_OTGPHY1 143 - #define SCLK_HDMI_PHY 144 -+#define SCLK_DDRC 145 - - /* dclk gates */ - #define DCLK_VOP 190 -@@ -115,6 +116,7 @@ - #define PCLK_HDMI_CTRL 364 - #define PCLK_HDMI_PHY 365 - #define PCLK_GMAC 367 -+#define PCLK_ACODECPHY 368 - - /* hclk gates */ - #define HCLK_I2S0_8CH 442 --- -2.17.1 - diff --git a/patch/kernel/rk322x-dev/01-linux-1002-arm-dts-rk322x-dts.patch b/patch/kernel/rk322x-dev/01-linux-1002-arm-dts-rk322x-dts.patch deleted file mode 100644 index 50ae37df8..000000000 --- a/patch/kernel/rk322x-dev/01-linux-1002-arm-dts-rk322x-dts.patch +++ /dev/null @@ -1,1586 +0,0 @@ -diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile -index e8dd99201..02d9d3ae7 100644 ---- a/arch/arm/boot/dts/Makefile -+++ b/arch/arm/boot/dts/Makefile -@@ -952,6 +952,12 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += \ - rk3188-px3-evb.dtb \ - rk3188-radxarock.dtb \ - rk3228-evb.dtb \ -+ rk3228a-box.dtb \ -+ rk3228a-box-h96mini.dtb \ -+ rk3228a-box-nand.dtb \ -+ rk3229-box.dtb \ -+ rk3229-box-a95xr1.dtb \ -+ rk3229-box-nand.dtb \ - rk3229-evb.dtb \ - rk3229-xms6.dtb \ - rk3288-evb-act8846.dtb \ -diff --git a/arch/arm/boot/dts/rk3228a-box-h96mini.dts b/arch/arm/boot/dts/rk3228a-box-h96mini.dts -new file mode 100644 -index 000000000..c624500d1 ---- /dev/null -+++ b/arch/arm/boot/dts/rk3228a-box-h96mini.dts -@@ -0,0 +1,106 @@ -+// SPDX-License-Identifier: (GPL-2.0+ OR MIT) -+ -+/dts-v1/; -+#include -+#include -+#include "rk3228a-box.dtsi" -+ -+/ { -+ compatible = "eledvb,h96mini", "rockchip,rk3228a-box", "rockchip,rk3229"; -+ model = "Rockchip RK3228A Box H96 mini"; -+ -+ leds { -+ compatible = "gpio-leds"; -+ -+ led_green { -+ gpios = <&gpio3 RK_PC5 GPIO_ACTIVE_HIGH>; -+ default-state = "on"; -+ }; -+ -+ led_red { -+ gpios = <&gpio0 RK_PB0 GPIO_ACTIVE_HIGH>; -+ default-state = "off"; -+ }; -+ }; -+ -+}; -+ -+&emmc { -+ mmc-hs200-1_8v; -+ status = "okay"; -+}; -+ -+&gmac { -+ tx_delay = <0x26>; -+ rx_delay = <0x11>; -+}; -+ -+&ir_receiver { -+ status = "okay"; -+}; -+ -+&pinctrl { -+ wifi { -+ wifi_host_wake_l: wifi-host-wake-l { -+ rockchip,pins = <0 RK_PD4 RK_FUNC_GPIO &pcfg_pull_none>; -+ }; -+ }; -+ -+ bt { -+ bt_host_wake_l: bt-host-wake-l { -+ rockchip,pins = <3 RK_PD2 RK_FUNC_GPIO &pcfg_pull_none>; -+ }; -+ -+ bt_reg_on_h: bt-reg-on-h { -+ rockchip,pins = <2 RK_PD5 RK_FUNC_GPIO &pcfg_pull_none>; -+ }; -+ -+ bt_wake_l: bt-wake-l { -+ rockchip,pins = <3 RK_PD3 RK_FUNC_GPIO &pcfg_pull_none>; -+ }; -+ }; -+}; -+ -+&power_key { -+ status = "okay"; -+}; -+ -+&sdio { -+ #address-cells = <1>; -+ #size-cells = <0>; -+ status = "okay"; -+ -+ brcmf: wifi@1 { -+ compatible = "brcm,bcm4329-fmac"; -+ reg = <1>; -+ interrupt-parent = <&gpio0>; -+ interrupts = ; -+ interrupt-names = "host-wake"; -+ brcm,drive-strength = <5>; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&wifi_host_wake_l>; -+ }; -+}; -+ -+&sdmmc { -+ disable-wp; -+ status = "okay"; -+}; -+ -+&uart1 { -+ status = "okay"; -+ -+ bluetooth { -+ compatible = "brcm,bcm4330-bt"; -+ host-wakeup-gpios = <&gpio3 RK_PD2 GPIO_ACTIVE_HIGH>; -+ device-wakeup-gpios = <&gpio3 RK_PD3 GPIO_ACTIVE_HIGH>; -+ shutdown-gpios = <&gpio2 RK_PD5 GPIO_ACTIVE_HIGH>; -+ max-speed = <4000000>; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&bt_reg_on_h &bt_host_wake_l &bt_wake_l>; -+ }; -+}; -+ -+&usb_otg { -+ dr_mode = "host"; -+}; -diff --git a/arch/arm/boot/dts/rk3228a-box-nand.dts b/arch/arm/boot/dts/rk3228a-box-nand.dts -new file mode 100644 -index 000000000..f3e5ab894 ---- /dev/null -+++ b/arch/arm/boot/dts/rk3228a-box-nand.dts -@@ -0,0 +1,57 @@ -+// SPDX-License-Identifier: (GPL-2.0+ OR MIT) -+ -+/dts-v1/; -+#include "rk3228a-box.dtsi" -+ -+/ { -+ model = "Rockchip RK3228A Box"; -+ -+ leds { -+ compatible = "gpio-leds"; -+ -+ led_blue { -+ gpios = <&gpio3 RK_PC5 GPIO_ACTIVE_HIGH>; -+ default-state = "on"; -+ }; -+ -+ led_red { -+ gpios = <&gpio1 RK_PA7 GPIO_ACTIVE_HIGH>; -+ default-state = "off"; -+ }; -+ }; -+ -+}; -+ -+&ir_receiver { -+ status = "okay"; -+}; -+ -+&nfc { -+ #address-cells = <1>; -+ #size-cells = <0>; -+ status = "okay"; -+ -+ nand@0 { -+ reg = <0>; -+ nand-ecc-mode = "hw"; -+ nand-ecc-strength = <60>; -+ nand-ecc-step-size = <1024>; -+ nand-bus-width = <8>; -+ }; -+}; -+ -+&sdio { -+ status = "okay"; -+}; -+ -+&sdmmc { -+ status = "okay"; -+}; -+ -+&uart1 { -+ status = "okay"; -+}; -+ -+&usb_otg { -+ dr_mode = "host"; -+}; -diff --git a/arch/arm/boot/dts/rk3228a-box.dts b/arch/arm/boot/dts/rk3228a-box.dts -new file mode 100644 -index 000000000..e68ef44b9 ---- /dev/null -+++ b/arch/arm/boot/dts/rk3228a-box.dts -@@ -0,0 +1,47 @@ -+// SPDX-License-Identifier: (GPL-2.0+ OR MIT) -+ -+/dts-v1/; -+#include "rk3228a-box.dtsi" -+ -+/ { -+ model = "Rockchip RK3228A Box"; -+ -+ leds { -+ compatible = "gpio-leds"; -+ -+ led_blue { -+ gpios = <&gpio3 RK_PC5 GPIO_ACTIVE_HIGH>; -+ default-state = "on"; -+ }; -+ -+ led_red { -+ gpios = <&gpio1 RK_PA7 GPIO_ACTIVE_HIGH>; -+ default-state = "off"; -+ }; -+ }; -+ -+}; -+ -+&emmc { -+ status = "okay"; -+}; -+ -+&ir_receiver { -+ status = "okay"; -+}; -+ -+&sdio { -+ status = "okay"; -+}; -+ -+&sdmmc { -+ status = "okay"; -+}; -+ -+&uart1 { -+ status = "okay"; -+}; -+ -+&usb_otg { -+ dr_mode = "host"; -+}; -diff --git a/arch/arm/boot/dts/rk3228a-box.dtsi b/arch/arm/boot/dts/rk3228a-box.dtsi -new file mode 100644 -index 000000000..dbd5c5dc4 ---- /dev/null -+++ b/arch/arm/boot/dts/rk3228a-box.dtsi -@@ -0,0 +1,12 @@ -+// SPDX-License-Identifier: (GPL-2.0+ OR MIT) -+ -+/dts-v1/; -+ -+#include "rk322x-box.dtsi" -+ -+/ { -+ -+ model = "Rockchip RK3228A Box"; -+ compatible = "rockchip,rk3228a-box", "rockchip,rk3229"; -+ -+}; -diff --git a/arch/arm/boot/dts/rk3229-box-a95xr1.dts b/arch/arm/boot/dts/rk3229-box-a95xr1.dts -new file mode 100644 -index 000000000..b3695fb0b ---- /dev/null -+++ b/arch/arm/boot/dts/rk3229-box-a95xr1.dts -@@ -0,0 +1,57 @@ -+// SPDX-License-Identifier: (GPL-2.0+ OR MIT) -+ -+/dts-v1/; -+#include -+#include -+#include "rk3229-box.dtsi" -+ -+/ { -+ model = "Rockchip RK3229 Box A95X-R1"; -+ -+ leds { -+ compatible = "gpio-leds"; -+ -+ led_blue { -+ gpios = <&gpio3 RK_PC5 GPIO_ACTIVE_HIGH>; -+ default-state = "on"; -+ }; -+ -+ led_red { -+ gpios = <&gpio1 RK_PA7 GPIO_ACTIVE_HIGH>; -+ default-state = "off"; -+ linux,default-trigger = "rc-feedback"; -+ }; -+ }; -+ -+}; -+ -+&emmc { -+ mmc-hs200-1_8v; -+ status = "okay"; -+}; -+ -+&gmac { -+ tx_delay = <0x26>; -+ rx_delay = <0x11>; -+}; -+ -+&ir_receiver { -+ status = "okay"; -+}; -+ -+&power_key { -+ status = "okay"; -+}; -+ -+&sdio { -+ status = "okay"; -+}; -+ -+&sdmmc { -+ disable-wp; -+ status = "okay"; -+}; -+ -+&usb_otg { -+ dr_mode = "host"; -+}; -diff --git a/arch/arm/boot/dts/rk3229-box-nand.dts b/arch/arm/boot/dts/rk3229-box-nand.dts -new file mode 100644 -index 000000000..5eca0f335 ---- /dev/null -+++ b/arch/arm/boot/dts/rk3229-box-nand.dts -@@ -0,0 +1,60 @@ -+// SPDX-License-Identifier: (GPL-2.0+ OR MIT) -+ -+/dts-v1/; -+#include "rk3229-box.dtsi" -+ -+/ { -+ model = "Rockchip RK3229 Box"; -+ -+ leds { -+ compatible = "gpio-leds"; -+ -+ led_green { -+ gpios = <&gpio3 RK_PC5 GPIO_ACTIVE_HIGH>; -+ default-state = "on"; -+ }; -+ -+ led_red { -+ gpios = <&gpio0 RK_PB0 GPIO_ACTIVE_HIGH>; -+ default-state = "off"; -+ }; -+ }; -+}; -+ -+&ir_receiver { -+ status = "okay"; -+}; -+ -+&nfc { -+ #address-cells = <1>; -+ #size-cells = <0>; -+ status = "okay"; -+ -+ nand@0 { -+ reg = <0>; -+ nand-ecc-mode = "hw"; -+ nand-ecc-strength = <60>; -+ nand-ecc-step-size = <1024>; -+ nand-bus-width = <8>; -+ }; -+}; -+ -+&power_key { -+ status = "okay"; -+}; -+ -+&sdio { -+ status = "okay"; -+}; -+ -+&sdmmc { -+ status = "okay"; -+}; -+ -+&uart1 { -+ status = "okay"; -+}; -+ -+&usb_otg { -+ dr_mode = "host"; -+}; -diff --git a/arch/arm/boot/dts/rk3229-box.dts b/arch/arm/boot/dts/rk3229-box.dts -new file mode 100644 -index 000000000..b63e61cda ---- /dev/null -+++ b/arch/arm/boot/dts/rk3229-box.dts -@@ -0,0 +1,50 @@ -+// SPDX-License-Identifier: (GPL-2.0+ OR MIT) -+ -+/dts-v1/; -+#include "rk3229-box.dtsi" -+ -+/ { -+ model = "Rockchip RK3229 Box"; -+ -+ leds { -+ compatible = "gpio-leds"; -+ -+ led_green { -+ gpios = <&gpio3 RK_PC5 GPIO_ACTIVE_HIGH>; -+ default-state = "on"; -+ }; -+ -+ led_red { -+ gpios = <&gpio0 RK_PB0 GPIO_ACTIVE_HIGH>; -+ default-state = "off"; -+ }; -+ }; -+}; -+ -+&emmc { -+ status = "okay"; -+}; -+ -+&ir_receiver { -+ status = "okay"; -+}; -+ -+&power_key { -+ status = "okay"; -+}; -+ -+&sdio { -+ status = "okay"; -+}; -+ -+&sdmmc { -+ status = "okay"; -+}; -+ -+&uart1 { -+ status = "okay"; -+}; -+ -+&usb_otg { -+ dr_mode = "host"; -+}; -diff --git a/arch/arm/boot/dts/rk3229-box.dtsi b/arch/arm/boot/dts/rk3229-box.dtsi -new file mode 100644 -index 000000000..79e2524e0 ---- /dev/null -+++ b/arch/arm/boot/dts/rk3229-box.dtsi -@@ -0,0 +1,21 @@ -+// SPDX-License-Identifier: (GPL-2.0+ OR MIT) -+ -+/dts-v1/; -+ -+#include "rk322x-box.dtsi" -+#include "rk3229-cpu-opp.dtsi" -+ -+/ { -+ -+ model = "Rockchip RK3229 Box"; -+ compatible = "rockchip,rk3229-box", "rockchip,rk3229"; -+ -+}; -+ -+&cpu0_opp_table { -+ -+ opp-1464000000 { -+ status = "disabled"; -+ }; -+ -+}; -diff --git a/arch/arm/boot/dts/rk3229-cpu-opp.dtsi b/arch/arm/boot/dts/rk3229-cpu-opp.dtsi -new file mode 100644 -index 000000000..c1c7613ba ---- /dev/null -+++ b/arch/arm/boot/dts/rk3229-cpu-opp.dtsi -@@ -0,0 +1,50 @@ -+// SPDX-License-Identifier: (GPL-2.0+ OR MIT) -+/* -+ * Copyright (c) 2017 Fuzhou Rockchip Electronics Co., Ltd -+ */ -+ -+/ { -+ compatible = "rockchip,rk3229"; -+ -+ /delete-node/ opp-table0; -+ -+ cpu0_opp_table: opp_table0 { -+ compatible = "operating-points-v2"; -+ opp-shared; -+ -+ opp-408000000 { -+ opp-hz = /bits/ 64 <408000000>; -+ opp-microvolt = <950000 950000 1400000>; -+ clock-latency-ns = <40000>; -+ opp-suspend; -+ }; -+ opp-600000000 { -+ opp-hz = /bits/ 64 <600000000>; -+ opp-microvolt = <975000 975000 1400000>; -+ }; -+ opp-816000000 { -+ opp-hz = /bits/ 64 <816000000>; -+ opp-microvolt = <1000000 1000000 1400000>; -+ }; -+ opp-1008000000 { -+ opp-hz = /bits/ 64 <1008000000>; -+ opp-microvolt = <1175000 1175000 1400000>; -+ }; -+ opp-1200000000 { -+ opp-hz = /bits/ 64 <1200000000>; -+ opp-microvolt = <1275000 1275000 1400000>; -+ }; -+ opp-1296000000 { -+ opp-hz = /bits/ 64 <1296000000>; -+ opp-microvolt = <1325000 1325000 1400000>; -+ }; -+ opp-1392000000 { -+ opp-hz = /bits/ 64 <1392000000>; -+ opp-microvolt = <1350000 1350000 1400000>; -+ }; -+ opp-1464000000 { -+ opp-hz = /bits/ 64 <1464000000>; -+ opp-microvolt = <1400000 1400000 1400000>; -+ }; -+ }; -+}; -diff --git a/arch/arm/boot/dts/rk322x-box.dtsi b/arch/arm/boot/dts/rk322x-box.dtsi -new file mode 100644 -index 000000000..44fb2f4ea ---- /dev/null -+++ b/arch/arm/boot/dts/rk322x-box.dtsi -@@ -0,0 +1,250 @@ -+// SPDX-License-Identifier: (GPL-2.0+ OR MIT) -+ -+/dts-v1/; -+ -+#include -+#include -+#include -+#include -+#include "rk322x-dcdc.dtsi" -+ -+/ { -+ model = "Rockchip RK322x Box"; -+ compatible = "rockchip,rk3229"; -+ -+ chosen { -+ bootargs = "earlyprintk=uart8250,mmio32,0x11030000"; -+ }; -+ -+ gpio_keys { -+ compatible = "gpio-keys"; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ autorepeat; -+ -+ pinctrl-names = "default"; -+ pinctrl-0 = <&pwr_key>; -+ -+ power_key: power-key { -+ label = "GPIO Key Power"; -+ gpios = <&gpio3 RK_PD1 GPIO_ACTIVE_LOW>; -+ linux,code = ; -+ debounce-interval = <100>; -+ wakeup-source; -+ status = "disabled"; -+ }; -+ }; -+ -+ ir_receiver: ir-receiver { -+ compatible = "gpio-ir-receiver"; -+ gpios = <&gpio1 RK_PB3 GPIO_ACTIVE_LOW>; -+ pinctrl-0 = <&ir_int>; -+ pinctrl-names = "default"; -+ status = "disabled"; -+ }; -+ -+ memory@60000000 { -+ device_type = "memory"; -+ reg = <0x60000000 0x40000000>; -+ }; -+ -+ reserved-memory { -+ #address-cells = <1>; -+ #size-cells = <1>; -+ ranges; -+ -+ trust_reserved: trust@68400000 { -+ reg = <0x68400000 0xe00000>; -+ no-map; -+ }; -+ }; -+ -+ sdio_pwrseq: sdio-pwrseq { -+ compatible = "mmc-pwrseq-simple"; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&wifi_enable_h>; -+ reset-gpios = <&gpio2 RK_PD2 GPIO_ACTIVE_LOW>; -+ }; -+ -+ timer { -+ arm,cpu-registers-not-fw-configured; -+ }; -+}; -+ -+&cpu_alert1 { -+ temperature = <105000>; -+}; -+ -+&cpu_crit { -+ temperature = <115000>; -+}; -+ -+&cpu_thermal { -+ cooling-maps { -+ /delete-node/ map0; -+ }; -+}; -+ -+&emmc { -+ cap-mmc-highspeed; -+ keep-power-in-suspend; -+ non-removable; -+}; -+ -+&gmac { -+ assigned-clocks = <&cru SCLK_MAC_SRC>; -+ assigned-clock-rates = <50000000>; -+ clock_in_out = "output"; -+ phy-handle = <&phy>; -+ phy-mode = "rmii"; -+ status = "okay"; -+ -+ mdio { -+ compatible = "snps,dwmac-mdio"; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ -+ phy: phy@0 { -+ compatible = "ethernet-phy-id1234.d400", -+ "ethernet-phy-ieee802.3-c22"; -+ reg = <0>; -+ clocks = <&cru SCLK_MAC_PHY>; -+ phy-is-integrated; -+ resets = <&cru SRST_MACPHY>; -+ }; -+ }; -+}; -+ -+&hdmi { -+ status = "okay"; -+}; -+ -+&hdmi_sound { -+ status = "okay"; -+}; -+ -+&hdmi_phy { -+ status = "okay"; -+}; -+ -+&i2s0 { -+ status = "okay"; -+}; -+ -+&pinctrl { -+ -+ ir { -+ ir_int: ir-int { -+ rockchip,pins = <1 RK_PB3 RK_FUNC_GPIO &pcfg_pull_none>; -+ }; -+ }; -+ -+ keys { -+ pwr_key: pwr-key { -+ rockchip,pins = <3 RK_PC7 RK_FUNC_GPIO &pcfg_pull_up>; -+ }; -+ }; -+ -+ sdio-pwrseq { -+ wifi_enable_h: wifi-enable-h { -+ rockchip,pins = <2 RK_PD2 RK_FUNC_GPIO &pcfg_pull_none>; -+ }; -+ }; -+ -+}; -+ -+&rga { -+ status = "okay"; -+}; -+ -+&sdio { -+ mmc-pwrseq = <&sdio_pwrseq>; -+ cap-sd-highspeed; -+ cap-sdio-irq; -+ keep-power-in-suspend; -+ non-removable; -+ no-sd; -+}; -+ -+&sdmmc { -+ cap-sd-highspeed; -+ keep-power-in-suspend; -+ no-sdio; -+}; -+ -+&spdif { -+ status = "okay"; -+}; -+ -+&spdif_out { -+ status = "okay"; -+}; -+ -+&spdif_sound { -+ status = "okay"; -+}; -+ -+&tsadc { -+ rockchip,hw-tshut-mode = <0>; -+ rockchip,hw-tshut-polarity = <1>; -+ status = "okay"; -+}; -+ -+&u2phy0 { -+ status = "okay"; -+}; -+ -+&u2phy1 { -+ status = "okay"; -+}; -+ -+&uart1 { -+ pinctrl-names = "default"; -+ pinctrl-0 = <&uart11_xfer &uart11_rts &uart11_cts>; -+}; -+ -+&uart2 { -+ status = "okay"; -+}; -+ -+&usb_host0_ehci { -+ status = "okay"; -+}; -+ -+&usb_host0_ohci { -+ status = "okay"; -+}; -+ -+&usb_host1_ehci { -+ status = "okay"; -+}; -+ -+&usb_host1_ohci { -+ status = "okay"; -+}; -+ -+&usb_host2_ehci { -+ status = "okay"; -+}; -+ -+&usb_host2_ohci { -+ status = "okay"; -+}; -+ -+&usb_otg { -+ status = "okay"; -+}; -+ -+&vop { -+ assigned-clocks = <&cru DCLK_VOP>; -+ assigned-clock-parents = <&cru SCLK_HDMI_PHY>; -+ status = "okay"; -+}; -+ -+&vop_mmu { -+ status = "okay"; -+}; -+ -+&wdt { -+ status = "okay"; -+}; -diff --git a/arch/arm/boot/dts/rk322x-dcdc.dtsi b/arch/arm/boot/dts/rk322x-dcdc.dtsi -new file mode 100644 -index 000000000..6076cb1d0 ---- /dev/null -+++ b/arch/arm/boot/dts/rk322x-dcdc.dtsi -@@ -0,0 +1,164 @@ -+// SPDX-License-Identifier: (GPL-2.0+ OR MIT) -+ -+/dts-v1/; -+ -+#include -+#include -+#include "rk322x.dtsi" -+ -+/ { -+ -+ vcc_host: vcc-host-regulator { -+ compatible = "regulator-fixed"; -+ enable-active-high; -+ gpio = <&gpio3 RK_PC4 GPIO_ACTIVE_HIGH>; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&host_vbus_drv>; -+ regulator-name = "vcc_host"; -+ regulator-always-on; -+ regulator-boot-on; -+ vin-supply = <&vcc_sys>; -+ }; -+ -+ vccio_1v8: vccio-1v8-regulator { -+ compatible = "regulator-fixed"; -+ regulator-name = "vccio_1v8"; -+ regulator-min-microvolt = <1800000>; -+ regulator-max-microvolt = <1800000>; -+ regulator-always-on; -+ vin-supply = <&vcc_sys>; -+ }; -+ -+ vccio_3v3: vccio-3v3-regulator { -+ compatible = "regulator-fixed"; -+ regulator-name = "vccio_3v3"; -+ regulator-min-microvolt = <3300000>; -+ regulator-max-microvolt = <3300000>; -+ regulator-always-on; -+ vin-supply = <&vcc_sys>; -+ }; -+ -+ -+ vcc_otg: vcc-otg-regulator { -+ compatible = "regulator-fixed"; -+ enable-active-high; -+ gpio = <&gpio3 RK_PC6 GPIO_ACTIVE_HIGH>; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&otg_vbus_drv>; -+ regulator-name = "vcc_otg_vbus"; -+ regulator-min-microvolt = <5000000>; -+ regulator-max-microvolt = <5000000>; -+ regulator-always-on; -+ regulator-boot-on; -+ vin-supply = <&vcc_sys>; -+ }; -+ -+ vcc_phy: vcc-phy-regulator { -+ compatible = "regulator-fixed"; -+ enable-active-high; -+ regulator-name = "vcc_phy"; -+ regulator-min-microvolt = <1800000>; -+ regulator-max-microvolt = <1800000>; -+ regulator-always-on; -+ regulator-boot-on; -+ vin-supply = <&vccio_1v8>; -+ }; -+ -+ vcc_sys: vcc-sys-regulator { -+ compatible = "regulator-fixed"; -+ regulator-name = "vcc_sys"; -+ regulator-always-on; -+ regulator-boot-on; -+ regulator-min-microvolt = <5000000>; -+ regulator-max-microvolt = <5000000>; -+ }; -+ -+ vdd_arm: vdd-arm-regulator { -+ compatible = "pwm-regulator"; -+ pwms = <&pwm1 0 5000 1>; -+ pwm-supply = <&vcc_sys>; -+ regulator-name = "vdd_arm"; -+ regulator-min-microvolt = <950000>; -+ regulator-max-microvolt = <1400000>; -+ regulator-ramp-delay = <12500>; -+ regulator-settling-time-up-us = <250>; -+ regulator-always-on; -+ regulator-boot-on; -+ }; -+ -+ vdd_log: vdd-log-regulator { -+ compatible = "pwm-regulator"; -+ pwms = <&pwm2 0 5000 1>; -+ pwm-supply = <&vcc_sys>; -+ regulator-name = "vdd_log"; -+ regulator-min-microvolt = <1000000>; -+ regulator-max-microvolt = <1300000>; -+ regulator-ramp-delay = <12500>; -+ regulator-settling-time-up-us = <250>; -+ regulator-always-on; -+ regulator-boot-on; -+ }; -+ -+}; -+ -+ -+&cpu0 { -+ cpu-supply = <&vdd_arm>; -+}; -+ -+&cpu1 { -+ cpu-supply = <&vdd_arm>; -+}; -+ -+&cpu2 { -+ cpu-supply = <&vdd_arm>; -+}; -+ -+&cpu3 { -+ cpu-supply = <&vdd_arm>; -+}; -+ -+&io_domains { -+ vccio1-supply = <&vccio_3v3>; -+ vccio2-supply = <&vccio_1v8>; -+ vccio4-supply = <&vccio_3v3>; -+ status = "okay"; -+}; -+ -+&gmac { -+ phy-supply = <&vcc_phy>; -+}; -+ -+&gpu { -+ mali-supply = <&vdd_log>; -+}; -+ -+&pwm1 { -+ pinctrl-0 = <&pwm1_pin_pull_down>; -+ status = "okay"; -+}; -+ -+&pwm2 { -+ pinctrl-0 = <&pwm2_pin_pull_up>; -+ status = "okay"; -+}; -+ -+&u2phy0 { -+ u2phy0_host: host-port { -+ phy-supply = <&vcc_host>; -+ }; -+ -+ u2phy0_otg: otg-port { -+ phy-supply = <&vcc_otg>; -+ }; -+}; -+ -+&u2phy1 { -+ u2phy1_host: host-port { -+ phy-supply = <&vcc_host>; -+ }; -+ -+ u2phy1_otg: otg-port { -+ phy-supply = <&vcc_otg>; -+ }; -+}; -diff --git a/arch/arm/boot/dts/rk322x.dtsi b/arch/arm/boot/dts/rk322x.dtsi -index 5485a9918..c3ca67301 100644 ---- a/arch/arm/boot/dts/rk322x.dtsi -+++ b/arch/arm/boot/dts/rk322x.dtsi -@@ -5,6 +5,8 @@ - #include - #include - #include -+#include -+#include - #include - - / { -@@ -14,6 +16,7 @@ / { - interrupt-parent = <&gic>; - - aliases { -+ ethernet0 = &gmac; - serial0 = &uart0; - serial1 = &uart1; - serial2 = &uart2; -@@ -73,25 +76,25 @@ cpu0_opp_table: opp_table0 { - - opp-408000000 { - opp-hz = /bits/ 64 <408000000>; -- opp-microvolt = <950000>; -+ opp-microvolt = <950000 950000 1275000>; - clock-latency-ns = <40000>; - opp-suspend; - }; - opp-600000000 { - opp-hz = /bits/ 64 <600000000>; -- opp-microvolt = <975000>; -+ opp-microvolt = <975000 975000 1275000>; - }; - opp-816000000 { - opp-hz = /bits/ 64 <816000000>; -- opp-microvolt = <1000000>; -+ opp-microvolt = <1000000 1000000 1275000>; - }; - opp-1008000000 { - opp-hz = /bits/ 64 <1008000000>; -- opp-microvolt = <1175000>; -+ opp-microvolt = <1175000 1175000 1275000>; - }; - opp-1200000000 { - opp-hz = /bits/ 64 <1200000000>; -- opp-microvolt = <1275000>; -+ opp-microvolt = <1275000 1275000 1275000>; - }; - }; - -@@ -121,11 +124,52 @@ arm-pmu { - interrupt-affinity = <&cpu0>, <&cpu1>, <&cpu2>, <&cpu3>; - }; - -+ display_subsystem: display-subsystem { -+ compatible = "rockchip,display-subsystem"; -+ ports = <&vop_out>; -+ }; -+ -+ hdmi_sound: hdmi-sound { -+ compatible = "simple-audio-card"; -+ simple-audio-card,name = "HDMI"; -+ simple-audio-card,format = "i2s"; -+ simple-audio-card,mclk-fs = <128>; -+ status = "disabled"; -+ -+ simple-audio-card,cpu { -+ sound-dai = <&i2s0>; -+ }; -+ -+ simple-audio-card,codec { -+ sound-dai = <&hdmi>; -+ }; -+ }; -+ - psci { - compatible = "arm,psci-1.0", "arm,psci-0.2"; - method = "smc"; - }; - -+ spdif_out: spdif-out { -+ compatible = "linux,spdif-dit"; -+ #sound-dai-cells = <0>; -+ status = "disabled"; -+ }; -+ -+ spdif_sound: spdif-sound { -+ compatible = "simple-audio-card"; -+ simple-audio-card,name = "SPDIF"; -+ status = "disabled"; -+ -+ simple-audio-card,cpu { -+ sound-dai = <&spdif>; -+ }; -+ -+ simple-audio-card,codec { -+ sound-dai = <&spdif_out>; -+ }; -+ }; -+ - timer { - compatible = "arm,armv7-timer"; - arm,cpu-registers-not-fw-configured; -@@ -143,15 +187,13 @@ xin24m: oscillator { - #clock-cells = <0>; - }; - -- display_subsystem: display-subsystem { -- compatible = "rockchip,display-subsystem"; -- ports = <&vop_out>; -- }; -- - i2s1: i2s1@100b0000 { - compatible = "rockchip,rk3228-i2s", "rockchip,rk3066-i2s"; - reg = <0x100b0000 0x4000>; - interrupts = ; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ #sound-dai-cells = <0>; - clock-names = "i2s_clk", "i2s_hclk"; - clocks = <&cru SCLK_I2S1>, <&cru HCLK_I2S1_8CH>; - dmas = <&pdma 14>, <&pdma 15>; -@@ -165,6 +207,9 @@ i2s0: i2s0@100c0000 { - compatible = "rockchip,rk3228-i2s", "rockchip,rk3066-i2s"; - reg = <0x100c0000 0x4000>; - interrupts = ; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ #sound-dai-cells = <0>; - clock-names = "i2s_clk", "i2s_hclk"; - clocks = <&cru SCLK_I2S0>, <&cru HCLK_I2S0_8CH>; - dmas = <&pdma 11>, <&pdma 12>; -@@ -182,6 +227,7 @@ spdif: spdif@100d0000 { - dma-names = "tx"; - pinctrl-names = "default"; - pinctrl-0 = <&spdif_tx>; -+ #sound-dai-cells = <0>; - status = "disabled"; - }; - -@@ -189,6 +235,9 @@ i2s2: i2s2@100e0000 { - compatible = "rockchip,rk3228-i2s", "rockchip,rk3066-i2s"; - reg = <0x100e0000 0x4000>; - interrupts = ; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ #sound-dai-cells = <0>; - clock-names = "i2s_clk", "i2s_hclk"; - clocks = <&cru SCLK_I2S2>, <&cru HCLK_I2S2_2CH>; - dmas = <&pdma 0>, <&pdma 1>; -@@ -207,6 +256,43 @@ io_domains: io-domains { - status = "disabled"; - }; - -+ power: power-controller { -+ compatible = "rockchip,rk3228-power-controller"; -+ #power-domain-cells = <1>; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ -+ pd_gpu@RK3228_PD_GPU { -+ reg = ; -+ clocks = <&cru ACLK_GPU>; -+ pm_qos = <&qos_gpu>; -+ }; -+ -+ pd_vpu@RK3228_PD_VPU { -+ reg = ; -+ clocks = <&cru ACLK_VPU>, <&cru HCLK_VPU>; -+ pm_qos = <&qos_vpu>; -+ }; -+ -+ pd_rkvdec@RK3228_PD_RKVDEC { -+ reg = ; -+ clocks = <&cru ACLK_RKVDEC>, -+ <&cru HCLK_RKVDEC>, -+ <&cru SCLK_VDEC_CABAC>, -+ <&cru SCLK_VDEC_CORE>; -+ pm_qos = <&qos_rkvdec_r>, <&qos_rkvdec_w>; -+ }; -+ }; -+ -+ reboot_mode: reboot-mode { -+ compatible = "syscon-reboot-mode"; -+ offset = <0x5c8>; -+ mode-normal = ; -+ mode-recovery = ; -+ mode-bootloader = ; -+ mode-loader = ; -+ }; -+ - u2phy0: usb2-phy@760 { - compatible = "rockchip,rk3228-usb2phy"; - reg = <0x0760 0x0c>; -@@ -257,6 +343,7 @@ u2phy1_host: host-port { - status = "disabled"; - }; - }; -+ - }; - - uart0: serial@11010000 { -@@ -295,7 +382,7 @@ uart2: serial@11030000 { - clocks = <&cru SCLK_UART2>, <&cru PCLK_UART2>; - clock-names = "baudclk", "apb_pclk"; - pinctrl-names = "default"; -- pinctrl-0 = <&uart2_xfer>; -+ pinctrl-0 = <&uart21_xfer>; - reg-shift = <2>; - reg-io-width = <4>; - status = "disabled"; -@@ -454,13 +541,13 @@ cru: clock-controller@110e0000 { - <&cru PLL_CPLL>, <&cru ACLK_PERI>, - <&cru HCLK_PERI>, <&cru PCLK_PERI>, - <&cru ACLK_CPU>, <&cru HCLK_CPU>, -- <&cru PCLK_CPU>; -+ <&cru PCLK_CPU>, <&cru ACLK_VOP>; - assigned-clock-rates = -- <594000000>, <816000000>, -+ <1200000000>, <816000000>, - <500000000>, <150000000>, - <150000000>, <75000000>, - <150000000>, <150000000>, -- <75000000>; -+ <75000000>, <400000000>; - }; - - thermal-zones { -@@ -505,6 +592,12 @@ map1 { - <&cpu2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&cpu3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; - }; -+ -+ map2 { -+ trip = <&cpu_alert1>; -+ cooling-device = -+ <&gpu THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; -+ }; - }; - }; - }; -@@ -523,8 +616,9 @@ tsadc: tsadc@11150000 { - pinctrl-0 = <&otp_gpio>; - pinctrl-1 = <&otp_out>; - pinctrl-2 = <&otp_gpio>; -+ rockchip,grf = <&grf>; -+ rockchip,hw-tshut-temp = <120000>; - #thermal-sensor-cells = <0>; -- rockchip,hw-tshut-temp = <95000>; - status = "disabled"; - }; - -@@ -554,10 +648,33 @@ gpu: gpu@20000000 { - "ppmmu0", - "pp1", - "ppmmu1"; -+ assigned-clocks = <&cru ACLK_GPU>; -+ assigned-clock-rates = <300000000>; - clocks = <&cru ACLK_GPU>, <&cru ACLK_GPU>; - clock-names = "bus", "core"; -+ operating-points-v2 = <&gpu_opp_table>; -+ #cooling-cells = <2>; /* min followed by max */ -+ power-domains = <&power RK3228_PD_GPU>; - resets = <&cru SRST_GPU_A>; -- status = "disabled"; -+ }; -+ -+ gpu_opp_table: opp-table2 { -+ compatible = "operating-points-v2"; -+ -+ opp-200000000 { -+ opp-hz = /bits/ 64 <200000000>; -+ opp-microvolt = <1050000>; -+ }; -+ -+ opp-300000000 { -+ opp-hz = /bits/ 64 <300000000>; -+ opp-microvolt = <1050000>; -+ }; -+ -+ opp-500000000 { -+ opp-hz = /bits/ 64 <500000000>; -+ opp-microvolt = <1150000>; -+ }; - }; - - vpu_mmu: iommu@20020800 { -@@ -567,8 +684,8 @@ vpu_mmu: iommu@20020800 { - interrupt-names = "vpu_mmu"; - clocks = <&cru ACLK_VPU>, <&cru HCLK_VPU>; - clock-names = "aclk", "iface"; -- iommu-cells = <0>; -- status = "disabled"; -+ power-domains = <&power RK3228_PD_VPU>; -+ #iommu-cells = <0>; - }; - - vdec_mmu: iommu@20030480 { -@@ -578,8 +695,8 @@ vdec_mmu: iommu@20030480 { - interrupt-names = "vdec_mmu"; - clocks = <&cru ACLK_RKVDEC>, <&cru HCLK_RKVDEC>; - clock-names = "aclk", "iface"; -- iommu-cells = <0>; -- status = "disabled"; -+ power-domains = <&power RK3228_PD_RKVDEC>; -+ #iommu-cells = <0>; - }; - - vop: vop@20050000 { -@@ -622,7 +739,7 @@ iep_mmu: iommu@20070800 { - interrupt-names = "iep_mmu"; - clocks = <&cru ACLK_IEP>, <&cru HCLK_IEP>; - clock-names = "aclk", "iface"; -- iommu-cells = <0>; -+ #iommu-cells = <0>; - status = "disabled"; - }; - -@@ -642,6 +759,7 @@ hdmi: hdmi@200a0000 { - phys = <&hdmi_phy>; - phy-names = "hdmi"; - rockchip,grf = <&grf>; -+ #sound-dai-cells = <0>; - status = "disabled"; - - ports { -@@ -663,9 +781,13 @@ sdmmc: mmc@30000000 { - clocks = <&cru HCLK_SDMMC>, <&cru SCLK_SDMMC>, - <&cru SCLK_SDMMC_DRV>, <&cru SCLK_SDMMC_SAMPLE>; - clock-names = "biu", "ciu", "ciu-drive", "ciu-sample"; -+ bus-width = <4>; - fifo-depth = <0x100>; -+ max-frequency = <150000000>; - pinctrl-names = "default"; -- pinctrl-0 = <&sdmmc_clk &sdmmc_cmd &sdmmc_bus4>; -+ pinctrl-0 = <&sdmmc_clk &sdmmc_cmd &sdmmc_bus4 &sdmmc_pwr>; -+ resets = <&cru SRST_SDMMC>; -+ reset-names = "reset"; - status = "disabled"; - }; - -@@ -675,10 +797,14 @@ sdio: mmc@30010000 { - interrupts = ; - clocks = <&cru HCLK_SDIO>, <&cru SCLK_SDIO>, - <&cru SCLK_SDIO_DRV>, <&cru SCLK_SDIO_SAMPLE>; -+ bus-width = <4>; - clock-names = "biu", "ciu", "ciu-drive", "ciu-sample"; - fifo-depth = <0x100>; -+ max-frequency = <150000000>; - pinctrl-names = "default"; - pinctrl-0 = <&sdio_clk &sdio_cmd &sdio_bus4>; -+ resets = <&cru SRST_SDIO>; -+ reset-names = "reset"; - status = "disabled"; - }; - -@@ -686,8 +812,7 @@ emmc: mmc@30020000 { - compatible = "rockchip,rk3228-dw-mshc", "rockchip,rk3288-dw-mshc"; - reg = <0x30020000 0x4000>; - interrupts = ; -- clock-frequency = <37500000>; -- max-frequency = <37500000>; -+ max-frequency = <150000000>; - clocks = <&cru HCLK_EMMC>, <&cru SCLK_EMMC>, - <&cru SCLK_EMMC_DRV>, <&cru SCLK_EMMC_SAMPLE>; - clock-names = "biu", "ciu", "ciu-drive", "ciu-sample"; -@@ -701,6 +826,22 @@ emmc: mmc@30020000 { - status = "disabled"; - }; - -+ nfc: nand-controller@ff4b0000 { -+ compatible = "rockchip,rk3228_nfc"; -+ reg = <0x30030000 0x4000>; -+ interrupts = ; -+ clocks = <&cru SCLK_NANDC>, <&cru HCLK_NANDC>; -+ clock-names = "nfc", "ahb"; -+ assigned-clocks = <&cru SCLK_NANDC>; -+ assigned-clock-rates = <150000000>; -+ -+ pinctrl-names = "default"; -+ pinctrl-0 = <&flash_cs0 &flash_rdy &flash_ale &flash_cle -+ &flash_wrn &flash_rdn &flash_bus8>; -+ status = "disabled"; -+ -+ }; -+ - usb_otg: usb@30040000 { - compatible = "rockchip,rk3228-usb", "rockchip,rk3066-usb", - "snps,dwc2"; -@@ -796,6 +937,26 @@ gmac: ethernet@30200000 { - status = "disabled"; - }; - -+ qos_vpu: qos@31040000 { -+ compatible = "syscon"; -+ reg = <0x31040000 0x20>; -+ }; -+ -+ qos_gpu: qos@31050000 { -+ compatible = "syscon"; -+ reg = <0x31050000 0x20>; -+ }; -+ -+ qos_rkvdec_r: qos@31070000 { -+ compatible = "syscon"; -+ reg = <0x31070000 0x20>; -+ }; -+ -+ qos_rkvdec_w: qos@31070080 { -+ compatible = "syscon"; -+ reg = <0x31070080 0x20>; -+ }; -+ - gic: interrupt-controller@32010000 { - compatible = "arm,gic-400"; - interrupt-controller; -@@ -884,6 +1045,11 @@ pcfg_pull_none_drv_12ma: pcfg-pull-none-drv-12ma { - drive-strength = <12>; - }; - -+ pcfg_pull_up_12ma: pcfg-pull-up-12ma { -+ bias-pull-up; -+ drive-strength = <12>; -+ }; -+ - sdmmc { - sdmmc_clk: sdmmc-clk { - rockchip,pins = <1 RK_PC0 1 &pcfg_pull_none_drv_12ma>; -@@ -899,6 +1065,10 @@ sdmmc_bus4: sdmmc-bus4 { - <1 RK_PC4 1 &pcfg_pull_none_drv_12ma>, - <1 RK_PC5 1 &pcfg_pull_none_drv_12ma>; - }; -+ -+ sdmmc_pwr: sdmmc-pwr { -+ rockchip,pins = <1 RK_PB6 RK_FUNC_GPIO &pcfg_pull_none>; -+ }; - }; - - sdio { -@@ -939,6 +1109,55 @@ emmc_bus8: emmc-bus8 { - }; - }; - -+ flash { -+ -+ flash_cs0: flash-cs0 { -+ rockchip,pins = -+ <2 RK_PA6 1 &pcfg_pull_none>; -+ }; -+ -+ flash_cs1: flash-cs1 { -+ rockchip,pins = -+ <0 RK_PC7 1 &pcfg_pull_none>; -+ }; -+ -+ flash_rdy: flash-rdy { -+ rockchip,pins = -+ <2 RK_PA4 1 &pcfg_pull_none>; -+ }; -+ -+ flash_ale: flash-ale { -+ rockchip,pins = -+ <2 RK_PA0 1 &pcfg_pull_none>; -+ }; -+ -+ flash_cle: flash-cle { -+ rockchip,pins = -+ <2 RK_PA1 1 &pcfg_pull_none>; -+ }; -+ -+ flash_wrn: flash-wrn { -+ rockchip,pins = -+ <2 RK_PA2 1 &pcfg_pull_none>; -+ }; -+ -+ flash_rdn: flash-rdn { -+ rockchip,pins = -+ <2 RK_PA3 1 &pcfg_pull_none>; -+ }; -+ -+ flash_bus8: flash-bus8 { -+ rockchip,pins = <1 RK_PD0 1 &pcfg_pull_none>, -+ <1 RK_PD1 1 &pcfg_pull_none>, -+ <1 RK_PD2 1 &pcfg_pull_none>, -+ <1 RK_PD3 1 &pcfg_pull_none>, -+ <1 RK_PD4 1 &pcfg_pull_none>, -+ <1 RK_PD5 1 &pcfg_pull_none>, -+ <1 RK_PD6 1 &pcfg_pull_none>, -+ <1 RK_PD7 1 &pcfg_pull_none>; -+ }; -+ }; -+ - gmac { - rgmii_pins: rgmii-pins { - rockchip,pins = <2 RK_PB6 1 &pcfg_pull_none>, -@@ -1080,12 +1299,20 @@ pwm1 { - pwm1_pin: pwm1-pin { - rockchip,pins = <0 RK_PD6 2 &pcfg_pull_none>; - }; -+ -+ pwm1_pin_pull_down: pwm1-pin-pull-down { -+ rockchip,pins = <0 RK_PD6 2 &pcfg_pull_down>; -+ }; - }; - - pwm2 { - pwm2_pin: pwm2-pin { - rockchip,pins = <1 RK_PB4 2 &pcfg_pull_none>; - }; -+ -+ pwm2_pin_pull_up: pwm2-pin-pull-up { -+ rockchip,pins = <1 RK_PB4 2 &pcfg_pull_up>; -+ }; - }; - - pwm3 { -@@ -1140,16 +1367,31 @@ uart1_rts: uart1-rts { - }; - }; - -+ uart1-1 { -+ uart11_xfer: uart11-xfer { -+ rockchip,pins = <3 RK_PB6 1 &pcfg_pull_up>, -+ <3 RK_PB5 1 &pcfg_pull_none>; -+ }; -+ -+ uart11_cts: uart11-cts { -+ rockchip,pins = <3 RK_PA7 1 &pcfg_pull_none>; -+ }; -+ -+ uart11_rts: uart11-rts { -+ rockchip,pins = <3 RK_PA6 1 &pcfg_pull_none>; -+ }; -+ -+ uart11_rts_gpio: uart11-rts-gpio { -+ rockchip,pins = <3 RK_PA6 RK_FUNC_GPIO &pcfg_pull_none>; -+ }; -+ }; -+ - uart2 { - uart2_xfer: uart2-xfer { - rockchip,pins = <1 RK_PC2 2 &pcfg_pull_up>, - <1 RK_PC3 2 &pcfg_pull_none>; - }; - -- uart21_xfer: uart21-xfer { -- rockchip,pins = <1 RK_PB2 2 &pcfg_pull_up>, -- <1 RK_PB1 2 &pcfg_pull_none>; -- }; - - uart2_cts: uart2-cts { - rockchip,pins = <0 RK_PD1 1 &pcfg_pull_none>; -@@ -1159,5 +1401,23 @@ uart2_rts: uart2-rts { - rockchip,pins = <0 RK_PD0 1 &pcfg_pull_none>; - }; - }; -+ -+ uart2-1 { -+ uart21_xfer: uart21-xfer { -+ rockchip,pins = <1 RK_PB2 2 &pcfg_pull_up>, -+ <1 RK_PB1 2 &pcfg_pull_none>; -+ }; -+ }; -+ -+ usb { -+ host_vbus_drv: host-vbus-drv { -+ rockchip,pins = <3 RK_PC4 RK_FUNC_GPIO &pcfg_pull_none>; -+ }; -+ -+ otg_vbus_drv: otg-vbus-drv { -+ rockchip,pins = <3 RK_PC6 RK_FUNC_GPIO &pcfg_pull_none>; -+ }; -+ }; -+ - }; - }; -diff --git a/arch/arm/boot/dts/rk322x.dtsi.rej b/arch/arm/boot/dts/rk322x.dtsi.rej -new file mode 100644 -index 000000000..cc36be3e9 ---- /dev/null -+++ b/arch/arm/boot/dts/rk322x.dtsi.rej -@@ -0,0 +1,45 @@ -+--- arch/arm/boot/dts/rk322x.dtsi -++++ arch/arm/boot/dts/rk322x.dtsi -+@@ -187,17 +231,13 @@ -+ #clock-cells = <0>; -+ }; -+ -+- display_subsystem: display-subsystem { -+- compatible = "rockchip,display-subsystem"; -+- ports = <&vop_out>; -+- }; -+- -+ i2s1: i2s1@100b0000 { -+ compatible = "rockchip,rk3228-i2s", "rockchip,rk3066-i2s"; -+ reg = <0x100b0000 0x4000>; -+ interrupts = ; -+ #address-cells = <1>; -+ #size-cells = <0>; -++ #sound-dai-cells = <0>; -+ clock-names = "i2s_clk", "i2s_hclk"; -+ clocks = <&cru SCLK_I2S1>, <&cru HCLK_I2S1_8CH>; -+ dmas = <&pdma 14>, <&pdma 15>; -+@@ -213,6 +253,7 @@ -+ interrupts = ; -+ #address-cells = <1>; -+ #size-cells = <0>; -++ #sound-dai-cells = <0>; -+ clock-names = "i2s_clk", "i2s_hclk"; -+ clocks = <&cru SCLK_I2S0>, <&cru HCLK_I2S0_8CH>; -+ dmas = <&pdma 11>, <&pdma 12>; -+@@ -825,14 +944,13 @@ -+ compatible = "rockchip,rk3228-dw-mshc", "rockchip,rk3288-dw-mshc"; -+ reg = <0x30020000 0x4000>; -+ interrupts = ; -+- clock-frequency = <37500000>; -+- max-frequency = <37500000>; -+ clocks = <&cru HCLK_EMMC>, <&cru SCLK_EMMC>, -+ <&cru SCLK_EMMC_DRV>, <&cru SCLK_EMMC_SAMPLE>; -+ clock-names = "biu", "ciu", "ciu-drive", "ciu-sample"; -+ bus-width = <8>; -+ default-sample-phase = <158>; -+ fifo-depth = <0x100>; -++ max-frequency = <150000000>; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&emmc_clk &emmc_cmd &emmc_bus8>; -+ resets = <&cru SRST_EMMC>; diff --git a/patch/kernel/rk322x-dev/01-linux-1003-rk322x-hantro.patch b/patch/kernel/rk322x-dev/01-linux-1003-rk322x-hantro.patch deleted file mode 100644 index e63bce853..000000000 --- a/patch/kernel/rk322x-dev/01-linux-1003-rk322x-hantro.patch +++ /dev/null @@ -1,98 +0,0 @@ -diff --git a/Documentation/devicetree/bindings/media/rockchip-vpu.yaml b/Documentation/devicetree/bindings/media/rockchip-vpu.yaml -index a0c45e05cf03..a20cfaa8973e 100644 ---- a/Documentation/devicetree/bindings/media/rockchip-vpu.yaml -+++ b/Documentation/devicetree/bindings/media/rockchip-vpu.yaml -@@ -16,6 +16,7 @@ description: - properties: - compatible: - enum: -+ - rockchip,rk322x-vpu - - rockchip,rk3288-vpu - - rockchip,rk3328-vpu - - rockchip,rk3399-vpu -diff --git a/arch/arm/boot/dts/rk322x.dtsi b/arch/arm/boot/dts/rk322x.dtsi -index f7a50b903a7d..2ed8aa7ae520 100644 ---- a/arch/arm/boot/dts/rk322x.dtsi -+++ b/arch/arm/boot/dts/rk322x.dtsi -@@ -676,6 +676,18 @@ - }; - }; - -+ vpu: video-codec@20020000 { -+ compatible = "rockchip,rk322x-vpu"; -+ reg = <0x20020000 0x800>; -+ interrupts = , -+ ; -+ interrupt-names = "vepu", "vdpu"; -+ clocks = <&cru ACLK_VPU>, <&cru HCLK_VPU>; -+ clock-names = "aclk", "hclk"; -+ iommus = <&vpu_mmu>; -+ power-domains = <&power RK3228_PD_VPU>; -+ }; -+ - vpu_mmu: iommu@20020800 { - compatible = "rockchip,iommu"; - reg = <0x20020800 0x100>; -diff --git a/drivers/staging/media/hantro/Kconfig b/drivers/staging/media/hantro/Kconfig -index de77fe6554e7..9f99d1c9f453 100644 ---- a/drivers/staging/media/hantro/Kconfig -+++ b/drivers/staging/media/hantro/Kconfig -@@ -20,4 +20,4 @@ config VIDEO_HANTRO_ROCKCHIP - depends on ARCH_ROCKCHIP || COMPILE_TEST - default y - help -- Enable support for RK3288, RK3328, and RK3399 SoCs. -+ Enable support for RK322x, RK3288, RK3328, and RK3399 SoCs. -diff --git a/drivers/staging/media/hantro/hantro_drv.c b/drivers/staging/media/hantro/hantro_drv.c -index a732beeb3bb6..fae9555a349b 100644 ---- a/drivers/staging/media/hantro/hantro_drv.c -+++ b/drivers/staging/media/hantro/hantro_drv.c -@@ -469,6 +469,7 @@ static const struct of_device_id of_hantro_match[] = { - { .compatible = "rockchip,rk3399-vpu", .data = &rk3399_vpu_variant, }, - { .compatible = "rockchip,rk3328-vpu", .data = &rk3328_vpu_variant, }, - { .compatible = "rockchip,rk3288-vpu", .data = &rk3288_vpu_variant, }, -+ { .compatible = "rockchip,rk322x-vpu", .data = &rk322x_vpu_variant, }, - #endif - { /* sentinel */ } - }; -diff --git a/drivers/staging/media/hantro/hantro_hw.h b/drivers/staging/media/hantro/hantro_hw.h -index 33c1ce169203..e64369e01a21 100644 ---- a/drivers/staging/media/hantro/hantro_hw.h -+++ b/drivers/staging/media/hantro/hantro_hw.h -@@ -157,6 +157,7 @@ enum hantro_enc_fmt { - extern const struct hantro_variant rk3399_vpu_variant; - extern const struct hantro_variant rk3328_vpu_variant; - extern const struct hantro_variant rk3288_vpu_variant; -+extern const struct hantro_variant rk322x_vpu_variant; - extern const struct hantro_variant imx8mq_vpu_variant; - - extern const struct hantro_postproc_regs hantro_g1_postproc_regs; - -diff --git a/drivers/staging/media/hantro/rk3399_vpu_hw.c b/drivers/staging/media/hantro/rk3399_vpu_hw.c -index 78f878ca01ff..0a6c021c2332 100644 ---- a/drivers/staging/media/hantro/rk3399_vpu_hw.c -+++ b/drivers/staging/media/hantro/rk3399_vpu_hw.c -@@ -241,3 +241,20 @@ const struct hantro_variant rk3328_vpu_variant = { - .clk_names = rk3399_clk_names, - .num_clocks = ARRAY_SIZE(rk3399_clk_names), - }; -+ -+const struct hantro_variant rk322x_vpu_variant = { -+ .enc_offset = 0x0, -+ .enc_fmts = rk3399_vpu_enc_fmts, -+ .num_enc_fmts = ARRAY_SIZE(rk3399_vpu_enc_fmts), -+ .dec_offset = 0x400, -+ .dec_fmts = rk3399_vpu_dec_fmts, -+ .num_dec_fmts = ARRAY_SIZE(rk3399_vpu_dec_fmts), -+ .codec = HANTRO_MPEG2_DECODER | HANTRO_VP8_DECODER | -+ HANTRO_H264_DECODER, -+ .codec_ops = rk3399_vpu_codec_ops, -+ .irqs = rk3399_irqs, -+ .num_irqs = ARRAY_SIZE(rk3399_irqs), -+ .init = rk3399_vpu_hw_init, -+ .clk_names = rk3399_clk_names, -+ .num_clocks = ARRAY_SIZE(rk3399_clk_names) -+}; --- -2.17.1 - diff --git a/patch/kernel/rk322x-dev/01-linux-1004-rockchip-rk322x-enhancements-and-fixes.patch b/patch/kernel/rk322x-dev/01-linux-1004-rockchip-rk322x-enhancements-and-fixes.patch deleted file mode 100644 index aa5a48973..000000000 --- a/patch/kernel/rk322x-dev/01-linux-1004-rockchip-rk322x-enhancements-and-fixes.patch +++ /dev/null @@ -1,383 +0,0 @@ -diff --git a/drivers/soc/rockchip/pm_domains.c b/drivers/soc/rockchip/pm_domains.c -index 54eb6cfc5d5b..c6b33f7c43df 100644 ---- a/drivers/soc/rockchip/pm_domains.c -+++ b/drivers/soc/rockchip/pm_domains.c -@@ -71,6 +71,7 @@ struct rockchip_pm_domain { - struct regmap **qos_regmap; - u32 *qos_save_regs[MAX_QOS_REGS_NUM]; - int num_clks; -+ bool is_ignore_pwr; - struct clk_bulk_data *clks; - }; - -@@ -330,6 +331,9 @@ static int rockchip_pd_power_on(struct generic_pm_domain *domain) - { - struct rockchip_pm_domain *pd = to_rockchip_pd(domain); - -+ if (pd->is_ignore_pwr) -+ return 0; -+ - return rockchip_pd_power(pd, true); - } - -@@ -337,6 +341,9 @@ static int rockchip_pd_power_off(struct generic_pm_domain *domain) - { - struct rockchip_pm_domain *pd = to_rockchip_pd(domain); - -+ if (pd->is_ignore_pwr) -+ return 0; -+ - return rockchip_pd_power(pd, false); - } - -@@ -416,6 +423,9 @@ static int rockchip_pm_add_one_domain(struct rockchip_pmu *pmu, - pd->info = pd_info; - pd->pmu = pmu; - -+ if (!pd_info->pwr_mask) -+ pd->is_ignore_pwr = true; -+ - pd->num_clks = of_clk_get_parent_count(node); - if (pd->num_clks > 0) { - pd->clks = devm_kcalloc(pmu->dev, pd->num_clks, -@@ -566,6 +576,7 @@ static int rockchip_pm_add_subdomain(struct rockchip_pmu *pmu, - { - struct device_node *np; - struct generic_pm_domain *child_domain, *parent_domain; -+ struct rockchip_pm_domain *child_pd, *parent_pd; - int error; - - for_each_child_of_node(parent, np) { -@@ -606,6 +617,18 @@ static int rockchip_pm_add_subdomain(struct rockchip_pmu *pmu, - parent_domain->name, child_domain->name); - } - -+ /* -+ * If child_pd doesn't do idle request or power on/off, -+ * parent_pd may fail to do power on/off, so if parent_pd -+ * need to power on/off, child_pd can't ignore to do idle -+ * request and power on/off. -+ */ -+ child_pd = to_rockchip_pd(child_domain); -+ parent_pd = to_rockchip_pd(parent_domain); -+ if (!parent_pd->is_ignore_pwr) -+ child_pd->is_ignore_pwr = false; -+ -+ - rockchip_pm_add_subdomain(pmu, np); - } - --- -2.17.1 - -From c94b1272290bafced10d79b7da1525466e8c843b Mon Sep 17 00:00:00 2001 -From: "Huang, Tao" -Date: Thu, 28 Jul 2016 10:59:22 +0800 -Subject: [PATCH] power: reset: reboot-mode: fix normal mode setup - -If cmd is empty in get_reboot_mode_magic, we should return normal magic. - -Change-Id: I10931adc49e33f72ae73d9471159f82cc02ff0c0 -Signed-off-by: Huang, Tao ---- - drivers/power/reset/reboot-mode.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/drivers/power/reset/reboot-mode.c b/drivers/power/reset/reboot-mode.c -index b4076b10b893..47f9a162807d 100644 ---- a/drivers/power/reset/reboot-mode.c -+++ b/drivers/power/reset/reboot-mode.c -@@ -26,7 +26,7 @@ static unsigned int get_reboot_mode_magic(struct reboot_mode_driver *reboot, - int magic = 0; - struct mode_info *info; - -- if (!cmd) -+ if (!cmd || !cmd[0]) - cmd = normal; - - list_for_each_entry(info, &reboot->head, list) { --- -2.17.1 - - -From be9674f270c97399f9f6b1facb11e93eced6ec34 Mon Sep 17 00:00:00 2001 -From: Andy Yan -Date: Thu, 8 Dec 2016 16:58:07 +0800 -Subject: [PATCH] power: reset: reboot-mode: treat unrecognized reboot mode as - normal mode - -Some bootloader will check the reboot mode to take different action, so -we treat unrecognized reboot mode as normal mode to prevent the system -run into abnormal case. - -Change-Id: I88063a5b41e4e645443229fa490b2b55db5ccf27 -Signed-off-by: Andy Yan ---- - drivers/power/reset/reboot-mode.c | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/drivers/power/reset/reboot-mode.c b/drivers/power/reset/reboot-mode.c -index 47f9a162807d..99bf938404e3 100644 ---- a/drivers/power/reset/reboot-mode.c -+++ b/drivers/power/reset/reboot-mode.c -@@ -47,6 +47,8 @@ static int reboot_mode_notify(struct notifier_block *this, - - reboot = container_of(this, struct reboot_mode_driver, reboot_notifier); - magic = get_reboot_mode_magic(reboot, cmd); -+ if (!magic) -+ magic = get_reboot_mode_magic(reboot, NULL); - if (magic) - reboot->write(reboot, magic); - --- -2.17.1 - -From 7c097120eb21a9bd15ab63c0ac60ffd5cba902b2 Mon Sep 17 00:00:00 2001 -From: Alex Bee -Date: Fri, 24 Apr 2020 13:01:07 +0200 -Subject: [PATCH] sound: soc: rockchip: use rouned rate for i2s - ---- - sound/soc/rockchip/rockchip_i2s.c | 9 +++++++-- - 1 file changed, 7 insertions(+), 2 deletions(-) - -diff --git a/sound/soc/rockchip/rockchip_i2s.c b/sound/soc/rockchip/rockchip_i2s.c -index 61c984f10d8e..efca853eba6b 100644 ---- a/sound/soc/rockchip/rockchip_i2s.c -+++ b/sound/soc/rockchip/rockchip_i2s.c -@@ -279,10 +279,13 @@ static int rockchip_i2s_hw_params(struct snd_pcm_substream *substream, - if (i2s->is_master_mode) { - mclk_rate = clk_get_rate(i2s->mclk); - bclk_rate = 2 * 32 * params_rate(params); -- if (bclk_rate && mclk_rate % bclk_rate) -+ if (!bclk_rate) { -+ dev_err(i2s->dev, "invalid bclk_rate: %d\n", -+ bclk_rate); - return -EINVAL; -+ } - -- div_bclk = mclk_rate / bclk_rate; -+ div_bclk = DIV_ROUND_CLOSEST(mclk_rate, bclk_rate); - div_lrck = bclk_rate / params_rate(params); - regmap_update_bits(i2s->regmap, I2S_CKR, - I2S_CKR_MDIV_MASK, -@@ -312,6 +315,8 @@ static int rockchip_i2s_hw_params(struct snd_pcm_substream *substream, - val |= I2S_TXCR_VDW(32); - break; - default: -+ dev_err(i2s->dev, "invalid format: %d\n", -+ params_format(params)); - return -EINVAL; - } - --- -2.17.1 - - -From 4102c5b07d8610c729d577612c1df52737fb9a0f Mon Sep 17 00:00:00 2001 -From: Alex Bee -Date: Fri, 24 Apr 2020 09:08:44 +0200 -Subject: [PATCH] phy: rockchip: hdmi: readout hdmi phy flag for RK3228 HDMI - phys - -Some RK3228 HDMI phys only get a stable pll on frequencies higher 337,5 MHz. -This is defined in a flag in efuse of those devices. ---- - arch/arm/boot/dts/rk322x.dtsi | 7 ++++ - drivers/phy/rockchip/phy-rockchip-inno-hdmi.c | 38 ++++++++++++++++++- - 2 files changed, 43 insertions(+), 2 deletions(-) - -diff --git a/arch/arm/boot/dts/rk322x.dtsi b/arch/arm/boot/dts/rk322x.dtsi -index 2ed8aa7ae520..8c50dcb0e9f1 100644 ---- a/arch/arm/boot/dts/rk322x.dtsi -+++ b/arch/arm/boot/dts/rk322x.dtsi -@@ -402,6 +402,11 @@ - cpu_leakage: cpu_leakage@17 { - reg = <0x17 0x1>; - }; -+ -+ hdmi_phy_flag: hdmi-phy-flag@1d { -+ reg = <0x1d 0x1>; -+ bits = <1 1>; -+ }; - }; - - i2c0: i2c@11050000 { -@@ -628,6 +633,8 @@ - clock-names = "sysclk", "refoclk", "refpclk"; - #clock-cells = <0>; - clock-output-names = "hdmiphy_phy"; -+ nvmem-cells = <&hdmi_phy_flag>; -+ nvmem-cell-names = "hdmi-phy-flag"; - #phy-cells = <0>; - status = "disabled"; - }; -diff --git a/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c b/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c -index bb8bdf5e3301..0c7a97352714 100644 ---- a/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c -+++ b/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c -@@ -237,6 +237,9 @@ struct inno_hdmi_phy { - struct clk *refoclk; - struct clk *refpclk; - -+ /* phy_flag flag */ -+ bool phy_flag; -+ - /* platform data */ - const struct inno_hdmi_phy_drv_data *plat_data; - int chip_version; -@@ -347,6 +350,7 @@ static const struct pre_pll_config pre_pll_cfg_table[] = { - static const struct post_pll_config post_pll_cfg_table[] = { - {33750000, 1, 40, 8, 1}, - {33750000, 1, 80, 8, 2}, -+ {33750000, 1, 10, 2, 4}, - {74250000, 1, 40, 8, 1}, - {74250000, 18, 80, 8, 2}, - {148500000, 2, 40, 4, 3}, -@@ -497,8 +501,11 @@ static int inno_hdmi_phy_power_on(struct phy *phy) - return -EINVAL; - - for (; cfg->tmdsclock != 0; cfg++) -- if (tmdsclock <= cfg->tmdsclock && -- cfg->version & inno->chip_version) -+ if (((!inno->phy_flag || tmdsclock > 33750000) -+ && tmdsclock <= cfg->tmdsclock -+ && cfg->version & inno->chip_version) || -+ (inno->phy_flag && tmdsclock <= 33750000 -+ && cfg->version & 4)) - break; - - for (; phy_cfg->tmdsclock != 0; phy_cfg++) -@@ -909,6 +916,10 @@ static int inno_hdmi_phy_clk_register(struct inno_hdmi_phy *inno) - - static int inno_hdmi_phy_rk3228_init(struct inno_hdmi_phy *inno) - { -+ struct nvmem_cell *cell; -+ unsigned char *efuse_buf; -+ size_t len; -+ - /* - * Use phy internal register control - * rxsense/poweron/pllpd/pdataen signal. -@@ -923,7 +934,28 @@ static int inno_hdmi_phy_rk3228_init(struct inno_hdmi_phy *inno) - inno_update_bits(inno, 0xaa, RK3228_POST_PLL_CTRL_MANUAL, - RK3228_POST_PLL_CTRL_MANUAL); - -+ - inno->chip_version = 1; -+ inno->phy_flag = false; -+ -+ cell = nvmem_cell_get(inno->dev, "hdmi-phy-flag"); -+ if (IS_ERR(cell)) { -+ if (PTR_ERR(cell) == -EPROBE_DEFER) -+ return -EPROBE_DEFER; -+ -+ return 0; -+ } -+ -+ efuse_buf = nvmem_cell_read(cell, &len); -+ nvmem_cell_put(cell); -+ -+ if (IS_ERR(efuse_buf)) -+ return 0; -+ if (len == 1) -+ inno->phy_flag = (efuse_buf[0] & BIT(1)) ? true : false; -+ kfree(efuse_buf); -+ -+ dev_info(inno->dev, "phy_flag is: %d\n", inno->phy_flag); - - return 0; - } -@@ -1023,6 +1055,8 @@ static int inno_hdmi_phy_rk3328_init(struct inno_hdmi_phy *inno) - - /* try to read the chip-version */ - inno->chip_version = 1; -+ inno->phy_flag = false; -+ - cell = nvmem_cell_get(inno->dev, "cpu-version"); - if (IS_ERR(cell)) { - if (PTR_ERR(cell) == -EPROBE_DEFER) --- -2.17.1 - - -From fe30b024a7a7d6261dff0b87c2aec270ad530c39 Mon Sep 17 00:00:00 2001 -From: Alex Bee -Date: Fri, 24 Apr 2020 14:23:38 +0200 -Subject: [PATCH] drm: rockchip: Use 2nd RK3228 plane as an overlay - -As per datasheet the second plane of RK3228 vop is an overlay window. For -the missing implementation of hardware cursor it is missued as such (as -already pointed in comment for RK3288). Furthermore the overlay window -does not support YUV modes with the current implementation - so it -supports only RGB modes for now. ---- - drivers/gpu/drm/rockchip/rockchip_vop_reg.c | 44 +++++++++++++++++++-- - 1 file changed, 41 insertions(+), 3 deletions(-) - -diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c -index 73d24c6bbf05..d4ac6e161ef2 100644 ---- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c -+++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c -@@ -614,6 +614,44 @@ static const struct vop_common rk3288_common = { - .dsp_background = VOP_REG(RK3288_DSP_BG, 0xffffffff, 0), - }; - -+static const struct vop_win_phy rk3228_win0_data = { -+ .scl = &rk3288_win_full_scl, -+ .data_formats = formats_win_full, -+ .nformats = ARRAY_SIZE(formats_win_full), -+ .enable = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 0), -+ .format = VOP_REG(RK3288_WIN0_CTRL0, 0x7, 1), -+ .rb_swap = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 12), -+ .act_info = VOP_REG(RK3288_WIN0_ACT_INFO, 0x1fff1fff, 0), -+ .dsp_info = VOP_REG(RK3288_WIN0_DSP_INFO, 0x0fff0fff, 0), -+ .dsp_st = VOP_REG(RK3288_WIN0_DSP_ST, 0x1fff1fff, 0), -+ .yrgb_mst = VOP_REG(RK3288_WIN0_YRGB_MST, 0xffffffff, 0), -+ .uv_mst = VOP_REG(RK3288_WIN0_CBR_MST, 0xffffffff, 0), -+ .yrgb_vir = VOP_REG(RK3288_WIN0_VIR, 0x3fff, 0), -+ .uv_vir = VOP_REG(RK3288_WIN0_VIR, 0x3fff, 16), -+ .src_alpha_ctl = VOP_REG(RK3288_WIN0_SRC_ALPHA_CTRL, 0xff, 0), -+ .dst_alpha_ctl = VOP_REG(RK3288_WIN0_DST_ALPHA_CTRL, 0xff, 0), -+ .channel = VOP_REG(RK3288_WIN0_CTRL2, 0xff, 0), -+}; -+ -+static const struct vop_win_phy rk3228_win1_data = { -+ .scl = &rk3288_win_full_scl, -+ .data_formats = formats_win_lite, -+ .nformats = ARRAY_SIZE(formats_win_lite), -+ .enable = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 0), -+ .format = VOP_REG(RK3288_WIN0_CTRL0, 0x7, 1), -+ .rb_swap = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 12), -+ .act_info = VOP_REG(RK3288_WIN0_ACT_INFO, 0x1fff1fff, 0), -+ .dsp_info = VOP_REG(RK3288_WIN0_DSP_INFO, 0x0fff0fff, 0), -+ .dsp_st = VOP_REG(RK3288_WIN0_DSP_ST, 0x1fff1fff, 0), -+ .yrgb_mst = VOP_REG(RK3288_WIN0_YRGB_MST, 0xffffffff, 0), -+ .uv_mst = VOP_REG(RK3288_WIN0_CBR_MST, 0xffffffff, 0), -+ .yrgb_vir = VOP_REG(RK3288_WIN0_VIR, 0x3fff, 0), -+ .uv_vir = VOP_REG(RK3288_WIN0_VIR, 0x3fff, 16), -+ .src_alpha_ctl = VOP_REG(RK3288_WIN0_SRC_ALPHA_CTRL, 0xff, 0), -+ .dst_alpha_ctl = VOP_REG(RK3288_WIN0_DST_ALPHA_CTRL, 0xff, 0), -+ .channel = VOP_REG(RK3288_WIN0_CTRL2, 0xff, 0), -+}; -+ - /* - * Note: rk3288 has a dedicated 'cursor' window, however, that window requires - * special support to get alpha blending working. For now, just use overlay -@@ -864,10 +902,10 @@ static const struct vop_data rk3399_vop_lit = { - }; - - static const struct vop_win_data rk3228_vop_win_data[] = { -- { .base = 0x00, .phy = &rk3288_win01_data, -+ { .base = 0x00, .phy = &rk3228_win0_data, - .type = DRM_PLANE_TYPE_PRIMARY }, -- { .base = 0x40, .phy = &rk3288_win01_data, -- .type = DRM_PLANE_TYPE_CURSOR }, -+ { .base = 0x40, .phy = &rk3228_win1_data, -+ .type = DRM_PLANE_TYPE_OVERLAY }, - }; - - static const struct vop_data rk3228_vop = { --- -2.17.1 - diff --git a/patch/kernel/rk322x-dev/01-linux-2000-rockchip-drm-wip.patch b/patch/kernel/rk322x-dev/01-linux-2000-rockchip-drm-wip.patch new file mode 100644 index 000000000..454c77a33 --- /dev/null +++ b/patch/kernel/rk322x-dev/01-linux-2000-rockchip-drm-wip.patch @@ -0,0 +1,5333 @@ +From 4fe70563eb6f08f737ecc7091b8c4806e18a2479 Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Wed, 8 Jan 2020 21:07:47 +0000 +Subject: [PATCH] phy/rockchip: inno-hdmi: use correct vco_div_5 macro on + rk3328 + +inno_hdmi_phy_rk3328_clk_set_rate() is using the RK3228 macro +when configuring vco_div_5 on RK3328. + +Fix this by using correct vco_div_5 macro for RK3328. + +Fixes: 53706a116863 ("phy: add Rockchip Innosilicon hdmi phy") +Signed-off-by: Jonas Karlman +--- + drivers/phy/rockchip/phy-rockchip-inno-hdmi.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c b/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c +index 9ca20c947283..b0ac1d3ee390 100644 +--- a/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c ++++ b/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c +@@ -790,8 +790,8 @@ static int inno_hdmi_phy_rk3328_clk_set_rate(struct clk_hw *hw, + RK3328_PRE_PLL_POWER_DOWN); + + /* Configure pre-pll */ +- inno_update_bits(inno, 0xa0, RK3228_PCLK_VCO_DIV_5_MASK, +- RK3228_PCLK_VCO_DIV_5(cfg->vco_div_5_en)); ++ inno_update_bits(inno, 0xa0, RK3328_PCLK_VCO_DIV_5_MASK, ++ RK3328_PCLK_VCO_DIV_5(cfg->vco_div_5_en)); + inno_write(inno, 0xa1, RK3328_PRE_PLL_PRE_DIV(cfg->prediv)); + + val = RK3328_SPREAD_SPECTRUM_MOD_DISABLE; + +From 619967c6bc6f6c81a3dabf8b2d4c0f5f3b3afc78 Mon Sep 17 00:00:00 2001 +From: Zheng Yang +Date: Wed, 8 Jan 2020 21:07:48 +0000 +Subject: [PATCH] phy/rockchip: inno-hdmi: round fractal pixclock in rk3328 + recalc_rate + +inno_hdmi_phy_rk3328_clk_recalc_rate() is returning a rate not found +in the pre pll config table when the fractal divider is used. +This can prevent proper power_on because a tmdsclock for the new rate +is not found in the pre pll config table. + +Fix this by saving and returning a rounded pixel rate that exist +in the pre pll config table. + +Fixes: 53706a116863 ("phy: add Rockchip Innosilicon hdmi phy") +Signed-off-by: Zheng Yang +Signed-off-by: Jonas Karlman +--- + drivers/phy/rockchip/phy-rockchip-inno-hdmi.c | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +diff --git a/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c b/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c +index b0ac1d3ee390..093d2334e8cd 100644 +--- a/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c ++++ b/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c +@@ -745,10 +745,12 @@ unsigned long inno_hdmi_phy_rk3328_clk_recalc_rate(struct clk_hw *hw, + do_div(vco, (nd * (no_a == 1 ? no_b : no_a) * no_d * 2)); + } + +- inno->pixclock = vco; +- dev_dbg(inno->dev, "%s rate %lu\n", __func__, inno->pixclock); ++ inno->pixclock = DIV_ROUND_CLOSEST((unsigned long)vco, 1000) * 1000; + +- return vco; ++ dev_dbg(inno->dev, "%s rate %lu vco %llu\n", ++ __func__, inno->pixclock, vco); ++ ++ return inno->pixclock; + } + + static long inno_hdmi_phy_rk3328_clk_round_rate(struct clk_hw *hw, + +From 8fe477a61c44d9df65a1f3a7bd9a0d7b4be7760b Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Wed, 8 Jan 2020 21:07:48 +0000 +Subject: [PATCH] phy/rockchip: inno-hdmi: remove unused no_c from rk3328 + recalc_rate + +no_c is not used in any calculation, lets remove it. + +Signed-off-by: Jonas Karlman +--- + drivers/phy/rockchip/phy-rockchip-inno-hdmi.c | 5 +---- + 1 file changed, 1 insertion(+), 4 deletions(-) + +diff --git a/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c b/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c +index 093d2334e8cd..06db69c8373e 100644 +--- a/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c ++++ b/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c +@@ -714,7 +714,7 @@ unsigned long inno_hdmi_phy_rk3328_clk_recalc_rate(struct clk_hw *hw, + { + struct inno_hdmi_phy *inno = to_inno_hdmi_phy(hw); + unsigned long frac; +- u8 nd, no_a, no_b, no_c, no_d; ++ u8 nd, no_a, no_b, no_d; + u64 vco; + u16 nf; + +@@ -737,9 +737,6 @@ unsigned long inno_hdmi_phy_rk3328_clk_recalc_rate(struct clk_hw *hw, + no_b = inno_read(inno, 0xa5) & RK3328_PRE_PLL_PCLK_DIV_B_MASK; + no_b >>= RK3328_PRE_PLL_PCLK_DIV_B_SHIFT; + no_b += 2; +- no_c = inno_read(inno, 0xa6) & RK3328_PRE_PLL_PCLK_DIV_C_MASK; +- no_c >>= RK3328_PRE_PLL_PCLK_DIV_C_SHIFT; +- no_c = 1 << no_c; + no_d = inno_read(inno, 0xa6) & RK3328_PRE_PLL_PCLK_DIV_D_MASK; + + do_div(vco, (nd * (no_a == 1 ? no_b : no_a) * no_d * 2)); + +From 428d1129cfacf119ed86954e6b21c938510ef2b2 Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Wed, 8 Jan 2020 21:07:48 +0000 +Subject: [PATCH] phy/rockchip: inno-hdmi: do not power on rk3328 post pll on + reg write + +inno_write is used to configure 0xaa reg, that also hold the +POST_PLL_POWER_DOWN bit. +When POST_PLL_REFCLK_SEL_TMDS is configured the power down bit is not +taken into consideration. + +Fix this by keeping the power down bit until configuration is complete. +Also reorder the reg write order for consistency. + +Fixes: 53706a116863 ("phy: add Rockchip Innosilicon hdmi phy") +Signed-off-by: Jonas Karlman +--- + drivers/phy/rockchip/phy-rockchip-inno-hdmi.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c b/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c +index 06db69c8373e..3a59a6da0440 100644 +--- a/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c ++++ b/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c +@@ -1020,9 +1020,10 @@ inno_hdmi_phy_rk3328_power_on(struct inno_hdmi_phy *inno, + + inno_write(inno, 0xac, RK3328_POST_PLL_FB_DIV_7_0(cfg->fbdiv)); + if (cfg->postdiv == 1) { +- inno_write(inno, 0xaa, RK3328_POST_PLL_REFCLK_SEL_TMDS); + inno_write(inno, 0xab, RK3328_POST_PLL_FB_DIV_8(cfg->fbdiv) | + RK3328_POST_PLL_PRE_DIV(cfg->prediv)); ++ inno_write(inno, 0xaa, RK3328_POST_PLL_REFCLK_SEL_TMDS | ++ RK3328_POST_PLL_POWER_DOWN); + } else { + v = (cfg->postdiv / 2) - 1; + v &= RK3328_POST_PLL_POST_DIV_MASK; +@@ -1030,7 +1031,8 @@ inno_hdmi_phy_rk3328_power_on(struct inno_hdmi_phy *inno, + inno_write(inno, 0xab, RK3328_POST_PLL_FB_DIV_8(cfg->fbdiv) | + RK3328_POST_PLL_PRE_DIV(cfg->prediv)); + inno_write(inno, 0xaa, RK3328_POST_PLL_POST_DIV_ENABLE | +- RK3328_POST_PLL_REFCLK_SEL_TMDS); ++ RK3328_POST_PLL_REFCLK_SEL_TMDS | ++ RK3328_POST_PLL_POWER_DOWN); + } + + for (v = 0; v < 14; v++) + +From 335bf9964e953ca56351df1c35ed4249740f548d Mon Sep 17 00:00:00 2001 +From: Huicong Xu +Date: Wed, 8 Jan 2020 21:07:49 +0000 +Subject: [PATCH] phy/rockchip: inno-hdmi: force set_rate on power_on + +Regular 8-bit and Deep Color video formats mainly differ in TMDS rate and +not in pixel clock rate. +When the hdmiphy clock is configured with the same pixel clock rate using +clk_set_rate() the clock framework do not signal the hdmi phy driver +to set_rate when switching between 8-bit and Deep Color. +This result in pre/post pll not being re-configured when switching between +regular 8-bit and Deep Color video formats. + +Fix this by calling set_rate in power_on to force pre pll re-configuration. + +Signed-off-by: Huicong Xu +Signed-off-by: Jonas Karlman +--- + drivers/phy/rockchip/phy-rockchip-inno-hdmi.c | 13 +++++++++++++ + 1 file changed, 13 insertions(+) + +diff --git a/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c b/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c +index 3a59a6da0440..3719309ad0d0 100644 +--- a/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c ++++ b/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c +@@ -245,6 +245,7 @@ struct inno_hdmi_phy { + struct clk_hw hw; + struct clk *phyclk; + unsigned long pixclock; ++ unsigned long tmdsclock; + }; + + struct pre_pll_config { +@@ -485,6 +486,8 @@ static int inno_hdmi_phy_power_on(struct phy *phy) + + dev_dbg(inno->dev, "Inno HDMI PHY Power On\n"); + ++ inno->plat_data->clk_ops->set_rate(&inno->hw, inno->pixclock, 24000000); ++ + ret = clk_prepare_enable(inno->phyclk); + if (ret) + return ret; +@@ -509,6 +512,8 @@ static int inno_hdmi_phy_power_off(struct phy *phy) + + clk_disable_unprepare(inno->phyclk); + ++ inno->tmdsclock = 0; ++ + dev_dbg(inno->dev, "Inno HDMI PHY Power Off\n"); + + return 0; +@@ -628,6 +633,9 @@ static int inno_hdmi_phy_rk3228_clk_set_rate(struct clk_hw *hw, + dev_dbg(inno->dev, "%s rate %lu tmdsclk %lu\n", + __func__, rate, tmdsclock); + ++ if (inno->pixclock == rate && inno->tmdsclock == tmdsclock) ++ return 0; ++ + cfg = inno_hdmi_phy_get_pre_pll_cfg(inno, rate); + if (IS_ERR(cfg)) + return PTR_ERR(cfg); +@@ -670,6 +678,7 @@ static int inno_hdmi_phy_rk3228_clk_set_rate(struct clk_hw *hw, + } + + inno->pixclock = rate; ++ inno->tmdsclock = tmdsclock; + + return 0; + } +@@ -781,6 +790,9 @@ static int inno_hdmi_phy_rk3328_clk_set_rate(struct clk_hw *hw, + dev_dbg(inno->dev, "%s rate %lu tmdsclk %lu\n", + __func__, rate, tmdsclock); + ++ if (inno->pixclock == rate && inno->tmdsclock == tmdsclock) ++ return 0; ++ + cfg = inno_hdmi_phy_get_pre_pll_cfg(inno, rate); + if (IS_ERR(cfg)) + return PTR_ERR(cfg); +@@ -820,6 +832,7 @@ static int inno_hdmi_phy_rk3328_clk_set_rate(struct clk_hw *hw, + } + + inno->pixclock = rate; ++ inno->tmdsclock = tmdsclock; + + return 0; + } + +From b4a0c66750a98eea4b1ab65026cd46a4364512cb Mon Sep 17 00:00:00 2001 +From: Algea Cao +Date: Wed, 8 Jan 2020 21:07:53 +0000 +Subject: [PATCH] phy/rockchip: inno-hdmi: Support more pre-pll configuration + +Adding the following freq cfg in 8-bit and 10-bit color depth: + +{ + 40000000, 65000000, 71000000, 83500000, 85750000, + 88750000, 108000000, 119000000, 162000000 +} + +New freq has been validated by quantumdata 980. + +For some freq which can't be got by only using integer freq div, +frac freq div is needed, Such as 88.75Mhz 10-bit. But The actual +freq is different from the target freq, We must try to narrow +the gap between them. RK322X only support integer freq div. + +The VCO of pre-PLL must be more than 2Ghz, otherwise PLL may be +unlocked. + +Signed-off-by: Algea Cao +Signed-off-by: Jonas Karlman +Acked-by: Heiko Stuebner +--- + drivers/phy/rockchip/phy-rockchip-inno-hdmi.c | 74 ++++++++++++------- + 1 file changed, 49 insertions(+), 25 deletions(-) + +diff --git a/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c b/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c +index 3719309ad0d0..bb8bdf5e3301 100644 +--- a/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c ++++ b/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c +@@ -291,32 +291,56 @@ struct inno_hdmi_phy_drv_data { + const struct phy_config *phy_cfg_table; + }; + ++/* ++ * If only using integer freq div can't get frequency we want, frac ++ * freq div is needed. For example, pclk 88.75 Mhz and tmdsclk ++ * 110.9375 Mhz must use frac div 0xF00000. The actual frequency is different ++ * from the target frequency. Such as the tmds clock 110.9375 Mhz, ++ * the actual tmds clock we get is 110.93719 Mhz. It is important ++ * to note that RK322X platforms do not support frac div. ++ */ + static const struct pre_pll_config pre_pll_cfg_table[] = { +- { 27000000, 27000000, 1, 90, 3, 2, 2, 10, 3, 3, 4, 0, 0}, +- { 27000000, 33750000, 1, 90, 1, 3, 3, 10, 3, 3, 4, 0, 0}, +- { 40000000, 40000000, 1, 80, 2, 2, 2, 12, 2, 2, 2, 0, 0}, +- { 59341000, 59341000, 1, 98, 3, 1, 2, 1, 3, 3, 4, 0, 0xE6AE6B}, +- { 59400000, 59400000, 1, 99, 3, 1, 1, 1, 3, 3, 4, 0, 0}, +- { 59341000, 74176250, 1, 98, 0, 3, 3, 1, 3, 3, 4, 0, 0xE6AE6B}, +- { 59400000, 74250000, 1, 99, 1, 2, 2, 1, 3, 3, 4, 0, 0}, +- { 74176000, 74176000, 1, 98, 1, 2, 2, 1, 2, 3, 4, 0, 0xE6AE6B}, +- { 74250000, 74250000, 1, 99, 1, 2, 2, 1, 2, 3, 4, 0, 0}, +- { 74176000, 92720000, 4, 494, 1, 2, 2, 1, 3, 3, 4, 0, 0x816817}, +- { 74250000, 92812500, 4, 495, 1, 2, 2, 1, 3, 3, 4, 0, 0}, +- {148352000, 148352000, 1, 98, 1, 1, 1, 1, 2, 2, 2, 0, 0xE6AE6B}, +- {148500000, 148500000, 1, 99, 1, 1, 1, 1, 2, 2, 2, 0, 0}, +- {148352000, 185440000, 4, 494, 0, 2, 2, 1, 3, 2, 2, 0, 0x816817}, +- {148500000, 185625000, 4, 495, 0, 2, 2, 1, 3, 2, 2, 0, 0}, +- {296703000, 296703000, 1, 98, 0, 1, 1, 1, 0, 2, 2, 0, 0xE6AE6B}, +- {297000000, 297000000, 1, 99, 0, 1, 1, 1, 0, 2, 2, 0, 0}, +- {296703000, 370878750, 4, 494, 1, 2, 0, 1, 3, 1, 1, 0, 0x816817}, +- {297000000, 371250000, 4, 495, 1, 2, 0, 1, 3, 1, 1, 0, 0}, +- {593407000, 296703500, 1, 98, 0, 1, 1, 1, 0, 2, 1, 0, 0xE6AE6B}, +- {594000000, 297000000, 1, 99, 0, 1, 1, 1, 0, 2, 1, 0, 0}, +- {593407000, 370879375, 4, 494, 1, 2, 0, 1, 3, 1, 1, 1, 0x816817}, +- {594000000, 371250000, 4, 495, 1, 2, 0, 1, 3, 1, 1, 1, 0}, +- {593407000, 593407000, 1, 98, 0, 2, 0, 1, 0, 1, 1, 0, 0xE6AE6B}, +- {594000000, 594000000, 1, 99, 0, 2, 0, 1, 0, 1, 1, 0, 0}, ++ { 27000000, 27000000, 1, 90, 3, 2, 2, 10, 3, 3, 4, 0, 0}, ++ { 27000000, 33750000, 1, 90, 1, 3, 3, 10, 3, 3, 4, 0, 0}, ++ { 40000000, 40000000, 1, 80, 2, 2, 2, 12, 2, 2, 2, 0, 0}, ++ { 40000000, 50000000, 1, 100, 2, 2, 2, 1, 0, 0, 15, 0, 0}, ++ { 59341000, 59341000, 1, 98, 3, 1, 2, 1, 3, 3, 4, 0, 0xE6AE6B}, ++ { 59400000, 59400000, 1, 99, 3, 1, 1, 1, 3, 3, 4, 0, 0}, ++ { 59341000, 74176250, 1, 98, 0, 3, 3, 1, 3, 3, 4, 0, 0xE6AE6B}, ++ { 59400000, 74250000, 1, 99, 1, 2, 2, 1, 3, 3, 4, 0, 0}, ++ { 65000000, 65000000, 1, 130, 2, 2, 2, 1, 0, 0, 12, 0, 0}, ++ { 65000000, 81250000, 3, 325, 0, 3, 3, 1, 0, 0, 10, 0, 0}, ++ { 71000000, 71000000, 3, 284, 0, 3, 3, 1, 0, 0, 8, 0, 0}, ++ { 71000000, 88750000, 3, 355, 0, 3, 3, 1, 0, 0, 10, 0, 0}, ++ { 74176000, 74176000, 1, 98, 1, 2, 2, 1, 2, 3, 4, 0, 0xE6AE6B}, ++ { 74250000, 74250000, 1, 99, 1, 2, 2, 1, 2, 3, 4, 0, 0}, ++ { 74176000, 92720000, 4, 494, 1, 2, 2, 1, 3, 3, 4, 0, 0x816817}, ++ { 74250000, 92812500, 4, 495, 1, 2, 2, 1, 3, 3, 4, 0, 0}, ++ { 83500000, 83500000, 2, 167, 2, 1, 1, 1, 0, 0, 6, 0, 0}, ++ { 83500000, 104375000, 1, 104, 2, 1, 1, 1, 1, 0, 5, 0, 0x600000}, ++ { 85750000, 85750000, 3, 343, 0, 3, 3, 1, 0, 0, 8, 0, 0}, ++ { 88750000, 88750000, 3, 355, 0, 3, 3, 1, 0, 0, 8, 0, 0}, ++ { 88750000, 110937500, 1, 110, 2, 1, 1, 1, 1, 0, 5, 0, 0xF00000}, ++ {108000000, 108000000, 1, 90, 3, 0, 0, 1, 0, 0, 5, 0, 0}, ++ {108000000, 135000000, 1, 90, 0, 2, 2, 1, 0, 0, 5, 0, 0}, ++ {119000000, 119000000, 1, 119, 2, 1, 1, 1, 0, 0, 6, 0, 0}, ++ {119000000, 148750000, 1, 99, 0, 2, 2, 1, 0, 0, 5, 0, 0x2AAAAA}, ++ {148352000, 148352000, 1, 98, 1, 1, 1, 1, 2, 2, 2, 0, 0xE6AE6B}, ++ {148500000, 148500000, 1, 99, 1, 1, 1, 1, 2, 2, 2, 0, 0}, ++ {148352000, 185440000, 4, 494, 0, 2, 2, 1, 3, 2, 2, 0, 0x816817}, ++ {148500000, 185625000, 4, 495, 0, 2, 2, 1, 3, 2, 2, 0, 0}, ++ {162000000, 162000000, 1, 108, 0, 2, 2, 1, 0, 0, 4, 0, 0}, ++ {162000000, 202500000, 1, 135, 0, 2, 2, 1, 0, 0, 5, 0, 0}, ++ {296703000, 296703000, 1, 98, 0, 1, 1, 1, 0, 2, 2, 0, 0xE6AE6B}, ++ {297000000, 297000000, 1, 99, 0, 1, 1, 1, 0, 2, 2, 0, 0}, ++ {296703000, 370878750, 4, 494, 1, 2, 0, 1, 3, 1, 1, 0, 0x816817}, ++ {297000000, 371250000, 4, 495, 1, 2, 0, 1, 3, 1, 1, 0, 0}, ++ {593407000, 296703500, 1, 98, 0, 1, 1, 1, 0, 2, 1, 0, 0xE6AE6B}, ++ {594000000, 297000000, 1, 99, 0, 1, 1, 1, 0, 2, 1, 0, 0}, ++ {593407000, 370879375, 4, 494, 1, 2, 0, 1, 3, 1, 1, 1, 0x816817}, ++ {594000000, 371250000, 4, 495, 1, 2, 0, 1, 3, 1, 1, 1, 0}, ++ {593407000, 593407000, 1, 98, 0, 2, 0, 1, 0, 1, 1, 0, 0xE6AE6B}, ++ {594000000, 594000000, 1, 99, 0, 2, 0, 1, 0, 1, 1, 0, 0}, + { /* sentinel */ } + }; + + +From ddc63db13e520a56bf1afbe6c5ebd3d9935f282f Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Sun, 3 May 2020 16:51:31 +0000 +Subject: [PATCH] drm/rockchip: vop: filter modes outside 0.5% pixel clock + tolerance + +Signed-off-by: Jonas Karlman +--- + drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 33 +++++++++++++++++++++ + 1 file changed, 33 insertions(+) + +diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +index c80f7d9fd13f..6cbdb4672a4b 100644 +--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c ++++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +@@ -1142,6 +1142,38 @@ static void vop_crtc_disable_vblank(struct drm_crtc *crtc) + spin_unlock_irqrestore(&vop->irq_lock, flags); + } + ++/* ++ * The VESA DMT standard specifies a 0.5% pixel clock frequency tolerance. ++ * The CVT spec reuses that tolerance in its examples. ++ */ ++#define CLOCK_TOLERANCE_PER_MILLE 5 ++ ++static enum drm_mode_status vop_crtc_mode_valid(struct drm_crtc *crtc, ++ const struct drm_display_mode *mode) ++{ ++ struct vop *vop = to_vop(crtc); ++ struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc->state); ++ long rounded_rate; ++ long lowest, highest; ++ ++ if (s->output_type != DRM_MODE_CONNECTOR_HDMIA) ++ return MODE_OK; ++ ++ rounded_rate = clk_round_rate(vop->dclk, mode->clock * 1000 + 999); ++ if (rounded_rate < 0) ++ return MODE_NOCLOCK; ++ ++ lowest = mode->clock * (1000 - CLOCK_TOLERANCE_PER_MILLE); ++ if (rounded_rate < lowest) ++ return MODE_CLOCK_LOW; ++ ++ highest = mode->clock * (1000 + CLOCK_TOLERANCE_PER_MILLE); ++ if (rounded_rate > highest) ++ return MODE_CLOCK_HIGH; ++ ++ return MODE_OK; ++} ++ + static bool vop_crtc_mode_fixup(struct drm_crtc *crtc, + const struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +@@ -1512,6 +1544,7 @@ static void vop_crtc_atomic_flush(struct drm_crtc *crtc, + } + + static const struct drm_crtc_helper_funcs vop_crtc_helper_funcs = { ++ .mode_valid = vop_crtc_mode_valid, + .mode_fixup = vop_crtc_mode_fixup, + .atomic_check = vop_crtc_atomic_check, + .atomic_begin = vop_crtc_atomic_begin, + +From 204bb448d3adbe5597d94ddf15ab7fa927931685 Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Mon, 20 Jul 2020 11:46:16 +0000 +Subject: [PATCH] WIP: drm/rockchip: vop: max_output + +--- + drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 5 +++++ + drivers/gpu/drm/rockchip/rockchip_drm_vop.h | 6 ++++++ + drivers/gpu/drm/rockchip/rockchip_vop_reg.c | 7 +++++++ + 3 files changed, 18 insertions(+) + +diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +index 6cbdb4672a4b..106b38ea12df 100644 +--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c ++++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +@@ -1152,6 +1152,7 @@ static enum drm_mode_status vop_crtc_mode_valid(struct drm_crtc *crtc, + const struct drm_display_mode *mode) + { + struct vop *vop = to_vop(crtc); ++ const struct vop_rect *max_output = &vop->data->max_output; + struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc->state); + long rounded_rate; + long lowest, highest; +@@ -1171,6 +1172,10 @@ static enum drm_mode_status vop_crtc_mode_valid(struct drm_crtc *crtc, + if (rounded_rate > highest) + return MODE_CLOCK_HIGH; + ++ if (max_output->width && max_output->height) ++ return drm_mode_validate_size(mode, max_output->width, ++ max_output->height); ++ + return MODE_OK; + } + +diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h +index 4a2099cb582e..1516231bbf93 100644 +--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h ++++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h +@@ -185,6 +185,11 @@ struct vop_win_data { + enum drm_plane_type type; + }; + ++struct vop_rect { ++ int width; ++ int height; ++}; ++ + struct vop_data { + uint32_t version; + const struct vop_intr *intr; +@@ -197,6 +202,7 @@ struct vop_data { + const struct vop_win_data *win; + unsigned int win_size; + unsigned int lut_size; ++ struct vop_rect max_output; + + #define VOP_FEATURE_OUTPUT_RGB10 BIT(0) + #define VOP_FEATURE_INTERNAL_RGB BIT(1) +diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c +index 80053d91a301..57c36e9207c1 100644 +--- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c ++++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c +@@ -682,6 +682,7 @@ static const struct vop_intr rk3288_vop_intr = { + static const struct vop_data rk3288_vop = { + .version = VOP_VERSION(3, 1), + .feature = VOP_FEATURE_OUTPUT_RGB10, ++ .max_output = { 3840, 2160 }, + .intr = &rk3288_vop_intr, + .common = &rk3288_common, + .modeset = &rk3288_modeset, +@@ -782,6 +783,7 @@ static const struct vop_misc rk3368_misc = { + + static const struct vop_data rk3368_vop = { + .version = VOP_VERSION(3, 2), ++ .max_output = { 4096, 2160 }, + .intr = &rk3368_vop_intr, + .common = &rk3288_common, + .modeset = &rk3288_modeset, +@@ -803,6 +805,7 @@ static const struct vop_intr rk3366_vop_intr = { + + static const struct vop_data rk3366_vop = { + .version = VOP_VERSION(3, 4), ++ .max_output = { 4096, 2160 }, + .intr = &rk3366_vop_intr, + .common = &rk3288_common, + .modeset = &rk3288_modeset, +@@ -909,6 +912,7 @@ static const struct vop_afbc rk3399_vop_afbc = { + static const struct vop_data rk3399_vop_big = { + .version = VOP_VERSION(3, 5), + .feature = VOP_FEATURE_OUTPUT_RGB10, ++ .max_output = { 4096, 2160 }, + .intr = &rk3366_vop_intr, + .common = &rk3288_common, + .modeset = &rk3288_modeset, +@@ -935,6 +939,7 @@ static const struct vop_win_yuv2yuv_data rk3399_vop_lit_win_yuv2yuv_data[] = { + + static const struct vop_data rk3399_vop_lit = { + .version = VOP_VERSION(3, 6), ++ .max_output = { 2560, 1600 }, + .intr = &rk3366_vop_intr, + .common = &rk3288_common, + .modeset = &rk3288_modeset, +@@ -955,6 +960,7 @@ static const struct vop_win_data rk3228_vop_win_data[] = { + static const struct vop_data rk3228_vop = { + .version = VOP_VERSION(3, 7), + .feature = VOP_FEATURE_OUTPUT_RGB10, ++ .max_output = { 4096, 2160 }, + .intr = &rk3366_vop_intr, + .common = &rk3288_common, + .modeset = &rk3288_modeset, +@@ -1026,6 +1032,7 @@ static const struct vop_win_data rk3328_vop_win_data[] = { + static const struct vop_data rk3328_vop = { + .version = VOP_VERSION(3, 8), + .feature = VOP_FEATURE_OUTPUT_RGB10, ++ .max_output = { 4096, 2160 }, + .intr = &rk3328_vop_intr, + .common = &rk3328_common, + .modeset = &rk3328_modeset, + +From 77dae737d6b7ab099707e746311bf683729b662b Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Wed, 8 Jan 2020 21:07:51 +0000 +Subject: [PATCH] arm64: dts: rockchip: increase vop clock rate on rk3328 + +The VOP on RK3328 needs to run at higher rate in order to +produce a proper 3840x2160 signal. + +Signed-off-by: Jonas Karlman +--- + arch/arm64/boot/dts/rockchip/rk3328.dtsi | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/arch/arm64/boot/dts/rockchip/rk3328.dtsi b/arch/arm64/boot/dts/rockchip/rk3328.dtsi +index bbdb19a3e85d..6547e2b4b617 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3328.dtsi ++++ b/arch/arm64/boot/dts/rockchip/rk3328.dtsi +@@ -802,8 +802,8 @@ cru: clock-controller@ff440000 { + <0>, <24000000>, + <24000000>, <24000000>, + <15000000>, <15000000>, +- <100000000>, <100000000>, +- <100000000>, <100000000>, ++ <300000000>, <100000000>, ++ <400000000>, <100000000>, + <50000000>, <100000000>, + <100000000>, <100000000>, + <50000000>, <50000000>, + +From 8312c58922e497f6d26c0845597bd23dbeba95d7 Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Wed, 8 Jan 2020 21:07:49 +0000 +Subject: [PATCH] drm/rockchip: dw-hdmi: allow high tmds bit rates + +Prepare support for High TMDS Bit Rates used by HDMI2.0 display modes. + +Signed-off-by: Jonas Karlman +--- + drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +index 23de359a1dec..cdf953850873 100644 +--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c ++++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +@@ -317,6 +317,8 @@ static int dw_hdmi_rockchip_genphy_init(struct dw_hdmi *dw_hdmi, void *data, + { + struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data; + ++ dw_hdmi_set_high_tmds_clock_ratio(dw_hdmi, display); ++ + return phy_power_on(hdmi->phy); + } + + +From 1638ed24fb959926267f59a590e61b04c1050b96 Mon Sep 17 00:00:00 2001 +From: Yakir Yang +Date: Mon, 11 Jul 2016 19:05:39 +0800 +Subject: [PATCH] drm/rockchip: dw_hdmi: adjust cklvl & txlvl for RF/EMI + +Dut to the high HDMI signal voltage driver, Mickey have meet +a serious RF/EMI problem, so we decided to reduce HDMI signal +voltage to a proper value. + +The default params for phy is cklvl = 20 & txlvl = 13 (RF/EMI failed) + ck: lvl = 13, term=100, vlo = 2.71, vhi=3.14, vswing = 0.43 + tx: lvl = 20, term=100, vlo = 2.81, vhi=3.16, vswing = 0.35 + +1. We decided to reduce voltage value to lower, but VSwing still +keep high, RF/EMI have been improved but still failed. + ck: lvl = 6, term=100, vlo = 2.61, vhi=3.11, vswing = 0.50 + tx: lvl = 6, term=100, vlo = 2.61, vhi=3.11, vswing = 0.50 + +2. We try to keep voltage value and vswing both lower, then RF/EMI +test all passed ;) + ck: lvl = 11, term= 66, vlo = 2.68, vhi=3.09, vswing = 0.40 + tx: lvl = 11, term= 66, vlo = 2.68, vhi=3.09, vswing = 0.40 +When we back to run HDMI different test and single-end test, we see +different test passed, but signle-end test failed. The oscilloscope +show that simgle-end clock's VL value is 1.78v (which remind LowLimit +should not lower then 2.6v). + +3. That's to say there are some different between PHY document and +measure value. And according to experiment 2 results, we need to +higher clock voltage and lower data voltage, then we can keep RF/EMI +satisfied and single-end & differen test passed. + ck: lvl = 9, term=100, vlo = 2.65, vhi=3.12, vswing = 0.47 + tx: lvl = 16, term=100, vlo = 2.75, vhi=3.15, vswing = 0.39 + +Signed-off-by: Yakir Yang +Signed-off-by: Jonas Karlman +--- + drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +index cdf953850873..4652c0e0dcd6 100644 +--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c ++++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +@@ -181,7 +181,7 @@ static const struct dw_hdmi_curr_ctrl rockchip_cur_ctr[] = { + static const struct dw_hdmi_phy_config rockchip_phy_config[] = { + /*pixelclk symbol term vlev*/ + { 74250000, 0x8009, 0x0004, 0x0272}, +- { 148500000, 0x802b, 0x0004, 0x028d}, ++ { 165000000, 0x802b, 0x0004, 0x0209}, + { 297000000, 0x8039, 0x0005, 0x028d}, + { ~0UL, 0x0000, 0x0000, 0x0000} + }; + +From f60a4b188ee2e3bfcc44dd8d1fa3b5fa19f90720 Mon Sep 17 00:00:00 2001 +From: Nickey Yang +Date: Mon, 13 Feb 2017 15:40:29 +0800 +Subject: [PATCH] drm/rockchip: dw_hdmi: add phy_config for 594Mhz pixel clock + +Add phy_config for 594Mhz pixel clock used for 4K@60hz + +Signed-off-by: Nickey Yang +Signed-off-by: Jonas Karlman +--- + drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +index 4652c0e0dcd6..10c3dc521cbd 100644 +--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c ++++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +@@ -183,6 +183,7 @@ static const struct dw_hdmi_phy_config rockchip_phy_config[] = { + { 74250000, 0x8009, 0x0004, 0x0272}, + { 165000000, 0x802b, 0x0004, 0x0209}, + { 297000000, 0x8039, 0x0005, 0x028d}, ++ { 594000000, 0x8039, 0x0000, 0x019d}, + { ~0UL, 0x0000, 0x0000, 0x0000} + }; + + +From 6835093bddcc3634ba0ebd98deb72ab59d916f9c Mon Sep 17 00:00:00 2001 +From: Douglas Anderson +Date: Mon, 11 Jul 2016 19:05:36 +0800 +Subject: [PATCH] drm/rockchip: dw_hdmi: Set cur_ctr to 0 always + +Jitter was improved by lowering the MPLL bandwidth to account for high +frequency noise in the rk3288 PLL. In each case MPLL bandwidth was +lowered only enough to get us a comfortable margin. We believe that +lowering the bandwidth like this is safe given sufficient testing. + +Signed-off-by: Douglas Anderson +Signed-off-by: Yakir Yang +Signed-off-by: Jonas Karlman +--- + drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 16 ++-------------- + 1 file changed, 2 insertions(+), 14 deletions(-) + +diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +index 10c3dc521cbd..cc7675638e4f 100644 +--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c ++++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +@@ -160,20 +160,8 @@ static const struct dw_hdmi_mpll_config rockchip_mpll_cfg[] = { + static const struct dw_hdmi_curr_ctrl rockchip_cur_ctr[] = { + /* pixelclk bpp8 bpp10 bpp12 */ + { +- 40000000, { 0x0018, 0x0018, 0x0018 }, +- }, { +- 65000000, { 0x0028, 0x0028, 0x0028 }, +- }, { +- 66000000, { 0x0038, 0x0038, 0x0038 }, +- }, { +- 74250000, { 0x0028, 0x0038, 0x0038 }, +- }, { +- 83500000, { 0x0028, 0x0038, 0x0038 }, +- }, { +- 146250000, { 0x0038, 0x0038, 0x0038 }, +- }, { +- 148500000, { 0x0000, 0x0038, 0x0038 }, +- }, { ++ 600000000, { 0x0000, 0x0000, 0x0000 }, ++ }, { + ~0UL, { 0x0000, 0x0000, 0x0000}, + } + }; + +From da024b1ee785c2443d32a955321dbae7e5b280d3 Mon Sep 17 00:00:00 2001 +From: Douglas Anderson +Date: Mon, 11 Jul 2016 19:05:42 +0800 +Subject: [PATCH] drm/rockchip: dw_hdmi: Use auto-generated tables + +The previous tables for mpll_cfg and curr_ctrl were created using the +20-pages of example settings provided by the PHY vendor. Those +example settings weren't particularly dense, so there were places +where we were guessing what the settings would be for 10-bit and +12-bit (not that we use those anyway). It was also always a lot of +extra work every time we wanted to add a new clock rate since we had +to cross-reference several tables. + +In I've gone through the work to figure +out how to generate this table automatically. Let's now use the +automatically generated table and then we'll never need to look at it +again. + +We only support 8-bit mode right now and only support a small number +of clock rates and and I've verified that the only 8-bit rate that was +affected was 148.5. That mode appears to have been wrong in the old +table. + +Signed-off-by: Douglas Anderson +Signed-off-by: Yakir Yang +Signed-off-by: Jonas Karlman +--- + drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 130 +++++++++++--------- + 1 file changed, 69 insertions(+), 61 deletions(-) + +diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +index cc7675638e4f..c4c158106ca4 100644 +--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c ++++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +@@ -79,80 +79,88 @@ struct rockchip_hdmi { + + static const struct dw_hdmi_mpll_config rockchip_mpll_cfg[] = { + { +- 27000000, { +- { 0x00b3, 0x0000}, +- { 0x2153, 0x0000}, +- { 0x40f3, 0x0000} ++ 30666000, { ++ { 0x00b3, 0x0000 }, ++ { 0x2153, 0x0000 }, ++ { 0x40f3, 0x0000 }, + }, +- }, { +- 36000000, { +- { 0x00b3, 0x0000}, +- { 0x2153, 0x0000}, +- { 0x40f3, 0x0000} ++ }, { ++ 36800000, { ++ { 0x00b3, 0x0000 }, ++ { 0x2153, 0x0000 }, ++ { 0x40a2, 0x0001 }, + }, +- }, { +- 40000000, { +- { 0x00b3, 0x0000}, +- { 0x2153, 0x0000}, +- { 0x40f3, 0x0000} ++ }, { ++ 46000000, { ++ { 0x00b3, 0x0000 }, ++ { 0x2142, 0x0001 }, ++ { 0x40a2, 0x0001 }, + }, +- }, { +- 54000000, { +- { 0x0072, 0x0001}, +- { 0x2142, 0x0001}, +- { 0x40a2, 0x0001}, ++ }, { ++ 61333000, { ++ { 0x0072, 0x0001 }, ++ { 0x2142, 0x0001 }, ++ { 0x40a2, 0x0001 }, + }, +- }, { +- 65000000, { +- { 0x0072, 0x0001}, +- { 0x2142, 0x0001}, +- { 0x40a2, 0x0001}, ++ }, { ++ 73600000, { ++ { 0x0072, 0x0001 }, ++ { 0x2142, 0x0001 }, ++ { 0x4061, 0x0002 }, + }, +- }, { +- 66000000, { +- { 0x013e, 0x0003}, +- { 0x217e, 0x0002}, +- { 0x4061, 0x0002} ++ }, { ++ 92000000, { ++ { 0x0072, 0x0001 }, ++ { 0x2145, 0x0002 }, ++ { 0x4061, 0x0002 }, ++ }, ++ }, { ++ 122666000, { ++ { 0x0051, 0x0002 }, ++ { 0x2145, 0x0002 }, ++ { 0x4061, 0x0002 }, + }, +- }, { +- 74250000, { +- { 0x0072, 0x0001}, +- { 0x2145, 0x0002}, +- { 0x4061, 0x0002} ++ }, { ++ 147200000, { ++ { 0x0051, 0x0002 }, ++ { 0x2145, 0x0002 }, ++ { 0x4064, 0x0003 }, + }, +- }, { +- 83500000, { +- { 0x0072, 0x0001}, ++ }, { ++ 184000000, { ++ { 0x0051, 0x0002 }, ++ { 0x214c, 0x0003 }, ++ { 0x4064, 0x0003 }, + }, +- }, { +- 108000000, { +- { 0x0051, 0x0002}, +- { 0x2145, 0x0002}, +- { 0x4061, 0x0002} ++ }, { ++ 226666000, { ++ { 0x0040, 0x0003 }, ++ { 0x214c, 0x0003 }, ++ { 0x4064, 0x0003 }, + }, +- }, { +- 106500000, { +- { 0x0051, 0x0002}, +- { 0x2145, 0x0002}, +- { 0x4061, 0x0002} ++ }, { ++ 272000000, { ++ { 0x0040, 0x0003 }, ++ { 0x214c, 0x0003 }, ++ { 0x5a64, 0x0003 }, + }, +- }, { +- 146250000, { +- { 0x0051, 0x0002}, +- { 0x2145, 0x0002}, +- { 0x4061, 0x0002} ++ }, { ++ 340000000, { ++ { 0x0040, 0x0003 }, ++ { 0x3b4c, 0x0003 }, ++ { 0x5a64, 0x0003 }, + }, +- }, { +- 148500000, { +- { 0x0051, 0x0003}, +- { 0x214c, 0x0003}, +- { 0x4064, 0x0003} ++ }, { ++ 600000000, { ++ { 0x1a40, 0x0003 }, ++ { 0x3b4c, 0x0003 }, ++ { 0x5a64, 0x0003 }, + }, +- }, { ++ }, { + ~0UL, { +- { 0x00a0, 0x000a }, +- { 0x2001, 0x000f }, +- { 0x4002, 0x000f }, ++ { 0x0000, 0x0000 }, ++ { 0x0000, 0x0000 }, ++ { 0x0000, 0x0000 }, + }, + } + }; + +From 45e1a78887ebd640f8518afc1cfd5b2f2beb3ba4 Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Wed, 8 Jan 2020 21:07:52 +0000 +Subject: [PATCH] drm/rockchip: dw-hdmi: limit tmds to 340mhz + +RK3228/RK3328 does not provide a stable hdmi signal at TMDS rates +above 371.25MHz (340MHz pixel clock). + +Limit the pixel clock rate to 340MHz to provide a stable signal. +Also limit the pixel clock to the display reported max tmds clock. + +This also enables use of pixel clocks up to 340MHz on RK3288/RK3399. + +Signed-off-by: Jonas Karlman +--- + drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 16 ++++------------ + 1 file changed, 4 insertions(+), 12 deletions(-) + +diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +index c4c158106ca4..b62d8f4fc9a8 100644 +--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c ++++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +@@ -221,19 +221,11 @@ dw_hdmi_rockchip_mode_valid(struct dw_hdmi *hdmi, void *data, + const struct drm_display_info *info, + const struct drm_display_mode *mode) + { +- const struct dw_hdmi_mpll_config *mpll_cfg = rockchip_mpll_cfg; +- int pclk = mode->clock * 1000; +- bool valid = false; +- int i; +- +- for (i = 0; mpll_cfg[i].mpixelclock != (~0UL); i++) { +- if (pclk == mpll_cfg[i].mpixelclock) { +- valid = true; +- break; +- } +- } ++ if (mode->clock > 340000 || ++ (info->max_tmds_clock && mode->clock > info->max_tmds_clock)) ++ return MODE_CLOCK_HIGH; + +- return (valid) ? MODE_OK : MODE_BAD; ++ return MODE_OK; + } + + static void dw_hdmi_rockchip_encoder_disable(struct drm_encoder *encoder) + +From 13fdba7d97013c909f5574dea1d006ae8380de82 Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Sun, 3 May 2020 22:36:23 +0000 +Subject: [PATCH] drm/rockchip: dw-hdmi: limit resolution to 3840x2160 + +Signed-off-by: Jonas Karlman +--- + drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +index b62d8f4fc9a8..6f7641fbe6cc 100644 +--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c ++++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +@@ -225,7 +225,7 @@ dw_hdmi_rockchip_mode_valid(struct dw_hdmi *hdmi, void *data, + (info->max_tmds_clock && mode->clock > info->max_tmds_clock)) + return MODE_CLOCK_HIGH; + +- return MODE_OK; ++ return drm_mode_validate_size(mode, 3840, 2160); + } + + static void dw_hdmi_rockchip_encoder_disable(struct drm_encoder *encoder) + +From af4d3cc6fbed0adca1b20bf25929b37c980c8b96 Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Wed, 8 Jan 2020 21:07:52 +0000 +Subject: [PATCH] drm/rockchip: dw-hdmi: remove unused plat_data on + rk3228/rk3328 + +mpll_cfg/cur_ctr/phy_config is not used when phy_force_vendor is true, +lets remove them. + +Signed-off-by: Jonas Karlman +--- + drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 6 ------ + 1 file changed, 6 deletions(-) + +diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +index 6f7641fbe6cc..cc20a83fa9b8 100644 +--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c ++++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +@@ -396,9 +396,6 @@ static struct rockchip_hdmi_chip_data rk3228_chip_data = { + + static const struct dw_hdmi_plat_data rk3228_hdmi_drv_data = { + .mode_valid = dw_hdmi_rockchip_mode_valid, +- .mpll_cfg = rockchip_mpll_cfg, +- .cur_ctr = rockchip_cur_ctr, +- .phy_config = rockchip_phy_config, + .phy_data = &rk3228_chip_data, + .phy_ops = &rk3228_hdmi_phy_ops, + .phy_name = "inno_dw_hdmi_phy2", +@@ -433,9 +430,6 @@ static struct rockchip_hdmi_chip_data rk3328_chip_data = { + + static const struct dw_hdmi_plat_data rk3328_hdmi_drv_data = { + .mode_valid = dw_hdmi_rockchip_mode_valid, +- .mpll_cfg = rockchip_mpll_cfg, +- .cur_ctr = rockchip_cur_ctr, +- .phy_config = rockchip_phy_config, + .phy_data = &rk3328_chip_data, + .phy_ops = &rk3328_hdmi_phy_ops, + .phy_name = "inno_dw_hdmi_phy2", + +From 8b696168a0ff4acd7b1add7ea689a51f9259f294 Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Wed, 8 Jan 2020 21:07:50 +0000 +Subject: [PATCH] clk: rockchip: set parent rate for DCLK_VOP clock on rk3228 + +Signed-off-by: Jonas Karlman +--- + drivers/clk/rockchip/clk-rk3228.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/clk/rockchip/clk-rk3228.c b/drivers/clk/rockchip/clk-rk3228.c +index d7243c09cc84..dd414c8255e3 100644 +--- a/drivers/clk/rockchip/clk-rk3228.c ++++ b/drivers/clk/rockchip/clk-rk3228.c +@@ -408,7 +408,7 @@ static struct rockchip_clk_branch rk3228_clk_branches[] __initdata = { + RK2928_CLKSEL_CON(29), 0, 3, DFLAGS), + DIV(0, "sclk_vop_pre", "sclk_vop_src", 0, + RK2928_CLKSEL_CON(27), 8, 8, DFLAGS), +- MUX(DCLK_VOP, "dclk_vop", mux_dclk_vop_p, 0, ++ MUX(DCLK_VOP, "dclk_vop", mux_dclk_vop_p, CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT, + RK2928_CLKSEL_CON(27), 1, 1, MFLAGS), + + FACTOR(0, "xin12m", "xin24m", 0, 1, 2), + +From 41fdeaa849dcebfd9a9c9e5d3d48fc146dc1e789 Mon Sep 17 00:00:00 2001 +From: Nickey Yang +Date: Mon, 17 Jul 2017 16:35:34 +0800 +Subject: [PATCH] HACK: clk: rockchip: rk3288: dedicate npll for vopb and hdmi + use + +MINIARM: set npll be used for hdmi only + +Signed-off-by: Nickey Yang +Signed-off-by: Jonas Karlman +--- + arch/arm/boot/dts/rk3288.dtsi | 2 ++ + drivers/clk/rockchip/clk-rk3288.c | 4 ++-- + 2 files changed, 4 insertions(+), 2 deletions(-) + +diff --git a/arch/arm/boot/dts/rk3288.dtsi b/arch/arm/boot/dts/rk3288.dtsi +index 68d5a58cfe88..a376dea3bb1b 100644 +--- a/arch/arm/boot/dts/rk3288.dtsi ++++ b/arch/arm/boot/dts/rk3288.dtsi +@@ -1046,6 +1046,8 @@ vopb: vop@ff930000 { + resets = <&cru SRST_LCDC0_AXI>, <&cru SRST_LCDC0_AHB>, <&cru SRST_LCDC0_DCLK>; + reset-names = "axi", "ahb", "dclk"; + iommus = <&vopb_mmu>; ++ assigned-clocks = <&cru DCLK_VOP0>; ++ assigned-clock-parents = <&cru PLL_NPLL>; + status = "disabled"; + + vopb_out: port { +diff --git a/drivers/clk/rockchip/clk-rk3288.c b/drivers/clk/rockchip/clk-rk3288.c +index 93c794695c46..db6c8bbb35f4 100644 +--- a/drivers/clk/rockchip/clk-rk3288.c ++++ b/drivers/clk/rockchip/clk-rk3288.c +@@ -231,7 +231,7 @@ static struct rockchip_pll_clock rk3288_pll_clks[] __initdata = { + [gpll] = PLL(pll_rk3066, PLL_GPLL, "gpll", mux_pll_p, 0, RK3288_PLL_CON(12), + RK3288_MODE_CON, 12, 8, ROCKCHIP_PLL_SYNC_RATE, rk3288_pll_rates), + [npll] = PLL(pll_rk3066, PLL_NPLL, "npll", mux_pll_p, 0, RK3288_PLL_CON(16), +- RK3288_MODE_CON, 14, 9, ROCKCHIP_PLL_SYNC_RATE, rk3288_pll_rates), ++ RK3288_MODE_CON, 14, 9, 0, rk3288_pll_rates), + }; + + static struct clk_div_table div_hclk_cpu_t[] = { +@@ -441,7 +441,7 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = { + RK3288_CLKSEL_CON(30), 14, 2, MFLAGS, 8, 5, DFLAGS, + RK3288_CLKGATE_CON(3), 4, GFLAGS), + +- COMPOSITE(DCLK_VOP0, "dclk_vop0", mux_pll_src_cpll_gpll_npll_p, 0, ++ COMPOSITE(DCLK_VOP0, "dclk_vop0", mux_pll_src_cpll_gpll_npll_p, CLK_SET_RATE_NO_REPARENT | CLK_SET_RATE_PARENT, + RK3288_CLKSEL_CON(27), 0, 2, MFLAGS, 8, 8, DFLAGS, + RK3288_CLKGATE_CON(3), 1, GFLAGS), + COMPOSITE(DCLK_VOP1, "dclk_vop1", mux_pll_src_cpll_gpll_npll_p, 0, + +From 0a33b20a1a890158d704b8a2cc759036952a09e2 Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Sat, 4 Aug 2018 14:51:14 +0200 +Subject: [PATCH] HACK: clk: rockchip: rk3288: use npll table to to improve + HDMI compatibility + +Based on https://github.com/TinkerBoard/debian_kernel/commit/3d90870530b8a2901681f7b7fa598ee7381e49f3 + +Signed-off-by: Jonas Karlman +--- + drivers/clk/rockchip/clk-rk3288.c | 23 ++++++++++++++++++++++- + 1 file changed, 22 insertions(+), 1 deletion(-) + +diff --git a/drivers/clk/rockchip/clk-rk3288.c b/drivers/clk/rockchip/clk-rk3288.c +index db6c8bbb35f4..426309f5dd44 100644 +--- a/drivers/clk/rockchip/clk-rk3288.c ++++ b/drivers/clk/rockchip/clk-rk3288.c +@@ -121,6 +121,27 @@ static struct rockchip_pll_rate_table rk3288_pll_rates[] = { + { /* sentinel */ }, + }; + ++static struct rockchip_pll_rate_table rk3288_npll_rates[] = { ++ RK3066_PLL_RATE_NB(594000000, 1, 99, 4, 32), ++ RK3066_PLL_RATE_NB(585000000, 6, 585, 4, 32), ++ RK3066_PLL_RATE_NB(432000000, 3, 216, 4, 32), ++ RK3066_PLL_RATE_NB(426000000, 3, 213, 4, 32), ++ RK3066_PLL_RATE_NB(400000000, 1, 100, 6, 32), ++ RK3066_PLL_RATE_NB(342000000, 3, 171, 4, 32), ++ RK3066_PLL_RATE_NB(297000000, 2, 198, 8, 16), ++ RK3066_PLL_RATE_NB(270000000, 1, 135, 12, 32), ++ RK3066_PLL_RATE_NB(260000000, 1, 130, 12, 32), ++ RK3066_PLL_RATE_NB(148500000, 1, 99, 16, 32), ++ RK3066_PLL_RATE(148352000, 13, 1125, 14), ++ RK3066_PLL_RATE_NB(146250000, 6, 585, 16, 32), ++ RK3066_PLL_RATE_NB(108000000, 1, 54, 12, 32), ++ RK3066_PLL_RATE_NB(106500000, 4, 213, 12, 32), ++ RK3066_PLL_RATE_NB(85500000, 4, 171, 12, 32), ++ RK3066_PLL_RATE_NB(74250000, 4, 198, 16, 32), ++ RK3066_PLL_RATE(74176000, 26, 1125, 14), ++ { /* sentinel */ }, ++}; ++ + #define RK3288_DIV_ACLK_CORE_M0_MASK 0xf + #define RK3288_DIV_ACLK_CORE_M0_SHIFT 0 + #define RK3288_DIV_ACLK_CORE_MP_MASK 0xf +@@ -231,7 +252,7 @@ static struct rockchip_pll_clock rk3288_pll_clks[] __initdata = { + [gpll] = PLL(pll_rk3066, PLL_GPLL, "gpll", mux_pll_p, 0, RK3288_PLL_CON(12), + RK3288_MODE_CON, 12, 8, ROCKCHIP_PLL_SYNC_RATE, rk3288_pll_rates), + [npll] = PLL(pll_rk3066, PLL_NPLL, "npll", mux_pll_p, 0, RK3288_PLL_CON(16), +- RK3288_MODE_CON, 14, 9, 0, rk3288_pll_rates), ++ RK3288_MODE_CON, 14, 9, 0, rk3288_npll_rates), + }; + + static struct clk_div_table div_hclk_cpu_t[] = { + +From 5c8dac1f946b2a4f2ec3e605a221d5cba56ee59f Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Sun, 28 Oct 2018 21:43:01 +0100 +Subject: [PATCH] HACK: clk: rockchip: rk3288: add more npll clocks + +Fixes 2560x1440@60Hz, 1600x1200@60Hz, 1920x1200@60Hz, 1680x1050@60Hz and 1440x900@60Hz modes on my monitor + +Signed-off-by: Jonas Karlman +--- + drivers/clk/rockchip/clk-rk3288.c | 16 ++++++++++++++++ + 1 file changed, 16 insertions(+) + +diff --git a/drivers/clk/rockchip/clk-rk3288.c b/drivers/clk/rockchip/clk-rk3288.c +index 426309f5dd44..b3247a3a7290 100644 +--- a/drivers/clk/rockchip/clk-rk3288.c ++++ b/drivers/clk/rockchip/clk-rk3288.c +@@ -127,18 +127,34 @@ static struct rockchip_pll_rate_table rk3288_npll_rates[] = { + RK3066_PLL_RATE_NB(432000000, 3, 216, 4, 32), + RK3066_PLL_RATE_NB(426000000, 3, 213, 4, 32), + RK3066_PLL_RATE_NB(400000000, 1, 100, 6, 32), ++ RK3066_PLL_RATE(348500000, 8, 697, 6), + RK3066_PLL_RATE_NB(342000000, 3, 171, 4, 32), + RK3066_PLL_RATE_NB(297000000, 2, 198, 8, 16), + RK3066_PLL_RATE_NB(270000000, 1, 135, 12, 32), + RK3066_PLL_RATE_NB(260000000, 1, 130, 12, 32), ++ RK3066_PLL_RATE(241500000, 2, 161, 8), ++ RK3066_PLL_RATE(162000000, 1, 81, 12), ++ RK3066_PLL_RATE(154000000, 6, 539, 14), + RK3066_PLL_RATE_NB(148500000, 1, 99, 16, 32), + RK3066_PLL_RATE(148352000, 13, 1125, 14), + RK3066_PLL_RATE_NB(146250000, 6, 585, 16, 32), ++ RK3066_PLL_RATE(121750000, 6, 487, 16), ++ RK3066_PLL_RATE(119000000, 3, 238, 16), + RK3066_PLL_RATE_NB(108000000, 1, 54, 12, 32), + RK3066_PLL_RATE_NB(106500000, 4, 213, 12, 32), ++ RK3066_PLL_RATE(101000000, 3, 202, 16), ++ RK3066_PLL_RATE(88750000, 6, 355, 16), + RK3066_PLL_RATE_NB(85500000, 4, 171, 12, 32), ++ RK3066_PLL_RATE(83500000, 3, 167, 16), ++ RK3066_PLL_RATE(79500000, 1, 53, 16), + RK3066_PLL_RATE_NB(74250000, 4, 198, 16, 32), + RK3066_PLL_RATE(74176000, 26, 1125, 14), ++ RK3066_PLL_RATE(72000000, 1, 48, 16), ++ RK3066_PLL_RATE(71000000, 3, 142, 16), ++ RK3066_PLL_RATE(68250000, 2, 91, 16), ++ RK3066_PLL_RATE(65000000, 3, 130, 16), ++ RK3066_PLL_RATE(40000000, 3, 80, 16), ++ RK3066_PLL_RATE(33750000, 2, 45, 16), + { /* sentinel */ }, + }; + + +From bcdd0b34aa22e3bf3d5750d003267cc072fed5db Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Mon, 25 May 2020 20:36:45 +0000 +Subject: [PATCH] HACK: clk: rockchip: rk3399: dedicate vpll for vopb and hdmi + use + +Signed-off-by: Jonas Karlman +--- + drivers/clk/rockchip/clk-rk3399.c | 32 +++++++++++++++++++++++++------ + 1 file changed, 26 insertions(+), 6 deletions(-) + +diff --git a/drivers/clk/rockchip/clk-rk3399.c b/drivers/clk/rockchip/clk-rk3399.c +index ce1d2446f142..f75df0afa2bd 100644 +--- a/drivers/clk/rockchip/clk-rk3399.c ++++ b/drivers/clk/rockchip/clk-rk3399.c +@@ -103,6 +103,25 @@ static struct rockchip_pll_rate_table rk3399_pll_rates[] = { + { /* sentinel */ }, + }; + ++static struct rockchip_pll_rate_table rk3399_vpll_rates[] = { ++ /* _mhz, _refdiv, _fbdiv, _postdiv1, _postdiv2, _dsmpd, _frac */ ++ RK3036_PLL_RATE( 594000000, 1, 123, 5, 1, 0, 12582912), /* vco = 2970000000 */ ++ RK3036_PLL_RATE( 593406592, 1, 123, 5, 1, 0, 10508804), /* vco = 2967032965 */ ++ RK3036_PLL_RATE( 297000000, 1, 123, 5, 2, 0, 12582912), /* vco = 2970000000 */ ++ RK3036_PLL_RATE( 296703296, 1, 123, 5, 2, 0, 10508807), /* vco = 2967032970 */ ++ RK3036_PLL_RATE( 148500000, 1, 129, 7, 3, 0, 15728640), /* vco = 3118500000 */ ++ RK3036_PLL_RATE( 148351648, 1, 123, 5, 4, 0, 10508800), /* vco = 2967032960 */ ++ RK3036_PLL_RATE( 106500000, 1, 124, 7, 4, 0, 4194304), /* vco = 2982000000 */ ++ RK3036_PLL_RATE( 74250000, 1, 129, 7, 6, 0, 15728640), /* vco = 3118500000 */ ++ RK3036_PLL_RATE( 74175824, 1, 129, 7, 6, 0, 13550823), /* vco = 3115384608 */ ++ RK3036_PLL_RATE( 65000000, 1, 113, 7, 6, 0, 12582912), /* vco = 2730000000 */ ++ RK3036_PLL_RATE( 59340659, 1, 121, 7, 7, 0, 2581098), /* vco = 2907692291 */ ++ RK3036_PLL_RATE( 54000000, 1, 110, 7, 7, 0, 4194304), /* vco = 2646000000 */ ++ RK3036_PLL_RATE( 27000000, 1, 55, 7, 7, 0, 2097152), /* vco = 1323000000 */ ++ RK3036_PLL_RATE( 26973026, 1, 55, 7, 7, 0, 1173232), /* vco = 1321678323 */ ++ { /* sentinel */ }, ++}; ++ + /* CRU parents */ + PNAME(mux_pll_p) = { "xin24m", "xin32k" }; + +@@ -121,7 +140,7 @@ PNAME(mux_ddrclk_p) = { "clk_ddrc_lpll_src", + PNAME(mux_aclk_cci_p) = { "cpll_aclk_cci_src", + "gpll_aclk_cci_src", + "npll_aclk_cci_src", +- "vpll_aclk_cci_src" }; ++ "prevent:vpll" }; + PNAME(mux_cci_trace_p) = { "cpll_cci_trace", + "gpll_cci_trace" }; + PNAME(mux_cs_p) = { "cpll_cs", "gpll_cs", +@@ -148,9 +167,10 @@ PNAME(mux_pll_src_cpll_gpll_npll_ppll_upll_24m_p) = { "cpll", "gpll", "npll", + "ppll", "upll", "xin24m" }; + + PNAME(mux_pll_src_vpll_cpll_gpll_p) = { "vpll", "cpll", "gpll" }; +-PNAME(mux_pll_src_vpll_cpll_gpll_npll_p) = { "vpll", "cpll", "gpll", ++ ++PNAME(mux_pll_src_vpll_cpll_gpll_npll_p) = { "prevent:vpll", "cpll", "gpll", + "npll" }; +-PNAME(mux_pll_src_vpll_cpll_gpll_24m_p) = { "vpll", "cpll", "gpll", ++PNAME(mux_pll_src_vpll_cpll_gpll_24m_p) = { "prevent:vpll", "cpll", "gpll", + "xin24m" }; + + PNAME(mux_dclk_vop0_p) = { "dclk_vop0_div", +@@ -227,7 +247,7 @@ static struct rockchip_pll_clock rk3399_pll_clks[] __initdata = { + [npll] = PLL(pll_rk3399, PLL_NPLL, "npll", mux_pll_p, 0, RK3399_PLL_CON(40), + RK3399_PLL_CON(43), 8, 31, ROCKCHIP_PLL_SYNC_RATE, rk3399_pll_rates), + [vpll] = PLL(pll_rk3399, PLL_VPLL, "vpll", mux_pll_p, 0, RK3399_PLL_CON(48), +- RK3399_PLL_CON(51), 8, 31, ROCKCHIP_PLL_SYNC_RATE, rk3399_pll_rates), ++ RK3399_PLL_CON(51), 8, 31, ROCKCHIP_PLL_SYNC_RATE, rk3399_vpll_rates), + }; + + static struct rockchip_pll_clock rk3399_pmu_pll_clks[] __initdata = { +@@ -277,7 +297,7 @@ static struct rockchip_clk_branch rk3399_uart4_pmu_fracmux __initdata = + RK3399_PMU_CLKSEL_CON(5), 8, 2, MFLAGS); + + static struct rockchip_clk_branch rk3399_dclk_vop0_fracmux __initdata = +- MUX(DCLK_VOP0, "dclk_vop0", mux_dclk_vop0_p, CLK_SET_RATE_PARENT, ++ MUX(DCLK_VOP0, "dclk_vop0", mux_dclk_vop0_p, CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT, + RK3399_CLKSEL_CON(49), 11, 1, MFLAGS); + + static struct rockchip_clk_branch rk3399_dclk_vop1_fracmux __initdata = +@@ -1158,7 +1178,7 @@ static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = { + GATE(HCLK_VOP0_NOC, "hclk_vop0_noc", "hclk_vop0_pre", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(28), 0, GFLAGS), + +- COMPOSITE(DCLK_VOP0_DIV, "dclk_vop0_div", mux_pll_src_vpll_cpll_gpll_p, 0, ++ COMPOSITE(DCLK_VOP0_DIV, "dclk_vop0_div", mux_pll_src_vpll_cpll_gpll_p, CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT, + RK3399_CLKSEL_CON(49), 8, 2, MFLAGS, 0, 8, DFLAGS, + RK3399_CLKGATE_CON(10), 12, GFLAGS), + + +From 1178026ac93b4a05b643d9e68b7c98d0434b8b0e Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Sun, 19 Jul 2020 16:35:11 +0000 +Subject: [PATCH] HACK: dts: rockchip: do not use vopl for hdmi + +--- + arch/arm/boot/dts/rk3288.dtsi | 9 --------- + arch/arm64/boot/dts/rockchip/rk3399.dtsi | 9 --------- + 2 files changed, 18 deletions(-) + +diff --git a/arch/arm/boot/dts/rk3288.dtsi b/arch/arm/boot/dts/rk3288.dtsi +index a376dea3bb1b..9757976d6e8a 100644 +--- a/arch/arm/boot/dts/rk3288.dtsi ++++ b/arch/arm/boot/dts/rk3288.dtsi +@@ -1104,11 +1104,6 @@ vopl_out: port { + #address-cells = <1>; + #size-cells = <0>; + +- vopl_out_hdmi: endpoint@0 { +- reg = <0>; +- remote-endpoint = <&hdmi_in_vopl>; +- }; +- + vopl_out_edp: endpoint@1 { + reg = <1>; + remote-endpoint = <&edp_in_vopl>; +@@ -1249,10 +1244,6 @@ hdmi_in_vopb: endpoint@0 { + reg = <0>; + remote-endpoint = <&vopb_out_hdmi>; + }; +- hdmi_in_vopl: endpoint@1 { +- reg = <1>; +- remote-endpoint = <&vopl_out_hdmi>; +- }; + }; + }; + }; +diff --git a/arch/arm64/boot/dts/rockchip/rk3399.dtsi b/arch/arm64/boot/dts/rockchip/rk3399.dtsi +index ada724b12f01..8973bf68d652 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3399.dtsi ++++ b/arch/arm64/boot/dts/rockchip/rk3399.dtsi +@@ -1637,11 +1637,6 @@ vopl_out_edp: endpoint@1 { + remote-endpoint = <&edp_in_vopl>; + }; + +- vopl_out_hdmi: endpoint@2 { +- reg = <2>; +- remote-endpoint = <&hdmi_in_vopl>; +- }; +- + vopl_out_mipi1: endpoint@3 { + reg = <3>; + remote-endpoint = <&mipi1_in_vopl>; +@@ -1787,10 +1782,6 @@ hdmi_in_vopb: endpoint@0 { + reg = <0>; + remote-endpoint = <&vopb_out_hdmi>; + }; +- hdmi_in_vopl: endpoint@1 { +- reg = <1>; +- remote-endpoint = <&vopl_out_hdmi>; +- }; + }; + }; + }; + +From df6bdd1b82221a3d03736963bdc1845222ff3b5c Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Tue, 26 Feb 2019 20:45:14 +0000 +Subject: [PATCH] WIP: dw-hdmi-cec: sleep 100ms on error + +Signed-off-by: Jonas Karlman +--- + drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c | 19 +++++++++++++++++-- + 1 file changed, 17 insertions(+), 2 deletions(-) + +diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c +index 70ab4fbdc23e..f6a85f73b90d 100644 +--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c ++++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c +@@ -4,6 +4,7 @@ + * + * Copyright (C) 2015-2017 Russell King. + */ ++#include + #include + #include + #include +@@ -129,8 +130,16 @@ static irqreturn_t dw_hdmi_cec_hardirq(int irq, void *data) + + dw_hdmi_write(cec, stat, HDMI_IH_CEC_STAT0); + +- if (stat & CEC_STAT_ERROR_INIT) { +- cec->tx_status = CEC_TX_STATUS_ERROR; ++ /* ++ * Status with both done and error_initiator bits have been seen ++ * on Rockchip RK3328 devices, transmit attempt seems to have failed ++ * when this happens, report as low drive and block cec-framework ++ * 100ms before core retransmits the failed message, this seems to ++ * mitigate the issue with failed transmit attempts. ++ */ ++ if ((stat & (CEC_STAT_DONE|CEC_STAT_ERROR_INIT)) == (CEC_STAT_DONE|CEC_STAT_ERROR_INIT)) { ++ pr_info("dw_hdmi_cec_hardirq: stat=%02x LOW_DRIVE\n", stat); ++ cec->tx_status = CEC_TX_STATUS_LOW_DRIVE; + cec->tx_done = true; + ret = IRQ_WAKE_THREAD; + } else if (stat & CEC_STAT_DONE) { +@@ -141,6 +150,10 @@ static irqreturn_t dw_hdmi_cec_hardirq(int irq, void *data) + cec->tx_status = CEC_TX_STATUS_NACK; + cec->tx_done = true; + ret = IRQ_WAKE_THREAD; ++ } else if (stat & CEC_STAT_ERROR_INIT) { ++ cec->tx_status = CEC_TX_STATUS_ERROR; ++ cec->tx_done = true; ++ ret = IRQ_WAKE_THREAD; + } + + if (stat & CEC_STAT_EOM) { +@@ -173,6 +186,8 @@ static irqreturn_t dw_hdmi_cec_thread(int irq, void *data) + + if (cec->tx_done) { + cec->tx_done = false; ++ if (cec->tx_status == CEC_TX_STATUS_LOW_DRIVE) ++ msleep(100); + cec_transmit_attempt_done(adap, cec->tx_status); + } + if (cec->rx_done) { + +From f482feeeeedc41f34892a05a0594d23924a0571a Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Sat, 18 Jul 2020 20:54:38 +0000 +Subject: [PATCH] asdf + +--- + drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c | 36 +++++++++++++++---- + drivers/media/cec/core/cec-adap.c | 2 +- + 2 files changed, 30 insertions(+), 8 deletions(-) + +diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c +index f6a85f73b90d..e6953219beee 100644 +--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c ++++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c +@@ -58,6 +58,7 @@ struct dw_hdmi_cec { + u32 addresses; + struct cec_adapter *adap; + struct cec_msg rx_msg; ++ unsigned int tx_attempts; + unsigned int tx_status; + bool tx_done; + bool rx_done; +@@ -96,6 +97,8 @@ static int dw_hdmi_cec_transmit(struct cec_adapter *adap, u8 attempts, + struct dw_hdmi_cec *cec = cec_get_drvdata(adap); + unsigned int i, ctrl; + ++ pr_info("%s: attempts=%u signal_free_time=%u msg=%*ph (sequence: %u)\n", __func__, attempts, signal_free_time, msg->len, msg->msg, msg->sequence); ++ + switch (signal_free_time) { + case CEC_SIGNAL_FREE_TIME_RETRY: + ctrl = CEC_CTRL_RETRY; +@@ -131,26 +134,35 @@ static irqreturn_t dw_hdmi_cec_hardirq(int irq, void *data) + dw_hdmi_write(cec, stat, HDMI_IH_CEC_STAT0); + + /* +- * Status with both done and error_initiator bits have been seen +- * on Rockchip RK3328 devices, transmit attempt seems to have failed +- * when this happens, report as low drive and block cec-framework ++ * Status with both done and error_initiator bits have been observed ++ * on Rockchip RK3328/RK3399 devices, transmit attempt seems to have ++ * failed when this happens, report as low drive and block cec-framework + * 100ms before core retransmits the failed message, this seems to + * mitigate the issue with failed transmit attempts. + */ + if ((stat & (CEC_STAT_DONE|CEC_STAT_ERROR_INIT)) == (CEC_STAT_DONE|CEC_STAT_ERROR_INIT)) { +- pr_info("dw_hdmi_cec_hardirq: stat=%02x LOW_DRIVE\n", stat); ++ if (!cec->tx_attempts) ++ cec->tx_attempts = 2; + cec->tx_status = CEC_TX_STATUS_LOW_DRIVE; + cec->tx_done = true; + ret = IRQ_WAKE_THREAD; ++ } else if (stat & CEC_STAT_ARBLOST) { ++ cec->tx_attempts = 0; ++ cec->tx_status = CEC_TX_STATUS_ARB_LOST; ++ cec->tx_done = true; ++ ret = IRQ_WAKE_THREAD; + } else if (stat & CEC_STAT_DONE) { ++ cec->tx_attempts = 0; + cec->tx_status = CEC_TX_STATUS_OK; + cec->tx_done = true; + ret = IRQ_WAKE_THREAD; + } else if (stat & CEC_STAT_NACK) { ++ cec->tx_attempts = 0; + cec->tx_status = CEC_TX_STATUS_NACK; + cec->tx_done = true; + ret = IRQ_WAKE_THREAD; + } else if (stat & CEC_STAT_ERROR_INIT) { ++ cec->tx_attempts = 0; + cec->tx_status = CEC_TX_STATUS_ERROR; + cec->tx_done = true; + ret = IRQ_WAKE_THREAD; +@@ -176,6 +188,8 @@ static irqreturn_t dw_hdmi_cec_hardirq(int irq, void *data) + ret = IRQ_WAKE_THREAD; + } + ++ pr_info("%s: stat=%x ret=%x tx_done=%d rx_done=%d tx_status=%u tx_attempts=%u\n", __func__, stat, ret, cec->tx_done, cec->rx_done, cec->tx_status, cec->tx_attempts); ++ + return ret; + } + +@@ -184,11 +198,19 @@ static irqreturn_t dw_hdmi_cec_thread(int irq, void *data) + struct cec_adapter *adap = data; + struct dw_hdmi_cec *cec = cec_get_drvdata(adap); + ++ //pr_info("%s: tx_done=%d rx_done=%d tx_status=%u tx_attempts=%u\n", __func__, cec->tx_done, cec->rx_done, cec->tx_status, cec->tx_attempts); ++ + if (cec->tx_done) { + cec->tx_done = false; + if (cec->tx_status == CEC_TX_STATUS_LOW_DRIVE) + msleep(100); +- cec_transmit_attempt_done(adap, cec->tx_status); ++ if (cec->tx_attempts > 1) { ++ cec->tx_attempts--; ++ dw_hdmi_write(cec, CEC_CTRL_RETRY | CEC_CTRL_START, HDMI_CEC_CTRL); ++ } else { ++ cec->tx_attempts = 0; ++ cec_transmit_attempt_done(adap, cec->tx_status); ++ } + } + if (cec->rx_done) { + cec->rx_done = false; +@@ -219,8 +241,8 @@ static int dw_hdmi_cec_enable(struct cec_adapter *adap, bool enable) + + cec->ops->enable(cec->hdmi); + +- irqs = CEC_STAT_ERROR_INIT | CEC_STAT_NACK | CEC_STAT_EOM | +- CEC_STAT_DONE; ++ irqs = CEC_STAT_ERROR_INIT | CEC_STAT_ARBLOST | CEC_STAT_NACK | ++ CEC_STAT_EOM | CEC_STAT_DONE; + dw_hdmi_write(cec, irqs, HDMI_CEC_POLARITY); + dw_hdmi_write(cec, ~irqs, HDMI_CEC_MASK); + dw_hdmi_write(cec, ~irqs, HDMI_IH_MUTE_CEC_STAT0); +diff --git a/drivers/media/cec/core/cec-adap.c b/drivers/media/cec/core/cec-adap.c +index 6a04d19a96b2..3d12f9d30bd0 100644 +--- a/drivers/media/cec/core/cec-adap.c ++++ b/drivers/media/cec/core/cec-adap.c +@@ -599,7 +599,6 @@ void cec_transmit_done_ts(struct cec_adapter *adap, u8 status, + unsigned int attempts_made = arb_lost_cnt + nack_cnt + + low_drive_cnt + error_cnt; + +- dprintk(2, "%s: status 0x%02x\n", __func__, status); + if (attempts_made < 1) + attempts_made = 1; + +@@ -620,6 +619,7 @@ void cec_transmit_done_ts(struct cec_adapter *adap, u8 status, + adap->transmit_in_progress = false; + + msg = &data->msg; ++ dprintk(2, "%s: %*ph (sequence: %u, attempts: %d, status: %02x)\n", __func__, msg->len, msg->msg, msg->sequence, attempts_made, status); + + /* Drivers must fill in the status! */ + WARN_ON(status == 0); + +From 7abf7a462dd2e503dd816277628ed09a46dc8c55 Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Mon, 20 Jul 2020 11:44:01 +0000 +Subject: [PATCH] cec dprintk revert + +--- + drivers/media/cec/core/cec-adap.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/media/cec/core/cec-adap.c b/drivers/media/cec/core/cec-adap.c +index 3d12f9d30bd0..6a04d19a96b2 100644 +--- a/drivers/media/cec/core/cec-adap.c ++++ b/drivers/media/cec/core/cec-adap.c +@@ -599,6 +599,7 @@ void cec_transmit_done_ts(struct cec_adapter *adap, u8 status, + unsigned int attempts_made = arb_lost_cnt + nack_cnt + + low_drive_cnt + error_cnt; + ++ dprintk(2, "%s: status 0x%02x\n", __func__, status); + if (attempts_made < 1) + attempts_made = 1; + +@@ -619,7 +620,6 @@ void cec_transmit_done_ts(struct cec_adapter *adap, u8 status, + adap->transmit_in_progress = false; + + msg = &data->msg; +- dprintk(2, "%s: %*ph (sequence: %u, attempts: %d, status: %02x)\n", __func__, msg->len, msg->msg, msg->sequence, attempts_made, status); + + /* Drivers must fill in the status! */ + WARN_ON(status == 0); + +From 8ca2d36b31a5921a9f7e0e1deba847915eac55bf Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Mon, 20 Jul 2020 12:33:01 +0000 +Subject: [PATCH] Revert "fixup! WIP: drm/rockchip: vop: max_output" + +This reverts commit c69612ca6820500cd1a0a3e4f8eb8c6f7b971cda. +--- + drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +index 106b38ea12df..138f449924f8 100644 +--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c ++++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +@@ -1184,8 +1184,19 @@ static bool vop_crtc_mode_fixup(struct drm_crtc *crtc, + struct drm_display_mode *adjusted_mode) + { + struct vop *vop = to_vop(crtc); ++ const struct vop_rect *max_output = &vop->data->max_output; + unsigned long rate; + ++ if (max_output->width && max_output->height) { ++ enum drm_mode_status status; ++ ++ status = drm_mode_validate_size(adjusted_mode, ++ max_output->width, ++ max_output->height); ++ if (status != MODE_OK) ++ return false; ++ } ++ + /* + * Clock craziness. + * + +From fff7adceb4d87d2fa0b4f108dbcd39748dfd0689 Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Wed, 15 Jul 2020 15:24:47 +0000 +Subject: [PATCH] drm/rockchip: vop: fix crtc duplicate state + +Signed-off-by: Jonas Karlman +--- + drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +index 138f449924f8..0a25de483515 100644 +--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c ++++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +@@ -1578,7 +1578,11 @@ static struct drm_crtc_state *vop_crtc_duplicate_state(struct drm_crtc *crtc) + { + struct rockchip_crtc_state *rockchip_state; + +- rockchip_state = kzalloc(sizeof(*rockchip_state), GFP_KERNEL); ++ if (WARN_ON(!crtc->state)) ++ return NULL; ++ ++ rockchip_state = kmemdup(to_rockchip_crtc_state(crtc->state), ++ sizeof(*rockchip_state), GFP_KERNEL); + if (!rockchip_state) + return NULL; + + +From 36a518702d98bb3c22276352f648ee1d206db475 Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Mon, 20 Jul 2020 15:15:50 +0000 +Subject: [PATCH] WIP: drm/rockchip: vop: filter interlaced modes + +--- + drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +index 0a25de483515..5ab1412173a7 100644 +--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c ++++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +@@ -1160,6 +1160,9 @@ static enum drm_mode_status vop_crtc_mode_valid(struct drm_crtc *crtc, + if (s->output_type != DRM_MODE_CONNECTOR_HDMIA) + return MODE_OK; + ++ if (mode->flags & DRM_MODE_FLAG_INTERLACE) ++ return MODE_NO_INTERLACE; ++ + rounded_rate = clk_round_rate(vop->dclk, mode->clock * 1000 + 999); + if (rounded_rate < 0) + return MODE_NOCLOCK; + +From 14ba7a75af03d8e3fd7274cfe8a21dd867b23ce5 Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Fri, 20 Dec 2019 08:12:42 +0000 +Subject: [PATCH] drm/rockchip: dw-hdmi: add bridge and switch to + drm_bridge_funcs + +Switch the dw-hdmi driver to drm_bridge_funcs by implementing +a new local bridge, connecting it to the dw-hdmi bridge. + +Also enable bridge format negotiation by implementing +atomic_get_input_bus_fmts and support for 8-bit RGB 4:4:4. + +Signed-off-by: Jonas Karlman +--- + drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 138 ++++++++++++++------ + 1 file changed, 95 insertions(+), 43 deletions(-) + +diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +index cc20a83fa9b8..745fd1c13cef 100644 +--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c ++++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +@@ -68,6 +68,7 @@ struct rockchip_hdmi { + struct device *dev; + struct regmap *regmap; + struct drm_encoder encoder; ++ struct drm_bridge bridge; + const struct rockchip_hdmi_chip_data *chip_data; + struct clk *vpll_clk; + struct clk *grf_clk; +@@ -228,30 +229,20 @@ dw_hdmi_rockchip_mode_valid(struct dw_hdmi *hdmi, void *data, + return drm_mode_validate_size(mode, 3840, 2160); + } + +-static void dw_hdmi_rockchip_encoder_disable(struct drm_encoder *encoder) ++static void ++dw_hdmi_rockchip_bridge_mode_set(struct drm_bridge *bridge, ++ const struct drm_display_mode *mode, ++ const struct drm_display_mode *adjusted_mode) + { +-} ++ struct rockchip_hdmi *hdmi = to_rockchip_hdmi(bridge); + +-static bool +-dw_hdmi_rockchip_encoder_mode_fixup(struct drm_encoder *encoder, +- const struct drm_display_mode *mode, +- struct drm_display_mode *adj_mode) +-{ +- return true; ++ clk_set_rate(hdmi->vpll_clk, adjusted_mode->clock * 1000); + } + +-static void dw_hdmi_rockchip_encoder_mode_set(struct drm_encoder *encoder, +- struct drm_display_mode *mode, +- struct drm_display_mode *adj_mode) ++static void dw_hdmi_rockchip_bridge_enable(struct drm_bridge *bridge) + { +- struct rockchip_hdmi *hdmi = to_rockchip_hdmi(encoder); +- +- clk_set_rate(hdmi->vpll_clk, adj_mode->clock * 1000); +-} +- +-static void dw_hdmi_rockchip_encoder_enable(struct drm_encoder *encoder) +-{ +- struct rockchip_hdmi *hdmi = to_rockchip_hdmi(encoder); ++ struct rockchip_hdmi *hdmi = to_rockchip_hdmi(bridge); ++ struct drm_encoder *encoder = bridge->encoder; + u32 val; + int ret; + +@@ -279,10 +270,21 @@ static void dw_hdmi_rockchip_encoder_enable(struct drm_encoder *encoder) + ret ? "LIT" : "BIG"); + } + ++static bool is_rgb(u32 format) ++{ ++ switch (format) { ++ case MEDIA_BUS_FMT_RGB888_1X24: ++ return true; ++ default: ++ return false; ++ } ++} ++ + static int +-dw_hdmi_rockchip_encoder_atomic_check(struct drm_encoder *encoder, +- struct drm_crtc_state *crtc_state, +- struct drm_connector_state *conn_state) ++dw_hdmi_rockchip_bridge_atomic_check(struct drm_bridge *bridge, ++ struct drm_bridge_state *bridge_state, ++ struct drm_crtc_state *crtc_state, ++ struct drm_connector_state *conn_state) + { + struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc_state); + +@@ -292,12 +294,38 @@ dw_hdmi_rockchip_encoder_atomic_check(struct drm_encoder *encoder, + return 0; + } + +-static const struct drm_encoder_helper_funcs dw_hdmi_rockchip_encoder_helper_funcs = { +- .mode_fixup = dw_hdmi_rockchip_encoder_mode_fixup, +- .mode_set = dw_hdmi_rockchip_encoder_mode_set, +- .enable = dw_hdmi_rockchip_encoder_enable, +- .disable = dw_hdmi_rockchip_encoder_disable, +- .atomic_check = dw_hdmi_rockchip_encoder_atomic_check, ++static u32 *dw_hdmi_rockchip_get_input_bus_fmts(struct drm_bridge *bridge, ++ struct drm_bridge_state *bridge_state, ++ struct drm_crtc_state *crtc_state, ++ struct drm_connector_state *conn_state, ++ u32 output_fmt, ++ unsigned int *num_input_fmts) ++{ ++ u32 *input_fmt; ++ ++ *num_input_fmts = 0; ++ ++ if (!is_rgb(output_fmt)) ++ return NULL; ++ ++ input_fmt = kzalloc(sizeof(*input_fmt), GFP_KERNEL); ++ if (!input_fmt) ++ return NULL; ++ ++ *num_input_fmts = 1; ++ *input_fmt = output_fmt; ++ ++ return input_fmt; ++} ++ ++static const struct drm_bridge_funcs dw_hdmi_rockchip_bridge_funcs = { ++ .mode_set = dw_hdmi_rockchip_bridge_mode_set, ++ .enable = dw_hdmi_rockchip_bridge_enable, ++ .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, ++ .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, ++ .atomic_get_input_bus_fmts = dw_hdmi_rockchip_get_input_bus_fmts, ++ .atomic_check = dw_hdmi_rockchip_bridge_atomic_check, ++ .atomic_reset = drm_atomic_helper_bridge_reset, + }; + + static int dw_hdmi_rockchip_genphy_init(struct dw_hdmi *dw_hdmi, void *data, +@@ -476,6 +504,7 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master, + struct dw_hdmi_plat_data *plat_data; + const struct of_device_id *match; + struct drm_device *drm = data; ++ struct drm_bridge *next_bridge; + struct drm_encoder *encoder; + struct rockchip_hdmi *hdmi; + int ret; +@@ -516,8 +545,7 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master, + + ret = clk_prepare_enable(hdmi->vpll_clk); + if (ret) { +- DRM_DEV_ERROR(hdmi->dev, "Failed to enable HDMI vpll: %d\n", +- ret); ++ DRM_DEV_ERROR(hdmi->dev, "Failed to enable vpll: %d\n", ret); + return ret; + } + +@@ -525,27 +553,51 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master, + if (IS_ERR(hdmi->phy)) { + ret = PTR_ERR(hdmi->phy); + if (ret != -EPROBE_DEFER) +- DRM_DEV_ERROR(hdmi->dev, "failed to get phy\n"); +- return ret; ++ DRM_DEV_ERROR(hdmi->dev, "Failed to get phy: %d\n", ret); ++ goto err_disable_clk; + } + +- drm_encoder_helper_add(encoder, &dw_hdmi_rockchip_encoder_helper_funcs); +- drm_simple_encoder_init(drm, encoder, DRM_MODE_ENCODER_TMDS); ++ ret = drm_simple_encoder_init(drm, encoder, DRM_MODE_ENCODER_TMDS); ++ if (ret) { ++ DRM_DEV_ERROR(hdmi->dev, "Failed to init encoder: %d\n", ret); ++ goto err_disable_clk; ++ } + +- platform_set_drvdata(pdev, hdmi); ++ hdmi->bridge.funcs = &dw_hdmi_rockchip_bridge_funcs; ++ drm_bridge_attach(encoder, &hdmi->bridge, NULL, 0); + +- hdmi->hdmi = dw_hdmi_bind(pdev, encoder, plat_data); ++ platform_set_drvdata(pdev, hdmi); + +- /* +- * If dw_hdmi_bind() fails we'll never call dw_hdmi_unbind(), +- * which would have called the encoder cleanup. Do it manually. +- */ ++ hdmi->hdmi = dw_hdmi_probe(pdev, plat_data); + if (IS_ERR(hdmi->hdmi)) { + ret = PTR_ERR(hdmi->hdmi); +- drm_encoder_cleanup(encoder); +- clk_disable_unprepare(hdmi->vpll_clk); ++ if (ret != -EPROBE_DEFER) ++ DRM_DEV_ERROR(hdmi->dev, "Failed to init dw-hdmi bridge: %d\n", ret); ++ goto err_encoder_cleanup; ++ } ++ ++ next_bridge = of_drm_find_bridge(pdev->dev.of_node); ++ if (!next_bridge) { ++ ret = -EPROBE_DEFER; ++ goto err_dw_hdmi_remove; ++ } ++ ++ ret = drm_bridge_attach(encoder, next_bridge, &hdmi->bridge, 0); ++ if (ret) { ++ if (ret != -EPROBE_DEFER) ++ DRM_DEV_ERROR(hdmi->dev, "Failed to attach dw-hdmi bridge: %d\n", ret); ++ goto err_dw_hdmi_remove; + } + ++ return 0; ++ ++err_dw_hdmi_remove: ++ dw_hdmi_remove(hdmi->hdmi); ++err_encoder_cleanup: ++ drm_encoder_cleanup(encoder); ++err_disable_clk: ++ clk_disable_unprepare(hdmi->vpll_clk); ++ + return ret; + } + +@@ -554,7 +606,7 @@ static void dw_hdmi_rockchip_unbind(struct device *dev, struct device *master, + { + struct rockchip_hdmi *hdmi = dev_get_drvdata(dev); + +- dw_hdmi_unbind(hdmi->hdmi); ++ dw_hdmi_remove(hdmi->hdmi); + clk_disable_unprepare(hdmi->vpll_clk); + } + + +From ffded51c4e7a79cca7d97b4fe0d98ee4b0b74e34 Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Mon, 20 Jul 2020 18:00:44 +0000 +Subject: [PATCH] drm/bridge: dw-hdmi: add mtmdsclock parameter to phy + configure ops + +Signed-off-by: Jonas Karlman +--- + drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 10 ++++++---- + drivers/gpu/drm/rcar-du/rcar_dw_hdmi.c | 3 ++- + include/drm/bridge/dw_hdmi.h | 3 ++- + 3 files changed, 10 insertions(+), 6 deletions(-) + +diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +index 748df1cacd2b..c25d5ac7bb07 100644 +--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c ++++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +@@ -137,7 +137,8 @@ struct dw_hdmi_phy_data { + bool has_svsret; + int (*configure)(struct dw_hdmi *hdmi, + const struct dw_hdmi_plat_data *pdata, +- unsigned long mpixelclock); ++ unsigned long mpixelclock, ++ unsigned long mtmdsclock); + }; + + struct dw_hdmi { +@@ -1441,7 +1442,8 @@ static int dw_hdmi_phy_power_on(struct dw_hdmi *hdmi) + */ + static int hdmi_phy_configure_dwc_hdmi_3d_tx(struct dw_hdmi *hdmi, + const struct dw_hdmi_plat_data *pdata, +- unsigned long mpixelclock) ++ unsigned long mpixelclock, ++ unsigned long mtmdsclock) + { + const struct dw_hdmi_mpll_config *mpll_config = pdata->mpll_cfg; + const struct dw_hdmi_curr_ctrl *curr_ctrl = pdata->cur_ctr; +@@ -1516,9 +1518,9 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi, + + /* Write to the PHY as configured by the platform */ + if (pdata->configure_phy) +- ret = pdata->configure_phy(hdmi, pdata->priv_data, mpixelclock); ++ ret = pdata->configure_phy(hdmi, pdata->priv_data, mpixelclock, mtmdsclock); + else +- ret = phy->configure(hdmi, pdata, mpixelclock); ++ ret = phy->configure(hdmi, pdata, mpixelclock, mtmdsclock); + if (ret) { + dev_err(hdmi->dev, "PHY configuration failed (clock %lu)\n", + mpixelclock); +diff --git a/drivers/gpu/drm/rcar-du/rcar_dw_hdmi.c b/drivers/gpu/drm/rcar-du/rcar_dw_hdmi.c +index 7b8ec8310699..539d86131fd4 100644 +--- a/drivers/gpu/drm/rcar-du/rcar_dw_hdmi.c ++++ b/drivers/gpu/drm/rcar-du/rcar_dw_hdmi.c +@@ -53,7 +53,8 @@ rcar_hdmi_mode_valid(struct dw_hdmi *hdmi, void *data, + } + + static int rcar_hdmi_phy_configure(struct dw_hdmi *hdmi, void *data, +- unsigned long mpixelclock) ++ unsigned long mpixelclock, ++ unsigned long mtmdsclock) + { + const struct rcar_hdmi_phy_params *params = rcar_hdmi_phy_params; + +diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h +index ea34ca146b82..4f61ede6486d 100644 +--- a/include/drm/bridge/dw_hdmi.h ++++ b/include/drm/bridge/dw_hdmi.h +@@ -152,7 +152,8 @@ struct dw_hdmi_plat_data { + const struct dw_hdmi_curr_ctrl *cur_ctr; + const struct dw_hdmi_phy_config *phy_config; + int (*configure_phy)(struct dw_hdmi *hdmi, void *data, +- unsigned long mpixelclock); ++ unsigned long mpixelclock, ++ unsigned long mtmdsclock); + }; + + struct dw_hdmi *dw_hdmi_probe(struct platform_device *pdev, + +From e3c32df45f5d84f541586a6c382008be538528ba Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Mon, 20 Jul 2020 21:34:48 +0000 +Subject: [PATCH] drm/bridge: dw-hdmi: support configuring phy for deep color + +Q: Should we rename dw_hdmi_curr_ctrl and dw_hdmi_phy_config mpixelclock to mtmdsclock ? + +Signed-off-by: Jonas Karlman +--- + drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 17 ++++++++++++----- + 1 file changed, 12 insertions(+), 5 deletions(-) + +diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +index c25d5ac7bb07..bcdd823907c2 100644 +--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c ++++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +@@ -1448,6 +1448,7 @@ static int hdmi_phy_configure_dwc_hdmi_3d_tx(struct dw_hdmi *hdmi, + const struct dw_hdmi_mpll_config *mpll_config = pdata->mpll_cfg; + const struct dw_hdmi_curr_ctrl *curr_ctrl = pdata->cur_ctr; + const struct dw_hdmi_phy_config *phy_config = pdata->phy_config; ++ int depth; + + /* TOFIX Will need 420 specific PHY configuration tables */ + +@@ -1457,11 +1458,11 @@ static int hdmi_phy_configure_dwc_hdmi_3d_tx(struct dw_hdmi *hdmi, + break; + + for (; curr_ctrl->mpixelclock != ~0UL; curr_ctrl++) +- if (mpixelclock <= curr_ctrl->mpixelclock) ++ if (mtmdsclock <= curr_ctrl->mpixelclock) + break; + + for (; phy_config->mpixelclock != ~0UL; phy_config++) +- if (mpixelclock <= phy_config->mpixelclock) ++ if (mtmdsclock <= phy_config->mpixelclock) + break; + + if (mpll_config->mpixelclock == ~0UL || +@@ -1469,11 +1470,17 @@ static int hdmi_phy_configure_dwc_hdmi_3d_tx(struct dw_hdmi *hdmi, + phy_config->mpixelclock == ~0UL) + return -EINVAL; + +- dw_hdmi_phy_i2c_write(hdmi, mpll_config->res[0].cpce, ++ depth = hdmi_bus_fmt_color_depth(hdmi->hdmi_data.enc_out_bus_format); ++ if (depth > 8 && mpixelclock != mtmdsclock) ++ depth = fls(depth - 8) - 1; ++ else ++ depth = 0; ++ ++ dw_hdmi_phy_i2c_write(hdmi, mpll_config->res[depth].cpce, + HDMI_3D_TX_PHY_CPCE_CTRL); +- dw_hdmi_phy_i2c_write(hdmi, mpll_config->res[0].gmp, ++ dw_hdmi_phy_i2c_write(hdmi, mpll_config->res[depth].gmp, + HDMI_3D_TX_PHY_GMPCTRL); +- dw_hdmi_phy_i2c_write(hdmi, curr_ctrl->curr[0], ++ dw_hdmi_phy_i2c_write(hdmi, curr_ctrl->curr[depth], + HDMI_3D_TX_PHY_CURRCTRL); + + dw_hdmi_phy_i2c_write(hdmi, 0, HDMI_3D_TX_PHY_PLLPHBYCTRL); + +From d391dfb202b03bad6d52efe7d0aa46225febe3c5 Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Mon, 20 Jul 2020 22:25:15 +0000 +Subject: [PATCH] drm/bridge: dw-hdmi: add mpll_cfg_420 for ycbcr420 mode + +Signed-off-by: Jonas Karlman +--- + drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 4 +++- + include/drm/bridge/dw_hdmi.h | 1 + + 2 files changed, 4 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +index bcdd823907c2..f5d048adf649 100644 +--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c ++++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +@@ -1450,7 +1450,9 @@ static int hdmi_phy_configure_dwc_hdmi_3d_tx(struct dw_hdmi *hdmi, + const struct dw_hdmi_phy_config *phy_config = pdata->phy_config; + int depth; + +- /* TOFIX Will need 420 specific PHY configuration tables */ ++ if (hdmi_bus_fmt_is_yuv420(hdmi->hdmi_data.enc_out_bus_format) && ++ pdata->mpll_cfg_420) ++ mpll_config = pdata->mpll_cfg_420; + + /* PLL/MPLL Cfg - always match on final entry */ + for (; mpll_config->mpixelclock != ~0UL; mpll_config++) +diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h +index 4f61ede6486d..0ebe01835d2a 100644 +--- a/include/drm/bridge/dw_hdmi.h ++++ b/include/drm/bridge/dw_hdmi.h +@@ -149,6 +149,7 @@ struct dw_hdmi_plat_data { + + /* Synopsys PHY support */ + const struct dw_hdmi_mpll_config *mpll_cfg; ++ const struct dw_hdmi_mpll_config *mpll_cfg_420; + const struct dw_hdmi_curr_ctrl *cur_ctr; + const struct dw_hdmi_phy_config *phy_config; + int (*configure_phy)(struct dw_hdmi *hdmi, void *data, + +From 08b2f123efe8bb641671ad038dd0dc37f877794d Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Wed, 15 Jul 2020 09:49:21 +0000 +Subject: [PATCH] drm/rockchip: dw-hdmi: mode_valid: allow 420 clock rate + +Signed-off-by: Jonas Karlman +--- + drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 12 ++++++++++-- + 1 file changed, 10 insertions(+), 2 deletions(-) + +diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +index 745fd1c13cef..9784111ea746 100644 +--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c ++++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +@@ -222,8 +222,15 @@ dw_hdmi_rockchip_mode_valid(struct dw_hdmi *hdmi, void *data, + const struct drm_display_info *info, + const struct drm_display_mode *mode) + { +- if (mode->clock > 340000 || +- (info->max_tmds_clock && mode->clock > info->max_tmds_clock)) ++ struct dw_hdmi_plat_data *pdata = (struct dw_hdmi_plat_data *)data; ++ int clock = mode->clock; ++ ++ if (pdata->ycbcr_420_allowed && drm_mode_is_420(info, mode) && ++ (info->color_formats & DRM_COLOR_FORMAT_YCRCB420)) ++ clock /= 2; ++ ++ if (clock > 340000 || ++ (info->max_tmds_clock && clock > info->max_tmds_clock)) + return MODE_CLOCK_HIGH; + + return drm_mode_validate_size(mode, 3840, 2160); +@@ -524,6 +531,7 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master, + + hdmi->dev = &pdev->dev; + hdmi->chip_data = plat_data->phy_data; ++ plat_data->priv_data = plat_data; + plat_data->phy_data = hdmi; + encoder = &hdmi->encoder; + + +From e8f87de2fef5c2be3110fcd23fa1b09325bbd041 Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Mon, 20 Jul 2020 22:26:19 +0000 +Subject: [PATCH] drm/rockchip: dw-hdmi: rk3399: add mpll_cfg_420 + +Signed-off-by: Jonas Karlman +--- + drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 41 +++++++++++++++++++++ + 1 file changed, 41 insertions(+) + +diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +index 9784111ea746..e7fbeb9132fb 100644 +--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c ++++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +@@ -166,6 +166,46 @@ static const struct dw_hdmi_mpll_config rockchip_mpll_cfg[] = { + } + }; + ++static const struct dw_hdmi_mpll_config rockchip_mpll_cfg_420[] = { ++ { ++ 30666000, { ++ { 0x00b7, 0x0000 }, ++ { 0x2157, 0x0000 }, ++ { 0x40f7, 0x0000 }, ++ }, ++ }, { ++ 92000000, { ++ { 0x00b7, 0x0000 }, ++ { 0x2143, 0x0001 }, ++ { 0x40a3, 0x0001 }, ++ }, ++ }, { ++ 184000000, { ++ { 0x0073, 0x0001 }, ++ { 0x2146, 0x0002 }, ++ { 0x4062, 0x0002 }, ++ }, ++ }, { ++ 340000000, { ++ { 0x0052, 0x0003 }, ++ { 0x214d, 0x0003 }, ++ { 0x4065, 0x0003 }, ++ }, ++ }, { ++ 600000000, { ++ { 0x0041, 0x0003 }, ++ { 0x3b4d, 0x0003 }, ++ { 0x5a65, 0x0003 }, ++ }, ++ }, { ++ ~0UL, { ++ { 0x0000, 0x0000 }, ++ { 0x0000, 0x0000 }, ++ { 0x0000, 0x0000 }, ++ }, ++ } ++}; ++ + static const struct dw_hdmi_curr_ctrl rockchip_cur_ctr[] = { + /* pixelclk bpp8 bpp10 bpp12 */ + { +@@ -481,6 +521,7 @@ static struct rockchip_hdmi_chip_data rk3399_chip_data = { + static const struct dw_hdmi_plat_data rk3399_hdmi_drv_data = { + .mode_valid = dw_hdmi_rockchip_mode_valid, + .mpll_cfg = rockchip_mpll_cfg, ++ .mpll_cfg_420 = rockchip_mpll_cfg_420, + .cur_ctr = rockchip_cur_ctr, + .phy_config = rockchip_phy_config, + .phy_data = &rk3399_chip_data, + +From 90cd0a2b9a02f11488bddcc9fe7dad15c04a8d36 Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Fri, 20 Dec 2019 08:12:43 +0000 +Subject: [PATCH] WIP: drm/bridge: dw-hdmi: limit mode and bus format to + max_tmds_clock + +--- + drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 120 ++++++++++++++-------- + 1 file changed, 76 insertions(+), 44 deletions(-) + +diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +index f5d048adf649..26c64cf2d00a 100644 +--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c ++++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +@@ -1859,6 +1859,21 @@ static void hdmi_config_drm_infoframe(struct dw_hdmi *hdmi, + HDMI_FC_PACKET_TX_EN_DRM_MASK, HDMI_FC_PACKET_TX_EN); + } + ++static unsigned int ++hdmi_get_tmdsclock(unsigned int bus_format, unsigned int pixelclock) ++{ ++ int color_depth = hdmi_bus_fmt_color_depth(bus_format); ++ unsigned int tmdsclock = pixelclock; ++ ++ if (!hdmi_bus_fmt_is_yuv422(bus_format) && color_depth > 8) ++ tmdsclock = (u64)pixelclock * color_depth / 8; ++ ++ if (hdmi_bus_fmt_is_yuv420(bus_format)) ++ tmdsclock /= 2; ++ ++ return tmdsclock; ++} ++ + static void hdmi_av_composer(struct dw_hdmi *hdmi, + const struct drm_display_info *display, + const struct drm_display_mode *mode) +@@ -1870,29 +1885,11 @@ static void hdmi_av_composer(struct dw_hdmi *hdmi, + unsigned int vdisplay, hdisplay; + + vmode->mpixelclock = mode->clock * 1000; ++ vmode->mtmdsclock = ++ hdmi_get_tmdsclock(hdmi->hdmi_data.enc_out_bus_format, ++ vmode->mpixelclock); + + dev_dbg(hdmi->dev, "final pixclk = %d\n", vmode->mpixelclock); +- +- vmode->mtmdsclock = vmode->mpixelclock; +- +- if (!hdmi_bus_fmt_is_yuv422(hdmi->hdmi_data.enc_out_bus_format)) { +- switch (hdmi_bus_fmt_color_depth( +- hdmi->hdmi_data.enc_out_bus_format)) { +- case 16: +- vmode->mtmdsclock = vmode->mpixelclock * 2; +- break; +- case 12: +- vmode->mtmdsclock = vmode->mpixelclock * 3 / 2; +- break; +- case 10: +- vmode->mtmdsclock = vmode->mpixelclock * 5 / 4; +- break; +- } +- } +- +- if (hdmi_bus_fmt_is_yuv420(hdmi->hdmi_data.enc_out_bus_format)) +- vmode->mtmdsclock /= 2; +- + dev_dbg(hdmi->dev, "final tmdsclock = %d\n", vmode->mtmdsclock); + + /* Set up HDMI_FC_INVIDCONF */ +@@ -2550,8 +2547,21 @@ static int dw_hdmi_connector_create(struct dw_hdmi *hdmi) + * - MEDIA_BUS_FMT_RGB888_1X24, + */ + +-/* Can return a maximum of 11 possible output formats for a mode/connector */ +-#define MAX_OUTPUT_SEL_FORMATS 11 ++/* Can return a maximum of 15 possible output formats for a mode/connector */ ++#define MAX_OUTPUT_SEL_FORMATS 15 ++ ++static bool is_tmds_allowed(struct drm_display_info *info, ++ struct drm_display_mode *mode, ++ u32 bus_format) ++{ ++ unsigned long tmdsclock = hdmi_get_tmdsclock(bus_format, mode->clock); ++ int max_tmds_clock = info->max_tmds_clock ? info->max_tmds_clock : 340000; ++ ++ if (max_tmds_clock >= tmdsclock) ++ return true; ++ ++ return false; ++} + + static u32 *dw_hdmi_bridge_atomic_get_output_bus_fmts(struct drm_bridge *bridge, + struct drm_bridge_state *bridge_state, +@@ -2563,8 +2573,6 @@ static u32 *dw_hdmi_bridge_atomic_get_output_bus_fmts(struct drm_bridge *bridge, + struct drm_display_info *info = &conn->display_info; + struct drm_display_mode *mode = &crtc_state->mode; + u8 max_bpc = conn_state->max_requested_bpc; +- bool is_hdmi2_sink = info->hdmi.scdc.supported || +- (info->color_formats & DRM_COLOR_FORMAT_YCRCB420); + u32 *output_fmts; + unsigned int i = 0; + +@@ -2587,29 +2595,33 @@ static u32 *dw_hdmi_bridge_atomic_get_output_bus_fmts(struct drm_bridge *bridge, + * If the current mode enforces 4:2:0, force the output but format + * to 4:2:0 and do not add the YUV422/444/RGB formats + */ +- if (conn->ycbcr_420_allowed && +- (drm_mode_is_420_only(info, mode) || +- (is_hdmi2_sink && drm_mode_is_420_also(info, mode)))) { ++ if (conn->ycbcr_420_allowed && drm_mode_is_420(info, mode) && ++ (info->color_formats & DRM_COLOR_FORMAT_YCRCB420)) { + + /* Order bus formats from 16bit to 8bit if supported */ + if (max_bpc >= 16 && info->bpc == 16 && +- (info->hdmi.y420_dc_modes & DRM_EDID_YCBCR420_DC_48)) ++ (info->hdmi.y420_dc_modes & DRM_EDID_YCBCR420_DC_48) && ++ is_tmds_allowed(info, mode, MEDIA_BUS_FMT_UYYVYY16_0_5X48)) + output_fmts[i++] = MEDIA_BUS_FMT_UYYVYY16_0_5X48; + + if (max_bpc >= 12 && info->bpc >= 12 && +- (info->hdmi.y420_dc_modes & DRM_EDID_YCBCR420_DC_36)) ++ (info->hdmi.y420_dc_modes & DRM_EDID_YCBCR420_DC_36) && ++ is_tmds_allowed(info, mode, MEDIA_BUS_FMT_UYYVYY12_0_5X36)) + output_fmts[i++] = MEDIA_BUS_FMT_UYYVYY12_0_5X36; + + if (max_bpc >= 10 && info->bpc >= 10 && +- (info->hdmi.y420_dc_modes & DRM_EDID_YCBCR420_DC_30)) ++ (info->hdmi.y420_dc_modes & DRM_EDID_YCBCR420_DC_30) && ++ is_tmds_allowed(info, mode, MEDIA_BUS_FMT_UYYVYY10_0_5X30)) + output_fmts[i++] = MEDIA_BUS_FMT_UYYVYY10_0_5X30; + + /* Default 8bit fallback */ +- output_fmts[i++] = MEDIA_BUS_FMT_UYYVYY8_0_5X24; ++ if (is_tmds_allowed(info, mode, MEDIA_BUS_FMT_UYYVYY8_0_5X24)) ++ output_fmts[i++] = MEDIA_BUS_FMT_UYYVYY8_0_5X24; + + *num_output_fmts = i; + +- return output_fmts; ++ if (drm_mode_is_420_only(info, mode)) ++ return output_fmts; + } + + /* +@@ -2618,40 +2630,51 @@ static u32 *dw_hdmi_bridge_atomic_get_output_bus_fmts(struct drm_bridge *bridge, + */ + + if (max_bpc >= 16 && info->bpc == 16) { +- if (info->color_formats & DRM_COLOR_FORMAT_YCRCB444) ++ if ((info->color_formats & DRM_COLOR_FORMAT_YCRCB444) && ++ is_tmds_allowed(info, mode, MEDIA_BUS_FMT_YUV16_1X48)) + output_fmts[i++] = MEDIA_BUS_FMT_YUV16_1X48; + +- output_fmts[i++] = MEDIA_BUS_FMT_RGB161616_1X48; ++ if (is_tmds_allowed(info, mode, MEDIA_BUS_FMT_RGB161616_1X48)) ++ output_fmts[i++] = MEDIA_BUS_FMT_RGB161616_1X48; + } + + if (max_bpc >= 12 && info->bpc >= 12) { +- if (info->color_formats & DRM_COLOR_FORMAT_YCRCB422) ++ if ((info->color_formats & DRM_COLOR_FORMAT_YCRCB422) && ++ is_tmds_allowed(info, mode, MEDIA_BUS_FMT_UYVY12_1X24)) + output_fmts[i++] = MEDIA_BUS_FMT_UYVY12_1X24; + +- if (info->color_formats & DRM_COLOR_FORMAT_YCRCB444) ++ if ((info->color_formats & DRM_COLOR_FORMAT_YCRCB444) && ++ is_tmds_allowed(info, mode, MEDIA_BUS_FMT_YUV12_1X36)) + output_fmts[i++] = MEDIA_BUS_FMT_YUV12_1X36; + +- output_fmts[i++] = MEDIA_BUS_FMT_RGB121212_1X36; ++ if (is_tmds_allowed(info, mode, MEDIA_BUS_FMT_RGB121212_1X36)) ++ output_fmts[i++] = MEDIA_BUS_FMT_RGB121212_1X36; + } + + if (max_bpc >= 10 && info->bpc >= 10) { +- if (info->color_formats & DRM_COLOR_FORMAT_YCRCB422) ++ if ((info->color_formats & DRM_COLOR_FORMAT_YCRCB422) && ++ is_tmds_allowed(info, mode, MEDIA_BUS_FMT_UYVY10_1X20)) + output_fmts[i++] = MEDIA_BUS_FMT_UYVY10_1X20; + +- if (info->color_formats & DRM_COLOR_FORMAT_YCRCB444) ++ if ((info->color_formats & DRM_COLOR_FORMAT_YCRCB444) && ++ is_tmds_allowed(info, mode, MEDIA_BUS_FMT_YUV10_1X30)) + output_fmts[i++] = MEDIA_BUS_FMT_YUV10_1X30; + +- output_fmts[i++] = MEDIA_BUS_FMT_RGB101010_1X30; ++ if (is_tmds_allowed(info, mode, MEDIA_BUS_FMT_RGB101010_1X30)) ++ output_fmts[i++] = MEDIA_BUS_FMT_RGB101010_1X30; + } + +- if (info->color_formats & DRM_COLOR_FORMAT_YCRCB422) ++ if ((info->color_formats & DRM_COLOR_FORMAT_YCRCB422) && ++ is_tmds_allowed(info, mode, MEDIA_BUS_FMT_UYVY8_1X16)) + output_fmts[i++] = MEDIA_BUS_FMT_UYVY8_1X16; + +- if (info->color_formats & DRM_COLOR_FORMAT_YCRCB444) ++ if ((info->color_formats & DRM_COLOR_FORMAT_YCRCB444) && ++ is_tmds_allowed(info, mode, MEDIA_BUS_FMT_YUV8_1X24)) + output_fmts[i++] = MEDIA_BUS_FMT_YUV8_1X24; + + /* Default 8bit RGB fallback */ +- output_fmts[i++] = MEDIA_BUS_FMT_RGB888_1X24; ++ if (is_tmds_allowed(info, mode, MEDIA_BUS_FMT_RGB888_1X24)) ++ output_fmts[i++] = MEDIA_BUS_FMT_RGB888_1X24; + + *num_output_fmts = i; + +@@ -2831,11 +2854,20 @@ dw_hdmi_bridge_mode_valid(struct drm_bridge *bridge, + struct dw_hdmi *hdmi = bridge->driver_private; + const struct dw_hdmi_plat_data *pdata = hdmi->plat_data; + enum drm_mode_status mode_status = MODE_OK; ++ int max_tmds_clock = info->max_tmds_clock ? info->max_tmds_clock : 340000; ++ int clock = mode->clock; + + /* We don't support double-clocked modes */ + if (mode->flags & DRM_MODE_FLAG_DBLCLK) + return MODE_BAD; + ++ if (pdata->ycbcr_420_allowed && drm_mode_is_420(info, mode) && ++ (info->color_formats & DRM_COLOR_FORMAT_YCRCB420)) ++ clock /= 2; ++ ++ if (clock > max_tmds_clock) ++ return MODE_CLOCK_HIGH; ++ + if (pdata->mode_valid) + mode_status = pdata->mode_valid(hdmi, pdata->priv_data, info, + mode); + +From 2960613151591dd65e3b7dac4bc760ad0cddd4b6 Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Fri, 20 Dec 2019 08:12:42 +0000 +Subject: [PATCH] WIP: drm/rockchip: dw_hdmi: add 10-bit rgb bus format + +--- + drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 41 +++++++++++++++++++++ + drivers/gpu/drm/rockchip/rockchip_drm_drv.h | 2 + + 2 files changed, 43 insertions(+) + +diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +index e7fbeb9132fb..cd87ee8a65c3 100644 +--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c ++++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +@@ -77,6 +77,7 @@ struct rockchip_hdmi { + }; + + #define to_rockchip_hdmi(x) container_of(x, struct rockchip_hdmi, x) ++#define to_crtc_state(x) container_of(x, struct drm_crtc_state, x) + + static const struct dw_hdmi_mpll_config rockchip_mpll_cfg[] = { + { +@@ -282,6 +283,11 @@ dw_hdmi_rockchip_bridge_mode_set(struct drm_bridge *bridge, + const struct drm_display_mode *adjusted_mode) + { + struct rockchip_hdmi *hdmi = to_rockchip_hdmi(bridge); ++ struct drm_crtc_state *crtc_state = to_crtc_state(adjusted_mode); ++ struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc_state); ++ ++ if (hdmi->phy) ++ phy_set_bus_width(hdmi->phy, s->bus_width); + + clk_set_rate(hdmi->vpll_clk, adjusted_mode->clock * 1000); + } +@@ -320,6 +326,7 @@ static void dw_hdmi_rockchip_bridge_enable(struct drm_bridge *bridge) + static bool is_rgb(u32 format) + { + switch (format) { ++ case MEDIA_BUS_FMT_RGB101010_1X30: + case MEDIA_BUS_FMT_RGB888_1X24: + return true; + default: +@@ -327,6 +334,16 @@ static bool is_rgb(u32 format) + } + } + ++static bool is_10bit(u32 format) ++{ ++ switch (format) { ++ case MEDIA_BUS_FMT_RGB101010_1X30: ++ return true; ++ default: ++ return false; ++ } ++} ++ + static int + dw_hdmi_rockchip_bridge_atomic_check(struct drm_bridge *bridge, + struct drm_bridge_state *bridge_state, +@@ -334,9 +351,24 @@ dw_hdmi_rockchip_bridge_atomic_check(struct drm_bridge *bridge, + struct drm_connector_state *conn_state) + { + struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc_state); ++ struct drm_atomic_state *state = bridge_state->base.state; ++ struct drm_crtc_state *old_crtc_state; ++ struct rockchip_crtc_state *old_state; ++ u32 format = bridge_state->output_bus_cfg.format; + + s->output_mode = ROCKCHIP_OUT_MODE_AAAA; + s->output_type = DRM_MODE_CONNECTOR_HDMIA; ++ s->output_bpc = 10; ++ s->bus_format = format; ++ s->bus_width = is_10bit(format) ? 10 : 8; ++ ++ old_crtc_state = drm_atomic_get_old_crtc_state(state, conn_state->crtc); ++ if (old_crtc_state && !crtc_state->mode_changed) { ++ old_state = to_rockchip_crtc_state(old_crtc_state); ++ if (s->bus_format != old_state->bus_format || ++ s->bus_width != old_state->bus_width) ++ crtc_state->mode_changed = true; ++ } + + return 0; + } +@@ -348,10 +380,19 @@ static u32 *dw_hdmi_rockchip_get_input_bus_fmts(struct drm_bridge *bridge, + u32 output_fmt, + unsigned int *num_input_fmts) + { ++ struct rockchip_hdmi *hdmi = to_rockchip_hdmi(bridge); ++ struct drm_encoder *encoder = bridge->encoder; + u32 *input_fmt; ++ bool has_10bit = true; + + *num_input_fmts = 0; + ++ if (drm_of_encoder_active_endpoint_id(hdmi->dev->of_node, encoder)) ++ has_10bit = false; ++ ++ if (!has_10bit && is_10bit(output_fmt)) ++ return NULL; ++ + if (!is_rgb(output_fmt)) + return NULL; + +diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h +index e33c2dcd0d4b..03944e08b6c7 100644 +--- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h ++++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h +@@ -31,6 +31,8 @@ struct rockchip_crtc_state { + int output_bpc; + int output_flags; + bool enable_afbc; ++ u32 bus_format; ++ int bus_width; + }; + #define to_rockchip_crtc_state(s) \ + container_of(s, struct rockchip_crtc_state, base) + +From 7eda226a69e0c2b4fd8ab41b51ddff08da682073 Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Sun, 8 Dec 2019 23:42:44 +0000 +Subject: [PATCH] WIP: drm: dw-hdmi: add content type connector property + +Signed-off-by: Jonas Karlman +--- + drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +index 26c64cf2d00a..ffb72e6874c8 100644 +--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c ++++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +@@ -1646,6 +1646,7 @@ static void hdmi_config_AVI(struct dw_hdmi *hdmi, + const struct drm_connector *connector, + const struct drm_display_mode *mode) + { ++ const struct drm_connector_state *conn_state = connector->state; + struct hdmi_avi_infoframe frame; + u8 val; + +@@ -1703,6 +1704,8 @@ static void hdmi_config_AVI(struct dw_hdmi *hdmi, + HDMI_EXTENDED_COLORIMETRY_XV_YCC_601; + } + ++ drm_hdmi_avi_infoframe_content_type(&frame, conn_state); ++ + /* + * The Designware IP uses a different byte format from standard + * AVI info frames, though generally the bits are in the correct +@@ -2437,7 +2440,8 @@ static int dw_hdmi_connector_atomic_check(struct drm_connector *connector, + if (!crtc) + return 0; + +- if (!hdr_metadata_equal(old_state, new_state)) { ++ if (!hdr_metadata_equal(old_state, new_state) || ++ old_state->content_type != new_state->content_type) { + crtc_state = drm_atomic_get_crtc_state(state, crtc); + if (IS_ERR(crtc_state)) + return PTR_ERR(crtc_state); +@@ -2505,6 +2509,8 @@ static int dw_hdmi_connector_create(struct dw_hdmi *hdmi) + + drm_connector_attach_max_bpc_property(connector, 8, 16); + ++ drm_connector_attach_content_type_property(connector); ++ + if (hdmi->version >= 0x200a && hdmi->plat_data->use_drm_infoframe) + drm_object_attach_property(&connector->base, + connector->dev->mode_config.hdr_output_metadata_property, 0); + +From 8e94faae53df05c7466387b65edc808218f15277 Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Fri, 20 Dec 2019 08:12:43 +0000 +Subject: [PATCH] WIP: drm/rockchip: add yuv444 support + +--- + drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 30 ++++++++++++++++++++- + drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 29 ++++++++++++++++++++ + drivers/gpu/drm/rockchip/rockchip_drm_vop.h | 6 +++++ + drivers/gpu/drm/rockchip/rockchip_vop_reg.c | 14 ++++++++++ + 4 files changed, 78 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +index cd87ee8a65c3..436a9223e5e4 100644 +--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c ++++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +@@ -62,6 +62,7 @@ struct rockchip_hdmi_chip_data { + int lcdsel_grf_reg; + u32 lcdsel_big; + u32 lcdsel_lit; ++ bool ycbcr_444_allowed; + }; + + struct rockchip_hdmi { +@@ -334,10 +335,22 @@ static bool is_rgb(u32 format) + } + } + ++static bool is_yuv444(u32 format) ++{ ++ switch (format) { ++ case MEDIA_BUS_FMT_YUV10_1X30: ++ case MEDIA_BUS_FMT_YUV8_1X24: ++ return true; ++ default: ++ return false; ++ } ++} ++ + static bool is_10bit(u32 format) + { + switch (format) { + case MEDIA_BUS_FMT_RGB101010_1X30: ++ case MEDIA_BUS_FMT_YUV10_1X30: + return true; + default: + return false; +@@ -354,12 +367,22 @@ dw_hdmi_rockchip_bridge_atomic_check(struct drm_bridge *bridge, + struct drm_atomic_state *state = bridge_state->base.state; + struct drm_crtc_state *old_crtc_state; + struct rockchip_crtc_state *old_state; ++ struct drm_bridge *next_bridge; ++ struct drm_bridge_state *next_bridge_state; + u32 format = bridge_state->output_bus_cfg.format; + + s->output_mode = ROCKCHIP_OUT_MODE_AAAA; + s->output_type = DRM_MODE_CONNECTOR_HDMIA; + s->output_bpc = 10; + s->bus_format = format; ++ ++ next_bridge = drm_bridge_get_next_bridge(bridge); ++ if (next_bridge) { ++ next_bridge_state = drm_atomic_get_new_bridge_state(state, ++ next_bridge); ++ format = next_bridge_state->output_bus_cfg.format; ++ } ++ + s->bus_width = is_10bit(format) ? 10 : 8; + + old_crtc_state = drm_atomic_get_old_crtc_state(state, conn_state->crtc); +@@ -393,7 +416,10 @@ static u32 *dw_hdmi_rockchip_get_input_bus_fmts(struct drm_bridge *bridge, + if (!has_10bit && is_10bit(output_fmt)) + return NULL; + +- if (!is_rgb(output_fmt)) ++ if (is_yuv444(output_fmt)) { ++ if (!hdmi->chip_data->ycbcr_444_allowed) ++ return NULL; ++ } else if (!is_rgb(output_fmt)) + return NULL; + + input_fmt = kzalloc(sizeof(*input_fmt), GFP_KERNEL); +@@ -542,6 +568,7 @@ static const struct dw_hdmi_phy_ops rk3328_hdmi_phy_ops = { + + static struct rockchip_hdmi_chip_data rk3328_chip_data = { + .lcdsel_grf_reg = -1, ++ .ycbcr_444_allowed = true, + }; + + static const struct dw_hdmi_plat_data rk3328_hdmi_drv_data = { +@@ -557,6 +584,7 @@ static struct rockchip_hdmi_chip_data rk3399_chip_data = { + .lcdsel_grf_reg = RK3399_GRF_SOC_CON20, + .lcdsel_big = HIWORD_UPDATE(0, RK3399_HDMI_LCDC_SEL), + .lcdsel_lit = HIWORD_UPDATE(RK3399_HDMI_LCDC_SEL, RK3399_HDMI_LCDC_SEL), ++ .ycbcr_444_allowed = true, + }; + + static const struct dw_hdmi_plat_data rk3399_hdmi_drv_data = { +diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +index 5ab1412173a7..a17bd4e90ba7 100644 +--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c ++++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +@@ -310,6 +310,17 @@ static int vop_convert_afbc_format(uint32_t format) + return -EINVAL; + } + ++static bool is_yuv_output(uint32_t bus_format) ++{ ++ switch (bus_format) { ++ case MEDIA_BUS_FMT_YUV8_1X24: ++ case MEDIA_BUS_FMT_YUV10_1X30: ++ return true; ++ default: ++ return false; ++ } ++} ++ + static uint16_t scl_vop_cal_scale(enum scale_mode mode, uint32_t src, + uint32_t dst, bool is_horizontal, + int vsu_mode, int *vskiplines) +@@ -1329,6 +1340,7 @@ static void vop_crtc_atomic_enable(struct drm_crtc *crtc, + u16 vact_end = vact_st + vdisplay; + uint32_t pin_pol, val; + int dither_bpc = s->output_bpc ? s->output_bpc : 10; ++ bool yuv_output = is_yuv_output(s->bus_format); + int ret; + + if (old_state && old_state->self_refresh_active) { +@@ -1402,6 +1414,8 @@ static void vop_crtc_atomic_enable(struct drm_crtc *crtc, + !(vop_data->feature & VOP_FEATURE_OUTPUT_RGB10)) + s->output_mode = ROCKCHIP_OUT_MODE_P888; + ++ VOP_REG_SET(vop, common, dsp_data_swap, yuv_output ? 2 : 0); ++ + if (s->output_mode == ROCKCHIP_OUT_MODE_AAAA && dither_bpc <= 8) + VOP_REG_SET(vop, common, pre_dither_down, 1); + else +@@ -1417,6 +1431,21 @@ static void vop_crtc_atomic_enable(struct drm_crtc *crtc, + + VOP_REG_SET(vop, common, out_mode, s->output_mode); + ++ VOP_REG_SET(vop, common, overlay_mode, yuv_output); ++ VOP_REG_SET(vop, common, dsp_out_yuv, yuv_output); ++ ++ /* ++ * Background color is 10bit depth if vop version >= 3.5 ++ */ ++ if (!yuv_output) ++ val = 0; ++ else if (VOP_MAJOR(vop_data->version) == 3 && ++ VOP_MINOR(vop_data->version) >= 5) ++ val = 0x20010200; ++ else ++ val = 0x801080; ++ VOP_REG_SET(vop, common, dsp_background, val); ++ + VOP_REG_SET(vop, modeset, htotal_pw, (htotal << 16) | hsync_len); + val = hact_st << 16; + val |= hact_end; +diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h +index 1516231bbf93..b820ad3fa091 100644 +--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h ++++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h +@@ -92,10 +92,16 @@ struct vop_common { + struct vop_reg mmu_en; + struct vop_reg out_mode; + struct vop_reg standby; ++ ++ struct vop_reg overlay_mode; ++ struct vop_reg dsp_data_swap; ++ struct vop_reg dsp_out_yuv; ++ struct vop_reg dsp_background; + }; + + struct vop_misc { + struct vop_reg global_regdone_en; ++ struct vop_reg win_channel[4]; + }; + + struct vop_intr { +diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c +index 57c36e9207c1..800b9341dd42 100644 +--- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c ++++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c +@@ -644,6 +644,11 @@ static const struct vop_common rk3288_common = { + .dsp_blank = VOP_REG(RK3288_DSP_CTRL0, 0x3, 18), + .out_mode = VOP_REG(RK3288_DSP_CTRL0, 0xf, 0), + .cfg_done = VOP_REG_SYNC(RK3288_REG_CFG_DONE, 0x1, 0), ++ ++ .overlay_mode = VOP_REG(RK3288_SYS_CTRL, 0x1, 16), ++ .dsp_data_swap = VOP_REG(RK3288_DSP_CTRL0, 0x1f, 12), ++ .dsp_out_yuv = VOP_REG(RK3288_POST_SCL_CTRL, 0x1, 2), ++ .dsp_background = VOP_REG(RK3288_DSP_BG, 0xffffffff, 0), + }; + + /* +@@ -996,6 +1001,10 @@ static const struct vop_output rk3328_output = { + + static const struct vop_misc rk3328_misc = { + .global_regdone_en = VOP_REG(RK3328_SYS_CTRL, 0x1, 11), ++ ++ .win_channel[0] = VOP_REG(RK3328_WIN0_CTRL2, 0xff, 0), ++ .win_channel[1] = VOP_REG(RK3328_WIN1_CTRL2, 0xff, 0), ++ .win_channel[2] = VOP_REG(RK3328_WIN2_CTRL2, 0xff, 0), + }; + + static const struct vop_common rk3328_common = { +@@ -1008,6 +1017,11 @@ static const struct vop_common rk3328_common = { + .dsp_blank = VOP_REG(RK3328_DSP_CTRL0, 0x3, 18), + .out_mode = VOP_REG(RK3328_DSP_CTRL0, 0xf, 0), + .cfg_done = VOP_REG_SYNC(RK3328_REG_CFG_DONE, 0x1, 0), ++ ++ .overlay_mode = VOP_REG(RK3328_SYS_CTRL, 0x1, 16), ++ .dsp_data_swap = VOP_REG(RK3328_DSP_CTRL0, 0x1f, 12), ++ .dsp_out_yuv = VOP_REG(RK3328_POST_SCL_CTRL, 0x1, 2), ++ .dsp_background = VOP_REG(RK3328_DSP_BG, 0xffffffff, 0), + }; + + static const struct vop_intr rk3328_vop_intr = { + +From d5563c9163f1a691e73c1b027d39c78672ff3e17 Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Fri, 20 Dec 2019 08:12:43 +0000 +Subject: [PATCH] WIP: drm/rockchip: add yuv420 support + +--- + drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 23 +++++++++++++++++++++ + drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 18 +++++++++++++++- + drivers/gpu/drm/rockchip/rockchip_drm_vop.h | 10 +++++---- + drivers/gpu/drm/rockchip/rockchip_vop_reg.c | 2 ++ + 4 files changed, 48 insertions(+), 5 deletions(-) + +diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +index 436a9223e5e4..1abc46a023a4 100644 +--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c ++++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +@@ -346,9 +346,21 @@ static bool is_yuv444(u32 format) + } + } + ++static bool is_yuv420(u32 format) ++{ ++ switch (format) { ++ case MEDIA_BUS_FMT_UYYVYY10_0_5X30: ++ case MEDIA_BUS_FMT_UYYVYY8_0_5X24: ++ return true; ++ default: ++ return false; ++ } ++} ++ + static bool is_10bit(u32 format) + { + switch (format) { ++ case MEDIA_BUS_FMT_UYYVYY10_0_5X30: + case MEDIA_BUS_FMT_RGB101010_1X30: + case MEDIA_BUS_FMT_YUV10_1X30: + return true; +@@ -385,6 +397,11 @@ dw_hdmi_rockchip_bridge_atomic_check(struct drm_bridge *bridge, + + s->bus_width = is_10bit(format) ? 10 : 8; + ++ if (is_yuv420(format)) { ++ s->output_mode = ROCKCHIP_OUT_MODE_YUV420; ++ s->bus_width /= 2; ++ } ++ + old_crtc_state = drm_atomic_get_old_crtc_state(state, conn_state->crtc); + if (old_crtc_state && !crtc_state->mode_changed) { + old_state = to_rockchip_crtc_state(old_crtc_state); +@@ -405,6 +422,7 @@ static u32 *dw_hdmi_rockchip_get_input_bus_fmts(struct drm_bridge *bridge, + { + struct rockchip_hdmi *hdmi = to_rockchip_hdmi(bridge); + struct drm_encoder *encoder = bridge->encoder; ++ struct drm_connector *connector = conn_state->connector; + u32 *input_fmt; + bool has_10bit = true; + +@@ -419,6 +437,9 @@ static u32 *dw_hdmi_rockchip_get_input_bus_fmts(struct drm_bridge *bridge, + if (is_yuv444(output_fmt)) { + if (!hdmi->chip_data->ycbcr_444_allowed) + return NULL; ++ } else if (is_yuv420(output_fmt)) { ++ if (!connector->ycbcr_420_allowed) ++ return NULL; + } else if (!is_rgb(output_fmt)) + return NULL; + +@@ -578,6 +599,7 @@ static const struct dw_hdmi_plat_data rk3328_hdmi_drv_data = { + .phy_name = "inno_dw_hdmi_phy2", + .phy_force_vendor = true, + .use_drm_infoframe = true, ++ .ycbcr_420_allowed = true, + }; + + static struct rockchip_hdmi_chip_data rk3399_chip_data = { +@@ -595,6 +617,7 @@ static const struct dw_hdmi_plat_data rk3399_hdmi_drv_data = { + .phy_config = rockchip_phy_config, + .phy_data = &rk3399_chip_data, + .use_drm_infoframe = true, ++ .ycbcr_420_allowed = true, + }; + + static const struct of_device_id dw_hdmi_rockchip_dt_ids[] = { +diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +index a17bd4e90ba7..5ea8031eb0f7 100644 +--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c ++++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +@@ -311,6 +311,19 @@ static int vop_convert_afbc_format(uint32_t format) + } + + static bool is_yuv_output(uint32_t bus_format) ++{ ++ switch (bus_format) { ++ case MEDIA_BUS_FMT_YUV8_1X24: ++ case MEDIA_BUS_FMT_YUV10_1X30: ++ case MEDIA_BUS_FMT_UYYVYY8_0_5X24: ++ case MEDIA_BUS_FMT_UYYVYY10_0_5X30: ++ return true; ++ default: ++ return false; ++ } ++} ++ ++static bool has_uv_swapped(uint32_t bus_format) + { + switch (bus_format) { + case MEDIA_BUS_FMT_YUV8_1X24: +@@ -1414,7 +1427,7 @@ static void vop_crtc_atomic_enable(struct drm_crtc *crtc, + !(vop_data->feature & VOP_FEATURE_OUTPUT_RGB10)) + s->output_mode = ROCKCHIP_OUT_MODE_P888; + +- VOP_REG_SET(vop, common, dsp_data_swap, yuv_output ? 2 : 0); ++ VOP_REG_SET(vop, common, dsp_data_swap, has_uv_swapped(s->bus_format) ? 2 : 0); + + if (s->output_mode == ROCKCHIP_OUT_MODE_AAAA && dither_bpc <= 8) + VOP_REG_SET(vop, common, pre_dither_down, 1); +@@ -1431,6 +1444,9 @@ static void vop_crtc_atomic_enable(struct drm_crtc *crtc, + + VOP_REG_SET(vop, common, out_mode, s->output_mode); + ++ VOP_REG_SET(vop, common, dclk_ddr, ++ s->output_mode == ROCKCHIP_OUT_MODE_YUV420 ? 1 : 0); ++ + VOP_REG_SET(vop, common, overlay_mode, yuv_output); + VOP_REG_SET(vop, common, dsp_out_yuv, yuv_output); + +diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h +index b820ad3fa091..8e6e999e5163 100644 +--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h ++++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h +@@ -94,6 +94,7 @@ struct vop_common { + struct vop_reg standby; + + struct vop_reg overlay_mode; ++ struct vop_reg dclk_ddr; + struct vop_reg dsp_data_swap; + struct vop_reg dsp_out_yuv; + struct vop_reg dsp_background; +@@ -257,11 +258,12 @@ struct vop_data { + /* + * display output interface supported by rockchip lcdc + */ +-#define ROCKCHIP_OUT_MODE_P888 0 +-#define ROCKCHIP_OUT_MODE_P666 1 +-#define ROCKCHIP_OUT_MODE_P565 2 ++#define ROCKCHIP_OUT_MODE_P888 0 ++#define ROCKCHIP_OUT_MODE_P666 1 ++#define ROCKCHIP_OUT_MODE_P565 2 ++#define ROCKCHIP_OUT_MODE_YUV420 14 + /* for use special outface */ +-#define ROCKCHIP_OUT_MODE_AAAA 15 ++#define ROCKCHIP_OUT_MODE_AAAA 15 + + /* output flags */ + #define ROCKCHIP_OUTPUT_DSI_DUAL BIT(0) +diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c +index 800b9341dd42..dd4546f9f410 100644 +--- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c ++++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c +@@ -646,6 +646,7 @@ static const struct vop_common rk3288_common = { + .cfg_done = VOP_REG_SYNC(RK3288_REG_CFG_DONE, 0x1, 0), + + .overlay_mode = VOP_REG(RK3288_SYS_CTRL, 0x1, 16), ++ .dclk_ddr = VOP_REG(RK3288_DSP_CTRL0, 0x1, 8), + .dsp_data_swap = VOP_REG(RK3288_DSP_CTRL0, 0x1f, 12), + .dsp_out_yuv = VOP_REG(RK3288_POST_SCL_CTRL, 0x1, 2), + .dsp_background = VOP_REG(RK3288_DSP_BG, 0xffffffff, 0), +@@ -1019,6 +1020,7 @@ static const struct vop_common rk3328_common = { + .cfg_done = VOP_REG_SYNC(RK3328_REG_CFG_DONE, 0x1, 0), + + .overlay_mode = VOP_REG(RK3328_SYS_CTRL, 0x1, 16), ++ .dclk_ddr = VOP_REG(RK3328_DSP_CTRL0, 0x1, 8), + .dsp_data_swap = VOP_REG(RK3328_DSP_CTRL0, 0x1f, 12), + .dsp_out_yuv = VOP_REG(RK3328_POST_SCL_CTRL, 0x1, 2), + .dsp_background = VOP_REG(RK3328_DSP_BG, 0xffffffff, 0), + +From 1b47a0a13f295cff2a50f6b4af272b7ee1f01534 Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Sun, 7 Jun 2020 20:25:25 +0000 +Subject: [PATCH] drm: drm_fourcc: add NV20 and NV30 YUV formats + +DRM_FORMAT_NV20 and DRM_FORMAT_NV30 formats is the 2x1 and non-subsampled +variant of NV15, a 10-bit 2-plane YUV format that has no padding between +components. Instead, luminance and chrominance samples are grouped into 4s +so that each group is packed into an integer number of bytes: + +YYYY = UVUV = 4 * 10 bits = 40 bits = 5 bytes + +The '20' and '30' suffix refers to the optimum effective bits per pixel +which is achieved when the total number of luminance samples is a multiple +of 4. + +V2: Added NV30 format + +Signed-off-by: Jonas Karlman +--- + drivers/gpu/drm/drm_fourcc.c | 8 ++++++++ + include/uapi/drm/drm_fourcc.h | 2 ++ + 2 files changed, 10 insertions(+) + +diff --git a/drivers/gpu/drm/drm_fourcc.c b/drivers/gpu/drm/drm_fourcc.c +index 722c7ebe4e88..2daf8a304b53 100644 +--- a/drivers/gpu/drm/drm_fourcc.c ++++ b/drivers/gpu/drm/drm_fourcc.c +@@ -278,6 +278,14 @@ const struct drm_format_info *__drm_format_info(u32 format) + .num_planes = 2, .char_per_block = { 5, 5, 0 }, + .block_w = { 4, 2, 0 }, .block_h = { 1, 1, 0 }, .hsub = 2, + .vsub = 2, .is_yuv = true }, ++ { .format = DRM_FORMAT_NV20, .depth = 0, ++ .num_planes = 2, .char_per_block = { 5, 5, 0 }, ++ .block_w = { 4, 2, 0 }, .block_h = { 1, 1, 0 }, .hsub = 2, ++ .vsub = 1, .is_yuv = true }, ++ { .format = DRM_FORMAT_NV30, .depth = 0, ++ .num_planes = 2, .char_per_block = { 5, 5, 0 }, ++ .block_w = { 4, 2, 0 }, .block_h = { 1, 1, 0 }, .hsub = 1, ++ .vsub = 1, .is_yuv = true }, + { .format = DRM_FORMAT_Q410, .depth = 0, + .num_planes = 3, .char_per_block = { 2, 2, 2 }, + .block_w = { 1, 1, 1 }, .block_h = { 1, 1, 1 }, .hsub = 0, +diff --git a/include/uapi/drm/drm_fourcc.h b/include/uapi/drm/drm_fourcc.h +index 82f327801267..d8e6159213dc 100644 +--- a/include/uapi/drm/drm_fourcc.h ++++ b/include/uapi/drm/drm_fourcc.h +@@ -242,6 +242,8 @@ extern "C" { + * index 1 = Cr:Cb plane, [39:0] Cr1:Cb1:Cr0:Cb0 little endian + */ + #define DRM_FORMAT_NV15 fourcc_code('N', 'V', '1', '5') /* 2x2 subsampled Cr:Cb plane */ ++#define DRM_FORMAT_NV20 fourcc_code('N', 'V', '2', '0') /* 2x1 subsampled Cr:Cb plane */ ++#define DRM_FORMAT_NV30 fourcc_code('N', 'V', '3', '0') /* non-subsampled Cr:Cb plane */ + + /* + * 2 plane YCbCr MSB aligned + +From 6c52f23c9f8215a7a5a99d6ac299701baa85a8cb Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Sun, 7 Jun 2020 20:25:26 +0000 +Subject: [PATCH] drm: rockchip: add NV15, NV20 and NV30 support + +Add support for displaying 10-bit 4:2:0 and 4:2:2 formats produced by the +Rockchip Video Decoder on RK322X, RK3288, RK3328, RK3368 and RK3399. +Also add support for 10-bit 4:4:4 format while at it. + +V2: Added NV30 support + +Signed-off-by: Jonas Karlman +--- + drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 29 +++++++++++++++++-- + drivers/gpu/drm/rockchip/rockchip_drm_vop.h | 1 + + drivers/gpu/drm/rockchip/rockchip_vop_reg.c | 32 +++++++++++++++++---- + 3 files changed, 54 insertions(+), 8 deletions(-) + +diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +index 5ea8031eb0f7..413534cf1a93 100644 +--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c ++++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +@@ -261,6 +261,18 @@ static bool has_rb_swapped(uint32_t format) + } + } + ++static bool is_fmt_10(uint32_t format) ++{ ++ switch (format) { ++ case DRM_FORMAT_NV15: ++ case DRM_FORMAT_NV20: ++ case DRM_FORMAT_NV30: ++ return true; ++ default: ++ return false; ++ } ++} ++ + static enum vop_data_format vop_convert_format(uint32_t format) + { + switch (format) { +@@ -276,10 +288,13 @@ static enum vop_data_format vop_convert_format(uint32_t format) + case DRM_FORMAT_BGR565: + return VOP_FMT_RGB565; + case DRM_FORMAT_NV12: ++ case DRM_FORMAT_NV15: + return VOP_FMT_YUV420SP; + case DRM_FORMAT_NV16: ++ case DRM_FORMAT_NV20: + return VOP_FMT_YUV422SP; + case DRM_FORMAT_NV24: ++ case DRM_FORMAT_NV30: + return VOP_FMT_YUV444SP; + default: + DRM_ERROR("unsupported format[%08x]\n", format); +@@ -946,7 +961,12 @@ static void vop_plane_atomic_update(struct drm_plane *plane, + dsp_sty = dest->y1 + crtc->mode.vtotal - crtc->mode.vsync_start; + dsp_st = dsp_sty << 16 | (dsp_stx & 0xffff); + +- offset = (src->x1 >> 16) * fb->format->cpp[0]; ++ if (fb->format->block_w[0]) ++ offset = (src->x1 >> 16) * fb->format->char_per_block[0] / ++ fb->format->block_w[0]; ++ else ++ offset = (src->x1 >> 16) * fb->format->cpp[0]; ++ + offset += (src->y1 >> 16) * fb->pitches[0]; + dma_addr = rk_obj->dma_addr + offset + fb->offsets[0]; + +@@ -972,6 +992,7 @@ static void vop_plane_atomic_update(struct drm_plane *plane, + } + + VOP_WIN_SET(vop, win, format, format); ++ VOP_WIN_SET(vop, win, fmt_10, is_fmt_10(fb->format->format)); + VOP_WIN_SET(vop, win, yrgb_vir, DIV_ROUND_UP(fb->pitches[0], 4)); + VOP_WIN_SET(vop, win, yrgb_mst, dma_addr); + VOP_WIN_YUV2YUV_SET(vop, win_yuv2yuv, y2r_en, is_yuv); +@@ -988,7 +1009,11 @@ static void vop_plane_atomic_update(struct drm_plane *plane, + uv_obj = fb->obj[1]; + rk_uv_obj = to_rockchip_obj(uv_obj); + +- offset = (src->x1 >> 16) * bpp / hsub; ++ if (fb->format->block_w[1]) ++ offset = (src->x1 >> 16) * bpp / ++ fb->format->block_w[1] / hsub; ++ else ++ offset = (src->x1 >> 16) * bpp / hsub; + offset += (src->y1 >> 16) * fb->pitches[1] / vsub; + + dma_addr = rk_uv_obj->dma_addr + offset + fb->offsets[1]; +diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h +index 8e6e999e5163..9f50e0e00127 100644 +--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h ++++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h +@@ -161,6 +161,7 @@ struct vop_win_phy { + struct vop_reg enable; + struct vop_reg gate; + struct vop_reg format; ++ struct vop_reg fmt_10; + struct vop_reg rb_swap; + struct vop_reg act_info; + struct vop_reg dsp_info; +diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c +index dd4546f9f410..7d5191421ddf 100644 +--- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c ++++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c +@@ -50,6 +50,23 @@ static const uint32_t formats_win_full[] = { + DRM_FORMAT_NV24, + }; + ++static const uint32_t formats_win_full_10[] = { ++ DRM_FORMAT_XRGB8888, ++ DRM_FORMAT_ARGB8888, ++ DRM_FORMAT_XBGR8888, ++ DRM_FORMAT_ABGR8888, ++ DRM_FORMAT_RGB888, ++ DRM_FORMAT_BGR888, ++ DRM_FORMAT_RGB565, ++ DRM_FORMAT_BGR565, ++ DRM_FORMAT_NV12, ++ DRM_FORMAT_NV16, ++ DRM_FORMAT_NV24, ++ DRM_FORMAT_NV15, ++ DRM_FORMAT_NV20, ++ DRM_FORMAT_NV30, ++}; ++ + static const uint64_t format_modifiers_win_full[] = { + DRM_FORMAT_MOD_LINEAR, + DRM_FORMAT_MOD_INVALID, +@@ -579,11 +596,12 @@ static const struct vop_scl_regs rk3288_win_full_scl = { + + static const struct vop_win_phy rk3288_win01_data = { + .scl = &rk3288_win_full_scl, +- .data_formats = formats_win_full, +- .nformats = ARRAY_SIZE(formats_win_full), ++ .data_formats = formats_win_full_10, ++ .nformats = ARRAY_SIZE(formats_win_full_10), + .format_modifiers = format_modifiers_win_full, + .enable = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 0), + .format = VOP_REG(RK3288_WIN0_CTRL0, 0x7, 1), ++ .fmt_10 = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 4), + .rb_swap = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 12), + .act_info = VOP_REG(RK3288_WIN0_ACT_INFO, 0x1fff1fff, 0), + .dsp_info = VOP_REG(RK3288_WIN0_DSP_INFO, 0x0fff0fff, 0), +@@ -720,11 +738,12 @@ static const struct vop_intr rk3368_vop_intr = { + + static const struct vop_win_phy rk3368_win01_data = { + .scl = &rk3288_win_full_scl, +- .data_formats = formats_win_full, +- .nformats = ARRAY_SIZE(formats_win_full), ++ .data_formats = formats_win_full_10, ++ .nformats = ARRAY_SIZE(formats_win_full_10), + .format_modifiers = format_modifiers_win_full, + .enable = VOP_REG(RK3368_WIN0_CTRL0, 0x1, 0), + .format = VOP_REG(RK3368_WIN0_CTRL0, 0x7, 1), ++ .fmt_10 = VOP_REG(RK3368_WIN0_CTRL0, 0x1, 4), + .rb_swap = VOP_REG(RK3368_WIN0_CTRL0, 0x1, 12), + .x_mir_en = VOP_REG(RK3368_WIN0_CTRL0, 0x1, 21), + .y_mir_en = VOP_REG(RK3368_WIN0_CTRL0, 0x1, 22), +@@ -871,11 +890,12 @@ static const struct vop_win_yuv2yuv_data rk3399_vop_big_win_yuv2yuv_data[] = { + + static const struct vop_win_phy rk3399_win01_data = { + .scl = &rk3288_win_full_scl, +- .data_formats = formats_win_full, +- .nformats = ARRAY_SIZE(formats_win_full), ++ .data_formats = formats_win_full_10, ++ .nformats = ARRAY_SIZE(formats_win_full_10), + .format_modifiers = format_modifiers_win_full_afbc, + .enable = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 0), + .format = VOP_REG(RK3288_WIN0_CTRL0, 0x7, 1), ++ .fmt_10 = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 4), + .rb_swap = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 12), + .y_mir_en = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 22), + .act_info = VOP_REG(RK3288_WIN0_ACT_INFO, 0x1fff1fff, 0), + +From 82b749d252ad0a50a36ad7ca93335e8d8e5416b7 Mon Sep 17 00:00:00 2001 +From: Alex Bee +Date: Sat, 15 Aug 2020 21:11:08 +0200 +Subject: [PATCH] drm/rockchip: rk3368's vop does not support 10-bit formats - + neither as input nor as output + +--- + drivers/gpu/drm/rockchip/rockchip_vop_reg.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c +index 7d5191421ddf..20c3e6248ec7 100644 +--- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c ++++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c +@@ -738,8 +738,8 @@ static const struct vop_intr rk3368_vop_intr = { + + static const struct vop_win_phy rk3368_win01_data = { + .scl = &rk3288_win_full_scl, +- .data_formats = formats_win_full_10, +- .nformats = ARRAY_SIZE(formats_win_full_10), ++ .data_formats = formats_win_full, ++ .nformats = ARRAY_SIZE(formats_win_full), + .format_modifiers = format_modifiers_win_full, + .enable = VOP_REG(RK3368_WIN0_CTRL0, 0x1, 0), + .format = VOP_REG(RK3368_WIN0_CTRL0, 0x7, 1), + +From 74b287a1526a234bd9450461087f7b3ae53ead5f Mon Sep 17 00:00:00 2001 +From: Alex Bee +Date: Sat, 15 Aug 2020 23:20:34 +0200 +Subject: [PATCH] drm/rockchip: enable ycbcr_420_allowed and ycbcr_444_allowed + for RK3228 + +--- + drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +index 1abc46a023a4..64a79b33ff18 100644 +--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c ++++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +@@ -555,6 +555,7 @@ static const struct dw_hdmi_phy_ops rk3228_hdmi_phy_ops = { + + static struct rockchip_hdmi_chip_data rk3228_chip_data = { + .lcdsel_grf_reg = -1, ++ .ycbcr_444_allowed = true, + }; + + static const struct dw_hdmi_plat_data rk3228_hdmi_drv_data = { +@@ -563,6 +564,7 @@ static const struct dw_hdmi_plat_data rk3228_hdmi_drv_data = { + .phy_ops = &rk3228_hdmi_phy_ops, + .phy_name = "inno_dw_hdmi_phy2", + .phy_force_vendor = true, ++ .ycbcr_420_allowed = true, + }; + + static struct rockchip_hdmi_chip_data rk3288_chip_data = { + +From 93f930ae209a684210098a2612df72b19b8db88a Mon Sep 17 00:00:00 2001 +From: Alex Bee +Date: Wed, 22 Jul 2020 20:13:28 +0200 +Subject: [PATCH] drm: rockchip: add scaling for RK3036 win1 + +Add the registers needed to make scaling work on RK3036's win1. + +Signed-off-by: Alex Bee +--- + drivers/gpu/drm/rockchip/rockchip_vop_reg.c | 10 ++++++++-- + 1 file changed, 8 insertions(+), 2 deletions(-) + +diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c +index 20c3e6248ec7..93a00b6ac295 100644 +--- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c ++++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c +@@ -94,15 +94,20 @@ static const uint64_t format_modifiers_win_lite[] = { + DRM_FORMAT_MOD_INVALID, + }; + +-static const struct vop_scl_regs rk3036_win_scl = { ++static const struct vop_scl_regs rk3036_win0_scl = { + .scale_yrgb_x = VOP_REG(RK3036_WIN0_SCL_FACTOR_YRGB, 0xffff, 0x0), + .scale_yrgb_y = VOP_REG(RK3036_WIN0_SCL_FACTOR_YRGB, 0xffff, 16), + .scale_cbcr_x = VOP_REG(RK3036_WIN0_SCL_FACTOR_CBR, 0xffff, 0x0), + .scale_cbcr_y = VOP_REG(RK3036_WIN0_SCL_FACTOR_CBR, 0xffff, 16), + }; + ++static const struct vop_scl_regs rk3036_win1_scl = { ++ .scale_yrgb_x = VOP_REG(RK3036_WIN1_SCL_FACTOR_YRGB, 0xffff, 0x0), ++ .scale_yrgb_y = VOP_REG(RK3036_WIN1_SCL_FACTOR_YRGB, 0xffff, 16), ++}; ++ + static const struct vop_win_phy rk3036_win0_data = { +- .scl = &rk3036_win_scl, ++ .scl = &rk3036_win0_scl, + .data_formats = formats_win_full, + .nformats = ARRAY_SIZE(formats_win_full), + .format_modifiers = format_modifiers_win_full, +@@ -119,6 +124,7 @@ static const struct vop_win_phy rk3036_win0_data = { + }; + + static const struct vop_win_phy rk3036_win1_data = { ++ .scl = &rk3036_win1_scl, + .data_formats = formats_win_lite, + .nformats = ARRAY_SIZE(formats_win_lite), + .format_modifiers = format_modifiers_win_lite, + +From 5251b3cefd51bbf0c28da354b8e59e4f540d4b94 Mon Sep 17 00:00:00 2001 +From: Alex Bee +Date: Wed, 22 Jul 2020 20:13:29 +0200 +Subject: [PATCH] drm: rockchip: add missing registers for RK3188 + +Add dither_up, dsp_lut_en and data_blank registers to enable their +respective functionality for RK3188's VOP. + +Signed-off-by: Alex Bee +--- + drivers/gpu/drm/rockchip/rockchip_vop_reg.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c +index 93a00b6ac295..2638d084f9ce 100644 +--- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c ++++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c +@@ -529,6 +529,9 @@ static const struct vop_common rk3188_common = { + .dither_down_en = VOP_REG(RK3188_DSP_CTRL0, 0x1, 11), + .dither_down_mode = VOP_REG(RK3188_DSP_CTRL0, 0x1, 10), + .dsp_blank = VOP_REG(RK3188_DSP_CTRL1, 0x3, 24), ++ .dither_up = VOP_REG(RK3188_DSP_CTRL0, 0x1, 9), ++ .dsp_lut_en = VOP_REG(RK3188_SYS_CTRL, 0x1, 28), ++ .data_blank = VOP_REG(RK3188_DSP_CTRL1, 0x1, 25), + }; + + static const struct vop_win_data rk3188_vop_win_data[] = { + +From cb6d552767e2ce4b79be85cdb3a1526869d11ce4 Mon Sep 17 00:00:00 2001 +From: Alex Bee +Date: Wed, 22 Jul 2020 20:13:30 +0200 +Subject: [PATCH] drm: rockchip: add alpha support for RK3036, RK3066, RK3126 + and RK3188 + +With commit 2aae8ed1f390 +("drm/rockchip: Add per-pixel alpha support for the PX30 VOP") alpha +support was introduced for PX30's VOP. +RK3036, RK3066, RK3126 and RK3188 VOPs support alpha blending in the +same manner. +With the exception of RK3066 all of them support pre-multiplied alpha. + +Lets add these registers to make this work for those VOPs as well. + +Signed-off-by: Alex Bee +--- + drivers/gpu/drm/rockchip/rockchip_vop_reg.c | 21 +++++++++++++++++++++ + drivers/gpu/drm/rockchip/rockchip_vop_reg.h | 1 + + 2 files changed, 22 insertions(+) + +diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c +index 2638d084f9ce..e1db4e57c51a 100644 +--- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c ++++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c +@@ -121,6 +121,9 @@ static const struct vop_win_phy rk3036_win0_data = { + .uv_mst = VOP_REG(RK3036_WIN0_CBR_MST, 0xffffffff, 0), + .yrgb_vir = VOP_REG(RK3036_WIN0_VIR, 0xffff, 0), + .uv_vir = VOP_REG(RK3036_WIN0_VIR, 0x1fff, 16), ++ .alpha_mode = VOP_REG(RK3036_DSP_CTRL0, 0x1, 18), ++ .alpha_en = VOP_REG(RK3036_ALPHA_CTRL, 0x1, 0), ++ .alpha_pre_mul = VOP_REG(RK3036_DSP_CTRL0, 0x1, 29), + }; + + static const struct vop_win_phy rk3036_win1_data = { +@@ -136,6 +139,9 @@ static const struct vop_win_phy rk3036_win1_data = { + .dsp_st = VOP_REG(RK3036_WIN1_DSP_ST, 0x1fff1fff, 0), + .yrgb_mst = VOP_REG(RK3036_WIN1_MST, 0xffffffff, 0), + .yrgb_vir = VOP_REG(RK3036_WIN1_VIR, 0xffff, 0), ++ .alpha_mode = VOP_REG(RK3036_DSP_CTRL0, 0x1, 19), ++ .alpha_en = VOP_REG(RK3036_ALPHA_CTRL, 0x1, 1), ++ .alpha_pre_mul = VOP_REG(RK3036_DSP_CTRL0, 0x1, 29), + }; + + static const struct vop_win_data rk3036_vop_win_data[] = { +@@ -202,6 +208,9 @@ static const struct vop_win_phy rk3126_win1_data = { + .dsp_st = VOP_REG(RK3126_WIN1_DSP_ST, 0x1fff1fff, 0), + .yrgb_mst = VOP_REG(RK3126_WIN1_MST, 0xffffffff, 0), + .yrgb_vir = VOP_REG(RK3036_WIN1_VIR, 0xffff, 0), ++ .alpha_mode = VOP_REG(RK3036_DSP_CTRL0, 0x1, 19), ++ .alpha_en = VOP_REG(RK3036_ALPHA_CTRL, 0x1, 1), ++ .alpha_pre_mul = VOP_REG(RK3036_DSP_CTRL0, 0x1, 29), + }; + + static const struct vop_win_data rk3126_vop_win_data[] = { +@@ -381,6 +390,8 @@ static const struct vop_win_phy rk3066_win0_data = { + .uv_mst = VOP_REG(RK3066_WIN0_CBR_MST0, 0xffffffff, 0), + .yrgb_vir = VOP_REG(RK3066_WIN0_VIR, 0xffff, 0), + .uv_vir = VOP_REG(RK3066_WIN0_VIR, 0x1fff, 16), ++ .alpha_mode = VOP_REG(RK3066_DSP_CTRL0, 0x1, 21), ++ .alpha_en = VOP_REG(RK3066_BLEND_CTRL, 0x1, 0), + }; + + static const struct vop_win_phy rk3066_win1_data = { +@@ -398,6 +409,8 @@ static const struct vop_win_phy rk3066_win1_data = { + .uv_mst = VOP_REG(RK3066_WIN1_CBR_MST, 0xffffffff, 0), + .yrgb_vir = VOP_REG(RK3066_WIN1_VIR, 0xffff, 0), + .uv_vir = VOP_REG(RK3066_WIN1_VIR, 0x1fff, 16), ++ .alpha_mode = VOP_REG(RK3066_DSP_CTRL0, 0x1, 22), ++ .alpha_en = VOP_REG(RK3066_BLEND_CTRL, 0x1, 1), + }; + + static const struct vop_win_phy rk3066_win2_data = { +@@ -411,6 +424,8 @@ static const struct vop_win_phy rk3066_win2_data = { + .dsp_st = VOP_REG(RK3066_WIN2_DSP_ST, 0x1fff1fff, 0), + .yrgb_mst = VOP_REG(RK3066_WIN2_MST, 0xffffffff, 0), + .yrgb_vir = VOP_REG(RK3066_WIN2_VIR, 0xffff, 0), ++ .alpha_mode = VOP_REG(RK3066_DSP_CTRL0, 0x1, 23), ++ .alpha_en = VOP_REG(RK3066_BLEND_CTRL, 0x1, 2), + }; + + static const struct vop_modeset rk3066_modeset = { +@@ -493,6 +508,9 @@ static const struct vop_win_phy rk3188_win0_data = { + .yrgb_mst = VOP_REG(RK3188_WIN0_YRGB_MST0, 0xffffffff, 0), + .uv_mst = VOP_REG(RK3188_WIN0_CBR_MST0, 0xffffffff, 0), + .yrgb_vir = VOP_REG(RK3188_WIN_VIR, 0x1fff, 0), ++ .alpha_mode = VOP_REG(RK3188_DSP_CTRL0, 0x1, 18), ++ .alpha_en = VOP_REG(RK3188_ALPHA_CTRL, 0x1, 0), ++ .alpha_pre_mul = VOP_REG(RK3188_DSP_CTRL0, 0x1, 29), + }; + + static const struct vop_win_phy rk3188_win1_data = { +@@ -507,6 +525,9 @@ static const struct vop_win_phy rk3188_win1_data = { + .dsp_st = VOP_REG(RK3188_WIN1_DSP_ST, 0x0fff0fff, 0), + .yrgb_mst = VOP_REG(RK3188_WIN1_MST, 0xffffffff, 0), + .yrgb_vir = VOP_REG(RK3188_WIN_VIR, 0x1fff, 16), ++ .alpha_mode = VOP_REG(RK3188_DSP_CTRL0, 0x1, 19), ++ .alpha_en = VOP_REG(RK3188_ALPHA_CTRL, 0x1, 1), ++ .alpha_pre_mul = VOP_REG(RK3188_DSP_CTRL0, 0x1, 29), + }; + + static const struct vop_modeset rk3188_modeset = { +diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.h b/drivers/gpu/drm/rockchip/rockchip_vop_reg.h +index 6e9fa5815d4d..0b3cd65ba5c1 100644 +--- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.h ++++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.h +@@ -955,6 +955,7 @@ + #define RK3188_DSP_CTRL0 0x04 + #define RK3188_DSP_CTRL1 0x08 + #define RK3188_INT_STATUS 0x10 ++#define RK3188_ALPHA_CTRL 0x14 + #define RK3188_WIN0_YRGB_MST0 0x20 + #define RK3188_WIN0_CBR_MST0 0x24 + #define RK3188_WIN0_YRGB_MST1 0x28 + +From 931fd5e26f3b2dd7a758124dc9c024e944eeedb4 Mon Sep 17 00:00:00 2001 +From: Alex Bee +Date: Wed, 22 Jul 2020 20:13:31 +0200 +Subject: [PATCH] drm: rockchip: set alpha_en to 0 if it is not used + +alpha_en should be set to 0 if it is not used, i.e. to disable alpha +blending if it was enabled before and should be disabled now. + +Fixes: 2aae8ed1f390 ("drm/rockchip: Add per-pixel alpha support for the PX30 VOP") + +Signed-off-by: Alex Bee +--- + drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +index 413534cf1a93..9b1cc0f413fc 100644 +--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c ++++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +@@ -1062,6 +1062,7 @@ static void vop_plane_atomic_update(struct drm_plane *plane, + VOP_WIN_SET(vop, win, alpha_en, 1); + } else { + VOP_WIN_SET(vop, win, src_alpha_ctl, SRC_ALPHA_EN(0)); ++ VOP_WIN_SET(vop, win, alpha_en, 0); + } + + VOP_WIN_SET(vop, win, enable, 1); + +From 87f111b8511eb1236c53ea4369502cf4c6847303 Mon Sep 17 00:00:00 2001 +From: Alex Bee +Date: Sat, 15 Aug 2020 23:38:05 +0200 +Subject: [PATCH] rockchip/drm: add dsp_data_swap register for RK3188 + +--- + drivers/gpu/drm/rockchip/rockchip_vop_reg.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c +index e1db4e57c51a..e10cb2d33951 100644 +--- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c ++++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c +@@ -553,6 +553,7 @@ static const struct vop_common rk3188_common = { + .dither_up = VOP_REG(RK3188_DSP_CTRL0, 0x1, 9), + .dsp_lut_en = VOP_REG(RK3188_SYS_CTRL, 0x1, 28), + .data_blank = VOP_REG(RK3188_DSP_CTRL1, 0x1, 25), ++ .dsp_data_swap = VOP_REG(RK3188_DSP_CTRL1, 0x1f, 26), + }; + + static const struct vop_win_data rk3188_vop_win_data[] = { + +From 75e43e951351c5f0d269d7b788a9469a1ccadb48 Mon Sep 17 00:00:00 2001 +From: Alex Bee +Date: Sun, 16 Aug 2020 00:55:19 +0200 +Subject: [PATCH] drm/rockchip: inno hdmi - add audio support - add required + aclk - fix video timing - fix phy pre-emphasis + +--- + .../display/rockchip/inno_hdmi-rockchip.txt | 6 +- + arch/arm/boot/dts/rk3036.dtsi | 24 +- + drivers/gpu/drm/rockchip/inno_hdmi.c | 266 +++++++++++++++++- + drivers/gpu/drm/rockchip/inno_hdmi.h | 2 + + 4 files changed, 279 insertions(+), 19 deletions(-) + +diff --git a/Documentation/devicetree/bindings/display/rockchip/inno_hdmi-rockchip.txt b/Documentation/devicetree/bindings/display/rockchip/inno_hdmi-rockchip.txt +index cec21714f0e0..b022c931e186 100644 +--- a/Documentation/devicetree/bindings/display/rockchip/inno_hdmi-rockchip.txt ++++ b/Documentation/devicetree/bindings/display/rockchip/inno_hdmi-rockchip.txt +@@ -7,7 +7,7 @@ Required properties: + - reg: + Physical base address and length of the controller's registers. + - clocks, clock-names: +- Phandle to hdmi controller clock, name should be "pclk" ++ Phandle to hdmi controller clock, name should be "aclk" and "pclk". + - interrupts: + HDMI interrupt number + - ports: +@@ -21,8 +21,8 @@ hdmi: hdmi@20034000 { + compatible = "rockchip,rk3036-inno-hdmi"; + reg = <0x20034000 0x4000>; + interrupts = ; +- clocks = <&cru PCLK_HDMI>; +- clock-names = "pclk"; ++ clocks = <&cru ACLK_VIO>, <&cru PCLK_HDMI>; ++ clock-names = "aclk", "pclk"; + pinctrl-names = "default"; + pinctrl-0 = <&hdmi_ctl>; + +diff --git a/arch/arm/boot/dts/rk3036.dtsi b/arch/arm/boot/dts/rk3036.dtsi +index dda5a1f79aca..6be6d9d134fe 100644 +--- a/arch/arm/boot/dts/rk3036.dtsi ++++ b/arch/arm/boot/dts/rk3036.dtsi +@@ -344,11 +344,14 @@ hdmi: hdmi@20034000 { + compatible = "rockchip,rk3036-inno-hdmi"; + reg = <0x20034000 0x4000>; + interrupts = ; +- clocks = <&cru PCLK_HDMI>; +- clock-names = "pclk"; ++ clocks = <&cru ACLK_VIO>, <&cru PCLK_HDMI>; ++ clock-names = "aclk", "pclk"; + rockchip,grf = <&grf>; + pinctrl-names = "default"; + pinctrl-0 = <&hdmi_ctl>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ #sound-dai-cells = <0>; + status = "disabled"; + + hdmi_in: port { +@@ -361,6 +364,23 @@ hdmi_in_vop: endpoint@0 { + }; + }; + ++ hdmi_sound: hdmi-sound { ++ compatible = "simple-audio-card"; ++ simple-audio-card,name = "HDMI"; ++ status = "disabled"; ++ ++ simple-audio-card,dai-link { ++ format = "i2s"; ++ mclk-fs = <256>; ++ cpu { ++ sound-dai = <&i2s>; ++ }; ++ codec { ++ sound-dai = <&hdmi>; ++ }; ++ }; ++ }; ++ + timer: timer@20044000 { + compatible = "rockchip,rk3036-timer", "rockchip,rk3288-timer"; + reg = <0x20044000 0x20>; +diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c b/drivers/gpu/drm/rockchip/inno_hdmi.c +index 7afdc54eb3ec..7e93208609a0 100644 +--- a/drivers/gpu/drm/rockchip/inno_hdmi.c ++++ b/drivers/gpu/drm/rockchip/inno_hdmi.c +@@ -14,6 +14,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -21,6 +22,8 @@ + #include + #include + ++#include ++ + #include "rockchip_drm_drv.h" + #include "rockchip_drm_vop.h" + +@@ -28,6 +31,12 @@ + + #define to_inno_hdmi(x) container_of(x, struct inno_hdmi, x) + ++struct audio_info { ++ int sample_rate; ++ int channels; ++ int sample_width; ++}; ++ + struct hdmi_data_info { + int vic; + bool sink_is_hdmi; +@@ -52,8 +61,10 @@ struct inno_hdmi { + struct drm_device *drm_dev; + + int irq; ++ struct clk *aclk; + struct clk *pclk; + void __iomem *regs; ++ struct regmap *regmap; + + struct drm_connector connector; + struct drm_encoder encoder; +@@ -63,6 +74,9 @@ struct inno_hdmi { + + unsigned int tmds_rate; + ++ struct platform_device *audio_pdev; ++ bool audio_enable; ++ + struct hdmi_data_info hdmi_data; + struct drm_display_mode previous_mode; + }; +@@ -189,11 +203,17 @@ static void inno_hdmi_sys_power(struct inno_hdmi *hdmi, bool enable) + + static void inno_hdmi_set_pwr_mode(struct inno_hdmi *hdmi, int mode) + { ++ ++ u8 value; ++ + switch (mode) { + case NORMAL: + inno_hdmi_sys_power(hdmi, false); +- +- hdmi_writeb(hdmi, HDMI_PHY_PRE_EMPHASIS, 0x6f); ++ if (hdmi->tmds_rate > 140000000) ++ value = 0x6f; ++ else ++ value = 0x3f; ++ hdmi_writeb(hdmi, HDMI_PHY_PRE_EMPHASIS, value); + hdmi_writeb(hdmi, HDMI_PHY_DRIVER, 0xbb); + + hdmi_writeb(hdmi, HDMI_PHY_SYS_CTL, 0x15); +@@ -301,6 +321,21 @@ static int inno_hdmi_config_video_avi(struct inno_hdmi *hdmi, + return inno_hdmi_upload_frame(hdmi, rc, &frame, INFOFRAME_AVI, 0, 0, 0); + } + ++static int inno_hdmi_config_audio_aai(struct inno_hdmi *hdmi, ++ struct audio_info *audio) ++{ ++ struct hdmi_audio_infoframe *faudio; ++ union hdmi_infoframe frame; ++ int rc; ++ ++ rc = hdmi_audio_infoframe_init(&frame.audio); ++ faudio = (struct hdmi_audio_infoframe *)&frame; ++ ++ faudio->channels = audio->channels; ++ ++ return inno_hdmi_upload_frame(hdmi, rc, &frame, INFOFRAME_AAI, 0, 0, 0); ++} ++ + static int inno_hdmi_config_video_csc(struct inno_hdmi *hdmi) + { + struct hdmi_data_info *data = &hdmi->hdmi_data; +@@ -383,6 +418,11 @@ static int inno_hdmi_config_video_timing(struct inno_hdmi *hdmi, + { + int value; + ++ value = BIT(20) | BIT(21); ++ value |= mode->flags & DRM_MODE_FLAG_PHSYNC ? BIT(4) : 0; ++ value |= mode->flags & DRM_MODE_FLAG_PVSYNC ? BIT(5) : 0; ++ regmap_write(hdmi->regmap, 0x148, value); ++ + /* Set detail external video timing polarity and interlace mode */ + value = v_EXTERANL_VIDEO(1); + value |= mode->flags & DRM_MODE_FLAG_PHSYNC ? +@@ -402,7 +442,7 @@ static int inno_hdmi_config_video_timing(struct inno_hdmi *hdmi, + hdmi_writeb(hdmi, HDMI_VIDEO_EXT_HBLANK_L, value & 0xFF); + hdmi_writeb(hdmi, HDMI_VIDEO_EXT_HBLANK_H, (value >> 8) & 0xFF); + +- value = mode->hsync_start - mode->hdisplay; ++ value = mode->htotal - mode->hsync_start; + hdmi_writeb(hdmi, HDMI_VIDEO_EXT_HDELAY_L, value & 0xFF); + hdmi_writeb(hdmi, HDMI_VIDEO_EXT_HDELAY_H, (value >> 8) & 0xFF); + +@@ -417,7 +457,7 @@ static int inno_hdmi_config_video_timing(struct inno_hdmi *hdmi, + value = mode->vtotal - mode->vdisplay; + hdmi_writeb(hdmi, HDMI_VIDEO_EXT_VBLANK, value & 0xFF); + +- value = mode->vsync_start - mode->vdisplay; ++ value = mode->vtotal - mode->vsync_start; + hdmi_writeb(hdmi, HDMI_VIDEO_EXT_VDELAY, value & 0xFF); + + value = mode->vsync_end - mode->vsync_start; +@@ -473,8 +513,9 @@ static int inno_hdmi_setup(struct inno_hdmi *hdmi, + inno_hdmi_i2c_init(hdmi); + + /* Unmute video and audio output */ +- hdmi_modb(hdmi, HDMI_AV_MUTE, m_AUDIO_MUTE | m_VIDEO_BLACK, +- v_AUDIO_MUTE(0) | v_VIDEO_MUTE(0)); ++ hdmi_modb(hdmi, HDMI_AV_MUTE, m_VIDEO_BLACK, v_VIDEO_MUTE(0)); ++ if (hdmi->audio_enable) ++ hdmi_modb(hdmi, HDMI_AV_MUTE, m_AUDIO_MUTE, v_AUDIO_MUTE(0)); + + return 0; + } +@@ -521,6 +562,7 @@ inno_hdmi_encoder_atomic_check(struct drm_encoder *encoder, + + s->output_mode = ROCKCHIP_OUT_MODE_P888; + s->output_type = DRM_MODE_CONNECTOR_HDMIA; ++ s->bus_format = MEDIA_BUS_FMT_RGB888_1X24; + + return 0; + } +@@ -597,6 +639,175 @@ static struct drm_connector_helper_funcs inno_hdmi_connector_helper_funcs = { + .mode_valid = inno_hdmi_connector_mode_valid, + }; + ++int inno_hdmi_audio_config_set(struct inno_hdmi *hdmi, struct audio_info *audio) ++{ ++ int rate, N, channel; ++ ++ if (audio->channels < 3) ++ channel = I2S_CHANNEL_1_2; ++ else if (audio->channels < 5) ++ channel = I2S_CHANNEL_3_4; ++ else if (audio->channels < 7) ++ channel = I2S_CHANNEL_5_6; ++ else ++ channel = I2S_CHANNEL_7_8; ++ ++ switch (audio->sample_rate) { ++ case 32000: ++ rate = AUDIO_32K; ++ N = N_32K; ++ break; ++ case 44100: ++ rate = AUDIO_441K; ++ N = N_441K; ++ break; ++ case 48000: ++ rate = AUDIO_48K; ++ N = N_48K; ++ break; ++ case 88200: ++ rate = AUDIO_882K; ++ N = N_882K; ++ break; ++ case 96000: ++ rate = AUDIO_96K; ++ N = N_96K; ++ break; ++ case 176400: ++ rate = AUDIO_1764K; ++ N = N_1764K; ++ break; ++ case 192000: ++ rate = AUDIO_192K; ++ N = N_192K; ++ break; ++ default: ++ dev_err(hdmi->dev, "[%s] not support such sample rate %d\n", ++ __func__, audio->sample_rate); ++ return -ENOENT; ++ } ++ ++ /* set_audio source I2S */ ++ hdmi_writeb(hdmi, HDMI_AUDIO_CTRL1, 0x01); ++ hdmi_writeb(hdmi, AUDIO_SAMPLE_RATE, rate); ++ hdmi_writeb(hdmi, AUDIO_I2S_MODE, v_I2S_MODE(I2S_STANDARD) | ++ v_I2S_CHANNEL(channel)); ++ ++ hdmi_writeb(hdmi, AUDIO_I2S_MAP, 0x00); ++ hdmi_writeb(hdmi, AUDIO_I2S_SWAPS_SPDIF, 0); ++ ++ /* Set N value */ ++ hdmi_writeb(hdmi, AUDIO_N_H, (N >> 16) & 0x0F); ++ hdmi_writeb(hdmi, AUDIO_N_M, (N >> 8) & 0xFF); ++ hdmi_writeb(hdmi, AUDIO_N_L, N & 0xFF); ++ ++ /*Set hdmi nlpcm mode to support hdmi bitstream*/ ++ hdmi_writeb(hdmi, HDMI_AUDIO_CHANNEL_STATUS, v_AUDIO_STATUS_NLPCM(0)); ++ ++ return inno_hdmi_config_audio_aai(hdmi, audio); ++} ++ ++static int inno_hdmi_audio_hw_params(struct device *dev, void *data, ++ struct hdmi_codec_daifmt *daifmt, ++ struct hdmi_codec_params *params) ++{ ++ struct inno_hdmi *hdmi = dev_get_drvdata(dev); ++ struct audio_info audio = { ++ .sample_width = params->sample_width, ++ .sample_rate = params->sample_rate, ++ .channels = params->channels, ++ }; ++ ++ if (!hdmi->hdmi_data.sink_has_audio) { ++ dev_err(hdmi->dev, "Sink do not support audio!\n"); ++ return -ENODEV; ++ } ++ ++ if (!hdmi->encoder.crtc) ++ return -ENODEV; ++ ++ switch (daifmt->fmt) { ++ case HDMI_I2S: ++ break; ++ default: ++ dev_err(dev, "%s: Invalid format %d\n", __func__, daifmt->fmt); ++ return -EINVAL; ++ } ++ ++ return inno_hdmi_audio_config_set(hdmi, &audio); ++} ++ ++static void inno_hdmi_audio_shutdown(struct device *dev, void *data) ++{ ++ /* do nothing */ ++} ++ ++static int inno_hdmi_audio_digital_mute(struct device *dev, void *data, bool mute) ++{ ++ struct inno_hdmi *hdmi = dev_get_drvdata(dev); ++ ++ if (!hdmi->hdmi_data.sink_has_audio) { ++ dev_err(hdmi->dev, "Sink do not support audio!\n"); ++ return -ENODEV; ++ } ++ ++ hdmi->audio_enable = !mute; ++ ++ if (mute) ++ hdmi_modb(hdmi, HDMI_AV_MUTE, m_AUDIO_MUTE | m_AUDIO_PD, ++ v_AUDIO_MUTE(1) | v_AUDIO_PD(1)); ++ else ++ hdmi_modb(hdmi, HDMI_AV_MUTE, m_AUDIO_MUTE | m_AUDIO_PD, ++ v_AUDIO_MUTE(0) | v_AUDIO_PD(0)); ++ ++ return 0; ++} ++ ++static int inno_hdmi_audio_get_eld(struct device *dev, void *data, ++ uint8_t *buf, size_t len) ++{ ++ struct inno_hdmi *hdmi = dev_get_drvdata(dev); ++ struct drm_mode_config *config = &hdmi->encoder.dev->mode_config; ++ struct drm_connector *connector; ++ int ret = -ENODEV; ++ ++ mutex_lock(&config->mutex); ++ list_for_each_entry(connector, &config->connector_list, head) { ++ if (&hdmi->encoder == connector->encoder) { ++ memcpy(buf, connector->eld, ++ min(sizeof(connector->eld), len)); ++ ret = 0; ++ } ++ } ++ mutex_unlock(&config->mutex); ++ ++ return ret; ++} ++ ++static const struct hdmi_codec_ops audio_codec_ops = { ++ .hw_params = inno_hdmi_audio_hw_params, ++ .audio_shutdown = inno_hdmi_audio_shutdown, ++ .digital_mute = inno_hdmi_audio_digital_mute, ++ .get_eld = inno_hdmi_audio_get_eld, ++}; ++ ++static int inno_hdmi_audio_codec_init(struct inno_hdmi *hdmi, ++ struct device *dev) ++{ ++ struct hdmi_codec_pdata codec_data = { ++ .i2s = 1, ++ .ops = &audio_codec_ops, ++ .max_i2s_channels = 8, ++ }; ++ ++ hdmi->audio_enable = false; ++ hdmi->audio_pdev = platform_device_register_data( ++ dev, HDMI_CODEC_DRV_NAME, PLATFORM_DEVID_NONE, ++ &codec_data, sizeof(codec_data)); ++ ++ return PTR_ERR_OR_ZERO(hdmi->audio_pdev); ++} ++ + static int inno_hdmi_register(struct drm_device *drm, struct inno_hdmi *hdmi) + { + struct drm_encoder *encoder = &hdmi->encoder; +@@ -627,6 +838,8 @@ static int inno_hdmi_register(struct drm_device *drm, struct inno_hdmi *hdmi) + + drm_connector_attach_encoder(&hdmi->connector, encoder); + ++ inno_hdmi_audio_codec_init(hdmi, dev); ++ + return 0; + } + +@@ -826,23 +1039,44 @@ static int inno_hdmi_bind(struct device *dev, struct device *master, + if (IS_ERR(hdmi->regs)) + return PTR_ERR(hdmi->regs); + ++ irq = platform_get_irq(pdev, 0); ++ if (irq < 0) ++ return irq; ++ ++ hdmi->aclk = devm_clk_get(hdmi->dev, "aclk"); ++ if (IS_ERR(hdmi->aclk)) { ++ dev_err(hdmi->dev, "Unable to get HDMI aclk clk\n"); ++ return PTR_ERR(hdmi->aclk); ++ } ++ + hdmi->pclk = devm_clk_get(hdmi->dev, "pclk"); + if (IS_ERR(hdmi->pclk)) { + DRM_DEV_ERROR(hdmi->dev, "Unable to get HDMI pclk clk\n"); + return PTR_ERR(hdmi->pclk); + } + ++ ret = clk_prepare_enable(hdmi->aclk); ++ if (ret) { ++ DRM_DEV_ERROR(hdmi->dev, ++ "Cannot enable HDMI aclk clock: %d\n", ret); ++ return ret; ++ } ++ ++ + ret = clk_prepare_enable(hdmi->pclk); + if (ret) { + DRM_DEV_ERROR(hdmi->dev, + "Cannot enable HDMI pclk clock: %d\n", ret); +- return ret; ++ goto err_disable_aclk; + } + +- irq = platform_get_irq(pdev, 0); +- if (irq < 0) { +- ret = irq; +- goto err_disable_clk; ++ hdmi->regmap = ++ syscon_regmap_lookup_by_phandle(hdmi->dev->of_node, ++ "rockchip,grf"); ++ if (IS_ERR(hdmi->regmap)) { ++ dev_err(hdmi->dev, "Unable to get rockchip,grf\n"); ++ ret = PTR_ERR(hdmi->regmap); ++ goto err_disable_aclk; + } + + inno_hdmi_reset(hdmi); +@@ -851,7 +1085,7 @@ static int inno_hdmi_bind(struct device *dev, struct device *master, + if (IS_ERR(hdmi->ddc)) { + ret = PTR_ERR(hdmi->ddc); + hdmi->ddc = NULL; +- goto err_disable_clk; ++ goto err_disable_pclk; + } + + /* +@@ -884,9 +1118,12 @@ static int inno_hdmi_bind(struct device *dev, struct device *master, + hdmi->encoder.funcs->destroy(&hdmi->encoder); + err_put_adapter: + i2c_put_adapter(hdmi->ddc); +-err_disable_clk: ++err_disable_pclk: + clk_disable_unprepare(hdmi->pclk); +- return ret; ++err_disable_aclk: ++ clk_disable_unprepare(hdmi->aclk); ++ ++return ret; + } + + static void inno_hdmi_unbind(struct device *dev, struct device *master, +@@ -899,6 +1136,7 @@ static void inno_hdmi_unbind(struct device *dev, struct device *master, + + i2c_put_adapter(hdmi->ddc); + clk_disable_unprepare(hdmi->pclk); ++ clk_disable_unprepare(hdmi->aclk); + } + + static const struct component_ops inno_hdmi_ops = { +diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.h b/drivers/gpu/drm/rockchip/inno_hdmi.h +index 93245b55f967..b722afc4e41f 100644 +--- a/drivers/gpu/drm/rockchip/inno_hdmi.h ++++ b/drivers/gpu/drm/rockchip/inno_hdmi.h +@@ -96,11 +96,13 @@ enum { + #define HDMI_AV_MUTE 0x05 + #define m_AVMUTE_CLEAR (1 << 7) + #define m_AVMUTE_ENABLE (1 << 6) ++#define m_AUDIO_PD (1 << 2) + #define m_AUDIO_MUTE (1 << 1) + #define m_VIDEO_BLACK (1 << 0) + #define v_AVMUTE_CLEAR(n) (n << 7) + #define v_AVMUTE_ENABLE(n) (n << 6) + #define v_AUDIO_MUTE(n) (n << 1) ++#define v_AUDIO_PD(n) (n << 2) + #define v_VIDEO_MUTE(n) (n << 0) + + #define HDMI_VIDEO_TIMING_CTL 0x08 + +From fd3c78e6eec709b6a70af8a175c6965d0112f372 Mon Sep 17 00:00:00 2001 +From: Phong LE +Date: Wed, 11 Mar 2020 13:51:33 +0100 +Subject: [PATCH] dt-bindings: display: bridge: add it66121 bindings + +Add the ITE bridge HDMI it66121 bindings. + +Signed-off-by: Phong LE +--- + .../bindings/display/bridge/ite,it66121.yaml | 98 +++++++++++++++++++ + 1 file changed, 98 insertions(+) + create mode 100644 Documentation/devicetree/bindings/display/bridge/ite,it66121.yaml + +diff --git a/Documentation/devicetree/bindings/display/bridge/ite,it66121.yaml b/Documentation/devicetree/bindings/display/bridge/ite,it66121.yaml +new file mode 100644 +index 000000000000..1717e880d130 +--- /dev/null ++++ b/Documentation/devicetree/bindings/display/bridge/ite,it66121.yaml +@@ -0,0 +1,98 @@ ++# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/display/bridge/ite,it66121.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: ITE it66121 HDMI bridge Device Tree Bindings ++ ++maintainers: ++ - Phong LE ++ - Neil Armstrong ++ ++description: | ++ The IT66121 is a high-performance and low-power single channel HDMI ++ transmitter, fully compliant with HDMI 1.3a, HDCP 1.2 and backward compatible ++ to DVI 1.0 specifications. ++ ++properties: ++ compatible: ++ const: ite,it66121 ++ ++ reg: ++ maxItems: 1 ++ description: base I2C address of the device ++ ++ reset-gpios: ++ maxItems: 1 ++ description: GPIO connected to active low reset ++ ++ vrf12-supply: ++ maxItems: 1 ++ description: Regulator for 1.2V analog core power. ++ ++ vcn33-supply: ++ maxItems: 1 ++ description: Regulator for 3.3V digital core power. ++ ++ vcn18-supply: ++ maxItems: 1 ++ description: Regulator for 1.8V IO core power. ++ ++ interrupts: ++ maxItems: 1 ++ ++ pclk-dual-edge: ++ maxItems: 1 ++ description: enable pclk dual edge mode. ++ ++ port: ++ type: object ++ ++ properties: ++ endpoint: ++ type: object ++ description: | ++ Input endpoints of the bridge. ++ ++ required: ++ - endpoint ++ ++required: ++ - compatible ++ - reg ++ - reset-gpios ++ - vrf12-supply ++ - vcn33-supply ++ - vcn18-supply ++ - interrupts ++ - port ++ ++additionalProperties: false ++ ++examples: ++ - | ++ i2c6 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ it66121hdmitx: it66121hdmitx@4c { ++ compatible = "ite,it66121"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&ite_pins_default>; ++ vcn33-supply = <&mt6358_vcn33_wifi_reg>; ++ vcn18-supply = <&mt6358_vcn18_reg>; ++ vrf12-supply = <&mt6358_vrf12_reg>; ++ reset-gpios = <&pio 160 1 /* GPIO_ACTIVE_LOW */>; ++ interrupt-parent = <&pio>; ++ interrupts = <4 8 /* IRQ_TYPE_LEVEL_LOW */>; ++ reg = <0x4c>; ++ pclk-dual-edge; ++ ++ port { ++ it66121_in: endpoint { ++ remote-endpoint = <&display_out>; ++ }; ++ }; ++ }; ++ }; + +From 28d8fb9319bee0252c3b756966298a065bfa16c5 Mon Sep 17 00:00:00 2001 +From: Phong LE +Date: Wed, 11 Mar 2020 13:51:34 +0100 +Subject: [PATCH] drm: bridge: add it66121 driver + +This commit is a simple driver for bridge HMDI it66121. +The input format is RBG and there is no color conversion. +Audio, HDCP and CEC are not supported yet. + +Signed-off-by: Phong LE +--- + drivers/gpu/drm/bridge/Kconfig | 8 + + drivers/gpu/drm/bridge/Makefile | 1 + + drivers/gpu/drm/bridge/ite-it66121.c | 997 +++++++++++++++++++++++++++ + 3 files changed, 1006 insertions(+) + create mode 100644 drivers/gpu/drm/bridge/ite-it66121.c + +diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig +index 43271c21d3fc..204246d65f44 100644 +--- a/drivers/gpu/drm/bridge/Kconfig ++++ b/drivers/gpu/drm/bridge/Kconfig +@@ -48,6 +48,14 @@ config DRM_DISPLAY_CONNECTOR + on ARM-based platforms. Saying Y here when this driver is not needed + will not cause any issue. + ++config DRM_ITE_IT66121 ++ tristate "ITE IT66121 HDMI bridge" ++ depends on OF ++ select DRM_KMS_HELPER ++ select REGMAP_I2C ++ help ++ Support for ITE IT66121 HDMI bridge. ++ + config DRM_LVDS_CODEC + tristate "Transparent LVDS encoders and decoders support" + depends on OF +diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile +index d63d4b7e4347..ffa91a5a6bda 100644 +--- a/drivers/gpu/drm/bridge/Makefile ++++ b/drivers/gpu/drm/bridge/Makefile +@@ -2,6 +2,7 @@ + obj-$(CONFIG_DRM_CDNS_DSI) += cdns-dsi.o + obj-$(CONFIG_DRM_CHRONTEL_CH7033) += chrontel-ch7033.o + obj-$(CONFIG_DRM_DISPLAY_CONNECTOR) += display-connector.o ++obj-$(CONFIG_DRM_ITE_IT66121) += ite-it66121.o + obj-$(CONFIG_DRM_LVDS_CODEC) += lvds-codec.o + obj-$(CONFIG_DRM_MEGACHIPS_STDPXXXX_GE_B850V3_FW) += megachips-stdpxxxx-ge-b850v3-fw.o + obj-$(CONFIG_DRM_NXP_PTN3460) += nxp-ptn3460.o +diff --git a/drivers/gpu/drm/bridge/ite-it66121.c b/drivers/gpu/drm/bridge/ite-it66121.c +new file mode 100644 +index 000000000000..7e1a90319a6a +--- /dev/null ++++ b/drivers/gpu/drm/bridge/ite-it66121.c +@@ -0,0 +1,997 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* ++ * Copyright (C) 2020 BayLibre, SAS ++ * Author: Phong LE ++ * Copyright (C) 2018-2019, Artem Mygaiev ++ * Copyright (C) 2017, Fresco Logic, Incorporated. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define IT66121_MASTER_SEL_REG 0x10 ++#define IT66121_MASTER_SEL_HOST BIT(0) ++ ++#define IT66121_AFE_DRV_REG 0x61 ++#define IT66121_AFE_DRV_RST BIT(4) ++#define IT66121_AFE_DRV_PWD BIT(5) ++ ++#define IT66121_INPUT_MODE_REG 0x70 ++#define IT66121_INPUT_MODE_RGB (0 << 6) ++#define IT66121_INPUT_MODE_YUV422 BIT(6) ++#define IT66121_INPUT_MODE_YUV444 (2 << 6) ++#define IT66121_INPUT_MODE_CCIR656 BIT(4) ++#define IT66121_INPUT_MODE_SYNCEMB BIT(3) ++#define IT66121_INPUT_MODE_DDR BIT(2) ++ ++#define IT66121_INPUT_CSC_REG 0x72 ++#define IT66121_INPUT_CSC_ENDITHER BIT(7) ++#define IT66121_INPUT_CSC_ENUDFILTER BIT(6) ++#define IT66121_INPUT_CSC_DNFREE_GO BIT(5) ++#define IT66121_INPUT_CSC_RGB_TO_YUV 0x02 ++#define IT66121_INPUT_CSC_YUV_TO_RGB 0x03 ++#define IT66121_INPUT_CSC_NO_CONV 0x00 ++ ++#define IT66121_AFE_XP_REG 0x62 ++#define IT66121_AFE_XP_GAINBIT BIT(7) ++#define IT66121_AFE_XP_PWDPLL BIT(6) ++#define IT66121_AFE_XP_ENI BIT(5) ++#define IT66121_AFE_XP_ENO BIT(4) ++#define IT66121_AFE_XP_RESETB BIT(3) ++#define IT66121_AFE_XP_PWDI BIT(2) ++ ++#define IT66121_AFE_IP_REG 0x64 ++#define IT66121_AFE_IP_GAINBIT BIT(7) ++#define IT66121_AFE_IP_PWDPLL BIT(6) ++#define IT66121_AFE_IP_CKSEL_05 (0 << 4) ++#define IT66121_AFE_IP_CKSEL_1 BIT(4) ++#define IT66121_AFE_IP_CKSEL_2 (2 << 4) ++#define IT66121_AFE_IP_CKSEL_2OR4 (3 << 4) ++#define IT66121_AFE_IP_ER0 BIT(3) ++#define IT66121_AFE_IP_RESETB BIT(2) ++#define IT66121_AFE_IP_ENC BIT(1) ++#define IT66121_AFE_IP_EC1 BIT(0) ++ ++#define IT66121_AFE_XP_EC1_REG 0x68 ++#define IT66121_AFE_XP_EC1_LOWCLK BIT(4) ++ ++#define IT66121_SW_RST_REG 0x04 ++#define IT66121_SW_RST_REF BIT(5) ++#define IT66121_SW_RST_AREF BIT(4) ++#define IT66121_SW_RST_VID BIT(3) ++#define IT66121_SW_RST_AUD BIT(2) ++#define IT66121_SW_RST_HDCP BIT(0) ++ ++#define IT66121_DDC_COMMAND_REG 0x15 ++#define IT66121_DDC_COMMAND_BURST_READ 0x0 ++#define IT66121_DDC_COMMAND_EDID_READ 0x3 ++#define IT66121_DDC_COMMAND_FIFO_CLR 0x9 ++#define IT66121_DDC_COMMAND_SCL_PULSE 0xA ++#define IT66121_DDC_COMMAND_ABORT 0xF ++ ++#define IT66121_HDCP_REG 0x20 ++#define IT66121_HDCP_CPDESIRED BIT(0) ++#define IT66121_HDCP_EN1P1FEAT BIT(1) ++ ++#define IT66121_INT_STATUS1_REG 0x06 ++#define IT66121_INT_STATUS1_AUD_OVF BIT(7) ++#define IT66121_INT_STATUS1_DDC_NOACK BIT(5) ++#define IT66121_INT_STATUS1_DDC_FIFOERR BIT(4) ++#define IT66121_INT_STATUS1_DDC_BUSHANG BIT(2) ++#define IT66121_INT_STATUS1_RX_SENS_STATUS BIT(1) ++#define IT66121_INT_STATUS1_HPD_STATUS BIT(0) ++ ++#define IT66121_DDC_HEADER_REG 0x11 ++#define IT66121_DDC_HEADER_HDCP 0x74 ++#define IT66121_DDC_HEADER_EDID 0xA0 ++ ++#define IT66121_DDC_OFFSET_REG 0x12 ++#define IT66121_DDC_BYTE_REG 0x13 ++#define IT66121_DDC_SEGMENT_REG 0x14 ++#define IT66121_DDC_RD_FIFO_REG 0x17 ++ ++#define IT66121_CLK_BANK_REG 0x0F ++#define IT66121_CLK_BANK_PWROFF_RCLK BIT(6) ++#define IT66121_CLK_BANK_PWROFF_ACLK BIT(5) ++#define IT66121_CLK_BANK_PWROFF_TXCLK BIT(4) ++#define IT66121_CLK_BANK_PWROFF_CRCLK BIT(3) ++#define IT66121_CLK_BANK_0 0 ++#define IT66121_CLK_BANK_1 1 ++ ++#define IT66121_INT_REG 0x05 ++#define IT66121_INT_ACTIVE_HIGH BIT(7) ++#define IT66121_INT_OPEN_DRAIN BIT(6) ++#define IT66121_INT_TX_CLK_OFF BIT(0) ++ ++#define IT66121_INT_MASK1_REG 0x09 ++#define IT66121_INT_MASK1_AUD_OVF BIT(7) ++#define IT66121_INT_MASK1_DDC_NOACK BIT(5) ++#define IT66121_INT_MASK1_DDC_FIFOERR BIT(4) ++#define IT66121_INT_MASK1_DDC_BUSHANG BIT(2) ++#define IT66121_INT_MASK1_RX_SENS BIT(1) ++#define IT66121_INT_MASK1_HPD BIT(0) ++ ++#define IT66121_INT_CLR1_REG 0x0C ++#define IT66121_INT_CLR1_PKTACP BIT(7) ++#define IT66121_INT_CLR1_PKTNULL BIT(6) ++#define IT66121_INT_CLR1_PKTGEN BIT(5) ++#define IT66121_INT_CLR1_KSVLISTCHK BIT(4) ++#define IT66121_INT_CLR1_AUTHDONE BIT(3) ++#define IT66121_INT_CLR1_AUTHFAIL BIT(2) ++#define IT66121_INT_CLR1_RX_SENS BIT(1) ++#define IT66121_INT_CLR1_HPD BIT(0) ++ ++#define IT66121_AV_MUTE_REG 0xC1 ++#define IT66121_AV_MUTE_ON BIT(0) ++#define IT66121_AV_MUTE_BLUESCR BIT(1) ++ ++#define IT66121_PKT_GEN_CTRL_REG 0xC6 ++#define IT66121_PKT_GEN_CTRL_ON BIT(0) ++#define IT66121_PKT_GEN_CTRL_RPT BIT(1) ++ ++#define IT66121_AVIINFO_DB1_REG 0x158 ++#define IT66121_AVIINFO_DB2_REG 0x159 ++#define IT66121_AVIINFO_DB3_REG 0x15A ++#define IT66121_AVIINFO_DB4_REG 0x15B ++#define IT66121_AVIINFO_DB5_REG 0x15C ++#define IT66121_AVIINFO_CSUM_REG 0x15D ++#define IT66121_AVIINFO_DB6_REG 0x15E ++#define IT66121_AVIINFO_DB7_REG 0x15F ++#define IT66121_AVIINFO_DB8_REG 0x160 ++#define IT66121_AVIINFO_DB9_REG 0x161 ++#define IT66121_AVIINFO_DB10_REG 0x162 ++#define IT66121_AVIINFO_DB11_REG 0x163 ++#define IT66121_AVIINFO_DB12_REG 0x164 ++#define IT66121_AVIINFO_DB13_REG 0x165 ++ ++#define IT66121_AVI_INFO_PKT_REG 0xCD ++#define IT66121_AVI_INFO_PKT_ON BIT(0) ++#define IT66121_AVI_INFO_PKT_RPT BIT(1) ++ ++#define IT66121_HDMI_MODE_REG 0xC0 ++#define IT66121_HDMI_MODE_HDMI BIT(0) ++ ++#define IT66121_SYS_STATUS_REG 0x0E ++#define IT66121_SYS_STATUS_ACTIVE_IRQ BIT(7) ++#define IT66121_SYS_STATUS_HPDETECT BIT(6) ++#define IT66121_SYS_STATUS_SENDECTECT BIT(5) ++#define IT66121_SYS_STATUS_VID_STABLE BIT(4) ++#define IT66121_SYS_STATUS_AUD_CTS_CLR BIT(1) ++#define IT66121_SYS_STATUS_CLEAR_IRQ BIT(0) ++ ++#define IT66121_DDC_STATUS_REG 0x16 ++#define IT66121_DDC_STATUS_TX_DONE BIT(7) ++#define IT66121_DDC_STATUS_ACTIVE BIT(6) ++#define IT66121_DDC_STATUS_NOACK BIT(5) ++#define IT66121_DDC_STATUS_WAIT_BUS BIT(4) ++#define IT66121_DDC_STATUS_ARBI_LOSE BIT(3) ++#define IT66121_DDC_STATUS_FIFO_FULL BIT(2) ++#define IT66121_DDC_STATUS_FIFO_EMPTY BIT(1) ++#define IT66121_DDC_STATUS_FIFO_VALID BIT(0) ++ ++#define IT66121_VENDOR_ID0 0x54 ++#define IT66121_VENDOR_ID1 0x49 ++#define IT66121_DEVICE_ID0 0x12 ++#define IT66121_DEVICE_ID1 0x06 ++#define IT66121_DEVICE_MASK 0x0F ++#define IT66121_EDID_SLEEP 20000 ++#define IT66121_EDID_TIMEOUT 200000 ++#define IT66121_EDID_FIFO_SIZE 32 ++#define IT66121_AFE_CLK_HIGH 80000 ++ ++struct it66121_conf { ++ unsigned int input_mode_reg; ++ unsigned int input_conversion_reg; ++}; ++ ++struct it66121_ctx { ++ struct regmap *regmap; ++ struct drm_bridge bridge; ++ struct drm_connector connector; ++ struct device *dev; ++ struct gpio_desc *gpio_reset; ++ struct i2c_client *client; ++ struct regulator_bulk_data supplies[3]; ++ bool dual_edge; ++ const struct it66121_conf *conf; ++ struct mutex lock; /* Protects fields below and device registers */ ++ struct edid *edid; ++ struct hdmi_avi_infoframe hdmi_avi_infoframe; ++}; ++ ++static const struct regmap_range_cfg it66121_regmap_banks[] = { ++ { ++ .name = "it66121", ++ .range_min = 0x00, ++ .range_max = 0x1FF, ++ .selector_reg = IT66121_CLK_BANK_REG, ++ .selector_mask = 0x1, ++ .selector_shift = 0, ++ .window_start = 0x00, ++ .window_len = 0x130, ++ }, ++}; ++ ++static const struct regmap_config it66121_regmap_config = { ++ .val_bits = 8, ++ .reg_bits = 8, ++ .max_register = 0x1FF, ++ .ranges = it66121_regmap_banks, ++ .num_ranges = ARRAY_SIZE(it66121_regmap_banks), ++}; ++ ++static const struct it66121_conf it66121_conf_simple = { ++ .input_mode_reg = IT66121_INPUT_MODE_RGB | IT66121_INPUT_MODE_DDR, ++ .input_conversion_reg = IT66121_INPUT_CSC_NO_CONV, ++}; ++ ++static void it66121_hw_reset(struct it66121_ctx *ctx) ++{ ++ gpiod_set_value(ctx->gpio_reset, 1); ++ msleep(20); ++ gpiod_set_value(ctx->gpio_reset, 0); ++} ++ ++static int ite66121_power_on(struct it66121_ctx *ctx) ++{ ++ return regulator_bulk_enable(ARRAY_SIZE(ctx->supplies), ctx->supplies); ++} ++ ++static int ite66121_power_off(struct it66121_ctx *ctx) ++{ ++ return regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies); ++} ++ ++static int it66121_preamble_ddc(struct it66121_ctx *ctx) ++{ ++ return regmap_write(ctx->regmap, IT66121_MASTER_SEL_REG, ++ IT66121_MASTER_SEL_HOST); ++} ++ ++static int it66121_fire_afe(struct it66121_ctx *ctx) ++{ ++ return regmap_write(ctx->regmap, IT66121_AFE_DRV_REG, 0); ++} ++ ++static int it66121_configure_input(struct it66121_ctx *ctx) ++{ ++ int ret; ++ ++ ret = regmap_write(ctx->regmap, IT66121_INPUT_MODE_REG, ++ ctx->conf->input_mode_reg); ++ if (ret) ++ return ret; ++ ++ return regmap_write(ctx->regmap, IT66121_INPUT_CSC_REG, ++ ctx->conf->input_conversion_reg); ++} ++ ++/** ++ * it66121_configure_afe() - Configure the analog front end ++ * @ctx: it66121_ctx object ++ * ++ * RETURNS: ++ * zero if success, a negative error code otherwise. ++ */ ++static int it66121_configure_afe(struct it66121_ctx *ctx, ++ const struct drm_display_mode *mode) ++{ ++ int ret; ++ ++ ret = regmap_write(ctx->regmap, IT66121_AFE_DRV_REG, ++ IT66121_AFE_DRV_RST); ++ if (ret) ++ return ret; ++ ++ if (mode->clock > IT66121_AFE_CLK_HIGH) { ++ ret = regmap_write_bits(ctx->regmap, IT66121_AFE_XP_REG, ++ IT66121_AFE_XP_GAINBIT | ++ IT66121_AFE_XP_ENO, ++ IT66121_AFE_XP_GAINBIT); ++ if (ret) ++ return ret; ++ ++ ret = regmap_write_bits(ctx->regmap, IT66121_AFE_IP_REG, ++ IT66121_AFE_IP_GAINBIT | ++ IT66121_AFE_IP_ER0 | ++ IT66121_AFE_IP_EC1, ++ IT66121_AFE_IP_GAINBIT); ++ if (ret) ++ return ret; ++ ++ ret = regmap_write_bits(ctx->regmap, IT66121_AFE_XP_EC1_REG, ++ IT66121_AFE_XP_EC1_LOWCLK, 0x80); ++ if (ret) ++ return ret; ++ } else { ++ ret = regmap_write_bits(ctx->regmap, IT66121_AFE_XP_REG, ++ IT66121_AFE_XP_GAINBIT | ++ IT66121_AFE_XP_ENO, ++ IT66121_AFE_XP_ENO); ++ if (ret) ++ return ret; ++ ++ ret = regmap_write_bits(ctx->regmap, IT66121_AFE_IP_REG, ++ IT66121_AFE_IP_GAINBIT | ++ IT66121_AFE_IP_ER0 | ++ IT66121_AFE_IP_EC1, IT66121_AFE_IP_ER0 | ++ IT66121_AFE_IP_EC1); ++ if (ret) ++ return ret; ++ ++ ret = regmap_write_bits(ctx->regmap, IT66121_AFE_XP_EC1_REG, ++ IT66121_AFE_XP_EC1_LOWCLK, ++ IT66121_AFE_XP_EC1_LOWCLK); ++ if (ret) ++ return ret; ++ } ++ ++ /* Clear reset flags */ ++ ret = regmap_write_bits(ctx->regmap, IT66121_SW_RST_REG, ++ IT66121_SW_RST_REF | IT66121_SW_RST_VID, ++ ~(IT66121_SW_RST_REF | IT66121_SW_RST_VID) & ++ 0xFF); ++ if (ret) ++ return ret; ++ ++ return it66121_fire_afe(ctx); ++} ++ ++static inline int it66121_wait_ddc_ready(struct it66121_ctx *ctx) ++{ ++ int ret, val; ++ ++ ret = regmap_read_poll_timeout(ctx->regmap, IT66121_DDC_STATUS_REG, ++ val, true, ++ IT66121_EDID_SLEEP, ++ IT66121_EDID_TIMEOUT); ++ if (ret) ++ return ret; ++ ++ if (val & (IT66121_DDC_STATUS_NOACK | IT66121_DDC_STATUS_WAIT_BUS | ++ IT66121_DDC_STATUS_ARBI_LOSE)) ++ return -EAGAIN; ++ ++ return 0; ++} ++ ++static int it66121_clear_ddc_fifo(struct it66121_ctx *ctx) ++{ ++ int ret; ++ ++ ret = it66121_preamble_ddc(ctx); ++ if (ret) ++ return ret; ++ ++ return regmap_write(ctx->regmap, IT66121_DDC_COMMAND_REG, ++ IT66121_DDC_COMMAND_FIFO_CLR); ++} ++ ++static int it66121_abort_ddc_ops(struct it66121_ctx *ctx) ++{ ++ int ret; ++ unsigned int swreset, cpdesire; ++ ++ ret = regmap_read(ctx->regmap, IT66121_SW_RST_REG, &swreset); ++ if (ret) ++ return ret; ++ ++ ret = regmap_read(ctx->regmap, IT66121_HDCP_REG, &cpdesire); ++ if (ret) ++ return ret; ++ ++ ret = regmap_write(ctx->regmap, IT66121_HDCP_REG, ++ cpdesire & (~IT66121_HDCP_CPDESIRED & 0xFF)); ++ if (ret) ++ return ret; ++ ++ ret = regmap_write(ctx->regmap, IT66121_SW_RST_REG, ++ swreset | IT66121_SW_RST_HDCP); ++ if (ret) ++ return ret; ++ ++ ret = it66121_preamble_ddc(ctx); ++ if (ret) ++ return ret; ++ ++ ret = regmap_write(ctx->regmap, IT66121_DDC_COMMAND_REG, ++ IT66121_DDC_COMMAND_ABORT); ++ if (ret) ++ return ret; ++ ++ return it66121_wait_ddc_ready(ctx); ++} ++ ++static int it66121_get_edid_block(void *context, u8 *buf, ++ unsigned int block, size_t len) ++{ ++ struct it66121_ctx *ctx = context; ++ unsigned int val; ++ int remain = len; ++ int offset = 0; ++ int ret, cnt; ++ ++ offset = (block % 2) * len; ++ block = block / 2; ++ ++ ret = regmap_read(ctx->regmap, IT66121_INT_STATUS1_REG, &val); ++ if (ret) ++ return ret; ++ ++ if (val & IT66121_INT_STATUS1_DDC_BUSHANG) { ++ ret = it66121_abort_ddc_ops(ctx); ++ if (ret) ++ return ret; ++ } ++ ++ ret = it66121_clear_ddc_fifo(ctx); ++ if (ret) ++ return ret; ++ ++ while (remain > 0) { ++ cnt = (remain > IT66121_EDID_FIFO_SIZE) ? ++ IT66121_EDID_FIFO_SIZE : remain; ++ ret = it66121_preamble_ddc(ctx); ++ if (ret) ++ return ret; ++ ++ ret = regmap_write(ctx->regmap, IT66121_DDC_COMMAND_REG, ++ IT66121_DDC_COMMAND_FIFO_CLR); ++ if (ret) ++ return ret; ++ ++ ret = it66121_wait_ddc_ready(ctx); ++ if (ret) ++ return ret; ++ ++ ret = regmap_read(ctx->regmap, IT66121_INT_STATUS1_REG, &val); ++ if (ret) ++ return ret; ++ ++ if (val & IT66121_INT_STATUS1_DDC_BUSHANG) { ++ ret = it66121_abort_ddc_ops(ctx); ++ if (ret) ++ return ret; ++ } ++ ++ ret = it66121_preamble_ddc(ctx); ++ if (ret) ++ return ret; ++ ++ ret = regmap_write(ctx->regmap, IT66121_DDC_HEADER_REG, ++ IT66121_DDC_HEADER_EDID); ++ if (ret) ++ return ret; ++ ++ ret = regmap_write(ctx->regmap, IT66121_DDC_OFFSET_REG, offset); ++ if (ret) ++ return ret; ++ ++ ret = regmap_write(ctx->regmap, IT66121_DDC_BYTE_REG, cnt); ++ if (ret) ++ return ret; ++ ++ ret = regmap_write(ctx->regmap, IT66121_DDC_SEGMENT_REG, block); ++ if (ret) ++ return ret; ++ ++ ret = regmap_write(ctx->regmap, IT66121_DDC_COMMAND_REG, ++ IT66121_DDC_COMMAND_EDID_READ); ++ if (ret) ++ return ret; ++ ++ offset += cnt; ++ remain -= cnt; ++ msleep(20); ++ ++ ret = it66121_wait_ddc_ready(ctx); ++ if (ret) ++ return ret; ++ ++ do { ++ ret = regmap_read(ctx->regmap, ++ IT66121_DDC_RD_FIFO_REG, &val); ++ if (ret) ++ return ret; ++ *(buf++) = val; ++ cnt--; ++ } while (cnt > 0); ++ } ++ ++ return 0; ++} ++ ++static int it66121_connector_get_modes(struct drm_connector *connector) ++{ ++ int ret, num_modes = 0; ++ struct it66121_ctx *ctx = container_of(connector, struct it66121_ctx, ++ connector); ++ ++ if (ctx->edid) ++ return drm_add_edid_modes(connector, ctx->edid); ++ ++ mutex_lock(&ctx->lock); ++ ++ ctx->edid = drm_do_get_edid(connector, it66121_get_edid_block, ctx); ++ if (!ctx->edid) { ++ DRM_ERROR("Failed to read EDID\n"); ++ goto unlock; ++ } ++ ++ ret = drm_connector_update_edid_property(connector, ++ ctx->edid); ++ if (ret) { ++ DRM_ERROR("Failed to update EDID property: %d\n", ret); ++ goto unlock; ++ } ++ ++ num_modes = drm_add_edid_modes(connector, ctx->edid); ++ ++unlock: ++ mutex_unlock(&ctx->lock); ++ ++ return num_modes; ++} ++ ++static bool it66121_is_hpd_detect(struct it66121_ctx *ctx) ++{ ++ int val; ++ ++ if (regmap_read(ctx->regmap, IT66121_SYS_STATUS_REG, &val)) ++ return false; ++ ++ return (val & IT66121_SYS_STATUS_HPDETECT); ++} ++ ++static int it66121_connector_detect_ctx(struct drm_connector *connector, ++ struct drm_modeset_acquire_ctx *c, ++ bool force) ++{ ++ struct it66121_ctx *ctx = container_of(connector, struct it66121_ctx, ++ connector); ++ ++ return (it66121_is_hpd_detect(ctx)) ? ++ connector_status_connected : connector_status_disconnected; ++} ++ ++static enum drm_mode_status ++it66121_connector_mode_valid(struct drm_connector *connector, ++ struct drm_display_mode *mode) ++{ ++ unsigned long max_clock; ++ struct it66121_ctx *ctx = container_of(connector, struct it66121_ctx, ++ connector); ++ ++ max_clock = ctx->dual_edge ? 74250 : 148500; ++ ++ if (mode->clock > max_clock) ++ return MODE_CLOCK_HIGH; ++ ++ if (mode->clock < 25000) ++ return MODE_CLOCK_LOW; ++ ++ return MODE_OK; ++} ++ ++static struct drm_connector_helper_funcs it66121_connector_helper_funcs = { ++ .get_modes = it66121_connector_get_modes, ++ .detect_ctx = it66121_connector_detect_ctx, ++ .mode_valid = it66121_connector_mode_valid, ++}; ++ ++static const struct drm_connector_funcs it66121_connector_funcs = { ++ .reset = drm_atomic_helper_connector_reset, ++ .fill_modes = drm_helper_probe_single_connector_modes, ++ .destroy = drm_connector_cleanup, ++ .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, ++ .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, ++}; ++ ++static int it66121_bridge_attach(struct drm_bridge *bridge, ++ enum drm_bridge_attach_flags flags) ++{ ++ int ret; ++ struct it66121_ctx *ctx = container_of(bridge, struct it66121_ctx, ++ bridge); ++ ++ if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR) { ++ DRM_ERROR("Fix bridge driver to make connector optional!"); ++ return -EINVAL; ++ } ++ ++ if (!bridge->encoder) { ++ DRM_ERROR("Parent encoder object not found"); ++ return -ENODEV; ++ } ++ ++ ret = regmap_write_bits(ctx->regmap, IT66121_CLK_BANK_REG, ++ IT66121_CLK_BANK_PWROFF_RCLK, 0); ++ if (ret) ++ return ret; ++ ++ ret = regmap_write_bits(ctx->regmap, IT66121_INT_REG, ++ IT66121_INT_TX_CLK_OFF, 0); ++ if (ret) ++ return ret; ++ ++ ret = regmap_write_bits(ctx->regmap, IT66121_AFE_DRV_REG, ++ IT66121_AFE_DRV_PWD, 0); ++ if (ret) ++ return ret; ++ ++ ret = regmap_write_bits(ctx->regmap, IT66121_AFE_XP_REG, ++ IT66121_AFE_XP_PWDI | IT66121_AFE_XP_PWDPLL, 0); ++ if (ret) ++ return ret; ++ ++ ret = regmap_write_bits(ctx->regmap, IT66121_AFE_IP_REG, ++ IT66121_AFE_IP_PWDPLL, 0); ++ if (ret) ++ return ret; ++ ++ ret = regmap_write_bits(ctx->regmap, IT66121_AFE_DRV_REG, ++ IT66121_AFE_DRV_RST, 0); ++ if (ret) ++ return ret; ++ ++ ret = regmap_write_bits(ctx->regmap, IT66121_AFE_XP_REG, ++ IT66121_AFE_XP_RESETB, IT66121_AFE_XP_RESETB); ++ if (ret) ++ return ret; ++ ++ ret = regmap_write_bits(ctx->regmap, IT66121_AFE_IP_REG, ++ IT66121_AFE_IP_RESETB, IT66121_AFE_IP_RESETB); ++ if (ret) ++ return ret; ++ ++ ret = regmap_write_bits(ctx->regmap, IT66121_SW_RST_REG, ++ IT66121_SW_RST_REF, ++ IT66121_SW_RST_REF); ++ if (ret) ++ return ret; ++ ++ msleep(50); ++ ++ ret = drm_connector_init(bridge->dev, &ctx->connector, ++ &it66121_connector_funcs, ++ DRM_MODE_CONNECTOR_HDMIA); ++ if (ret) ++ return ret; ++ ++ ctx->connector.polled = DRM_CONNECTOR_POLL_HPD; ++ drm_connector_helper_add(&ctx->connector, ++ &it66121_connector_helper_funcs); ++ ++ ret = drm_connector_attach_encoder(&ctx->connector, bridge->encoder); ++ if (ret) ++ return ret; ++ ++ ret = drm_connector_register(&ctx->connector); ++ if (ret) ++ return ret; ++ ++ /* Start interrupts */ ++ return regmap_write_bits(ctx->regmap, IT66121_INT_MASK1_REG, ++ IT66121_INT_MASK1_DDC_NOACK | ++ IT66121_INT_MASK1_HPD | ++ IT66121_INT_MASK1_DDC_FIFOERR | ++ IT66121_INT_MASK1_DDC_BUSHANG, ++ ~(IT66121_INT_MASK1_DDC_NOACK | ++ IT66121_INT_MASK1_HPD | ++ IT66121_INT_MASK1_DDC_FIFOERR | ++ IT66121_INT_MASK1_DDC_BUSHANG) & 0xFF); ++} ++ ++static int it66121_set_mute(struct it66121_ctx *ctx, bool mute) ++{ ++ int ret; ++ unsigned int val; ++ ++ val = mute ? IT66121_AV_MUTE_ON : (~IT66121_AV_MUTE_ON & 0xFF); ++ ret = regmap_write_bits(ctx->regmap, IT66121_AV_MUTE_REG, ++ IT66121_AV_MUTE_ON, val); ++ if (ret) ++ return ret; ++ ++ return regmap_write(ctx->regmap, IT66121_PKT_GEN_CTRL_REG, ++ IT66121_PKT_GEN_CTRL_ON | ++ IT66121_PKT_GEN_CTRL_RPT); ++} ++ ++static void it66121_bridge_enable(struct drm_bridge *bridge) ++{ ++ struct it66121_ctx *ctx = container_of(bridge, struct it66121_ctx, ++ bridge); ++ ++ it66121_set_mute(ctx, false); ++} ++ ++static void it66121_bridge_disable(struct drm_bridge *bridge) ++{ ++ struct it66121_ctx *ctx = container_of(bridge, struct it66121_ctx, ++ bridge); ++ ++ it66121_set_mute(ctx, true); ++} ++ ++static ++void it66121_bridge_mode_set(struct drm_bridge *bridge, ++ const struct drm_display_mode *mode, ++ const struct drm_display_mode *adjusted_mode) ++{ ++ int ret, i; ++ u8 buf[HDMI_INFOFRAME_SIZE(AVI)]; ++ struct it66121_ctx *ctx = container_of(bridge, struct it66121_ctx, ++ bridge); ++ const u16 aviinfo_reg[HDMI_AVI_INFOFRAME_SIZE] = { ++ IT66121_AVIINFO_DB1_REG, ++ IT66121_AVIINFO_DB2_REG, ++ IT66121_AVIINFO_DB3_REG, ++ IT66121_AVIINFO_DB4_REG, ++ IT66121_AVIINFO_DB5_REG, ++ IT66121_AVIINFO_DB6_REG, ++ IT66121_AVIINFO_DB7_REG, ++ IT66121_AVIINFO_DB8_REG, ++ IT66121_AVIINFO_DB9_REG, ++ IT66121_AVIINFO_DB10_REG, ++ IT66121_AVIINFO_DB11_REG, ++ IT66121_AVIINFO_DB12_REG, ++ IT66121_AVIINFO_DB13_REG ++ }; ++ ++ mutex_lock(&ctx->lock); ++ ++ hdmi_avi_infoframe_init(&ctx->hdmi_avi_infoframe); ++ ++ ret = drm_hdmi_avi_infoframe_from_display_mode(&ctx->hdmi_avi_infoframe, ++ &ctx->connector, ++ adjusted_mode); ++ if (ret) { ++ DRM_ERROR("Failed to setup AVI infoframe: %d\n", ret); ++ goto unlock; ++ } ++ ++ ret = hdmi_avi_infoframe_pack(&ctx->hdmi_avi_infoframe, buf, ++ sizeof(buf)); ++ if (ret < 0) { ++ DRM_ERROR("Failed to pack infoframe: %d\n", ret); ++ goto unlock; ++ } ++ ++ /* Write new AVI infoframe packet */ ++ for (i = 0; i < HDMI_AVI_INFOFRAME_SIZE; i++) { ++ if (regmap_write(ctx->regmap, aviinfo_reg[i], ++ buf[i + HDMI_INFOFRAME_HEADER_SIZE])) ++ goto unlock; ++ } ++ if (regmap_write(ctx->regmap, IT66121_AVIINFO_CSUM_REG, buf[3])) ++ goto unlock; ++ ++ /* Enable AVI infoframe */ ++ if (regmap_write(ctx->regmap, IT66121_AVI_INFO_PKT_REG, ++ IT66121_AVI_INFO_PKT_ON | ++ IT66121_AVI_INFO_PKT_RPT)) ++ goto unlock; ++ ++ /* Set TX mode to HDMI */ ++ if (regmap_write(ctx->regmap, IT66121_HDMI_MODE_REG, ++ IT66121_HDMI_MODE_HDMI)) ++ goto unlock; ++ ++ if (regmap_write_bits(ctx->regmap, IT66121_CLK_BANK_REG, ++ IT66121_CLK_BANK_PWROFF_TXCLK, ++ IT66121_CLK_BANK_PWROFF_TXCLK)) ++ goto unlock; ++ ++ if (it66121_configure_input(ctx)) ++ goto unlock; ++ ++ if (it66121_configure_afe(ctx, adjusted_mode)) ++ goto unlock; ++ ++ regmap_write_bits(ctx->regmap, IT66121_CLK_BANK_REG, ++ IT66121_CLK_BANK_PWROFF_TXCLK, ++ ~IT66121_CLK_BANK_PWROFF_TXCLK & 0xFF); ++ ++unlock: ++ mutex_unlock(&ctx->lock); ++} ++ ++static const struct drm_bridge_funcs it66121_bridge_funcs = { ++ .attach = it66121_bridge_attach, ++ .enable = it66121_bridge_enable, ++ .disable = it66121_bridge_disable, ++ .mode_set = it66121_bridge_mode_set, ++}; ++ ++static irqreturn_t it66121_irq_threaded_handler(int irq, void *dev_id) ++{ ++ int ret; ++ unsigned int val; ++ struct it66121_ctx *ctx = dev_id; ++ struct device *dev = ctx->dev; ++ bool event = false; ++ ++ mutex_lock(&ctx->lock); ++ ++ ret = regmap_read(ctx->regmap, IT66121_SYS_STATUS_REG, &val); ++ if (ret) ++ goto unlock; ++ ++ if (val & IT66121_SYS_STATUS_ACTIVE_IRQ) { ++ ret = regmap_read(ctx->regmap, IT66121_INT_STATUS1_REG, &val); ++ if (ret) { ++ dev_err(dev, "Cannot read STATUS1_REG %d\n", ret); ++ } else { ++ if (val & IT66121_INT_STATUS1_DDC_FIFOERR) ++ it66121_clear_ddc_fifo(ctx); ++ if (val & (IT66121_INT_STATUS1_DDC_BUSHANG | ++ IT66121_INT_STATUS1_DDC_NOACK)) ++ it66121_abort_ddc_ops(ctx); ++ if (val & IT66121_INT_STATUS1_HPD_STATUS) { ++ regmap_write_bits(ctx->regmap, ++ IT66121_INT_CLR1_REG, ++ IT66121_INT_CLR1_HPD, ++ IT66121_INT_CLR1_HPD); ++ ++ if (!it66121_is_hpd_detect(ctx)) { ++ kfree(ctx->edid); ++ ctx->edid = NULL; ++ } ++ event = true; ++ } ++ } ++ ++ regmap_write_bits(ctx->regmap, IT66121_SYS_STATUS_REG, ++ IT66121_SYS_STATUS_CLEAR_IRQ, ++ IT66121_SYS_STATUS_CLEAR_IRQ); ++ } ++ ++unlock: ++ mutex_unlock(&ctx->lock); ++ ++ if (event) ++ drm_helper_hpd_irq_event(ctx->bridge.dev); ++ ++ return IRQ_HANDLED; ++} ++ ++static int it66121_probe(struct i2c_client *client, ++ const struct i2c_device_id *id) ++{ ++ u8 ids[4]; ++ int i, ret; ++ struct it66121_ctx *ctx; ++ struct device *dev = &client->dev; ++ ++ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { ++ dev_err(dev, "I2C check functionality failed.\n"); ++ return -ENXIO; ++ } ++ ++ ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); ++ if (!ctx) ++ return -ENOMEM; ++ ++ ctx->dev = dev; ++ ctx->client = client; ++ i2c_set_clientdata(client, ctx); ++ mutex_init(&ctx->lock); ++ ctx->conf = (struct it66121_conf *)of_device_get_match_data(dev); ++ if (!ctx->conf) ++ return -ENODEV; ++ ++ ctx->supplies[0].supply = "vcn33"; ++ ctx->supplies[1].supply = "vcn18"; ++ ctx->supplies[2].supply = "vrf12"; ++ ret = devm_regulator_bulk_get(ctx->dev, 3, ctx->supplies); ++ if (ret) { ++ dev_err(ctx->dev, "regulator_bulk failed\n"); ++ return ret; ++ } ++ ++ ctx->dual_edge = of_property_read_bool(dev->of_node, "pclk-dual-edge"); ++ ++ ret = ite66121_power_on(ctx); ++ if (ret) ++ return ret; ++ ++ it66121_hw_reset(ctx); ++ ++ ctx->regmap = devm_regmap_init_i2c(client, &it66121_regmap_config); ++ if (IS_ERR(ctx->regmap)) { ++ ite66121_power_off(ctx); ++ return PTR_ERR(ctx); ++ } ++ ++ for (i = 0; i < 4; i++) { ++ regmap_read(ctx->regmap, i, &ret); ++ ids[i] = ret; ++ } ++ ++ if (ids[0] != IT66121_VENDOR_ID0 || ++ ids[1] != IT66121_VENDOR_ID1 || ++ ids[2] != IT66121_DEVICE_ID0 || ++ ((ids[3] & IT66121_DEVICE_MASK) != IT66121_DEVICE_ID1)) { ++ ite66121_power_off(ctx); ++ return -ENODEV; ++ } ++ ++ ctx->bridge.funcs = &it66121_bridge_funcs; ++ ctx->bridge.of_node = dev->of_node; ++ ++ ret = devm_request_threaded_irq(dev, client->irq, NULL, ++ it66121_irq_threaded_handler, ++ IRQF_SHARED | IRQF_TRIGGER_LOW | ++ IRQF_ONESHOT, ++ dev_name(dev), ++ ctx); ++ if (ret < 0) { ++ dev_err(dev, "Failed to request irq %d:%d\n", client->irq, ret); ++ ite66121_power_off(ctx); ++ return ret; ++ } ++ ++ drm_bridge_add(&ctx->bridge); ++ ++ return 0; ++} ++ ++static int it66121_remove(struct i2c_client *client) ++{ ++ struct it66121_ctx *ctx = i2c_get_clientdata(client); ++ ++ ite66121_power_off(ctx); ++ drm_bridge_remove(&ctx->bridge); ++ kfree(ctx->edid); ++ mutex_destroy(&ctx->lock); ++ ++ return 0; ++} ++ ++static const struct of_device_id it66121_dt_match[] = { ++ { .compatible = "ite,it66121", ++ .data = &it66121_conf_simple, ++ }, ++ { }, ++}; ++MODULE_DEVICE_TABLE(of, it66121_dt_match); ++ ++static const struct i2c_device_id it66121_id[] = { ++ { "it66121", 0 }, ++ { }, ++}; ++MODULE_DEVICE_TABLE(i2c, it66121_id); ++ ++static struct i2c_driver it66121_driver = { ++ .driver = { ++ .name = "it66121", ++ .of_match_table = it66121_dt_match, ++ }, ++ .probe = it66121_probe, ++ .remove = it66121_remove, ++ .id_table = it66121_id, ++}; ++ ++module_i2c_driver(it66121_driver); ++ ++MODULE_AUTHOR("Phong LE"); ++MODULE_DESCRIPTION("IT66121 HDMI transmitter driver"); ++MODULE_LICENSE("GPL v2"); + +From ec5271e4d8d6d57545a284ee5bd365f17990fdc6 Mon Sep 17 00:00:00 2001 +From: Phong LE +Date: Wed, 11 Mar 2020 13:51:35 +0100 +Subject: [PATCH] MAINTAINERS: add it66121 HDMI bridge driver entry + +Add Neil Armstrong and myself as maintainers + +Signed-off-by: Phong LE +--- + MAINTAINERS | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/MAINTAINERS b/MAINTAINERS +index db98a799f409..5a34ca2f0e11 100644 +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -9193,6 +9193,14 @@ Q: http://patchwork.linuxtv.org/project/linux-media/list/ + T: git git://linuxtv.org/anttip/media_tree.git + F: drivers/media/tuners/it913x* + ++ITE IT66121 HDMI BRIDGE DRIVER ++M: Phong LE ++M: Neil Armstrong ++S: Maintained ++F: drivers/gpu/drm/bridge/ite-it66121.c ++T: git git://anongit.freedesktop.org/drm/drm-misc ++F: Documentation/devicetree/bindings/display/bridge/ite,it66121.yaml ++ + IVTV VIDEO4LINUX DRIVER + M: Andy Walls + L: linux-media@vger.kernel.org + +From b8f225a1145ac25cd5df830d557e5be6d212a798 Mon Sep 17 00:00:00 2001 +From: Alex Bee +Date: Tue, 26 May 2020 13:48:12 +0200 +Subject: [PATCH] drm: bridge: it66121: add IT66121FN variant + +--- + drivers/gpu/drm/bridge/ite-it66121.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/drivers/gpu/drm/bridge/ite-it66121.c b/drivers/gpu/drm/bridge/ite-it66121.c +index 7e1a90319a6a..68f7e50fdddd 100644 +--- a/drivers/gpu/drm/bridge/ite-it66121.c ++++ b/drivers/gpu/drm/bridge/ite-it66121.c +@@ -242,6 +242,11 @@ static const struct it66121_conf it66121_conf_simple = { + .input_conversion_reg = IT66121_INPUT_CSC_NO_CONV, + }; + ++static const struct it66121_conf it66121fn_conf_simple = { ++ .input_mode_reg = IT66121_INPUT_MODE_RGB, ++ .input_conversion_reg = IT66121_INPUT_CSC_NO_CONV, ++}; ++ + static void it66121_hw_reset(struct it66121_ctx *ctx) + { + gpiod_set_value(ctx->gpio_reset, 1); +@@ -970,6 +975,9 @@ static const struct of_device_id it66121_dt_match[] = { + { .compatible = "ite,it66121", + .data = &it66121_conf_simple, + }, ++ { .compatible = "ite,it66121fn", ++ .data = &it66121fn_conf_simple, ++ }, + { }, + }; + MODULE_DEVICE_TABLE(of, it66121_dt_match); + +From e7ebcc04f15308b5ece1b5f99689d8577be2625d Mon Sep 17 00:00:00 2001 +From: Alex Bee +Date: Sun, 16 Aug 2020 23:40:24 +0200 +Subject: [PATCH] WIP: ARM: dts: rockchip add vpll clock to RK322Xs hdmi node + +--- + arch/arm/boot/dts/rk322x.dtsi | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/arch/arm/boot/dts/rk322x.dtsi b/arch/arm/boot/dts/rk322x.dtsi +index 48e6e8d44a1a..b69b5be110c3 100644 +--- a/arch/arm/boot/dts/rk322x.dtsi ++++ b/arch/arm/boot/dts/rk322x.dtsi +@@ -644,8 +644,8 @@ hdmi: hdmi@200a0000 { + interrupts = ; + assigned-clocks = <&cru SCLK_HDMI_PHY>; + assigned-clock-parents = <&hdmi_phy>; +- clocks = <&cru SCLK_HDMI_HDCP>, <&cru PCLK_HDMI_CTRL>, <&cru SCLK_HDMI_CEC>; +- clock-names = "isfr", "iahb", "cec"; ++ clocks = <&cru SCLK_HDMI_HDCP>, <&cru PCLK_HDMI_CTRL>, <&hdmi_phy>, <&cru SCLK_HDMI_CEC>; ++ clock-names = "isfr", "iahb", "vpll", "cec"; + pinctrl-names = "default"; + pinctrl-0 = <&hdmii2c_xfer &hdmi_hpd &hdmi_cec>; + resets = <&cru SRST_HDMI_P>; + +From e1dd22643e8fc82021c3ed8f5355bffa33899b9c Mon Sep 17 00:00:00 2001 +From: Alex Bee +Date: Tue, 18 Aug 2020 11:19:53 +0200 +Subject: [PATCH] drm/bridge: !cleanup: remove pr_infos + +--- + drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c | 6 ------ + 1 file changed, 6 deletions(-) + +diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c +index e6953219beee..2cfd5b418c05 100644 +--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c ++++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c +@@ -97,8 +97,6 @@ static int dw_hdmi_cec_transmit(struct cec_adapter *adap, u8 attempts, + struct dw_hdmi_cec *cec = cec_get_drvdata(adap); + unsigned int i, ctrl; + +- pr_info("%s: attempts=%u signal_free_time=%u msg=%*ph (sequence: %u)\n", __func__, attempts, signal_free_time, msg->len, msg->msg, msg->sequence); +- + switch (signal_free_time) { + case CEC_SIGNAL_FREE_TIME_RETRY: + ctrl = CEC_CTRL_RETRY; +@@ -188,8 +186,6 @@ static irqreturn_t dw_hdmi_cec_hardirq(int irq, void *data) + ret = IRQ_WAKE_THREAD; + } + +- pr_info("%s: stat=%x ret=%x tx_done=%d rx_done=%d tx_status=%u tx_attempts=%u\n", __func__, stat, ret, cec->tx_done, cec->rx_done, cec->tx_status, cec->tx_attempts); +- + return ret; + } + +@@ -198,8 +194,6 @@ static irqreturn_t dw_hdmi_cec_thread(int irq, void *data) + struct cec_adapter *adap = data; + struct dw_hdmi_cec *cec = cec_get_drvdata(adap); + +- //pr_info("%s: tx_done=%d rx_done=%d tx_status=%u tx_attempts=%u\n", __func__, cec->tx_done, cec->rx_done, cec->tx_status, cec->tx_attempts); +- + if (cec->tx_done) { + cec->tx_done = false; + if (cec->tx_status == CEC_TX_STATUS_LOW_DRIVE) diff --git a/patch/kernel/rk322x-dev/01-linux-3000-rockchip-v4l-wip.patch b/patch/kernel/rk322x-dev/01-linux-3000-rockchip-v4l-wip.patch new file mode 100644 index 000000000..e19954c6d --- /dev/null +++ b/patch/kernel/rk322x-dev/01-linux-3000-rockchip-v4l-wip.patch @@ -0,0 +1,4647 @@ +From d9d1bb6e72ad344280be5887718444f110aec86f Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Fri, 22 May 2020 20:42:11 +0000 +Subject: [PATCH] fixup! media: rkvdec: Fix .buf_prepare + +--- + drivers/staging/media/rkvdec/rkvdec.c | 10 ++++------ + 1 file changed, 4 insertions(+), 6 deletions(-) + +diff --git a/drivers/staging/media/rkvdec/rkvdec.c b/drivers/staging/media/rkvdec/rkvdec.c +index f0f28f6a68cf..9edaea98a483 100644 +--- a/drivers/staging/media/rkvdec/rkvdec.c ++++ b/drivers/staging/media/rkvdec/rkvdec.c +@@ -599,13 +599,11 @@ static int rkvdec_buf_prepare(struct vb2_buffer *vb) + } + + /* +- * Buffer's bytesused is written by the driver for CAPTURE buffers, +- * or if the application passed zero bytesused on an OUTPUT buffer. ++ * Buffer's bytesused is written by the driver for CAPTURE buffers. + */ +- if (!V4L2_TYPE_IS_OUTPUT(vq->type) || +- (V4L2_TYPE_IS_OUTPUT(vq->type) && !vb2_get_plane_payload(vb, 0))) +- vb2_set_plane_payload(vb, 0, +- f->fmt.pix_mp.plane_fmt[0].sizeimage); ++ if (!V4L2_TYPE_IS_OUTPUT(vq->type)) ++ vb2_set_plane_payload(vb, 0, f->fmt.pix_mp.plane_fmt[0].sizeimage); ++ + return 0; + } + + +From e5c9031e74c1ff2c597654f172c9f1e856810544 Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Sat, 15 Aug 2020 08:28:56 +0000 +Subject: [PATCH] fixup! media: rkvdec: Add the VP9 backend + +--- + drivers/staging/media/rkvdec/rkvdec.c | 5 ----- + 1 file changed, 5 deletions(-) + +diff --git a/drivers/staging/media/rkvdec/rkvdec.c b/drivers/staging/media/rkvdec/rkvdec.c +index 9edaea98a483..9accbe889040 100644 +--- a/drivers/staging/media/rkvdec/rkvdec.c ++++ b/drivers/staging/media/rkvdec/rkvdec.c +@@ -161,24 +161,19 @@ static const u32 rkvdec_h264_decoded_fmts[] = { + + static const struct rkvdec_ctrl_desc rkvdec_vp9_ctrl_descs[] = { + { +- .per_request = true, + .mandatory = true, + .cfg.id = V4L2_CID_MPEG_VIDEO_VP9_FRAME_DECODE_PARAMS, + }, + { +- .mandatory = true, + .cfg.id = V4L2_CID_MPEG_VIDEO_VP9_FRAME_CONTEXT(0), + }, + { +- .mandatory = true, + .cfg.id = V4L2_CID_MPEG_VIDEO_VP9_FRAME_CONTEXT(1), + }, + { +- .mandatory = true, + .cfg.id = V4L2_CID_MPEG_VIDEO_VP9_FRAME_CONTEXT(2), + }, + { +- .mandatory = true, + .cfg.id = V4L2_CID_MPEG_VIDEO_VP9_FRAME_CONTEXT(3), + }, + { + +From 9a9b9efc39a879ef65d7f9bec29fd8f0b8ce89fc Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Sat, 23 May 2020 10:18:16 +0000 +Subject: [PATCH] WIP: media: rkvdec: continue to gate clock when decoding + finish + +Signed-off-by: Jonas Karlman +--- + drivers/staging/media/rkvdec/rkvdec.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/drivers/staging/media/rkvdec/rkvdec.c b/drivers/staging/media/rkvdec/rkvdec.c +index 9accbe889040..a282b7e6d6e8 100644 +--- a/drivers/staging/media/rkvdec/rkvdec.c ++++ b/drivers/staging/media/rkvdec/rkvdec.c +@@ -1079,7 +1079,8 @@ static irqreturn_t rkvdec_irq_handler(int irq, void *priv) + state = (status & RKVDEC_RDY_STA) ? + VB2_BUF_STATE_DONE : VB2_BUF_STATE_ERROR; + +- writel(0, rkvdec->regs + RKVDEC_REG_INTERRUPT); ++ writel(RKVDEC_CONFIG_DEC_CLK_GATE_E, ++ rkvdec->regs + RKVDEC_REG_INTERRUPT); + if (cancel_delayed_work(&rkvdec->watchdog_work)) { + struct rkvdec_ctx *ctx; + +@@ -1100,7 +1101,8 @@ static void rkvdec_watchdog_func(struct work_struct *work) + ctx = v4l2_m2m_get_curr_priv(rkvdec->m2m_dev); + if (ctx) { + dev_err(rkvdec->dev, "Frame processing timed out!\n"); +- writel(RKVDEC_IRQ_DIS, rkvdec->regs + RKVDEC_REG_INTERRUPT); ++ writel(RKVDEC_CONFIG_DEC_CLK_GATE_E | RKVDEC_IRQ_DIS, ++ rkvdec->regs + RKVDEC_REG_INTERRUPT); + writel(0, rkvdec->regs + RKVDEC_REG_SYSCTRL); + rkvdec_job_finish(ctx, VB2_BUF_STATE_ERROR); + } + +From 126fa7ad4de4368fe4938d59b327813a8649ff3b Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Sat, 23 May 2020 10:16:01 +0000 +Subject: [PATCH] WIP: media: rkvdec: pm runtime dont use autosuspend before + disable and cleanup + +Signed-off-by: Jonas Karlman +--- + drivers/staging/media/rkvdec/rkvdec.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/staging/media/rkvdec/rkvdec.c b/drivers/staging/media/rkvdec/rkvdec.c +index a282b7e6d6e8..658fb6028e72 100644 +--- a/drivers/staging/media/rkvdec/rkvdec.c ++++ b/drivers/staging/media/rkvdec/rkvdec.c +@@ -1200,9 +1200,9 @@ static int rkvdec_remove(struct platform_device *pdev) + { + struct rkvdec_dev *rkvdec = platform_get_drvdata(pdev); + +- rkvdec_v4l2_cleanup(rkvdec); +- pm_runtime_disable(&pdev->dev); + pm_runtime_dont_use_autosuspend(&pdev->dev); ++ pm_runtime_disable(&pdev->dev); ++ rkvdec_v4l2_cleanup(rkvdec); + return 0; + } + + +From c7382800a8af054b62ff6edea7d62bc30a160b74 Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Sat, 23 May 2020 11:23:04 +0000 +Subject: [PATCH] WIP: media: rkvdec: h264: return early when no reference + pictures + +NOTE: also change from a switch statement to access reflists from a pointer array, +should simplify once we add support for field reference list + +Signed-off-by: Jonas Karlman +--- + drivers/staging/media/rkvdec/rkvdec-h264.c | 18 +++++------------- + 1 file changed, 5 insertions(+), 13 deletions(-) + +diff --git a/drivers/staging/media/rkvdec/rkvdec-h264.c b/drivers/staging/media/rkvdec/rkvdec-h264.c +index afc695d32186..1716bfb596ae 100644 +--- a/drivers/staging/media/rkvdec/rkvdec-h264.c ++++ b/drivers/staging/media/rkvdec/rkvdec-h264.c +@@ -734,6 +734,7 @@ static void assemble_hw_rps(struct rkvdec_ctx *ctx, + const struct v4l2_ctrl_h264_sps *sps = run->sps; + struct rkvdec_h264_priv_tbl *priv_tbl = h264_ctx->priv_tbl.cpu; + u32 max_frame_num = 1 << (sps->log2_max_frame_num_minus4 + 4); ++ u8 *reflists[3] = { h264_ctx->reflists.p, h264_ctx->reflists.b0, h264_ctx->reflists.b1 }; + + u32 *hw_rps = priv_tbl->rps; + u32 i, j; +@@ -741,6 +742,9 @@ static void assemble_hw_rps(struct rkvdec_ctx *ctx, + + memset(hw_rps, 0, sizeof(priv_tbl->rps)); + ++ if (!h264_ctx->reflists.num_valid) ++ return; ++ + /* + * Assign an invalid pic_num if DPB entry at that position is inactive. + * If we assign 0 in that position hardware will treat that as a real +@@ -763,19 +767,7 @@ static void assemble_hw_rps(struct rkvdec_ctx *ctx, + for (j = 0; j < RKVDEC_NUM_REFLIST; j++) { + for (i = 0; i < h264_ctx->reflists.num_valid; i++) { + u8 dpb_valid = 0; +- u8 idx = 0; +- +- switch (j) { +- case 0: +- idx = h264_ctx->reflists.p[i]; +- break; +- case 1: +- idx = h264_ctx->reflists.b0[i]; +- break; +- case 2: +- idx = h264_ctx->reflists.b1[i]; +- break; +- } ++ u8 idx = reflists[j][i]; + + if (idx >= ARRAY_SIZE(dec_params->dpb)) + continue; + +From 70eb1d9dfa98bf6a6662280de58e01dffa347add Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Sat, 23 May 2020 14:42:27 +0000 +Subject: [PATCH] WIP: media: rkvdec: h264: add field decoding support + +Signed-off-by: Jonas Karlman +--- + drivers/staging/media/rkvdec/rkvdec-h264.c | 79 ++++++++++++++++++---- + 1 file changed, 64 insertions(+), 15 deletions(-) + +diff --git a/drivers/staging/media/rkvdec/rkvdec-h264.c b/drivers/staging/media/rkvdec/rkvdec-h264.c +index 1716bfb596ae..c388bf3da079 100644 +--- a/drivers/staging/media/rkvdec/rkvdec-h264.c ++++ b/drivers/staging/media/rkvdec/rkvdec-h264.c +@@ -737,7 +737,7 @@ static void assemble_hw_rps(struct rkvdec_ctx *ctx, + u8 *reflists[3] = { h264_ctx->reflists.p, h264_ctx->reflists.b0, h264_ctx->reflists.b1 }; + + u32 *hw_rps = priv_tbl->rps; +- u32 i, j; ++ u32 i, j, k; + u16 *p = (u16 *)hw_rps; + + memset(hw_rps, 0, sizeof(priv_tbl->rps)); +@@ -764,18 +764,71 @@ static void assemble_hw_rps(struct rkvdec_ctx *ctx, + p[i] = dpb[i].frame_num - max_frame_num; + } + +- for (j = 0; j < RKVDEC_NUM_REFLIST; j++) { +- for (i = 0; i < h264_ctx->reflists.num_valid; i++) { +- u8 dpb_valid = 0; +- u8 idx = reflists[j][i]; ++ if (!(dec_params->flags & V4L2_H264_DECODE_PARAM_FLAG_FIELD_PIC)) { ++ for (j = 0; j < RKVDEC_NUM_REFLIST; j++) { ++ for (i = 0; i < h264_ctx->reflists.num_valid; i++) { ++ u8 dpb_valid = 0; ++ u8 idx = reflists[j][i]; + +- if (idx >= ARRAY_SIZE(dec_params->dpb)) +- continue; +- dpb_valid = !!(dpb[idx].flags & +- V4L2_H264_DPB_ENTRY_FLAG_ACTIVE); ++ if (idx >= ARRAY_SIZE(dec_params->dpb)) ++ continue; ++ dpb_valid = !!(dpb[idx].flags & ++ V4L2_H264_DPB_ENTRY_FLAG_ACTIVE); + +- set_ps_field(hw_rps, DPB_INFO(i, j), +- idx | dpb_valid << 4); ++ set_ps_field(hw_rps, DPB_INFO(i, j), ++ idx | dpb_valid << 4); ++ } ++ } ++ return; ++ } ++ ++ for (j = 0; j < RKVDEC_NUM_REFLIST; j++) { ++ enum v4l2_h264_field_reference a_parity = ++ (dec_params->flags & V4L2_H264_DECODE_PARAM_FLAG_BOTTOM_FIELD) ++ ? V4L2_H264_BOTTOM_FIELD_REF : V4L2_H264_TOP_FIELD_REF; ++ enum v4l2_h264_field_reference b_parity = ++ (dec_params->flags & V4L2_H264_DECODE_PARAM_FLAG_BOTTOM_FIELD) ++ ? V4L2_H264_TOP_FIELD_REF : V4L2_H264_BOTTOM_FIELD_REF; ++ u32 flags = V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM; ++ i = 0; ++ ++ for (k = 0; k < 2; k++) { ++ u8 a = 0; ++ u8 b = 0; ++ u32 long_term = k ? V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM : 0; ++ ++ while (a < h264_ctx->reflists.num_valid || b < h264_ctx->reflists.num_valid) { ++ for (; a < h264_ctx->reflists.num_valid; a++) { ++ u8 idx = reflists[j][a]; ++ if (idx >= ARRAY_SIZE(dec_params->dpb)) ++ continue; ++ if ((dpb[idx].reference & a_parity) == a_parity && ++ (dpb[idx].flags & flags) == long_term) { ++ set_ps_field(hw_rps, DPB_INFO(i, j), ++ idx | (1 << 4)); ++ set_ps_field(hw_rps, BOTTOM_FLAG(i, j), ++ a_parity == V4L2_H264_BOTTOM_FIELD_REF); ++ i++; ++ a++; ++ break; ++ } ++ } ++ for (; b < h264_ctx->reflists.num_valid; b++) { ++ u8 idx = reflists[j][b]; ++ if (idx >= ARRAY_SIZE(dec_params->dpb)) ++ continue; ++ if ((dpb[idx].reference & b_parity) == b_parity && ++ (dpb[idx].flags & flags) == long_term) { ++ set_ps_field(hw_rps, DPB_INFO(i, j), ++ idx | (1 << 4)); ++ set_ps_field(hw_rps, BOTTOM_FLAG(i, j), ++ b_parity == V4L2_H264_BOTTOM_FIELD_REF); ++ i++; ++ b++; ++ break; ++ } ++ } ++ } + } + } + } +@@ -968,10 +1021,6 @@ static void config_registers(struct rkvdec_ctx *ctx, + rkvdec->regs + RKVDEC_REG_H264_BASE_REFER15); + } + +- /* +- * Since support frame mode only +- * top_field_order_cnt is the same as bottom_field_order_cnt +- */ + reg = RKVDEC_CUR_POC(dec_params->top_field_order_cnt); + writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_CUR_POC0); + + +From 7032b50b559ff869d47ae06ec94cf7b50f7a8eb1 Mon Sep 17 00:00:00 2001 +From: Jernej Skrabec +Date: Sat, 26 Oct 2019 13:55:15 +0200 +Subject: [PATCH] media: uapi: hevc: Add scaling matrix control + +HEVC has a scaling matrix concept. Add support for it. + +Signed-off-by: Jernej Skrabec +--- + .../media/v4l/ext-ctrls-codec.rst | 41 +++++++++++++++++++ + .../media/v4l/pixfmt-compressed.rst | 1 + + drivers/media/v4l2-core/v4l2-ctrls.c | 10 +++++ + include/media/hevc-ctrls.h | 11 +++++ + 4 files changed, 63 insertions(+) + +diff --git a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst +index ca13b141d8c2..578de53ff929 100644 +--- a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst ++++ b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst +@@ -4777,6 +4777,47 @@ enum v4l2_mpeg_video_hevc_size_of_length_field - + - ``padding[6]`` + - Applications and drivers must set this to zero. + ++``V4L2_CID_MPEG_VIDEO_HEVC_SCALING_MATRIX (struct)`` ++ Specifies the scaling matrix (as extracted from the bitstream) for ++ the associated HEVC slice data. The bitstream parameters are ++ defined according to :ref:`hevc`, section 7.4.5 "Scaling list ++ data semantics". For further documentation, refer to the above ++ specification, unless there is an explicit comment stating ++ otherwise. ++ ++ .. note:: ++ ++ This compound control is not yet part of the public kernel API and ++ it is expected to change. ++ ++.. c:type:: v4l2_ctrl_hevc_scaling_matrix ++ ++.. cssclass:: longtable ++ ++.. flat-table:: struct v4l2_ctrl_hevc_scaling_matrix ++ :header-rows: 0 ++ :stub-columns: 0 ++ :widths: 1 1 2 ++ ++ * - __u8 ++ - ``scaling_list_4x4[6][16]`` ++ - ++ * - __u8 ++ - ``scaling_list_8x8[6][64]`` ++ - ++ * - __u8 ++ - ``scaling_list_16x16[6][64]`` ++ - ++ * - __u8 ++ - ``scaling_list_32x32[2][64]`` ++ - ++ * - __u8 ++ - ``scaling_list_dc_coef_16x16[6]`` ++ - ++ * - __u8 ++ - ``scaling_list_dc_coef_32x32[2]`` ++ - ++ + ``V4L2_CID_MPEG_VIDEO_HEVC_DECODE_MODE (enum)`` + Specifies the decoding mode to use. Currently exposes slice-based and + frame-based decoding but new modes might be added later on. +diff --git a/Documentation/userspace-api/media/v4l/pixfmt-compressed.rst b/Documentation/userspace-api/media/v4l/pixfmt-compressed.rst +index 3828bb79225d..a77560204c21 100644 +--- a/Documentation/userspace-api/media/v4l/pixfmt-compressed.rst ++++ b/Documentation/userspace-api/media/v4l/pixfmt-compressed.rst +@@ -207,6 +207,7 @@ Compressed Formats + * ``V4L2_CID_MPEG_VIDEO_HEVC_SPS`` + * ``V4L2_CID_MPEG_VIDEO_HEVC_PPS`` + * ``V4L2_CID_MPEG_VIDEO_HEVC_SLICE_PARAMS`` ++ * ``V4L2_CID_MPEG_VIDEO_HEVC_SCALING_MATRIX`` + See the :ref:`associated Codec Control IDs `. + Buffers associated with this pixel format must contain the appropriate + number of macroblocks to decode a full corresponding frame. +diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c +index 5913088cbc6f..6f7df51cb633 100644 +--- a/drivers/media/v4l2-core/v4l2-ctrls.c ++++ b/drivers/media/v4l2-core/v4l2-ctrls.c +@@ -995,6 +995,7 @@ const char *v4l2_ctrl_get_name(u32 id) + case V4L2_CID_MPEG_VIDEO_HEVC_SPS: return "HEVC Sequence Parameter Set"; + case V4L2_CID_MPEG_VIDEO_HEVC_PPS: return "HEVC Picture Parameter Set"; + case V4L2_CID_MPEG_VIDEO_HEVC_SLICE_PARAMS: return "HEVC Slice Parameters"; ++ case V4L2_CID_MPEG_VIDEO_HEVC_SCALING_MATRIX: return "HEVC Scaling Matrix"; + case V4L2_CID_MPEG_VIDEO_HEVC_DECODE_MODE: return "HEVC Decode Mode"; + case V4L2_CID_MPEG_VIDEO_HEVC_START_CODE: return "HEVC Start Code"; + +@@ -1442,6 +1443,9 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type, + case V4L2_CID_MPEG_VIDEO_HEVC_SLICE_PARAMS: + *type = V4L2_CTRL_TYPE_HEVC_SLICE_PARAMS; + break; ++ case V4L2_CID_MPEG_VIDEO_HEVC_SCALING_MATRIX: ++ *type = V4L2_CTRL_TYPE_HEVC_SCALING_MATRIX; ++ break; + case V4L2_CID_UNIT_CELL_SIZE: + *type = V4L2_CTRL_TYPE_AREA; + *flags |= V4L2_CTRL_FLAG_READ_ONLY; +@@ -2134,6 +2138,9 @@ static int std_validate_compound(const struct v4l2_ctrl *ctrl, u32 idx, + zero_padding(*p_hevc_slice_params); + break; + ++ case V4L2_CTRL_TYPE_HEVC_SCALING_MATRIX: ++ break; ++ + case V4L2_CTRL_TYPE_AREA: + area = p; + if (!area->width || !area->height) +@@ -2832,6 +2839,9 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl, + case V4L2_CTRL_TYPE_HEVC_SLICE_PARAMS: + elem_size = sizeof(struct v4l2_ctrl_hevc_slice_params); + break; ++ case V4L2_CTRL_TYPE_HEVC_SCALING_MATRIX: ++ elem_size = sizeof(struct v4l2_ctrl_hevc_scaling_matrix); ++ break; + case V4L2_CTRL_TYPE_AREA: + elem_size = sizeof(struct v4l2_area); + break; +diff --git a/include/media/hevc-ctrls.h b/include/media/hevc-ctrls.h +index 1009cf0891cc..1592e52c3614 100644 +--- a/include/media/hevc-ctrls.h ++++ b/include/media/hevc-ctrls.h +@@ -19,6 +19,7 @@ + #define V4L2_CID_MPEG_VIDEO_HEVC_SPS (V4L2_CID_MPEG_BASE + 1008) + #define V4L2_CID_MPEG_VIDEO_HEVC_PPS (V4L2_CID_MPEG_BASE + 1009) + #define V4L2_CID_MPEG_VIDEO_HEVC_SLICE_PARAMS (V4L2_CID_MPEG_BASE + 1010) ++#define V4L2_CID_MPEG_VIDEO_HEVC_SCALING_MATRIX (V4L2_CID_MPEG_BASE + 1011) + #define V4L2_CID_MPEG_VIDEO_HEVC_DECODE_MODE (V4L2_CID_MPEG_BASE + 1015) + #define V4L2_CID_MPEG_VIDEO_HEVC_START_CODE (V4L2_CID_MPEG_BASE + 1016) + +@@ -26,6 +27,7 @@ + #define V4L2_CTRL_TYPE_HEVC_SPS 0x0120 + #define V4L2_CTRL_TYPE_HEVC_PPS 0x0121 + #define V4L2_CTRL_TYPE_HEVC_SLICE_PARAMS 0x0122 ++#define V4L2_CTRL_TYPE_HEVC_SCALING_MATRIX 0x0123 + + enum v4l2_mpeg_video_hevc_decode_mode { + V4L2_MPEG_VIDEO_HEVC_DECODE_MODE_SLICE_BASED, +@@ -209,4 +211,13 @@ struct v4l2_ctrl_hevc_slice_params { + __u64 flags; + }; + ++struct v4l2_ctrl_hevc_scaling_matrix { ++ __u8 scaling_list_4x4[6][16]; ++ __u8 scaling_list_8x8[6][64]; ++ __u8 scaling_list_16x16[6][64]; ++ __u8 scaling_list_32x32[2][64]; ++ __u8 scaling_list_dc_coef_16x16[6]; ++ __u8 scaling_list_dc_coef_32x32[2]; ++}; ++ + #endif + +From e8b0441e3d60b0e936b975f2467d1604158a1d6c Mon Sep 17 00:00:00 2001 +From: Jernej Skrabec +Date: Sat, 26 Oct 2019 15:42:28 +0200 +Subject: [PATCH] media: uapi: hevc: Add segment address field + +If HEVC frame consists of multiple slices, segment address has to be +known in order to properly decode it. + +Add segment address field to slice parameters. + +Signed-off-by: Jernej Skrabec +--- + Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst | 5 ++++- + include/media/hevc-ctrls.h | 5 ++++- + 2 files changed, 8 insertions(+), 2 deletions(-) + +diff --git a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst +index 578de53ff929..bca71e38b85d 100644 +--- a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst ++++ b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst +@@ -4572,6 +4572,9 @@ enum v4l2_mpeg_video_hevc_size_of_length_field - + * - __u32 + - ``data_bit_offset`` + - Offset (in bits) to the video data in the current slice data. ++ * - __u32 ++ - ``slice_segment_addr`` ++ - + * - __u8 + - ``nal_unit_type`` + - +@@ -4649,7 +4652,7 @@ enum v4l2_mpeg_video_hevc_size_of_length_field - + - ``num_rps_poc_lt_curr`` + - The number of reference pictures in the long-term set. + * - __u8 +- - ``padding[7]`` ++ - ``padding[5]`` + - Applications and drivers must set this to zero. + * - struct :c:type:`v4l2_hevc_dpb_entry` + - ``dpb[V4L2_HEVC_DPB_ENTRIES_NUM_MAX]`` +diff --git a/include/media/hevc-ctrls.h b/include/media/hevc-ctrls.h +index 1592e52c3614..3e2e32098312 100644 +--- a/include/media/hevc-ctrls.h ++++ b/include/media/hevc-ctrls.h +@@ -167,6 +167,9 @@ struct v4l2_ctrl_hevc_slice_params { + __u32 bit_size; + __u32 data_bit_offset; + ++ /* ISO/IEC 23008-2, ITU-T Rec. H.265: General slice segment header */ ++ __u32 slice_segment_addr; ++ + /* ISO/IEC 23008-2, ITU-T Rec. H.265: NAL unit header */ + __u8 nal_unit_type; + __u8 nuh_temporal_id_plus1; +@@ -200,7 +203,7 @@ struct v4l2_ctrl_hevc_slice_params { + __u8 num_rps_poc_st_curr_after; + __u8 num_rps_poc_lt_curr; + +- __u8 padding; ++ __u8 padding[5]; + + /* ISO/IEC 23008-2, ITU-T Rec. H.265: General slice segment header */ + struct v4l2_hevc_dpb_entry dpb[V4L2_HEVC_DPB_ENTRIES_NUM_MAX]; + +From 180280b4b2e59865227ac90235ae902ce8088369 Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Sat, 23 May 2020 15:03:46 +0000 +Subject: [PATCH] WIP: media: uapi: hevc: add fields needed for rkvdec + +NOTE: these fields are used by rkvdec hevc backend + +Signed-off-by: Jonas Karlman +--- + include/media/hevc-ctrls.h | 16 ++++++++++++---- + 1 file changed, 12 insertions(+), 4 deletions(-) + +diff --git a/include/media/hevc-ctrls.h b/include/media/hevc-ctrls.h +index 3e2e32098312..3cc3b47e1417 100644 +--- a/include/media/hevc-ctrls.h ++++ b/include/media/hevc-ctrls.h +@@ -56,6 +56,9 @@ enum v4l2_mpeg_video_hevc_start_code { + /* The controls are not stable at the moment and will likely be reworked. */ + struct v4l2_ctrl_hevc_sps { + /* ISO/IEC 23008-2, ITU-T Rec. H.265: Sequence parameter set */ ++ __u8 video_parameter_set_id; ++ __u8 seq_parameter_set_id; ++ __u8 chroma_format_idc; + __u16 pic_width_in_luma_samples; + __u16 pic_height_in_luma_samples; + __u8 bit_depth_luma_minus8; +@@ -76,9 +79,8 @@ struct v4l2_ctrl_hevc_sps { + __u8 log2_diff_max_min_pcm_luma_coding_block_size; + __u8 num_short_term_ref_pic_sets; + __u8 num_long_term_ref_pics_sps; +- __u8 chroma_format_idc; + +- __u8 padding; ++ __u8 padding[7]; + + __u64 flags; + }; +@@ -105,7 +107,10 @@ struct v4l2_ctrl_hevc_sps { + + struct v4l2_ctrl_hevc_pps { + /* ISO/IEC 23008-2, ITU-T Rec. H.265: Picture parameter set */ ++ __u8 pic_parameter_set_id; + __u8 num_extra_slice_header_bits; ++ __u8 num_ref_idx_l0_default_active_minus1; ++ __u8 num_ref_idx_l1_default_active_minus1; + __s8 init_qp_minus26; + __u8 diff_cu_qp_delta_depth; + __s8 pps_cb_qp_offset; +@@ -118,7 +123,7 @@ struct v4l2_ctrl_hevc_pps { + __s8 pps_tc_offset_div2; + __u8 log2_parallel_merge_level_minus2; + +- __u8 padding[4]; ++ __u8 padding; + __u64 flags; + }; + +@@ -203,7 +208,10 @@ struct v4l2_ctrl_hevc_slice_params { + __u8 num_rps_poc_st_curr_after; + __u8 num_rps_poc_lt_curr; + +- __u8 padding[5]; ++ __u16 short_term_ref_pic_set_size; ++ __u16 long_term_ref_pic_set_size; ++ ++ __u8 padding; + + /* ISO/IEC 23008-2, ITU-T Rec. H.265: General slice segment header */ + struct v4l2_hevc_dpb_entry dpb[V4L2_HEVC_DPB_ENTRIES_NUM_MAX]; + +From 80ec0ecb1f7555aae1daa174cde084b3d9f42459 Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Sat, 23 May 2020 15:07:15 +0000 +Subject: [PATCH] HACK: media: uapi: hevc: tiles and num_slices + +--- + include/media/hevc-ctrls.h | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/include/media/hevc-ctrls.h b/include/media/hevc-ctrls.h +index 3cc3b47e1417..b33e1a8141e1 100644 +--- a/include/media/hevc-ctrls.h ++++ b/include/media/hevc-ctrls.h +@@ -80,7 +80,8 @@ struct v4l2_ctrl_hevc_sps { + __u8 num_short_term_ref_pic_sets; + __u8 num_long_term_ref_pics_sps; + +- __u8 padding[7]; ++ __u8 num_slices; ++ __u8 padding[6]; + + __u64 flags; + }; +@@ -174,6 +175,7 @@ struct v4l2_ctrl_hevc_slice_params { + + /* ISO/IEC 23008-2, ITU-T Rec. H.265: General slice segment header */ + __u32 slice_segment_addr; ++ __u32 num_entry_point_offsets; + + /* ISO/IEC 23008-2, ITU-T Rec. H.265: NAL unit header */ + __u8 nal_unit_type; +@@ -211,7 +213,9 @@ struct v4l2_ctrl_hevc_slice_params { + __u16 short_term_ref_pic_set_size; + __u16 long_term_ref_pic_set_size; + +- __u8 padding; ++ __u8 padding[5]; ++ ++ __u32 entry_point_offset_minus1[256]; + + /* ISO/IEC 23008-2, ITU-T Rec. H.265: General slice segment header */ + struct v4l2_hevc_dpb_entry dpb[V4L2_HEVC_DPB_ENTRIES_NUM_MAX]; + +From f35f02f322ebb97970d021bc82d9cad0b6432e15 Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Sat, 23 May 2020 15:17:45 +0000 +Subject: [PATCH] WIP: media: rkvdec: add HEVC backend + +NOTE: cabac table and scailing list code is copied 1:1 from mpp +TODO: fix lowdelay flag and rework the scaling list part + +Signed-off-by: Jonas Karlman +--- + drivers/staging/media/rkvdec/Makefile | 2 +- + drivers/staging/media/rkvdec/rkvdec-hevc.c | 2522 ++++++++++++++++++++ + drivers/staging/media/rkvdec/rkvdec-regs.h | 1 + + drivers/staging/media/rkvdec/rkvdec.c | 70 + + drivers/staging/media/rkvdec/rkvdec.h | 1 + + 5 files changed, 2595 insertions(+), 1 deletion(-) + create mode 100644 drivers/staging/media/rkvdec/rkvdec-hevc.c + +diff --git a/drivers/staging/media/rkvdec/Makefile b/drivers/staging/media/rkvdec/Makefile +index cb86b429cfaa..a77122641d14 100644 +--- a/drivers/staging/media/rkvdec/Makefile ++++ b/drivers/staging/media/rkvdec/Makefile +@@ -1,3 +1,3 @@ + obj-$(CONFIG_VIDEO_ROCKCHIP_VDEC) += rockchip-vdec.o + +-rockchip-vdec-y += rkvdec.o rkvdec-h264.o rkvdec-vp9.o ++rockchip-vdec-y += rkvdec.o rkvdec-h264.o rkvdec-hevc.o rkvdec-vp9.o +diff --git a/drivers/staging/media/rkvdec/rkvdec-hevc.c b/drivers/staging/media/rkvdec/rkvdec-hevc.c +new file mode 100644 +index 000000000000..03ba848411c6 +--- /dev/null ++++ b/drivers/staging/media/rkvdec/rkvdec-hevc.c +@@ -0,0 +1,2522 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Rockchip Video Decoder HEVC backend ++ * ++ * Copyright (C) 2019 Collabora, Ltd. ++ * Boris Brezillon ++ * ++ * Copyright (C) 2016 Rockchip Electronics Co., Ltd. ++ * Jeffy Chen ++ */ ++ ++#include ++ ++#include "rkvdec.h" ++#include "rkvdec-regs.h" ++ ++/* Size in u8/u32 units. */ ++#define RKV_CABAC_TABLE_SIZE 27456 ++#define RKV_SCALING_LIST_SIZE 1360 ++#define RKV_PPS_SIZE (80 / 4) ++#define RKV_PPS_LEN 64 ++#define RKV_RPS_SIZE (32 / 4) ++#define RKV_RPS_LEN 600 ++ ++struct rkvdec_sps_pps_packet { ++ u32 info[RKV_PPS_SIZE]; ++}; ++ ++struct rkvdec_rps_packet { ++ u32 info[RKV_RPS_SIZE]; ++}; ++ ++struct rkvdec_ps_field { ++ u16 offset; ++ u8 len; ++}; ++ ++#define PS_FIELD(_offset, _len) \ ++ ((struct rkvdec_ps_field){ _offset, _len }) ++ ++/* SPS */ ++#define VIDEO_PARAMETER_SET_ID PS_FIELD(0, 4) ++#define SEQ_PARAMETER_SET_ID PS_FIELD(4, 4) ++#define CHROMA_FORMAT_IDC PS_FIELD(8, 2) ++#define PIC_WIDTH_IN_LUMA_SAMPLES PS_FIELD(10, 13) ++#define PIC_HEIGHT_IN_LUMA_SAMPLES PS_FIELD(23, 13) ++#define BIT_DEPTH_LUMA PS_FIELD(36, 4) ++#define BIT_DEPTH_CHROMA PS_FIELD(40, 4) ++#define LOG2_MAX_PIC_ORDER_CNT_LSB PS_FIELD(44, 5) ++#define LOG2_DIFF_MAX_MIN_LUMA_CODING_BLOCK_SIZE PS_FIELD(49, 2) ++#define LOG2_MIN_LUMA_CODING_BLOCK_SIZE PS_FIELD(51, 3) ++#define LOG2_MIN_TRANSFORM_BLOCK_SIZE PS_FIELD(54, 3) ++#define LOG2_DIFF_MAX_MIN_LUMA_TRANSFORM_BLOCK_SIZE PS_FIELD(57, 2) ++#define MAX_TRANSFORM_HIERARCHY_DEPTH_INTER PS_FIELD(59, 3) ++#define MAX_TRANSFORM_HIERARCHY_DEPTH_INTRA PS_FIELD(62, 3) ++#define SCALING_LIST_ENABLED_FLAG PS_FIELD(65, 1) ++#define AMP_ENABLED_FLAG PS_FIELD(66, 1) ++#define SAMPLE_ADAPTIVE_OFFSET_ENABLED_FLAG PS_FIELD(67, 1) ++#define PCM_ENABLED_FLAG PS_FIELD(68, 1) ++#define PCM_SAMPLE_BIT_DEPTH_LUMA PS_FIELD(69, 4) ++#define PCM_SAMPLE_BIT_DEPTH_CHROMA PS_FIELD(73, 4) ++#define PCM_LOOP_FILTER_DISABLED_FLAG PS_FIELD(77, 1) ++#define LOG2_DIFF_MAX_MIN_PCM_LUMA_CODING_BLOCK_SIZE PS_FIELD(78, 3) ++#define LOG2_MIN_PCM_LUMA_CODING_BLOCK_SIZE PS_FIELD(81, 3) ++#define NUM_SHORT_TERM_REF_PIC_SETS PS_FIELD(84, 7) ++#define LONG_TERM_REF_PICS_PRESENT_FLAG PS_FIELD(91, 1) ++#define NUM_LONG_TERM_REF_PICS_SPS PS_FIELD(92, 6) ++#define SPS_TEMPORAL_MVP_ENABLED_FLAG PS_FIELD(98, 1) ++#define STRONG_INTRA_SMOOTHING_ENABLED_FLAG PS_FIELD(99, 1) ++/* PPS */ ++#define PIC_PARAMETER_SET_ID PS_FIELD(128, 6) ++#define PPS_SEQ_PARAMETER_SET_ID PS_FIELD(134, 4) ++#define DEPENDENT_SLICE_SEGMENTS_ENABLED_FLAG PS_FIELD(138, 1) ++#define OUTPUT_FLAG_PRESENT_FLAG PS_FIELD(139, 1) ++#define NUM_EXTRA_SLICE_HEADER_BITS PS_FIELD(140, 13) ++#define SIGN_DATA_HIDING_ENABLED_FLAG PS_FIELD(153, 1) ++#define CABAC_INIT_PRESENT_FLAG PS_FIELD(154, 1) ++#define NUM_REF_IDX_L0_DEFAULT_ACTIVE PS_FIELD(155, 4) ++#define NUM_REF_IDX_L1_DEFAULT_ACTIVE PS_FIELD(159, 4) ++#define INIT_QP_MINUS26 PS_FIELD(163, 7) ++#define CONSTRAINED_INTRA_PRED_FLAG PS_FIELD(170, 1) ++#define TRANSFORM_SKIP_ENABLED_FLAG PS_FIELD(171, 1) ++#define CU_QP_DELTA_ENABLED_FLAG PS_FIELD(172, 1) ++#define LOG2_MIN_CU_QP_DELTA_SIZE PS_FIELD(173, 3) ++#define PPS_CB_QP_OFFSET PS_FIELD(176, 5) ++#define PPS_CR_QP_OFFSET PS_FIELD(181, 5) ++#define PPS_SLICE_CHROMA_QP_OFFSETS_PRESENT_FLAG PS_FIELD(186, 1) ++#define WEIGHTED_PRED_FLAG PS_FIELD(187, 1) ++#define WEIGHTED_BIPRED_FLAG PS_FIELD(188, 1) ++#define TRANSQUANT_BYPASS_ENABLED_FLAG PS_FIELD(189, 1) ++#define TILES_ENABLED_FLAG PS_FIELD(190, 1) ++#define ENTROPY_CODING_SYNC_ENABLED_FLAG PS_FIELD(191, 1) ++#define PPS_LOOP_FILTER_ACROSS_SLICES_ENABLED_FLAG PS_FIELD(192, 1) ++#define LOOP_FILTER_ACROSS_TILES_ENABLED_FLAG PS_FIELD(193, 1) ++#define DEBLOCKING_FILTER_OVERRIDE_ENABLED_FLAG PS_FIELD(194, 1) ++#define PPS_DEBLOCKING_FILTER_DISABLED_FLAG PS_FIELD(195, 1) ++#define PPS_BETA_OFFSET_DIV2 PS_FIELD(196, 4) ++#define PPS_TC_OFFSET_DIV2 PS_FIELD(200, 4) ++#define LISTS_MODIFICATION_PRESENT_FLAG PS_FIELD(204, 1) ++#define LOG2_PARALLEL_MERGE_LEVEL PS_FIELD(205, 3) ++#define SLICE_SEGMENT_HEADER_EXTENSION_PRESENT_FLAG PS_FIELD(208, 1) ++#define NUM_TILE_COLUMNS PS_FIELD(212, 5) ++#define NUM_TILE_ROWS PS_FIELD(217, 5) ++#define COLUMN_WIDTH(i) PS_FIELD(256 + (i * 8), 8) ++#define ROW_HEIGHT(i) PS_FIELD(416 + (i * 8), 8) ++#define SCALING_LIST_ADDRESS PS_FIELD(592, 32) ++ ++/* Data structure describing auxiliary buffer format. */ ++struct rkvdec_hevc_priv_tbl { ++ u8 cabac_table[RKV_CABAC_TABLE_SIZE]; ++ u8 scaling_list[RKV_SCALING_LIST_SIZE]; ++ struct rkvdec_sps_pps_packet param_set[RKV_PPS_LEN]; ++ struct rkvdec_rps_packet rps[RKV_RPS_LEN]; ++}; ++ ++struct rkvdec_hevc_run { ++ struct rkvdec_run base; ++ const struct v4l2_ctrl_hevc_slice_params *slices_params; ++ const struct v4l2_ctrl_hevc_sps *sps; ++ const struct v4l2_ctrl_hevc_pps *pps; ++ const struct v4l2_ctrl_hevc_scaling_matrix *scaling_matrix; ++ int num_slices; ++}; ++ ++struct rkvdec_hevc_ctx { ++ struct rkvdec_aux_buf priv_tbl; ++ struct v4l2_ctrl_hevc_scaling_matrix scaling_matrix_cache; ++}; ++ ++// TODO: refactor scaling list code, was copied 1:1 from mpp ++ ++typedef struct ScalingList { ++ /* This is a little wasteful, since sizeID 0 only needs 8 coeffs, ++ * and size ID 3 only has 2 arrays, not 6. */ ++ u8 sl[4][6][64]; ++ u8 sl_dc[2][6]; ++} scalingList_t; ++ ++typedef struct ScalingFactor_Model { ++ u8 scalingfactor0[1248]; ++ u8 scalingfactor1[96]; /*4X4 TU Rotate, total 16X4*/ ++ u8 scalingdc[12]; /*N1005 Vienna Meeting*/ ++ u8 reserverd[4]; /*16Bytes align*/ ++} scalingFactor_t; ++ ++#define SCALING_LIST_SIZE_NUM 4 ++ ++static void ++hal_record_scaling_list(scalingFactor_t *pScalingFactor_out, ++ scalingList_t *pScalingList) ++{ ++ int i; ++ u32 g_scalingListNum_model[SCALING_LIST_SIZE_NUM] = {6, 6, 6, 2}; // from C Model ++ u32 nIndex = 0; ++ u32 sizeId, matrixId, listId; ++ u8 *p = pScalingFactor_out->scalingfactor0; ++ u8 tmpBuf[8 * 8]; ++ ++ //output non-default scalingFactor Table (1248 BYTES) ++ for (sizeId = 0; sizeId < SCALING_LIST_SIZE_NUM; sizeId++) { ++ for (listId = 0; listId < g_scalingListNum_model[sizeId]; listId++) { ++ if (sizeId < 3) { ++ for (i = 0; i < (sizeId == 0 ? 16 : 64); i++) { ++ pScalingFactor_out->scalingfactor0[nIndex++] = (u8)pScalingList->sl[sizeId][listId][i]; ++ } ++ } else { ++ for (i = 0; i < 64; i ++) { ++ pScalingFactor_out->scalingfactor0[nIndex++] = (u8)pScalingList->sl[sizeId][listId][i]; ++ } ++ for (i = 0; i < 128; i ++) { ++ pScalingFactor_out->scalingfactor0[nIndex++] = 0; ++ } ++ } ++ } ++ } ++ //output non-default scalingFactor Table Rotation(96 Bytes) ++ nIndex = 0; ++ for (listId = 0; listId < g_scalingListNum_model[0]; listId++) { ++ u8 temp16[16] = {0}; ++ for (i = 0; i < 16; i ++) { ++ temp16[i] = (u8)pScalingList->sl[0][listId][i]; ++ } ++ for (i = 0; i < 4; i ++) { ++ pScalingFactor_out->scalingfactor1[nIndex++] = temp16[i]; ++ pScalingFactor_out->scalingfactor1[nIndex++] = temp16[i + 4]; ++ pScalingFactor_out->scalingfactor1[nIndex++] = temp16[i + 8]; ++ pScalingFactor_out->scalingfactor1[nIndex++] = temp16[i + 12]; ++ } ++ } ++ //output non-default ScalingList_DC_Coeff (12 BYTES) ++ nIndex = 0; ++ for (listId = 0; listId < g_scalingListNum_model[2]; listId++) { //sizeId = 2 ++ pScalingFactor_out->scalingdc[nIndex++] = (u8)pScalingList->sl_dc[0][listId];// zrh warning: sl_dc differed from scalingList->getScalingListDC ++ } ++ for (listId = 0; listId < g_scalingListNum_model[3]; listId++) { //sizeId = 3 ++ pScalingFactor_out->scalingdc[nIndex++] = (u8)pScalingList->sl_dc[1][listId];// zrh warning: sl_dc differed from scalingList->getScalingListDC ++ pScalingFactor_out->scalingdc[nIndex++] = 0; ++ pScalingFactor_out->scalingdc[nIndex++] = 0; ++ } ++ ++ //align 16X address ++ nIndex = 0; ++ for (i = 0; i < 4; i ++) { ++ pScalingFactor_out->reserverd[nIndex++] = 0; ++ } ++ ++ //----------------------All above code show the normal store way in HM-------------------------- ++ //--------from now on, the scalingfactor0 is rotated 90', the scalingfactor1 is also rotated 90' ++ ++ //sizeId == 0 ++ for (matrixId = 0; matrixId < 6; matrixId++) { ++ p = pScalingFactor_out->scalingfactor0 + matrixId * 16; ++ ++ for (i = 0; i < 4; i++) { ++ tmpBuf[4 * 0 + i] = p[i * 4 + 0]; ++ tmpBuf[4 * 1 + i] = p[i * 4 + 1]; ++ tmpBuf[4 * 2 + i] = p[i * 4 + 2]; ++ tmpBuf[4 * 3 + i] = p[i * 4 + 3]; ++ } ++ memcpy(p, tmpBuf, 4 * 4 * sizeof(u8)); ++ } ++ //sizeId == 1 ++ for (matrixId = 0; matrixId < 6; matrixId++) { ++ p = pScalingFactor_out->scalingfactor0 + 6 * 16 + matrixId * 64; ++ ++ for (i = 0; i < 8; i++) { ++ tmpBuf[8 * 0 + i] = p[i * 8 + 0]; ++ tmpBuf[8 * 1 + i] = p[i * 8 + 1]; ++ tmpBuf[8 * 2 + i] = p[i * 8 + 2]; ++ tmpBuf[8 * 3 + i] = p[i * 8 + 3]; ++ tmpBuf[8 * 4 + i] = p[i * 8 + 4]; ++ tmpBuf[8 * 5 + i] = p[i * 8 + 5]; ++ tmpBuf[8 * 6 + i] = p[i * 8 + 6]; ++ tmpBuf[8 * 7 + i] = p[i * 8 + 7]; ++ } ++ memcpy(p, tmpBuf, 8 * 8 * sizeof(u8)); ++ } ++ //sizeId == 2 ++ for (matrixId = 0; matrixId < 6; matrixId++) { ++ p = pScalingFactor_out->scalingfactor0 + 6 * 16 + 6 * 64 + matrixId * 64; ++ ++ for (i = 0; i < 8; i++) { ++ tmpBuf[8 * 0 + i] = p[i * 8 + 0]; ++ tmpBuf[8 * 1 + i] = p[i * 8 + 1]; ++ tmpBuf[8 * 2 + i] = p[i * 8 + 2]; ++ tmpBuf[8 * 3 + i] = p[i * 8 + 3]; ++ tmpBuf[8 * 4 + i] = p[i * 8 + 4]; ++ tmpBuf[8 * 5 + i] = p[i * 8 + 5]; ++ tmpBuf[8 * 6 + i] = p[i * 8 + 6]; ++ tmpBuf[8 * 7 + i] = p[i * 8 + 7]; ++ } ++ memcpy(p, tmpBuf, 8 * 8 * sizeof(u8)); ++ } ++ //sizeId == 3 ++ for (matrixId = 0; matrixId < 6; matrixId++) { ++ p = pScalingFactor_out->scalingfactor0 + 6 * 16 + 6 * 64 + 6 * 64 + matrixId * 64; ++ ++ for (i = 0; i < 8; i++) { ++ tmpBuf[8 * 0 + i] = p[i * 8 + 0]; ++ tmpBuf[8 * 1 + i] = p[i * 8 + 1]; ++ tmpBuf[8 * 2 + i] = p[i * 8 + 2]; ++ tmpBuf[8 * 3 + i] = p[i * 8 + 3]; ++ tmpBuf[8 * 4 + i] = p[i * 8 + 4]; ++ tmpBuf[8 * 5 + i] = p[i * 8 + 5]; ++ tmpBuf[8 * 6 + i] = p[i * 8 + 6]; ++ tmpBuf[8 * 7 + i] = p[i * 8 + 7]; ++ } ++ memcpy(p, tmpBuf, 8 * 8 * sizeof(u8)); ++ } ++ ++ //sizeId == 0 ++ for (matrixId = 0; matrixId < 6; matrixId++) { ++ p = pScalingFactor_out->scalingfactor1 + matrixId * 16; ++ ++ for (i = 0; i < 4; i++) { ++ tmpBuf[4 * 0 + i] = p[i * 4 + 0]; ++ tmpBuf[4 * 1 + i] = p[i * 4 + 1]; ++ tmpBuf[4 * 2 + i] = p[i * 4 + 2]; ++ tmpBuf[4 * 3 + i] = p[i * 4 + 3]; ++ } ++ memcpy(p, tmpBuf, 4 * 4 * sizeof(u8)); ++ } ++} ++ ++static const u8 rkvdec_hevc_cabac_table[RKV_CABAC_TABLE_SIZE] = { ++ 0x07, 0x0f, 0x48, 0x58, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x0f, 0x40, 0x40, 0x40, 0x0f, 0x68, ++ 0x48, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x40, 0x40, 0x68, ++ 0x58, 0x60, 0x40, 0x1f, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x48, 0x48, 0x60, 0x60, 0x50, 0x58, ++ 0x50, 0x07, 0x58, 0x68, 0x50, 0x58, 0x68, 0x68, 0x68, 0x68, 0x68, 0x50, 0x48, 0x68, 0x60, 0x60, ++ 0x50, 0x58, 0x50, 0x07, 0x58, 0x68, 0x50, 0x58, 0x68, 0x68, 0x68, 0x68, 0x68, 0x50, 0x48, 0x68, ++ 0x48, 0x48, 0x1f, 0x58, 0x68, 0x68, 0x58, 0x60, 0x60, 0x60, 0x50, 0x50, 0x50, 0x48, 0x58, 0x58, ++ 0x37, 0x07, 0x58, 0x48, 0x58, 0x58, 0x37, 0x07, 0x58, 0x48, 0x58, 0x58, 0x37, 0x07, 0x58, 0x50, ++ 0x48, 0x1f, 0x1f, 0x0f, 0x0f, 0x0f, 0x0f, 0x07, 0x0f, 0x48, 0x68, 0x0f, 0x48, 0x68, 0x40, 0x40, ++ 0x50, 0x50, 0x07, 0x40, 0x50, 0x0f, 0x40, 0x48, 0x07, 0x40, 0x27, 0x50, 0x48, 0x48, 0x40, 0x0f, ++ 0x50, 0x37, 0x1f, 0x1f, 0x50, 0x37, 0x40, 0x27, 0x40, 0x07, 0x0f, 0x17, 0x0f, 0x0f, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x0f, 0x47, 0x57, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x0f, 0x40, 0x40, 0x40, 0x0f, 0x66, ++ 0x47, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x00, 0x00, 0x67, ++ 0x57, 0x5e, 0x00, 0x1f, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x47, 0x47, 0x5f, 0x5f, 0x4f, 0x57, ++ 0x4f, 0x07, 0x57, 0x67, 0x4f, 0x57, 0x67, 0x67, 0x67, 0x67, 0x66, 0x4f, 0x47, 0x66, 0x5f, 0x5f, ++ 0x4f, 0x57, 0x4f, 0x07, 0x57, 0x67, 0x4f, 0x57, 0x67, 0x67, 0x67, 0x67, 0x66, 0x4f, 0x47, 0x66, ++ 0x46, 0x48, 0x20, 0x57, 0x67, 0x67, 0x57, 0x5f, 0x5f, 0x5e, 0x4f, 0x4f, 0x4f, 0x47, 0x57, 0x57, ++ 0x37, 0x07, 0x57, 0x47, 0x57, 0x57, 0x37, 0x07, 0x57, 0x47, 0x57, 0x57, 0x37, 0x07, 0x57, 0x4f, ++ 0x47, 0x1f, 0x1f, 0x0f, 0x10, 0x0f, 0x10, 0x07, 0x10, 0x47, 0x67, 0x10, 0x47, 0x67, 0x40, 0x40, ++ 0x4f, 0x4e, 0x08, 0x00, 0x4f, 0x0f, 0x00, 0x47, 0x07, 0x01, 0x27, 0x4e, 0x47, 0x47, 0x00, 0x0f, ++ 0x4f, 0x37, 0x1f, 0x1f, 0x4f, 0x36, 0x00, 0x27, 0x00, 0x07, 0x10, 0x17, 0x0f, 0x0f, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x0e, 0x47, 0x57, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x0e, 0x40, 0x40, 0x40, 0x0e, 0x64, ++ 0x47, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x00, 0x00, 0x66, ++ 0x57, 0x5d, 0x00, 0x1e, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x47, 0x47, 0x5e, 0x5e, 0x4e, 0x56, ++ 0x4f, 0x07, 0x56, 0x66, 0x4f, 0x56, 0x66, 0x67, 0x66, 0x66, 0x64, 0x4e, 0x46, 0x64, 0x5e, 0x5e, ++ 0x4e, 0x56, 0x4f, 0x07, 0x56, 0x66, 0x4f, 0x56, 0x66, 0x67, 0x66, 0x66, 0x64, 0x4e, 0x46, 0x64, ++ 0x45, 0x48, 0x20, 0x57, 0x66, 0x66, 0x56, 0x5e, 0x5e, 0x5d, 0x4e, 0x4e, 0x4e, 0x46, 0x56, 0x57, ++ 0x36, 0x07, 0x56, 0x46, 0x56, 0x57, 0x36, 0x07, 0x56, 0x46, 0x56, 0x57, 0x36, 0x07, 0x56, 0x4f, ++ 0x47, 0x1e, 0x1e, 0x0f, 0x10, 0x0f, 0x10, 0x07, 0x10, 0x47, 0x66, 0x10, 0x47, 0x66, 0x40, 0x40, ++ 0x4f, 0x4d, 0x08, 0x00, 0x4f, 0x0f, 0x00, 0x47, 0x07, 0x03, 0x27, 0x4d, 0x47, 0x46, 0x01, 0x0f, ++ 0x4f, 0x36, 0x1f, 0x1e, 0x4f, 0x34, 0x01, 0x26, 0x00, 0x07, 0x10, 0x17, 0x0f, 0x0f, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x0d, 0x47, 0x57, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x0e, 0x40, 0x40, 0x40, 0x0e, 0x62, ++ 0x47, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x00, 0x00, 0x65, ++ 0x57, 0x5c, 0x00, 0x1e, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x47, 0x47, 0x5d, 0x5d, 0x4e, 0x56, ++ 0x4f, 0x07, 0x56, 0x66, 0x4f, 0x55, 0x65, 0x67, 0x66, 0x65, 0x63, 0x4d, 0x46, 0x62, 0x5d, 0x5d, ++ 0x4e, 0x56, 0x4f, 0x07, 0x56, 0x66, 0x4f, 0x55, 0x65, 0x67, 0x66, 0x65, 0x63, 0x4d, 0x46, 0x62, ++ 0x44, 0x48, 0x20, 0x57, 0x65, 0x65, 0x56, 0x5d, 0x5d, 0x5c, 0x4e, 0x4d, 0x4e, 0x45, 0x56, 0x57, ++ 0x36, 0x07, 0x56, 0x45, 0x56, 0x57, 0x36, 0x07, 0x56, 0x45, 0x56, 0x57, 0x36, 0x07, 0x56, 0x4f, ++ 0x47, 0x1e, 0x1e, 0x0f, 0x10, 0x0f, 0x10, 0x07, 0x10, 0x47, 0x65, 0x10, 0x47, 0x65, 0x40, 0x40, ++ 0x4f, 0x4c, 0x08, 0x00, 0x4f, 0x0f, 0x00, 0x47, 0x07, 0x04, 0x27, 0x4c, 0x47, 0x45, 0x01, 0x0f, ++ 0x4f, 0x36, 0x1f, 0x1e, 0x4f, 0x33, 0x01, 0x25, 0x00, 0x07, 0x10, 0x17, 0x0f, 0x0f, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x0c, 0x46, 0x56, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x0d, 0x40, 0x40, 0x40, 0x0d, 0x60, ++ 0x46, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x01, 0x01, 0x64, ++ 0x56, 0x5b, 0x01, 0x1d, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x46, 0x46, 0x5c, 0x5c, 0x4d, 0x55, ++ 0x4e, 0x07, 0x55, 0x65, 0x4e, 0x54, 0x64, 0x66, 0x65, 0x64, 0x61, 0x4c, 0x45, 0x60, 0x5c, 0x5c, ++ 0x4d, 0x55, 0x4e, 0x07, 0x55, 0x65, 0x4e, 0x54, 0x64, 0x66, 0x65, 0x64, 0x61, 0x4c, 0x45, 0x60, ++ 0x43, 0x49, 0x21, 0x56, 0x64, 0x64, 0x55, 0x5c, 0x5c, 0x5b, 0x4d, 0x4c, 0x4d, 0x44, 0x55, 0x56, ++ 0x35, 0x07, 0x55, 0x44, 0x55, 0x56, 0x35, 0x07, 0x55, 0x44, 0x55, 0x56, 0x35, 0x07, 0x55, 0x4e, ++ 0x46, 0x1d, 0x1d, 0x0f, 0x11, 0x0f, 0x11, 0x07, 0x11, 0x46, 0x64, 0x11, 0x46, 0x64, 0x40, 0x40, ++ 0x4e, 0x4b, 0x09, 0x01, 0x4e, 0x0f, 0x01, 0x46, 0x07, 0x06, 0x27, 0x4b, 0x46, 0x44, 0x02, 0x0f, ++ 0x4e, 0x35, 0x1e, 0x1d, 0x4e, 0x31, 0x02, 0x24, 0x01, 0x07, 0x11, 0x16, 0x0f, 0x0f, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x0b, 0x46, 0x56, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x0c, 0x40, 0x40, 0x40, 0x0c, 0x5e, ++ 0x46, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x01, 0x01, 0x63, ++ 0x56, 0x59, 0x01, 0x1c, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x46, 0x46, 0x5b, 0x5b, 0x4c, 0x54, ++ 0x4e, 0x07, 0x54, 0x64, 0x4e, 0x53, 0x63, 0x66, 0x64, 0x63, 0x60, 0x4b, 0x44, 0x5e, 0x5b, 0x5b, ++ 0x4c, 0x54, 0x4e, 0x07, 0x54, 0x64, 0x4e, 0x53, 0x63, 0x66, 0x64, 0x63, 0x60, 0x4b, 0x44, 0x5e, ++ 0x41, 0x49, 0x21, 0x56, 0x63, 0x63, 0x54, 0x5b, 0x5b, 0x59, 0x4c, 0x4b, 0x4c, 0x43, 0x54, 0x56, ++ 0x34, 0x07, 0x54, 0x43, 0x54, 0x56, 0x34, 0x07, 0x54, 0x43, 0x54, 0x56, 0x34, 0x07, 0x54, 0x4e, ++ 0x46, 0x1c, 0x1c, 0x0f, 0x11, 0x0f, 0x11, 0x07, 0x11, 0x46, 0x63, 0x11, 0x46, 0x63, 0x40, 0x40, ++ 0x4e, 0x49, 0x09, 0x01, 0x4e, 0x0f, 0x01, 0x46, 0x07, 0x07, 0x27, 0x49, 0x46, 0x43, 0x03, 0x0f, ++ 0x4e, 0x34, 0x1e, 0x1c, 0x4e, 0x30, 0x03, 0x23, 0x01, 0x07, 0x11, 0x16, 0x0f, 0x0f, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x0a, 0x46, 0x56, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x0c, 0x40, 0x40, 0x40, 0x0c, 0x5c, ++ 0x46, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x01, 0x01, 0x62, ++ 0x56, 0x58, 0x01, 0x1c, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x46, 0x46, 0x5a, 0x5a, 0x4c, 0x54, ++ 0x4e, 0x07, 0x54, 0x64, 0x4e, 0x52, 0x62, 0x66, 0x64, 0x62, 0x5e, 0x4a, 0x44, 0x5c, 0x5a, 0x5a, ++ 0x4c, 0x54, 0x4e, 0x07, 0x54, 0x64, 0x4e, 0x52, 0x62, 0x66, 0x64, 0x62, 0x5e, 0x4a, 0x44, 0x5c, ++ 0x40, 0x49, 0x21, 0x56, 0x62, 0x62, 0x54, 0x5a, 0x5a, 0x58, 0x4c, 0x4a, 0x4c, 0x42, 0x54, 0x56, ++ 0x34, 0x07, 0x54, 0x42, 0x54, 0x56, 0x34, 0x07, 0x54, 0x42, 0x54, 0x56, 0x34, 0x07, 0x54, 0x4e, ++ 0x46, 0x1c, 0x1c, 0x0f, 0x11, 0x0f, 0x11, 0x07, 0x11, 0x46, 0x62, 0x11, 0x46, 0x62, 0x40, 0x40, ++ 0x4e, 0x48, 0x09, 0x01, 0x4e, 0x0f, 0x01, 0x46, 0x07, 0x09, 0x27, 0x48, 0x46, 0x42, 0x03, 0x0f, ++ 0x4e, 0x34, 0x1e, 0x1c, 0x4e, 0x2e, 0x03, 0x22, 0x01, 0x07, 0x11, 0x16, 0x0f, 0x0f, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x09, 0x45, 0x55, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x0b, 0x40, 0x40, 0x40, 0x0b, 0x5a, ++ 0x45, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x02, 0x02, 0x61, ++ 0x55, 0x57, 0x02, 0x1b, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x45, 0x45, 0x59, 0x59, 0x4b, 0x53, ++ 0x4d, 0x07, 0x53, 0x63, 0x4d, 0x51, 0x61, 0x65, 0x63, 0x61, 0x5d, 0x49, 0x43, 0x5a, 0x59, 0x59, ++ 0x4b, 0x53, 0x4d, 0x07, 0x53, 0x63, 0x4d, 0x51, 0x61, 0x65, 0x63, 0x61, 0x5d, 0x49, 0x43, 0x5a, ++ 0x00, 0x4a, 0x22, 0x55, 0x61, 0x61, 0x53, 0x59, 0x59, 0x57, 0x4b, 0x49, 0x4b, 0x41, 0x53, 0x55, ++ 0x33, 0x07, 0x53, 0x41, 0x53, 0x55, 0x33, 0x07, 0x53, 0x41, 0x53, 0x55, 0x33, 0x07, 0x53, 0x4d, ++ 0x45, 0x1b, 0x1b, 0x0f, 0x12, 0x0f, 0x12, 0x07, 0x12, 0x45, 0x61, 0x12, 0x45, 0x61, 0x40, 0x40, ++ 0x4d, 0x47, 0x0a, 0x02, 0x4d, 0x0f, 0x02, 0x45, 0x07, 0x0a, 0x27, 0x47, 0x45, 0x41, 0x04, 0x0f, ++ 0x4d, 0x33, 0x1d, 0x1b, 0x4d, 0x2d, 0x04, 0x21, 0x02, 0x07, 0x12, 0x15, 0x0f, 0x0f, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x08, 0x45, 0x55, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x0a, 0x40, 0x40, 0x40, 0x0a, 0x59, ++ 0x45, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x02, 0x02, 0x60, ++ 0x55, 0x56, 0x02, 0x1a, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x45, 0x45, 0x58, 0x58, 0x4b, 0x53, ++ 0x4d, 0x07, 0x53, 0x63, 0x4d, 0x50, 0x60, 0x65, 0x63, 0x60, 0x5b, 0x48, 0x43, 0x59, 0x58, 0x58, ++ 0x4b, 0x53, 0x4d, 0x07, 0x53, 0x63, 0x4d, 0x50, 0x60, 0x65, 0x63, 0x60, 0x5b, 0x48, 0x43, 0x59, ++ 0x01, 0x4a, 0x22, 0x55, 0x60, 0x60, 0x53, 0x58, 0x58, 0x56, 0x4b, 0x48, 0x4b, 0x40, 0x53, 0x55, ++ 0x32, 0x07, 0x53, 0x40, 0x53, 0x55, 0x32, 0x07, 0x53, 0x40, 0x53, 0x55, 0x32, 0x07, 0x53, 0x4d, ++ 0x45, 0x1a, 0x1a, 0x0f, 0x12, 0x0f, 0x12, 0x07, 0x12, 0x45, 0x60, 0x12, 0x45, 0x60, 0x40, 0x40, ++ 0x4d, 0x46, 0x0a, 0x02, 0x4d, 0x0f, 0x02, 0x45, 0x07, 0x0c, 0x27, 0x46, 0x45, 0x40, 0x04, 0x0f, ++ 0x4d, 0x32, 0x1d, 0x1a, 0x4d, 0x2b, 0x04, 0x20, 0x02, 0x07, 0x12, 0x15, 0x0f, 0x0f, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x07, 0x45, 0x55, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x0a, 0x40, 0x40, 0x40, 0x0a, 0x57, ++ 0x45, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x02, 0x02, 0x5f, ++ 0x55, 0x54, 0x02, 0x1a, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x45, 0x45, 0x57, 0x57, 0x4a, 0x52, ++ 0x4d, 0x07, 0x52, 0x62, 0x4d, 0x4f, 0x5f, 0x65, 0x62, 0x5f, 0x59, 0x47, 0x42, 0x57, 0x57, 0x57, ++ 0x4a, 0x52, 0x4d, 0x07, 0x52, 0x62, 0x4d, 0x4f, 0x5f, 0x65, 0x62, 0x5f, 0x59, 0x47, 0x42, 0x57, ++ 0x03, 0x4a, 0x22, 0x55, 0x5f, 0x5f, 0x52, 0x57, 0x57, 0x54, 0x4a, 0x47, 0x4a, 0x00, 0x52, 0x55, ++ 0x32, 0x07, 0x52, 0x00, 0x52, 0x55, 0x32, 0x07, 0x52, 0x00, 0x52, 0x55, 0x32, 0x07, 0x52, 0x4d, ++ 0x45, 0x1a, 0x1a, 0x0f, 0x12, 0x0f, 0x12, 0x07, 0x12, 0x45, 0x5f, 0x12, 0x45, 0x5f, 0x40, 0x40, ++ 0x4d, 0x44, 0x0a, 0x02, 0x4d, 0x0f, 0x02, 0x45, 0x07, 0x0e, 0x27, 0x44, 0x45, 0x00, 0x05, 0x0f, ++ 0x4d, 0x32, 0x1d, 0x1a, 0x4d, 0x29, 0x05, 0x1f, 0x02, 0x07, 0x12, 0x15, 0x0f, 0x0f, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x06, 0x44, 0x54, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x09, 0x40, 0x40, 0x40, 0x09, 0x55, ++ 0x44, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x03, 0x03, 0x5e, ++ 0x54, 0x53, 0x03, 0x19, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x44, 0x44, 0x56, 0x56, 0x49, 0x51, ++ 0x4c, 0x07, 0x51, 0x61, 0x4c, 0x4e, 0x5e, 0x64, 0x61, 0x5e, 0x58, 0x46, 0x41, 0x55, 0x56, 0x56, ++ 0x49, 0x51, 0x4c, 0x07, 0x51, 0x61, 0x4c, 0x4e, 0x5e, 0x64, 0x61, 0x5e, 0x58, 0x46, 0x41, 0x55, ++ 0x04, 0x4b, 0x23, 0x54, 0x5e, 0x5e, 0x51, 0x56, 0x56, 0x53, 0x49, 0x46, 0x49, 0x01, 0x51, 0x54, ++ 0x31, 0x07, 0x51, 0x01, 0x51, 0x54, 0x31, 0x07, 0x51, 0x01, 0x51, 0x54, 0x31, 0x07, 0x51, 0x4c, ++ 0x44, 0x19, 0x19, 0x0f, 0x13, 0x0f, 0x13, 0x07, 0x13, 0x44, 0x5e, 0x13, 0x44, 0x5e, 0x40, 0x40, ++ 0x4c, 0x43, 0x0b, 0x03, 0x4c, 0x0f, 0x03, 0x44, 0x07, 0x0f, 0x27, 0x43, 0x44, 0x01, 0x06, 0x0f, ++ 0x4c, 0x31, 0x1c, 0x19, 0x4c, 0x28, 0x06, 0x1e, 0x03, 0x07, 0x13, 0x14, 0x0f, 0x0f, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x05, 0x44, 0x54, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x09, 0x40, 0x40, 0x40, 0x09, 0x53, ++ 0x44, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x03, 0x03, 0x5d, ++ 0x54, 0x52, 0x03, 0x19, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x44, 0x44, 0x55, 0x55, 0x49, 0x51, ++ 0x4c, 0x07, 0x51, 0x61, 0x4c, 0x4d, 0x5d, 0x64, 0x61, 0x5d, 0x56, 0x45, 0x41, 0x53, 0x55, 0x55, ++ 0x49, 0x51, 0x4c, 0x07, 0x51, 0x61, 0x4c, 0x4d, 0x5d, 0x64, 0x61, 0x5d, 0x56, 0x45, 0x41, 0x53, ++ 0x05, 0x4b, 0x23, 0x54, 0x5d, 0x5d, 0x51, 0x55, 0x55, 0x52, 0x49, 0x45, 0x49, 0x02, 0x51, 0x54, ++ 0x31, 0x07, 0x51, 0x02, 0x51, 0x54, 0x31, 0x07, 0x51, 0x02, 0x51, 0x54, 0x31, 0x07, 0x51, 0x4c, ++ 0x44, 0x19, 0x19, 0x0f, 0x13, 0x0f, 0x13, 0x07, 0x13, 0x44, 0x5d, 0x13, 0x44, 0x5d, 0x40, 0x40, ++ 0x4c, 0x42, 0x0b, 0x03, 0x4c, 0x0f, 0x03, 0x44, 0x07, 0x11, 0x27, 0x42, 0x44, 0x02, 0x06, 0x0f, ++ 0x4c, 0x31, 0x1c, 0x19, 0x4c, 0x26, 0x06, 0x1d, 0x03, 0x07, 0x13, 0x14, 0x0f, 0x0f, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x04, 0x44, 0x54, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x08, 0x40, 0x40, 0x40, 0x08, 0x51, ++ 0x44, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x03, 0x03, 0x5c, ++ 0x54, 0x51, 0x03, 0x18, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x44, 0x44, 0x54, 0x54, 0x48, 0x50, ++ 0x4c, 0x07, 0x50, 0x60, 0x4c, 0x4c, 0x5c, 0x64, 0x60, 0x5c, 0x55, 0x44, 0x40, 0x51, 0x54, 0x54, ++ 0x48, 0x50, 0x4c, 0x07, 0x50, 0x60, 0x4c, 0x4c, 0x5c, 0x64, 0x60, 0x5c, 0x55, 0x44, 0x40, 0x51, ++ 0x06, 0x4b, 0x23, 0x54, 0x5c, 0x5c, 0x50, 0x54, 0x54, 0x51, 0x48, 0x44, 0x48, 0x03, 0x50, 0x54, ++ 0x30, 0x07, 0x50, 0x03, 0x50, 0x54, 0x30, 0x07, 0x50, 0x03, 0x50, 0x54, 0x30, 0x07, 0x50, 0x4c, ++ 0x44, 0x18, 0x18, 0x0f, 0x13, 0x0f, 0x13, 0x07, 0x13, 0x44, 0x5c, 0x13, 0x44, 0x5c, 0x40, 0x40, ++ 0x4c, 0x41, 0x0b, 0x03, 0x4c, 0x0f, 0x03, 0x44, 0x07, 0x12, 0x27, 0x41, 0x44, 0x03, 0x07, 0x0f, ++ 0x4c, 0x30, 0x1c, 0x18, 0x4c, 0x25, 0x07, 0x1c, 0x03, 0x07, 0x13, 0x14, 0x0f, 0x0f, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x03, 0x43, 0x53, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x40, 0x40, 0x40, 0x07, 0x4f, ++ 0x43, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x04, 0x04, 0x5b, ++ 0x53, 0x4f, 0x04, 0x17, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x43, 0x43, 0x53, 0x53, 0x47, 0x4f, ++ 0x4b, 0x07, 0x4f, 0x5f, 0x4b, 0x4b, 0x5b, 0x63, 0x5f, 0x5b, 0x53, 0x43, 0x00, 0x4f, 0x53, 0x53, ++ 0x47, 0x4f, 0x4b, 0x07, 0x4f, 0x5f, 0x4b, 0x4b, 0x5b, 0x63, 0x5f, 0x5b, 0x53, 0x43, 0x00, 0x4f, ++ 0x08, 0x4c, 0x24, 0x53, 0x5b, 0x5b, 0x4f, 0x53, 0x53, 0x4f, 0x47, 0x43, 0x47, 0x04, 0x4f, 0x53, ++ 0x2f, 0x07, 0x4f, 0x04, 0x4f, 0x53, 0x2f, 0x07, 0x4f, 0x04, 0x4f, 0x53, 0x2f, 0x07, 0x4f, 0x4b, ++ 0x43, 0x17, 0x17, 0x0f, 0x14, 0x0f, 0x14, 0x07, 0x14, 0x43, 0x5b, 0x14, 0x43, 0x5b, 0x40, 0x40, ++ 0x4b, 0x00, 0x0c, 0x04, 0x4b, 0x0f, 0x04, 0x43, 0x07, 0x14, 0x27, 0x00, 0x43, 0x04, 0x08, 0x0f, ++ 0x4b, 0x2f, 0x1b, 0x17, 0x4b, 0x23, 0x08, 0x1b, 0x04, 0x07, 0x14, 0x13, 0x0f, 0x0f, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x02, 0x43, 0x53, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x40, 0x40, 0x40, 0x07, 0x4d, ++ 0x43, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x04, 0x04, 0x5a, ++ 0x53, 0x4e, 0x04, 0x17, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x43, 0x43, 0x52, 0x52, 0x47, 0x4f, ++ 0x4b, 0x07, 0x4f, 0x5f, 0x4b, 0x4a, 0x5a, 0x63, 0x5f, 0x5a, 0x52, 0x42, 0x00, 0x4d, 0x52, 0x52, ++ 0x47, 0x4f, 0x4b, 0x07, 0x4f, 0x5f, 0x4b, 0x4a, 0x5a, 0x63, 0x5f, 0x5a, 0x52, 0x42, 0x00, 0x4d, ++ 0x09, 0x4c, 0x24, 0x53, 0x5a, 0x5a, 0x4f, 0x52, 0x52, 0x4e, 0x47, 0x42, 0x47, 0x05, 0x4f, 0x53, ++ 0x2f, 0x07, 0x4f, 0x05, 0x4f, 0x53, 0x2f, 0x07, 0x4f, 0x05, 0x4f, 0x53, 0x2f, 0x07, 0x4f, 0x4b, ++ 0x43, 0x17, 0x17, 0x0f, 0x14, 0x0f, 0x14, 0x07, 0x14, 0x43, 0x5a, 0x14, 0x43, 0x5a, 0x40, 0x40, ++ 0x4b, 0x01, 0x0c, 0x04, 0x4b, 0x0f, 0x04, 0x43, 0x07, 0x15, 0x27, 0x01, 0x43, 0x05, 0x08, 0x0f, ++ 0x4b, 0x2f, 0x1b, 0x17, 0x4b, 0x22, 0x08, 0x1a, 0x04, 0x07, 0x14, 0x13, 0x0f, 0x0f, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x01, 0x43, 0x53, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x06, 0x40, 0x40, 0x40, 0x06, 0x4b, ++ 0x43, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x04, 0x04, 0x59, ++ 0x53, 0x4d, 0x04, 0x16, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x43, 0x43, 0x51, 0x51, 0x46, 0x4e, ++ 0x4b, 0x07, 0x4e, 0x5e, 0x4b, 0x49, 0x59, 0x63, 0x5e, 0x59, 0x50, 0x41, 0x01, 0x4b, 0x51, 0x51, ++ 0x46, 0x4e, 0x4b, 0x07, 0x4e, 0x5e, 0x4b, 0x49, 0x59, 0x63, 0x5e, 0x59, 0x50, 0x41, 0x01, 0x4b, ++ 0x0a, 0x4c, 0x24, 0x53, 0x59, 0x59, 0x4e, 0x51, 0x51, 0x4d, 0x46, 0x41, 0x46, 0x06, 0x4e, 0x53, ++ 0x2e, 0x07, 0x4e, 0x06, 0x4e, 0x53, 0x2e, 0x07, 0x4e, 0x06, 0x4e, 0x53, 0x2e, 0x07, 0x4e, 0x4b, ++ 0x43, 0x16, 0x16, 0x0f, 0x14, 0x0f, 0x14, 0x07, 0x14, 0x43, 0x59, 0x14, 0x43, 0x59, 0x40, 0x40, ++ 0x4b, 0x02, 0x0c, 0x04, 0x4b, 0x0f, 0x04, 0x43, 0x07, 0x17, 0x27, 0x02, 0x43, 0x06, 0x09, 0x0f, ++ 0x4b, 0x2e, 0x1b, 0x16, 0x4b, 0x20, 0x09, 0x19, 0x04, 0x07, 0x14, 0x13, 0x0f, 0x0f, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x00, 0x43, 0x53, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x05, 0x40, 0x40, 0x40, 0x05, 0x4a, ++ 0x43, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x04, 0x04, 0x59, ++ 0x53, 0x4c, 0x04, 0x15, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x43, 0x43, 0x51, 0x51, 0x46, 0x4e, ++ 0x4b, 0x07, 0x4e, 0x5e, 0x4b, 0x49, 0x59, 0x63, 0x5e, 0x59, 0x4f, 0x41, 0x01, 0x4a, 0x51, 0x51, ++ 0x46, 0x4e, 0x4b, 0x07, 0x4e, 0x5e, 0x4b, 0x49, 0x59, 0x63, 0x5e, 0x59, 0x4f, 0x41, 0x01, 0x4a, ++ 0x0b, 0x4d, 0x24, 0x53, 0x59, 0x59, 0x4e, 0x51, 0x51, 0x4c, 0x46, 0x41, 0x46, 0x06, 0x4e, 0x53, ++ 0x2d, 0x07, 0x4e, 0x06, 0x4e, 0x53, 0x2d, 0x07, 0x4e, 0x06, 0x4e, 0x53, 0x2d, 0x07, 0x4e, 0x4b, ++ 0x43, 0x15, 0x15, 0x0f, 0x14, 0x0f, 0x14, 0x07, 0x14, 0x43, 0x59, 0x14, 0x43, 0x59, 0x40, 0x40, ++ 0x4b, 0x03, 0x0c, 0x04, 0x4b, 0x0f, 0x04, 0x43, 0x07, 0x18, 0x27, 0x03, 0x43, 0x06, 0x09, 0x0f, ++ 0x4b, 0x2d, 0x1a, 0x15, 0x4b, 0x1e, 0x09, 0x18, 0x04, 0x07, 0x14, 0x12, 0x0f, 0x0f, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x00, 0x42, 0x52, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x05, 0x40, 0x40, 0x40, 0x05, 0x48, ++ 0x42, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x05, 0x05, 0x58, ++ 0x52, 0x4a, 0x05, 0x15, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x42, 0x42, 0x50, 0x50, 0x45, 0x4d, ++ 0x4a, 0x07, 0x4d, 0x5d, 0x4a, 0x48, 0x58, 0x62, 0x5d, 0x58, 0x4d, 0x40, 0x02, 0x48, 0x50, 0x50, ++ 0x45, 0x4d, 0x4a, 0x07, 0x4d, 0x5d, 0x4a, 0x48, 0x58, 0x62, 0x5d, 0x58, 0x4d, 0x40, 0x02, 0x48, ++ 0x0d, 0x4d, 0x25, 0x52, 0x58, 0x58, 0x4d, 0x50, 0x50, 0x4a, 0x45, 0x40, 0x45, 0x07, 0x4d, 0x52, ++ 0x2d, 0x07, 0x4d, 0x07, 0x4d, 0x52, 0x2d, 0x07, 0x4d, 0x07, 0x4d, 0x52, 0x2d, 0x07, 0x4d, 0x4a, ++ 0x42, 0x15, 0x15, 0x0f, 0x15, 0x0f, 0x15, 0x07, 0x15, 0x42, 0x58, 0x15, 0x42, 0x58, 0x40, 0x40, ++ 0x4a, 0x05, 0x0d, 0x05, 0x4a, 0x0f, 0x05, 0x42, 0x07, 0x1a, 0x27, 0x05, 0x42, 0x07, 0x0a, 0x0f, ++ 0x4a, 0x2d, 0x1a, 0x15, 0x4a, 0x1d, 0x0a, 0x18, 0x05, 0x07, 0x15, 0x12, 0x0f, 0x0f, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x40, 0x42, 0x52, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x04, 0x40, 0x40, 0x40, 0x04, 0x46, ++ 0x42, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x05, 0x05, 0x57, ++ 0x52, 0x49, 0x05, 0x14, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x42, 0x42, 0x4f, 0x4f, 0x44, 0x4c, ++ 0x4a, 0x07, 0x4c, 0x5c, 0x4a, 0x47, 0x57, 0x62, 0x5c, 0x57, 0x4b, 0x00, 0x03, 0x46, 0x4f, 0x4f, ++ 0x44, 0x4c, 0x4a, 0x07, 0x4c, 0x5c, 0x4a, 0x47, 0x57, 0x62, 0x5c, 0x57, 0x4b, 0x00, 0x03, 0x46, ++ 0x0e, 0x4d, 0x25, 0x52, 0x57, 0x57, 0x4c, 0x4f, 0x4f, 0x49, 0x44, 0x00, 0x44, 0x08, 0x4c, 0x52, ++ 0x2c, 0x07, 0x4c, 0x08, 0x4c, 0x52, 0x2c, 0x07, 0x4c, 0x08, 0x4c, 0x52, 0x2c, 0x07, 0x4c, 0x4a, ++ 0x42, 0x14, 0x14, 0x0f, 0x15, 0x0f, 0x15, 0x07, 0x15, 0x42, 0x57, 0x15, 0x42, 0x57, 0x40, 0x40, ++ 0x4a, 0x06, 0x0d, 0x05, 0x4a, 0x0f, 0x05, 0x42, 0x07, 0x1c, 0x27, 0x06, 0x42, 0x08, 0x0b, 0x0f, ++ 0x4a, 0x2c, 0x1a, 0x14, 0x4a, 0x1b, 0x0b, 0x17, 0x05, 0x07, 0x15, 0x12, 0x0f, 0x0f, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x41, 0x42, 0x52, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x04, 0x40, 0x40, 0x40, 0x04, 0x44, ++ 0x42, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x05, 0x05, 0x56, ++ 0x52, 0x48, 0x05, 0x14, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x42, 0x42, 0x4e, 0x4e, 0x44, 0x4c, ++ 0x4a, 0x07, 0x4c, 0x5c, 0x4a, 0x46, 0x56, 0x62, 0x5c, 0x56, 0x4a, 0x01, 0x03, 0x44, 0x4e, 0x4e, ++ 0x44, 0x4c, 0x4a, 0x07, 0x4c, 0x5c, 0x4a, 0x46, 0x56, 0x62, 0x5c, 0x56, 0x4a, 0x01, 0x03, 0x44, ++ 0x0f, 0x4d, 0x25, 0x52, 0x56, 0x56, 0x4c, 0x4e, 0x4e, 0x48, 0x44, 0x01, 0x44, 0x09, 0x4c, 0x52, ++ 0x2c, 0x07, 0x4c, 0x09, 0x4c, 0x52, 0x2c, 0x07, 0x4c, 0x09, 0x4c, 0x52, 0x2c, 0x07, 0x4c, 0x4a, ++ 0x42, 0x14, 0x14, 0x0f, 0x15, 0x0f, 0x15, 0x07, 0x15, 0x42, 0x56, 0x15, 0x42, 0x56, 0x40, 0x40, ++ 0x4a, 0x07, 0x0d, 0x05, 0x4a, 0x0f, 0x05, 0x42, 0x07, 0x1d, 0x27, 0x07, 0x42, 0x09, 0x0b, 0x0f, ++ 0x4a, 0x2c, 0x1a, 0x14, 0x4a, 0x1a, 0x0b, 0x16, 0x05, 0x07, 0x15, 0x12, 0x0f, 0x0f, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x42, 0x41, 0x51, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x03, 0x40, 0x40, 0x40, 0x03, 0x42, ++ 0x41, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x06, 0x06, 0x55, ++ 0x51, 0x47, 0x06, 0x13, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x41, 0x41, 0x4d, 0x4d, 0x43, 0x4b, ++ 0x49, 0x07, 0x4b, 0x5b, 0x49, 0x45, 0x55, 0x61, 0x5b, 0x55, 0x48, 0x02, 0x04, 0x42, 0x4d, 0x4d, ++ 0x43, 0x4b, 0x49, 0x07, 0x4b, 0x5b, 0x49, 0x45, 0x55, 0x61, 0x5b, 0x55, 0x48, 0x02, 0x04, 0x42, ++ 0x10, 0x4e, 0x26, 0x51, 0x55, 0x55, 0x4b, 0x4d, 0x4d, 0x47, 0x43, 0x02, 0x43, 0x0a, 0x4b, 0x51, ++ 0x2b, 0x07, 0x4b, 0x0a, 0x4b, 0x51, 0x2b, 0x07, 0x4b, 0x0a, 0x4b, 0x51, 0x2b, 0x07, 0x4b, 0x49, ++ 0x41, 0x13, 0x13, 0x0f, 0x16, 0x0f, 0x16, 0x07, 0x16, 0x41, 0x55, 0x16, 0x41, 0x55, 0x40, 0x40, ++ 0x49, 0x08, 0x0e, 0x06, 0x49, 0x0f, 0x06, 0x41, 0x07, 0x1f, 0x27, 0x08, 0x41, 0x0a, 0x0c, 0x0f, ++ 0x49, 0x2b, 0x19, 0x13, 0x49, 0x18, 0x0c, 0x15, 0x06, 0x07, 0x16, 0x11, 0x0f, 0x0f, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x43, 0x41, 0x51, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x02, 0x40, 0x40, 0x40, 0x02, 0x40, ++ 0x41, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x06, 0x06, 0x54, ++ 0x51, 0x45, 0x06, 0x12, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x41, 0x41, 0x4c, 0x4c, 0x42, 0x4a, ++ 0x49, 0x07, 0x4a, 0x5a, 0x49, 0x44, 0x54, 0x61, 0x5a, 0x54, 0x47, 0x03, 0x05, 0x40, 0x4c, 0x4c, ++ 0x42, 0x4a, 0x49, 0x07, 0x4a, 0x5a, 0x49, 0x44, 0x54, 0x61, 0x5a, 0x54, 0x47, 0x03, 0x05, 0x40, ++ 0x12, 0x4e, 0x26, 0x51, 0x54, 0x54, 0x4a, 0x4c, 0x4c, 0x45, 0x42, 0x03, 0x42, 0x0b, 0x4a, 0x51, ++ 0x2a, 0x07, 0x4a, 0x0b, 0x4a, 0x51, 0x2a, 0x07, 0x4a, 0x0b, 0x4a, 0x51, 0x2a, 0x07, 0x4a, 0x49, ++ 0x41, 0x12, 0x12, 0x0f, 0x16, 0x0f, 0x16, 0x07, 0x16, 0x41, 0x54, 0x16, 0x41, 0x54, 0x40, 0x40, ++ 0x49, 0x0a, 0x0e, 0x06, 0x49, 0x0f, 0x06, 0x41, 0x07, 0x20, 0x27, 0x0a, 0x41, 0x0b, 0x0d, 0x0f, ++ 0x49, 0x2a, 0x19, 0x12, 0x49, 0x17, 0x0d, 0x14, 0x06, 0x07, 0x16, 0x11, 0x0f, 0x0f, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x44, 0x41, 0x51, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x02, 0x40, 0x40, 0x40, 0x02, 0x01, ++ 0x41, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x06, 0x06, 0x53, ++ 0x51, 0x44, 0x06, 0x12, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x41, 0x41, 0x4b, 0x4b, 0x42, 0x4a, ++ 0x49, 0x07, 0x4a, 0x5a, 0x49, 0x43, 0x53, 0x61, 0x5a, 0x53, 0x45, 0x04, 0x05, 0x01, 0x4b, 0x4b, ++ 0x42, 0x4a, 0x49, 0x07, 0x4a, 0x5a, 0x49, 0x43, 0x53, 0x61, 0x5a, 0x53, 0x45, 0x04, 0x05, 0x01, ++ 0x13, 0x4e, 0x26, 0x51, 0x53, 0x53, 0x4a, 0x4b, 0x4b, 0x44, 0x42, 0x04, 0x42, 0x0c, 0x4a, 0x51, ++ 0x2a, 0x07, 0x4a, 0x0c, 0x4a, 0x51, 0x2a, 0x07, 0x4a, 0x0c, 0x4a, 0x51, 0x2a, 0x07, 0x4a, 0x49, ++ 0x41, 0x12, 0x12, 0x0f, 0x16, 0x0f, 0x16, 0x07, 0x16, 0x41, 0x53, 0x16, 0x41, 0x53, 0x40, 0x40, ++ 0x49, 0x0b, 0x0e, 0x06, 0x49, 0x0f, 0x06, 0x41, 0x07, 0x22, 0x27, 0x0b, 0x41, 0x0c, 0x0d, 0x0f, ++ 0x49, 0x2a, 0x19, 0x12, 0x49, 0x15, 0x0d, 0x13, 0x06, 0x07, 0x16, 0x11, 0x0f, 0x0f, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x45, 0x40, 0x50, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x01, 0x40, 0x40, 0x40, 0x01, 0x03, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x07, 0x07, 0x52, ++ 0x50, 0x43, 0x07, 0x11, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x4a, 0x4a, 0x41, 0x49, ++ 0x48, 0x07, 0x49, 0x59, 0x48, 0x42, 0x52, 0x60, 0x59, 0x52, 0x44, 0x05, 0x06, 0x03, 0x4a, 0x4a, ++ 0x41, 0x49, 0x48, 0x07, 0x49, 0x59, 0x48, 0x42, 0x52, 0x60, 0x59, 0x52, 0x44, 0x05, 0x06, 0x03, ++ 0x14, 0x4f, 0x27, 0x50, 0x52, 0x52, 0x49, 0x4a, 0x4a, 0x43, 0x41, 0x05, 0x41, 0x0d, 0x49, 0x50, ++ 0x29, 0x07, 0x49, 0x0d, 0x49, 0x50, 0x29, 0x07, 0x49, 0x0d, 0x49, 0x50, 0x29, 0x07, 0x49, 0x48, ++ 0x40, 0x11, 0x11, 0x0f, 0x17, 0x0f, 0x17, 0x07, 0x17, 0x40, 0x52, 0x17, 0x40, 0x52, 0x40, 0x40, ++ 0x48, 0x0c, 0x0f, 0x07, 0x48, 0x0f, 0x07, 0x40, 0x07, 0x23, 0x27, 0x0c, 0x40, 0x0d, 0x0e, 0x0f, ++ 0x48, 0x29, 0x18, 0x11, 0x48, 0x14, 0x0e, 0x12, 0x07, 0x07, 0x17, 0x10, 0x0f, 0x0f, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x46, 0x40, 0x50, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x40, 0x40, 0x40, 0x00, 0x04, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x07, 0x07, 0x51, ++ 0x50, 0x42, 0x07, 0x10, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x49, 0x49, 0x41, 0x49, ++ 0x48, 0x07, 0x49, 0x59, 0x48, 0x41, 0x51, 0x60, 0x59, 0x51, 0x42, 0x06, 0x06, 0x04, 0x49, 0x49, ++ 0x41, 0x49, 0x48, 0x07, 0x49, 0x59, 0x48, 0x41, 0x51, 0x60, 0x59, 0x51, 0x42, 0x06, 0x06, 0x04, ++ 0x15, 0x4f, 0x27, 0x50, 0x51, 0x51, 0x49, 0x49, 0x49, 0x42, 0x41, 0x06, 0x41, 0x0e, 0x49, 0x50, ++ 0x28, 0x07, 0x49, 0x0e, 0x49, 0x50, 0x28, 0x07, 0x49, 0x0e, 0x49, 0x50, 0x28, 0x07, 0x49, 0x48, ++ 0x40, 0x10, 0x10, 0x0f, 0x17, 0x0f, 0x17, 0x07, 0x17, 0x40, 0x51, 0x17, 0x40, 0x51, 0x40, 0x40, ++ 0x48, 0x0d, 0x0f, 0x07, 0x48, 0x0f, 0x07, 0x40, 0x07, 0x25, 0x27, 0x0d, 0x40, 0x0e, 0x0e, 0x0f, ++ 0x48, 0x28, 0x18, 0x10, 0x48, 0x12, 0x0e, 0x11, 0x07, 0x07, 0x17, 0x10, 0x0f, 0x0f, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x47, 0x40, 0x50, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x40, 0x40, 0x40, 0x00, 0x06, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x07, 0x07, 0x50, ++ 0x50, 0x40, 0x07, 0x10, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x48, 0x48, 0x40, 0x48, ++ 0x48, 0x07, 0x48, 0x58, 0x48, 0x40, 0x50, 0x60, 0x58, 0x50, 0x40, 0x07, 0x07, 0x06, 0x48, 0x48, ++ 0x40, 0x48, 0x48, 0x07, 0x48, 0x58, 0x48, 0x40, 0x50, 0x60, 0x58, 0x50, 0x40, 0x07, 0x07, 0x06, ++ 0x17, 0x4f, 0x27, 0x50, 0x50, 0x50, 0x48, 0x48, 0x48, 0x40, 0x40, 0x07, 0x40, 0x0f, 0x48, 0x50, ++ 0x28, 0x07, 0x48, 0x0f, 0x48, 0x50, 0x28, 0x07, 0x48, 0x0f, 0x48, 0x50, 0x28, 0x07, 0x48, 0x48, ++ 0x40, 0x10, 0x10, 0x0f, 0x17, 0x0f, 0x17, 0x07, 0x17, 0x40, 0x50, 0x17, 0x40, 0x50, 0x40, 0x40, ++ 0x48, 0x0f, 0x0f, 0x07, 0x48, 0x0f, 0x07, 0x40, 0x07, 0x27, 0x27, 0x0f, 0x40, 0x0f, 0x0f, 0x0f, ++ 0x48, 0x28, 0x18, 0x10, 0x48, 0x10, 0x0f, 0x10, 0x07, 0x07, 0x17, 0x10, 0x0f, 0x0f, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x48, 0x00, 0x4f, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x08, ++ 0x00, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x08, 0x08, 0x4f, ++ 0x4f, 0x00, 0x08, 0x0f, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x47, 0x47, 0x00, 0x47, ++ 0x47, 0x07, 0x47, 0x57, 0x47, 0x00, 0x4f, 0x5f, 0x57, 0x4f, 0x00, 0x08, 0x08, 0x08, 0x47, 0x47, ++ 0x00, 0x47, 0x47, 0x07, 0x47, 0x57, 0x47, 0x00, 0x4f, 0x5f, 0x57, 0x4f, 0x00, 0x08, 0x08, 0x08, ++ 0x18, 0x50, 0x28, 0x4f, 0x4f, 0x4f, 0x47, 0x47, 0x47, 0x00, 0x00, 0x08, 0x00, 0x10, 0x47, 0x4f, ++ 0x27, 0x07, 0x47, 0x10, 0x47, 0x4f, 0x27, 0x07, 0x47, 0x10, 0x47, 0x4f, 0x27, 0x07, 0x47, 0x47, ++ 0x00, 0x0f, 0x0f, 0x0f, 0x18, 0x0f, 0x18, 0x07, 0x18, 0x00, 0x4f, 0x18, 0x00, 0x4f, 0x40, 0x40, ++ 0x47, 0x10, 0x10, 0x08, 0x47, 0x0f, 0x08, 0x00, 0x07, 0x28, 0x27, 0x10, 0x00, 0x10, 0x10, 0x0f, ++ 0x47, 0x27, 0x17, 0x0f, 0x47, 0x0f, 0x10, 0x0f, 0x08, 0x07, 0x18, 0x0f, 0x0f, 0x0f, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x49, 0x00, 0x4f, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x0a, ++ 0x00, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x08, 0x08, 0x4e, ++ 0x4f, 0x01, 0x08, 0x0f, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x46, 0x46, 0x00, 0x47, ++ 0x47, 0x07, 0x47, 0x57, 0x47, 0x01, 0x4e, 0x5f, 0x57, 0x4e, 0x02, 0x09, 0x08, 0x0a, 0x46, 0x46, ++ 0x00, 0x47, 0x47, 0x07, 0x47, 0x57, 0x47, 0x01, 0x4e, 0x5f, 0x57, 0x4e, 0x02, 0x09, 0x08, 0x0a, ++ 0x19, 0x50, 0x28, 0x4f, 0x4e, 0x4e, 0x47, 0x46, 0x46, 0x01, 0x00, 0x09, 0x00, 0x11, 0x47, 0x4f, ++ 0x27, 0x07, 0x47, 0x11, 0x47, 0x4f, 0x27, 0x07, 0x47, 0x11, 0x47, 0x4f, 0x27, 0x07, 0x47, 0x47, ++ 0x00, 0x0f, 0x0f, 0x0f, 0x18, 0x0f, 0x18, 0x07, 0x18, 0x00, 0x4e, 0x18, 0x00, 0x4e, 0x40, 0x40, ++ 0x47, 0x11, 0x10, 0x08, 0x47, 0x0f, 0x08, 0x00, 0x07, 0x2a, 0x27, 0x11, 0x00, 0x11, 0x10, 0x0f, ++ 0x47, 0x27, 0x17, 0x0f, 0x47, 0x0d, 0x10, 0x0e, 0x08, 0x07, 0x18, 0x0f, 0x0f, 0x0f, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x4a, 0x00, 0x4f, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x41, 0x40, 0x40, 0x40, 0x41, 0x0c, ++ 0x00, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x08, 0x08, 0x4d, ++ 0x4f, 0x02, 0x08, 0x0e, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x45, 0x45, 0x01, 0x46, ++ 0x47, 0x07, 0x46, 0x56, 0x47, 0x02, 0x4d, 0x5f, 0x56, 0x4d, 0x03, 0x0a, 0x09, 0x0c, 0x45, 0x45, ++ 0x01, 0x46, 0x47, 0x07, 0x46, 0x56, 0x47, 0x02, 0x4d, 0x5f, 0x56, 0x4d, 0x03, 0x0a, 0x09, 0x0c, ++ 0x1a, 0x50, 0x28, 0x4f, 0x4d, 0x4d, 0x46, 0x45, 0x45, 0x02, 0x01, 0x0a, 0x01, 0x12, 0x46, 0x4f, ++ 0x26, 0x07, 0x46, 0x12, 0x46, 0x4f, 0x26, 0x07, 0x46, 0x12, 0x46, 0x4f, 0x26, 0x07, 0x46, 0x47, ++ 0x00, 0x0e, 0x0e, 0x0f, 0x18, 0x0f, 0x18, 0x07, 0x18, 0x00, 0x4d, 0x18, 0x00, 0x4d, 0x40, 0x40, ++ 0x47, 0x12, 0x10, 0x08, 0x47, 0x0f, 0x08, 0x00, 0x07, 0x2b, 0x27, 0x12, 0x00, 0x12, 0x11, 0x0f, ++ 0x47, 0x26, 0x17, 0x0e, 0x47, 0x0c, 0x11, 0x0d, 0x08, 0x07, 0x18, 0x0f, 0x0f, 0x0f, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x4b, 0x01, 0x4e, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x42, 0x40, 0x40, 0x40, 0x42, 0x0e, ++ 0x01, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x09, 0x09, 0x4c, ++ 0x4e, 0x04, 0x09, 0x0d, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x01, 0x01, 0x44, 0x44, 0x02, 0x45, ++ 0x46, 0x07, 0x45, 0x55, 0x46, 0x03, 0x4c, 0x5e, 0x55, 0x4c, 0x05, 0x0b, 0x0a, 0x0e, 0x44, 0x44, ++ 0x02, 0x45, 0x46, 0x07, 0x45, 0x55, 0x46, 0x03, 0x4c, 0x5e, 0x55, 0x4c, 0x05, 0x0b, 0x0a, 0x0e, ++ 0x1c, 0x51, 0x29, 0x4e, 0x4c, 0x4c, 0x45, 0x44, 0x44, 0x04, 0x02, 0x0b, 0x02, 0x13, 0x45, 0x4e, ++ 0x25, 0x07, 0x45, 0x13, 0x45, 0x4e, 0x25, 0x07, 0x45, 0x13, 0x45, 0x4e, 0x25, 0x07, 0x45, 0x46, ++ 0x01, 0x0d, 0x0d, 0x0f, 0x19, 0x0f, 0x19, 0x07, 0x19, 0x01, 0x4c, 0x19, 0x01, 0x4c, 0x40, 0x40, ++ 0x46, 0x14, 0x11, 0x09, 0x46, 0x0f, 0x09, 0x01, 0x07, 0x2d, 0x27, 0x14, 0x01, 0x13, 0x12, 0x0f, ++ 0x46, 0x25, 0x16, 0x0d, 0x46, 0x0a, 0x12, 0x0c, 0x09, 0x07, 0x19, 0x0e, 0x0f, 0x0f, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x4c, 0x01, 0x4e, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x42, 0x40, 0x40, 0x40, 0x42, 0x10, ++ 0x01, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x09, 0x09, 0x4b, ++ 0x4e, 0x05, 0x09, 0x0d, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x01, 0x01, 0x43, 0x43, 0x02, 0x45, ++ 0x46, 0x07, 0x45, 0x55, 0x46, 0x04, 0x4b, 0x5e, 0x55, 0x4b, 0x06, 0x0c, 0x0a, 0x10, 0x43, 0x43, ++ 0x02, 0x45, 0x46, 0x07, 0x45, 0x55, 0x46, 0x04, 0x4b, 0x5e, 0x55, 0x4b, 0x06, 0x0c, 0x0a, 0x10, ++ 0x1d, 0x51, 0x29, 0x4e, 0x4b, 0x4b, 0x45, 0x43, 0x43, 0x05, 0x02, 0x0c, 0x02, 0x14, 0x45, 0x4e, ++ 0x25, 0x07, 0x45, 0x14, 0x45, 0x4e, 0x25, 0x07, 0x45, 0x14, 0x45, 0x4e, 0x25, 0x07, 0x45, 0x46, ++ 0x01, 0x0d, 0x0d, 0x0f, 0x19, 0x0f, 0x19, 0x07, 0x19, 0x01, 0x4b, 0x19, 0x01, 0x4b, 0x40, 0x40, ++ 0x46, 0x15, 0x11, 0x09, 0x46, 0x0f, 0x09, 0x01, 0x07, 0x2e, 0x27, 0x15, 0x01, 0x14, 0x12, 0x0f, ++ 0x46, 0x25, 0x16, 0x0d, 0x46, 0x09, 0x12, 0x0b, 0x09, 0x07, 0x19, 0x0e, 0x0f, 0x0f, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x4d, 0x01, 0x4e, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x43, 0x40, 0x40, 0x40, 0x43, 0x12, ++ 0x01, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x09, 0x09, 0x4a, ++ 0x4e, 0x06, 0x09, 0x0c, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x01, 0x01, 0x42, 0x42, 0x03, 0x44, ++ 0x46, 0x07, 0x44, 0x54, 0x46, 0x05, 0x4a, 0x5e, 0x54, 0x4a, 0x08, 0x0d, 0x0b, 0x12, 0x42, 0x42, ++ 0x03, 0x44, 0x46, 0x07, 0x44, 0x54, 0x46, 0x05, 0x4a, 0x5e, 0x54, 0x4a, 0x08, 0x0d, 0x0b, 0x12, ++ 0x1e, 0x51, 0x29, 0x4e, 0x4a, 0x4a, 0x44, 0x42, 0x42, 0x06, 0x03, 0x0d, 0x03, 0x15, 0x44, 0x4e, ++ 0x24, 0x07, 0x44, 0x15, 0x44, 0x4e, 0x24, 0x07, 0x44, 0x15, 0x44, 0x4e, 0x24, 0x07, 0x44, 0x46, ++ 0x01, 0x0c, 0x0c, 0x0f, 0x19, 0x0f, 0x19, 0x07, 0x19, 0x01, 0x4a, 0x19, 0x01, 0x4a, 0x40, 0x40, ++ 0x46, 0x16, 0x11, 0x09, 0x46, 0x0f, 0x09, 0x01, 0x07, 0x30, 0x27, 0x16, 0x01, 0x15, 0x13, 0x0f, ++ 0x46, 0x24, 0x16, 0x0c, 0x46, 0x07, 0x13, 0x0a, 0x09, 0x07, 0x19, 0x0e, 0x0f, 0x0f, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x4e, 0x01, 0x4e, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x44, 0x40, 0x40, 0x40, 0x44, 0x13, ++ 0x01, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x09, 0x09, 0x4a, ++ 0x4e, 0x07, 0x09, 0x0b, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x01, 0x01, 0x42, 0x42, 0x03, 0x44, ++ 0x46, 0x07, 0x44, 0x54, 0x46, 0x05, 0x4a, 0x5e, 0x54, 0x4a, 0x09, 0x0d, 0x0b, 0x13, 0x42, 0x42, ++ 0x03, 0x44, 0x46, 0x07, 0x44, 0x54, 0x46, 0x05, 0x4a, 0x5e, 0x54, 0x4a, 0x09, 0x0d, 0x0b, 0x13, ++ 0x1f, 0x52, 0x29, 0x4e, 0x4a, 0x4a, 0x44, 0x42, 0x42, 0x07, 0x03, 0x0d, 0x03, 0x15, 0x44, 0x4e, ++ 0x23, 0x07, 0x44, 0x15, 0x44, 0x4e, 0x23, 0x07, 0x44, 0x15, 0x44, 0x4e, 0x23, 0x07, 0x44, 0x46, ++ 0x01, 0x0b, 0x0b, 0x0f, 0x19, 0x0f, 0x19, 0x07, 0x19, 0x01, 0x4a, 0x19, 0x01, 0x4a, 0x40, 0x40, ++ 0x46, 0x17, 0x11, 0x09, 0x46, 0x0f, 0x09, 0x01, 0x07, 0x31, 0x27, 0x17, 0x01, 0x15, 0x13, 0x0f, ++ 0x46, 0x23, 0x15, 0x0b, 0x46, 0x05, 0x13, 0x09, 0x09, 0x07, 0x19, 0x0d, 0x0f, 0x0f, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x4e, 0x02, 0x4d, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x44, 0x40, 0x40, 0x40, 0x44, 0x15, ++ 0x02, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x0a, 0x0a, 0x49, ++ 0x4d, 0x09, 0x0a, 0x0b, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x02, 0x02, 0x41, 0x41, 0x04, 0x43, ++ 0x45, 0x07, 0x43, 0x53, 0x45, 0x06, 0x49, 0x5d, 0x53, 0x49, 0x0b, 0x0e, 0x0c, 0x15, 0x41, 0x41, ++ 0x04, 0x43, 0x45, 0x07, 0x43, 0x53, 0x45, 0x06, 0x49, 0x5d, 0x53, 0x49, 0x0b, 0x0e, 0x0c, 0x15, ++ 0x21, 0x52, 0x2a, 0x4d, 0x49, 0x49, 0x43, 0x41, 0x41, 0x09, 0x04, 0x0e, 0x04, 0x16, 0x43, 0x4d, ++ 0x23, 0x07, 0x43, 0x16, 0x43, 0x4d, 0x23, 0x07, 0x43, 0x16, 0x43, 0x4d, 0x23, 0x07, 0x43, 0x45, ++ 0x02, 0x0b, 0x0b, 0x0f, 0x1a, 0x0f, 0x1a, 0x07, 0x1a, 0x02, 0x49, 0x1a, 0x02, 0x49, 0x40, 0x40, ++ 0x45, 0x19, 0x12, 0x0a, 0x45, 0x0f, 0x0a, 0x02, 0x07, 0x33, 0x27, 0x19, 0x02, 0x16, 0x14, 0x0f, ++ 0x45, 0x23, 0x15, 0x0b, 0x45, 0x04, 0x14, 0x09, 0x0a, 0x07, 0x1a, 0x0d, 0x0f, 0x0f, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x4f, 0x02, 0x4d, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x45, 0x40, 0x40, 0x40, 0x45, 0x17, ++ 0x02, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x0a, 0x0a, 0x48, ++ 0x4d, 0x0a, 0x0a, 0x0a, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x02, 0x02, 0x40, 0x40, 0x05, 0x42, ++ 0x45, 0x07, 0x42, 0x52, 0x45, 0x07, 0x48, 0x5d, 0x52, 0x48, 0x0d, 0x0f, 0x0d, 0x17, 0x40, 0x40, ++ 0x05, 0x42, 0x45, 0x07, 0x42, 0x52, 0x45, 0x07, 0x48, 0x5d, 0x52, 0x48, 0x0d, 0x0f, 0x0d, 0x17, ++ 0x22, 0x52, 0x2a, 0x4d, 0x48, 0x48, 0x42, 0x40, 0x40, 0x0a, 0x05, 0x0f, 0x05, 0x17, 0x42, 0x4d, ++ 0x22, 0x07, 0x42, 0x17, 0x42, 0x4d, 0x22, 0x07, 0x42, 0x17, 0x42, 0x4d, 0x22, 0x07, 0x42, 0x45, ++ 0x02, 0x0a, 0x0a, 0x0f, 0x1a, 0x0f, 0x1a, 0x07, 0x1a, 0x02, 0x48, 0x1a, 0x02, 0x48, 0x40, 0x40, ++ 0x45, 0x1a, 0x12, 0x0a, 0x45, 0x0f, 0x0a, 0x02, 0x07, 0x35, 0x27, 0x1a, 0x02, 0x17, 0x15, 0x0f, ++ 0x45, 0x22, 0x15, 0x0a, 0x45, 0x02, 0x15, 0x08, 0x0a, 0x07, 0x1a, 0x0d, 0x0f, 0x0f, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x50, 0x02, 0x4d, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x45, 0x40, 0x40, 0x40, 0x45, 0x19, ++ 0x02, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x0a, 0x0a, 0x47, ++ 0x4d, 0x0b, 0x0a, 0x0a, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x02, 0x02, 0x00, 0x00, 0x05, 0x42, ++ 0x45, 0x07, 0x42, 0x52, 0x45, 0x08, 0x47, 0x5d, 0x52, 0x47, 0x0e, 0x10, 0x0d, 0x19, 0x00, 0x00, ++ 0x05, 0x42, 0x45, 0x07, 0x42, 0x52, 0x45, 0x08, 0x47, 0x5d, 0x52, 0x47, 0x0e, 0x10, 0x0d, 0x19, ++ 0x23, 0x52, 0x2a, 0x4d, 0x47, 0x47, 0x42, 0x00, 0x00, 0x0b, 0x05, 0x10, 0x05, 0x18, 0x42, 0x4d, ++ 0x22, 0x07, 0x42, 0x18, 0x42, 0x4d, 0x22, 0x07, 0x42, 0x18, 0x42, 0x4d, 0x22, 0x07, 0x42, 0x45, ++ 0x02, 0x0a, 0x0a, 0x0f, 0x1a, 0x0f, 0x1a, 0x07, 0x1a, 0x02, 0x47, 0x1a, 0x02, 0x47, 0x40, 0x40, ++ 0x45, 0x1b, 0x12, 0x0a, 0x45, 0x0f, 0x0a, 0x02, 0x07, 0x36, 0x27, 0x1b, 0x02, 0x18, 0x15, 0x0f, ++ 0x45, 0x22, 0x15, 0x0a, 0x45, 0x01, 0x15, 0x07, 0x0a, 0x07, 0x1a, 0x0d, 0x0f, 0x0f, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x51, 0x03, 0x4c, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x46, 0x40, 0x40, 0x40, 0x46, 0x1b, ++ 0x03, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x0b, 0x0b, 0x46, ++ 0x4c, 0x0c, 0x0b, 0x09, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x03, 0x03, 0x01, 0x01, 0x06, 0x41, ++ 0x44, 0x07, 0x41, 0x51, 0x44, 0x09, 0x46, 0x5c, 0x51, 0x46, 0x10, 0x11, 0x0e, 0x1b, 0x01, 0x01, ++ 0x06, 0x41, 0x44, 0x07, 0x41, 0x51, 0x44, 0x09, 0x46, 0x5c, 0x51, 0x46, 0x10, 0x11, 0x0e, 0x1b, ++ 0x24, 0x53, 0x2b, 0x4c, 0x46, 0x46, 0x41, 0x01, 0x01, 0x0c, 0x06, 0x11, 0x06, 0x19, 0x41, 0x4c, ++ 0x21, 0x07, 0x41, 0x19, 0x41, 0x4c, 0x21, 0x07, 0x41, 0x19, 0x41, 0x4c, 0x21, 0x07, 0x41, 0x44, ++ 0x03, 0x09, 0x09, 0x0f, 0x1b, 0x0f, 0x1b, 0x07, 0x1b, 0x03, 0x46, 0x1b, 0x03, 0x46, 0x40, 0x40, ++ 0x44, 0x1c, 0x13, 0x0b, 0x44, 0x0f, 0x0b, 0x03, 0x07, 0x38, 0x27, 0x1c, 0x03, 0x19, 0x16, 0x0f, ++ 0x44, 0x21, 0x14, 0x09, 0x44, 0x40, 0x16, 0x06, 0x0b, 0x07, 0x1b, 0x0c, 0x0f, 0x0f, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x52, 0x03, 0x4c, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x47, 0x40, 0x40, 0x40, 0x47, 0x1d, ++ 0x03, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x0b, 0x0b, 0x45, ++ 0x4c, 0x0e, 0x0b, 0x08, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x03, 0x03, 0x02, 0x02, 0x07, 0x40, ++ 0x44, 0x07, 0x40, 0x50, 0x44, 0x0a, 0x45, 0x5c, 0x50, 0x45, 0x11, 0x12, 0x0f, 0x1d, 0x02, 0x02, ++ 0x07, 0x40, 0x44, 0x07, 0x40, 0x50, 0x44, 0x0a, 0x45, 0x5c, 0x50, 0x45, 0x11, 0x12, 0x0f, 0x1d, ++ 0x26, 0x53, 0x2b, 0x4c, 0x45, 0x45, 0x40, 0x02, 0x02, 0x0e, 0x07, 0x12, 0x07, 0x1a, 0x40, 0x4c, ++ 0x20, 0x07, 0x40, 0x1a, 0x40, 0x4c, 0x20, 0x07, 0x40, 0x1a, 0x40, 0x4c, 0x20, 0x07, 0x40, 0x44, ++ 0x03, 0x08, 0x08, 0x0f, 0x1b, 0x0f, 0x1b, 0x07, 0x1b, 0x03, 0x45, 0x1b, 0x03, 0x45, 0x40, 0x40, ++ 0x44, 0x1e, 0x13, 0x0b, 0x44, 0x0f, 0x0b, 0x03, 0x07, 0x39, 0x27, 0x1e, 0x03, 0x1a, 0x17, 0x0f, ++ 0x44, 0x20, 0x14, 0x08, 0x44, 0x41, 0x17, 0x05, 0x0b, 0x07, 0x1b, 0x0c, 0x0f, 0x0f, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x53, 0x03, 0x4c, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x47, 0x40, 0x40, 0x40, 0x47, 0x1f, ++ 0x03, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x0b, 0x0b, 0x44, ++ 0x4c, 0x0f, 0x0b, 0x08, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x03, 0x03, 0x03, 0x03, 0x07, 0x40, ++ 0x44, 0x07, 0x40, 0x50, 0x44, 0x0b, 0x44, 0x5c, 0x50, 0x44, 0x13, 0x13, 0x0f, 0x1f, 0x03, 0x03, ++ 0x07, 0x40, 0x44, 0x07, 0x40, 0x50, 0x44, 0x0b, 0x44, 0x5c, 0x50, 0x44, 0x13, 0x13, 0x0f, 0x1f, ++ 0x27, 0x53, 0x2b, 0x4c, 0x44, 0x44, 0x40, 0x03, 0x03, 0x0f, 0x07, 0x13, 0x07, 0x1b, 0x40, 0x4c, ++ 0x20, 0x07, 0x40, 0x1b, 0x40, 0x4c, 0x20, 0x07, 0x40, 0x1b, 0x40, 0x4c, 0x20, 0x07, 0x40, 0x44, ++ 0x03, 0x08, 0x08, 0x0f, 0x1b, 0x0f, 0x1b, 0x07, 0x1b, 0x03, 0x44, 0x1b, 0x03, 0x44, 0x40, 0x40, ++ 0x44, 0x1f, 0x13, 0x0b, 0x44, 0x0f, 0x0b, 0x03, 0x07, 0x3b, 0x27, 0x1f, 0x03, 0x1b, 0x17, 0x0f, ++ 0x44, 0x20, 0x14, 0x08, 0x44, 0x43, 0x17, 0x04, 0x0b, 0x07, 0x1b, 0x0c, 0x0f, 0x0f, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x54, 0x04, 0x4b, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x48, 0x40, 0x40, 0x40, 0x48, 0x21, ++ 0x04, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x0c, 0x0c, 0x43, ++ 0x4b, 0x10, 0x0c, 0x07, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x04, 0x04, 0x04, 0x04, 0x08, 0x00, ++ 0x43, 0x07, 0x00, 0x4f, 0x43, 0x0c, 0x43, 0x5b, 0x4f, 0x43, 0x14, 0x14, 0x10, 0x21, 0x04, 0x04, ++ 0x08, 0x00, 0x43, 0x07, 0x00, 0x4f, 0x43, 0x0c, 0x43, 0x5b, 0x4f, 0x43, 0x14, 0x14, 0x10, 0x21, ++ 0x28, 0x54, 0x2c, 0x4b, 0x43, 0x43, 0x00, 0x04, 0x04, 0x10, 0x08, 0x14, 0x08, 0x1c, 0x00, 0x4b, ++ 0x1f, 0x07, 0x00, 0x1c, 0x00, 0x4b, 0x1f, 0x07, 0x00, 0x1c, 0x00, 0x4b, 0x1f, 0x07, 0x00, 0x43, ++ 0x04, 0x07, 0x07, 0x0f, 0x1c, 0x0f, 0x1c, 0x07, 0x1c, 0x04, 0x43, 0x1c, 0x04, 0x43, 0x40, 0x40, ++ 0x43, 0x20, 0x14, 0x0c, 0x43, 0x0f, 0x0c, 0x04, 0x07, 0x3c, 0x27, 0x20, 0x04, 0x1c, 0x18, 0x0f, ++ 0x43, 0x1f, 0x13, 0x07, 0x43, 0x44, 0x18, 0x03, 0x0c, 0x07, 0x1c, 0x0b, 0x0f, 0x0f, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x55, 0x04, 0x4b, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x49, 0x40, 0x40, 0x40, 0x49, 0x22, ++ 0x04, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x0c, 0x0c, 0x42, ++ 0x4b, 0x11, 0x0c, 0x06, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x04, 0x04, 0x05, 0x05, 0x08, 0x00, ++ 0x43, 0x07, 0x00, 0x4f, 0x43, 0x0d, 0x42, 0x5b, 0x4f, 0x42, 0x16, 0x15, 0x10, 0x22, 0x05, 0x05, ++ 0x08, 0x00, 0x43, 0x07, 0x00, 0x4f, 0x43, 0x0d, 0x42, 0x5b, 0x4f, 0x42, 0x16, 0x15, 0x10, 0x22, ++ 0x29, 0x54, 0x2c, 0x4b, 0x42, 0x42, 0x00, 0x05, 0x05, 0x11, 0x08, 0x15, 0x08, 0x1d, 0x00, 0x4b, ++ 0x1e, 0x07, 0x00, 0x1d, 0x00, 0x4b, 0x1e, 0x07, 0x00, 0x1d, 0x00, 0x4b, 0x1e, 0x07, 0x00, 0x43, ++ 0x04, 0x06, 0x06, 0x0f, 0x1c, 0x0f, 0x1c, 0x07, 0x1c, 0x04, 0x42, 0x1c, 0x04, 0x42, 0x40, 0x40, ++ 0x43, 0x21, 0x14, 0x0c, 0x43, 0x0f, 0x0c, 0x04, 0x07, 0x3e, 0x27, 0x21, 0x04, 0x1d, 0x18, 0x0f, ++ 0x43, 0x1e, 0x13, 0x06, 0x43, 0x46, 0x18, 0x02, 0x0c, 0x07, 0x1c, 0x0b, 0x0f, 0x0f, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x56, 0x04, 0x4b, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x49, 0x40, 0x40, 0x40, 0x49, 0x24, ++ 0x04, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x0c, 0x0c, 0x41, ++ 0x4b, 0x13, 0x0c, 0x06, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x04, 0x04, 0x06, 0x06, 0x09, 0x01, ++ 0x43, 0x07, 0x01, 0x4e, 0x43, 0x0e, 0x41, 0x5b, 0x4e, 0x41, 0x18, 0x16, 0x11, 0x24, 0x06, 0x06, ++ 0x09, 0x01, 0x43, 0x07, 0x01, 0x4e, 0x43, 0x0e, 0x41, 0x5b, 0x4e, 0x41, 0x18, 0x16, 0x11, 0x24, ++ 0x2b, 0x54, 0x2c, 0x4b, 0x41, 0x41, 0x01, 0x06, 0x06, 0x13, 0x09, 0x16, 0x09, 0x1e, 0x01, 0x4b, ++ 0x1e, 0x07, 0x01, 0x1e, 0x01, 0x4b, 0x1e, 0x07, 0x01, 0x1e, 0x01, 0x4b, 0x1e, 0x07, 0x01, 0x43, ++ 0x04, 0x06, 0x06, 0x0f, 0x1c, 0x0f, 0x1c, 0x07, 0x1c, 0x04, 0x41, 0x1c, 0x04, 0x41, 0x40, 0x40, ++ 0x43, 0x23, 0x14, 0x0c, 0x43, 0x0f, 0x0c, 0x04, 0x07, 0x3e, 0x27, 0x23, 0x04, 0x1e, 0x19, 0x0f, ++ 0x43, 0x1e, 0x13, 0x06, 0x43, 0x48, 0x19, 0x01, 0x0c, 0x07, 0x1c, 0x0b, 0x0f, 0x0f, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x57, 0x05, 0x4a, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x4a, 0x40, 0x40, 0x40, 0x4a, 0x26, ++ 0x05, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x0d, 0x0d, 0x40, ++ 0x4a, 0x14, 0x0d, 0x05, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x05, 0x05, 0x07, 0x07, 0x0a, 0x02, ++ 0x42, 0x07, 0x02, 0x4d, 0x42, 0x0f, 0x40, 0x5a, 0x4d, 0x40, 0x19, 0x17, 0x12, 0x26, 0x07, 0x07, ++ 0x0a, 0x02, 0x42, 0x07, 0x02, 0x4d, 0x42, 0x0f, 0x40, 0x5a, 0x4d, 0x40, 0x19, 0x17, 0x12, 0x26, ++ 0x2c, 0x55, 0x2d, 0x4a, 0x40, 0x40, 0x02, 0x07, 0x07, 0x14, 0x0a, 0x17, 0x0a, 0x1f, 0x02, 0x4a, ++ 0x1d, 0x07, 0x02, 0x1f, 0x02, 0x4a, 0x1d, 0x07, 0x02, 0x1f, 0x02, 0x4a, 0x1d, 0x07, 0x02, 0x42, ++ 0x05, 0x05, 0x05, 0x0f, 0x1d, 0x0f, 0x1d, 0x07, 0x1d, 0x05, 0x40, 0x1d, 0x05, 0x40, 0x40, 0x40, ++ 0x42, 0x24, 0x15, 0x0d, 0x42, 0x0f, 0x0d, 0x05, 0x07, 0x3e, 0x27, 0x24, 0x05, 0x1f, 0x1a, 0x0f, ++ 0x42, 0x1d, 0x12, 0x05, 0x42, 0x49, 0x1a, 0x00, 0x0d, 0x07, 0x1d, 0x0a, 0x0f, 0x0f, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x58, 0x05, 0x4a, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x4a, 0x40, 0x40, 0x40, 0x4a, 0x28, ++ 0x05, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x0d, 0x0d, 0x00, ++ 0x4a, 0x15, 0x0d, 0x05, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x05, 0x05, 0x08, 0x08, 0x0a, 0x02, ++ 0x42, 0x07, 0x02, 0x4d, 0x42, 0x10, 0x00, 0x5a, 0x4d, 0x00, 0x1b, 0x18, 0x12, 0x28, 0x08, 0x08, ++ 0x0a, 0x02, 0x42, 0x07, 0x02, 0x4d, 0x42, 0x10, 0x00, 0x5a, 0x4d, 0x00, 0x1b, 0x18, 0x12, 0x28, ++ 0x2d, 0x55, 0x2d, 0x4a, 0x00, 0x00, 0x02, 0x08, 0x08, 0x15, 0x0a, 0x18, 0x0a, 0x20, 0x02, 0x4a, ++ 0x1d, 0x07, 0x02, 0x20, 0x02, 0x4a, 0x1d, 0x07, 0x02, 0x20, 0x02, 0x4a, 0x1d, 0x07, 0x02, 0x42, ++ 0x05, 0x05, 0x05, 0x0f, 0x1d, 0x0f, 0x1d, 0x07, 0x1d, 0x05, 0x00, 0x1d, 0x05, 0x00, 0x40, 0x40, ++ 0x42, 0x25, 0x15, 0x0d, 0x42, 0x0f, 0x0d, 0x05, 0x07, 0x3e, 0x27, 0x25, 0x05, 0x20, 0x1a, 0x0f, ++ 0x42, 0x1d, 0x12, 0x05, 0x42, 0x4b, 0x1a, 0x40, 0x0d, 0x07, 0x1d, 0x0a, 0x0f, 0x0f, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x59, 0x05, 0x4a, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x4b, 0x40, 0x40, 0x40, 0x4b, 0x2a, ++ 0x05, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x0d, 0x0d, 0x01, ++ 0x4a, 0x16, 0x0d, 0x04, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x05, 0x05, 0x09, 0x09, 0x0b, 0x03, ++ 0x42, 0x07, 0x03, 0x4c, 0x42, 0x11, 0x01, 0x5a, 0x4c, 0x01, 0x1c, 0x19, 0x13, 0x2a, 0x09, 0x09, ++ 0x0b, 0x03, 0x42, 0x07, 0x03, 0x4c, 0x42, 0x11, 0x01, 0x5a, 0x4c, 0x01, 0x1c, 0x19, 0x13, 0x2a, ++ 0x2e, 0x55, 0x2d, 0x4a, 0x01, 0x01, 0x03, 0x09, 0x09, 0x16, 0x0b, 0x19, 0x0b, 0x21, 0x03, 0x4a, ++ 0x1c, 0x07, 0x03, 0x21, 0x03, 0x4a, 0x1c, 0x07, 0x03, 0x21, 0x03, 0x4a, 0x1c, 0x07, 0x03, 0x42, ++ 0x05, 0x04, 0x04, 0x0f, 0x1d, 0x0f, 0x1d, 0x07, 0x1d, 0x05, 0x01, 0x1d, 0x05, 0x01, 0x40, 0x40, ++ 0x42, 0x26, 0x15, 0x0d, 0x42, 0x0f, 0x0d, 0x05, 0x07, 0x3e, 0x27, 0x26, 0x05, 0x21, 0x1b, 0x0f, ++ 0x42, 0x1c, 0x12, 0x04, 0x42, 0x4c, 0x1b, 0x41, 0x0d, 0x07, 0x1d, 0x0a, 0x0f, 0x0f, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x5a, 0x06, 0x49, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x4c, 0x40, 0x40, 0x40, 0x4c, 0x2c, ++ 0x06, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x0e, 0x0e, 0x02, ++ 0x49, 0x18, 0x0e, 0x03, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x06, 0x06, 0x0a, 0x0a, 0x0c, 0x04, ++ 0x41, 0x07, 0x04, 0x4b, 0x41, 0x12, 0x02, 0x59, 0x4b, 0x02, 0x1e, 0x1a, 0x14, 0x2c, 0x0a, 0x0a, ++ 0x0c, 0x04, 0x41, 0x07, 0x04, 0x4b, 0x41, 0x12, 0x02, 0x59, 0x4b, 0x02, 0x1e, 0x1a, 0x14, 0x2c, ++ 0x30, 0x56, 0x2e, 0x49, 0x02, 0x02, 0x04, 0x0a, 0x0a, 0x18, 0x0c, 0x1a, 0x0c, 0x22, 0x04, 0x49, ++ 0x1b, 0x07, 0x04, 0x22, 0x04, 0x49, 0x1b, 0x07, 0x04, 0x22, 0x04, 0x49, 0x1b, 0x07, 0x04, 0x41, ++ 0x06, 0x03, 0x03, 0x0f, 0x1e, 0x0f, 0x1e, 0x07, 0x1e, 0x06, 0x02, 0x1e, 0x06, 0x02, 0x40, 0x40, ++ 0x41, 0x28, 0x16, 0x0e, 0x41, 0x0f, 0x0e, 0x06, 0x07, 0x3e, 0x27, 0x28, 0x06, 0x22, 0x1c, 0x0f, ++ 0x41, 0x1b, 0x11, 0x03, 0x41, 0x4e, 0x1c, 0x42, 0x0e, 0x07, 0x1e, 0x09, 0x0f, 0x0f, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x5b, 0x06, 0x49, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x4c, 0x40, 0x40, 0x40, 0x4c, 0x2e, ++ 0x06, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x0e, 0x0e, 0x03, ++ 0x49, 0x19, 0x0e, 0x03, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x06, 0x06, 0x0b, 0x0b, 0x0c, 0x04, ++ 0x41, 0x07, 0x04, 0x4b, 0x41, 0x13, 0x03, 0x59, 0x4b, 0x03, 0x1f, 0x1b, 0x14, 0x2e, 0x0b, 0x0b, ++ 0x0c, 0x04, 0x41, 0x07, 0x04, 0x4b, 0x41, 0x13, 0x03, 0x59, 0x4b, 0x03, 0x1f, 0x1b, 0x14, 0x2e, ++ 0x31, 0x56, 0x2e, 0x49, 0x03, 0x03, 0x04, 0x0b, 0x0b, 0x19, 0x0c, 0x1b, 0x0c, 0x23, 0x04, 0x49, ++ 0x1b, 0x07, 0x04, 0x23, 0x04, 0x49, 0x1b, 0x07, 0x04, 0x23, 0x04, 0x49, 0x1b, 0x07, 0x04, 0x41, ++ 0x06, 0x03, 0x03, 0x0f, 0x1e, 0x0f, 0x1e, 0x07, 0x1e, 0x06, 0x03, 0x1e, 0x06, 0x03, 0x40, 0x40, ++ 0x41, 0x29, 0x16, 0x0e, 0x41, 0x0f, 0x0e, 0x06, 0x07, 0x3e, 0x27, 0x29, 0x06, 0x23, 0x1c, 0x0f, ++ 0x41, 0x1b, 0x11, 0x03, 0x41, 0x4f, 0x1c, 0x43, 0x0e, 0x07, 0x1e, 0x09, 0x0f, 0x0f, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x5c, 0x06, 0x49, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x4d, 0x40, 0x40, 0x40, 0x4d, 0x30, ++ 0x06, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x0e, 0x0e, 0x04, ++ 0x49, 0x1a, 0x0e, 0x02, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x06, 0x06, 0x0c, 0x0c, 0x0d, 0x05, ++ 0x41, 0x07, 0x05, 0x4a, 0x41, 0x14, 0x04, 0x59, 0x4a, 0x04, 0x21, 0x1c, 0x15, 0x30, 0x0c, 0x0c, ++ 0x0d, 0x05, 0x41, 0x07, 0x05, 0x4a, 0x41, 0x14, 0x04, 0x59, 0x4a, 0x04, 0x21, 0x1c, 0x15, 0x30, ++ 0x32, 0x56, 0x2e, 0x49, 0x04, 0x04, 0x05, 0x0c, 0x0c, 0x1a, 0x0d, 0x1c, 0x0d, 0x24, 0x05, 0x49, ++ 0x1a, 0x07, 0x05, 0x24, 0x05, 0x49, 0x1a, 0x07, 0x05, 0x24, 0x05, 0x49, 0x1a, 0x07, 0x05, 0x41, ++ 0x06, 0x02, 0x02, 0x0f, 0x1e, 0x0f, 0x1e, 0x07, 0x1e, 0x06, 0x04, 0x1e, 0x06, 0x04, 0x40, 0x40, ++ 0x41, 0x2a, 0x16, 0x0e, 0x41, 0x0f, 0x0e, 0x06, 0x07, 0x3e, 0x27, 0x2a, 0x06, 0x24, 0x1d, 0x0f, ++ 0x41, 0x1a, 0x11, 0x02, 0x41, 0x51, 0x1d, 0x44, 0x0e, 0x07, 0x1e, 0x09, 0x0f, 0x0f, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x5d, 0x06, 0x49, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x4e, 0x40, 0x40, 0x40, 0x4e, 0x31, ++ 0x06, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x0e, 0x0e, 0x04, ++ 0x49, 0x1b, 0x0e, 0x01, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x06, 0x06, 0x0c, 0x0c, 0x0d, 0x05, ++ 0x41, 0x07, 0x05, 0x4a, 0x41, 0x14, 0x04, 0x59, 0x4a, 0x04, 0x22, 0x1c, 0x15, 0x31, 0x0c, 0x0c, ++ 0x0d, 0x05, 0x41, 0x07, 0x05, 0x4a, 0x41, 0x14, 0x04, 0x59, 0x4a, 0x04, 0x22, 0x1c, 0x15, 0x31, ++ 0x33, 0x57, 0x2e, 0x49, 0x04, 0x04, 0x05, 0x0c, 0x0c, 0x1b, 0x0d, 0x1c, 0x0d, 0x24, 0x05, 0x49, ++ 0x19, 0x07, 0x05, 0x24, 0x05, 0x49, 0x19, 0x07, 0x05, 0x24, 0x05, 0x49, 0x19, 0x07, 0x05, 0x41, ++ 0x06, 0x01, 0x01, 0x0f, 0x1e, 0x0f, 0x1e, 0x07, 0x1e, 0x06, 0x04, 0x1e, 0x06, 0x04, 0x40, 0x40, ++ 0x41, 0x2b, 0x16, 0x0e, 0x41, 0x0f, 0x0e, 0x06, 0x07, 0x3e, 0x27, 0x2b, 0x06, 0x24, 0x1d, 0x0f, ++ 0x41, 0x19, 0x10, 0x01, 0x41, 0x53, 0x1d, 0x45, 0x0e, 0x07, 0x1e, 0x08, 0x0f, 0x0f, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x5d, 0x07, 0x48, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x4e, 0x40, 0x40, 0x40, 0x4e, 0x33, ++ 0x07, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x0f, 0x0f, 0x05, ++ 0x48, 0x1d, 0x0f, 0x01, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x07, 0x0d, 0x0d, 0x0e, 0x06, ++ 0x40, 0x07, 0x06, 0x49, 0x40, 0x15, 0x05, 0x58, 0x49, 0x05, 0x24, 0x1d, 0x16, 0x33, 0x0d, 0x0d, ++ 0x0e, 0x06, 0x40, 0x07, 0x06, 0x49, 0x40, 0x15, 0x05, 0x58, 0x49, 0x05, 0x24, 0x1d, 0x16, 0x33, ++ 0x35, 0x57, 0x2f, 0x48, 0x05, 0x05, 0x06, 0x0d, 0x0d, 0x1d, 0x0e, 0x1d, 0x0e, 0x25, 0x06, 0x48, ++ 0x19, 0x07, 0x06, 0x25, 0x06, 0x48, 0x19, 0x07, 0x06, 0x25, 0x06, 0x48, 0x19, 0x07, 0x06, 0x40, ++ 0x07, 0x01, 0x01, 0x0f, 0x1f, 0x0f, 0x1f, 0x07, 0x1f, 0x07, 0x05, 0x1f, 0x07, 0x05, 0x40, 0x40, ++ 0x40, 0x2d, 0x17, 0x0f, 0x40, 0x0f, 0x0f, 0x07, 0x07, 0x3e, 0x27, 0x2d, 0x07, 0x25, 0x1e, 0x0f, ++ 0x40, 0x19, 0x10, 0x01, 0x40, 0x54, 0x1e, 0x45, 0x0f, 0x07, 0x1f, 0x08, 0x0f, 0x0f, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x5e, 0x07, 0x48, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x4f, 0x40, 0x40, 0x40, 0x4f, 0x35, ++ 0x07, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x0f, 0x0f, 0x06, ++ 0x48, 0x1e, 0x0f, 0x00, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x07, 0x0e, 0x0e, 0x0f, 0x07, ++ 0x40, 0x07, 0x07, 0x48, 0x40, 0x16, 0x06, 0x58, 0x48, 0x06, 0x26, 0x1e, 0x17, 0x35, 0x0e, 0x0e, ++ 0x0f, 0x07, 0x40, 0x07, 0x07, 0x48, 0x40, 0x16, 0x06, 0x58, 0x48, 0x06, 0x26, 0x1e, 0x17, 0x35, ++ 0x36, 0x57, 0x2f, 0x48, 0x06, 0x06, 0x07, 0x0e, 0x0e, 0x1e, 0x0f, 0x1e, 0x0f, 0x26, 0x07, 0x48, ++ 0x18, 0x07, 0x07, 0x26, 0x07, 0x48, 0x18, 0x07, 0x07, 0x26, 0x07, 0x48, 0x18, 0x07, 0x07, 0x40, ++ 0x07, 0x00, 0x00, 0x0f, 0x1f, 0x0f, 0x1f, 0x07, 0x1f, 0x07, 0x06, 0x1f, 0x07, 0x06, 0x40, 0x40, ++ 0x40, 0x2e, 0x17, 0x0f, 0x40, 0x0f, 0x0f, 0x07, 0x07, 0x3e, 0x27, 0x2e, 0x07, 0x26, 0x1f, 0x0f, ++ 0x40, 0x18, 0x10, 0x00, 0x40, 0x56, 0x1f, 0x46, 0x0f, 0x07, 0x1f, 0x08, 0x0f, 0x0f, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x5f, 0x07, 0x48, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x4f, 0x40, 0x40, 0x40, 0x4f, 0x37, ++ 0x07, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x0f, 0x0f, 0x07, ++ 0x48, 0x1f, 0x0f, 0x00, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x07, 0x0f, 0x0f, 0x0f, 0x07, ++ 0x40, 0x07, 0x07, 0x48, 0x40, 0x17, 0x07, 0x58, 0x48, 0x07, 0x27, 0x1f, 0x17, 0x37, 0x0f, 0x0f, ++ 0x0f, 0x07, 0x40, 0x07, 0x07, 0x48, 0x40, 0x17, 0x07, 0x58, 0x48, 0x07, 0x27, 0x1f, 0x17, 0x37, ++ 0x37, 0x57, 0x2f, 0x48, 0x07, 0x07, 0x07, 0x0f, 0x0f, 0x1f, 0x0f, 0x1f, 0x0f, 0x27, 0x07, 0x48, ++ 0x18, 0x07, 0x07, 0x27, 0x07, 0x48, 0x18, 0x07, 0x07, 0x27, 0x07, 0x48, 0x18, 0x07, 0x07, 0x40, ++ 0x07, 0x00, 0x00, 0x0f, 0x1f, 0x0f, 0x1f, 0x07, 0x1f, 0x07, 0x07, 0x1f, 0x07, 0x07, 0x40, 0x40, ++ 0x40, 0x2f, 0x17, 0x0f, 0x40, 0x0f, 0x0f, 0x07, 0x07, 0x3e, 0x27, 0x2f, 0x07, 0x27, 0x1f, 0x0f, ++ 0x40, 0x18, 0x10, 0x00, 0x40, 0x57, 0x1f, 0x47, 0x0f, 0x07, 0x1f, 0x08, 0x0f, 0x0f, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x07, 0x48, 0x48, 0x60, 0x40, 0x27, 0x07, 0x07, 0x27, 0x40, 0x48, 0x40, 0x40, 0x40, 0x0f, ++ 0x48, 0x68, 0x60, 0x40, 0x68, 0x68, 0x68, 0x68, 0x68, 0x07, 0x07, 0x0f, 0x50, 0x40, 0x60, 0x07, ++ 0x68, 0x27, 0x48, 0x17, 0x40, 0x50, 0x1f, 0x40, 0x40, 0x40, 0x48, 0x48, 0x58, 0x60, 0x60, 0x60, ++ 0x68, 0x68, 0x58, 0x68, 0x60, 0x60, 0x60, 0x68, 0x68, 0x68, 0x60, 0x50, 0x48, 0x50, 0x58, 0x60, ++ 0x60, 0x60, 0x68, 0x68, 0x58, 0x68, 0x60, 0x60, 0x60, 0x68, 0x68, 0x68, 0x60, 0x50, 0x48, 0x50, ++ 0x07, 0x50, 0x58, 0x40, 0x48, 0x40, 0x48, 0x07, 0x48, 0x48, 0x48, 0x68, 0x07, 0x1f, 0x17, 0x50, ++ 0x0f, 0x07, 0x40, 0x1f, 0x17, 0x50, 0x0f, 0x07, 0x40, 0x1f, 0x17, 0x50, 0x0f, 0x07, 0x40, 0x40, ++ 0x07, 0x48, 0x48, 0x48, 0x07, 0x48, 0x07, 0x17, 0x17, 0x17, 0x50, 0x17, 0x17, 0x50, 0x40, 0x40, ++ 0x40, 0x2f, 0x2f, 0x17, 0x40, 0x0f, 0x17, 0x1f, 0x1f, 0x1f, 0x27, 0x0f, 0x07, 0x07, 0x0f, 0x07, ++ 0x07, 0x3e, 0x1f, 0x17, 0x40, 0x17, 0x07, 0x1f, 0x48, 0x17, 0x48, 0x40, 0x48, 0x17, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x07, 0x47, 0x47, 0x5f, 0x40, 0x27, 0x07, 0x07, 0x27, 0x40, 0x47, 0x40, 0x40, 0x40, 0x0f, ++ 0x47, 0x66, 0x5f, 0x00, 0x66, 0x66, 0x66, 0x65, 0x65, 0x07, 0x07, 0x0f, 0x4f, 0x00, 0x5e, 0x07, ++ 0x67, 0x27, 0x47, 0x17, 0x40, 0x4f, 0x1f, 0x40, 0x40, 0x40, 0x47, 0x47, 0x57, 0x5f, 0x5e, 0x5f, ++ 0x66, 0x66, 0x57, 0x67, 0x5f, 0x5e, 0x5f, 0x67, 0x67, 0x66, 0x5e, 0x4f, 0x47, 0x4f, 0x57, 0x5f, ++ 0x5e, 0x5f, 0x66, 0x66, 0x57, 0x67, 0x5f, 0x5e, 0x5f, 0x67, 0x67, 0x66, 0x5e, 0x4f, 0x47, 0x4f, ++ 0x08, 0x4f, 0x56, 0x40, 0x48, 0x40, 0x47, 0x07, 0x47, 0x47, 0x47, 0x66, 0x07, 0x1f, 0x17, 0x4f, ++ 0x10, 0x07, 0x40, 0x1f, 0x17, 0x4f, 0x10, 0x07, 0x40, 0x1f, 0x17, 0x4f, 0x10, 0x07, 0x40, 0x40, ++ 0x07, 0x47, 0x47, 0x47, 0x08, 0x47, 0x08, 0x17, 0x17, 0x17, 0x4f, 0x17, 0x17, 0x4f, 0x40, 0x40, ++ 0x40, 0x2f, 0x2f, 0x17, 0x40, 0x0f, 0x17, 0x1f, 0x1f, 0x20, 0x27, 0x10, 0x07, 0x08, 0x10, 0x08, ++ 0x07, 0x3e, 0x1f, 0x17, 0x40, 0x17, 0x08, 0x1f, 0x47, 0x17, 0x46, 0x00, 0x47, 0x17, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x06, 0x46, 0x47, 0x5e, 0x40, 0x26, 0x06, 0x06, 0x27, 0x40, 0x47, 0x40, 0x40, 0x40, 0x0f, ++ 0x47, 0x64, 0x5e, 0x01, 0x65, 0x64, 0x64, 0x63, 0x63, 0x07, 0x07, 0x0f, 0x4e, 0x00, 0x5d, 0x07, ++ 0x66, 0x27, 0x46, 0x17, 0x40, 0x4f, 0x1e, 0x40, 0x40, 0x40, 0x47, 0x47, 0x56, 0x5e, 0x5d, 0x5e, ++ 0x65, 0x64, 0x56, 0x66, 0x5e, 0x5c, 0x5e, 0x66, 0x66, 0x65, 0x5d, 0x4e, 0x46, 0x4e, 0x56, 0x5e, ++ 0x5d, 0x5e, 0x65, 0x64, 0x56, 0x66, 0x5e, 0x5c, 0x5e, 0x66, 0x66, 0x65, 0x5d, 0x4e, 0x46, 0x4e, ++ 0x09, 0x4f, 0x54, 0x40, 0x48, 0x40, 0x47, 0x07, 0x47, 0x46, 0x46, 0x64, 0x07, 0x1f, 0x16, 0x4f, ++ 0x10, 0x07, 0x40, 0x1f, 0x16, 0x4f, 0x10, 0x07, 0x40, 0x1f, 0x16, 0x4f, 0x10, 0x07, 0x40, 0x40, ++ 0x07, 0x46, 0x46, 0x46, 0x09, 0x46, 0x09, 0x17, 0x17, 0x16, 0x4f, 0x17, 0x16, 0x4f, 0x40, 0x40, ++ 0x40, 0x2e, 0x2e, 0x17, 0x40, 0x0f, 0x17, 0x1e, 0x1e, 0x20, 0x27, 0x10, 0x07, 0x09, 0x10, 0x08, ++ 0x07, 0x3e, 0x1f, 0x17, 0x40, 0x17, 0x08, 0x1e, 0x46, 0x17, 0x45, 0x01, 0x46, 0x17, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x06, 0x45, 0x47, 0x5e, 0x40, 0x25, 0x06, 0x05, 0x27, 0x40, 0x47, 0x40, 0x40, 0x40, 0x0f, ++ 0x47, 0x63, 0x5d, 0x01, 0x64, 0x63, 0x62, 0x60, 0x60, 0x07, 0x07, 0x0f, 0x4e, 0x00, 0x5c, 0x07, ++ 0x65, 0x27, 0x45, 0x17, 0x40, 0x4f, 0x1d, 0x40, 0x40, 0x40, 0x47, 0x47, 0x56, 0x5d, 0x5c, 0x5d, ++ 0x64, 0x63, 0x56, 0x65, 0x5d, 0x5b, 0x5d, 0x65, 0x65, 0x64, 0x5c, 0x4d, 0x46, 0x4d, 0x56, 0x5d, ++ 0x5c, 0x5d, 0x64, 0x63, 0x56, 0x65, 0x5d, 0x5b, 0x5d, 0x65, 0x65, 0x64, 0x5c, 0x4d, 0x46, 0x4d, ++ 0x09, 0x4f, 0x52, 0x40, 0x48, 0x40, 0x47, 0x07, 0x47, 0x46, 0x46, 0x62, 0x07, 0x1f, 0x16, 0x4f, ++ 0x10, 0x07, 0x40, 0x1f, 0x16, 0x4f, 0x10, 0x07, 0x40, 0x1f, 0x16, 0x4f, 0x10, 0x07, 0x40, 0x40, ++ 0x07, 0x46, 0x46, 0x45, 0x09, 0x45, 0x09, 0x17, 0x17, 0x16, 0x4f, 0x17, 0x16, 0x4f, 0x40, 0x40, ++ 0x40, 0x2d, 0x2d, 0x17, 0x40, 0x0f, 0x17, 0x1e, 0x1e, 0x20, 0x27, 0x10, 0x07, 0x09, 0x10, 0x08, ++ 0x07, 0x3d, 0x1f, 0x17, 0x40, 0x17, 0x08, 0x1e, 0x45, 0x17, 0x44, 0x01, 0x45, 0x17, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x05, 0x44, 0x46, 0x5d, 0x40, 0x24, 0x05, 0x04, 0x27, 0x40, 0x46, 0x40, 0x40, 0x40, 0x0f, ++ 0x46, 0x61, 0x5c, 0x02, 0x63, 0x61, 0x60, 0x5e, 0x5e, 0x07, 0x07, 0x0e, 0x4d, 0x01, 0x5b, 0x07, ++ 0x64, 0x27, 0x44, 0x16, 0x40, 0x4e, 0x1c, 0x40, 0x40, 0x40, 0x46, 0x46, 0x55, 0x5c, 0x5b, 0x5c, ++ 0x63, 0x61, 0x55, 0x64, 0x5c, 0x59, 0x5c, 0x64, 0x64, 0x63, 0x5b, 0x4c, 0x45, 0x4c, 0x55, 0x5c, ++ 0x5b, 0x5c, 0x63, 0x61, 0x55, 0x64, 0x5c, 0x59, 0x5c, 0x64, 0x64, 0x63, 0x5b, 0x4c, 0x45, 0x4c, ++ 0x0a, 0x4e, 0x50, 0x40, 0x48, 0x40, 0x46, 0x07, 0x46, 0x45, 0x45, 0x60, 0x07, 0x1e, 0x15, 0x4e, ++ 0x11, 0x07, 0x40, 0x1e, 0x15, 0x4e, 0x11, 0x07, 0x40, 0x1e, 0x15, 0x4e, 0x11, 0x07, 0x40, 0x41, ++ 0x07, 0x45, 0x45, 0x44, 0x0a, 0x44, 0x0a, 0x16, 0x17, 0x15, 0x4e, 0x17, 0x15, 0x4e, 0x40, 0x40, ++ 0x40, 0x2c, 0x2c, 0x16, 0x40, 0x0f, 0x16, 0x1d, 0x1d, 0x21, 0x27, 0x11, 0x07, 0x0a, 0x11, 0x09, ++ 0x06, 0x3c, 0x1e, 0x16, 0x40, 0x16, 0x09, 0x1d, 0x44, 0x16, 0x43, 0x02, 0x44, 0x16, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x04, 0x43, 0x46, 0x5c, 0x40, 0x23, 0x04, 0x03, 0x27, 0x40, 0x46, 0x40, 0x40, 0x40, 0x0f, ++ 0x46, 0x60, 0x5b, 0x03, 0x61, 0x60, 0x5e, 0x5b, 0x5b, 0x07, 0x07, 0x0e, 0x4c, 0x01, 0x59, 0x07, ++ 0x63, 0x27, 0x43, 0x16, 0x40, 0x4e, 0x1b, 0x40, 0x40, 0x40, 0x46, 0x46, 0x54, 0x5b, 0x59, 0x5b, ++ 0x61, 0x60, 0x54, 0x63, 0x5b, 0x58, 0x5b, 0x63, 0x63, 0x61, 0x59, 0x4b, 0x44, 0x4b, 0x54, 0x5b, ++ 0x59, 0x5b, 0x61, 0x60, 0x54, 0x63, 0x5b, 0x58, 0x5b, 0x63, 0x63, 0x61, 0x59, 0x4b, 0x44, 0x4b, ++ 0x0b, 0x4e, 0x4e, 0x40, 0x48, 0x40, 0x46, 0x07, 0x46, 0x44, 0x44, 0x5e, 0x07, 0x1e, 0x14, 0x4e, ++ 0x11, 0x07, 0x40, 0x1e, 0x14, 0x4e, 0x11, 0x07, 0x40, 0x1e, 0x14, 0x4e, 0x11, 0x07, 0x40, 0x41, ++ 0x07, 0x44, 0x44, 0x43, 0x0b, 0x43, 0x0b, 0x16, 0x17, 0x14, 0x4e, 0x17, 0x14, 0x4e, 0x40, 0x40, ++ 0x40, 0x2b, 0x2b, 0x16, 0x40, 0x0f, 0x16, 0x1c, 0x1c, 0x21, 0x27, 0x11, 0x07, 0x0b, 0x11, 0x09, ++ 0x06, 0x3b, 0x1e, 0x16, 0x40, 0x16, 0x09, 0x1c, 0x43, 0x16, 0x41, 0x03, 0x43, 0x16, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x04, 0x42, 0x46, 0x5c, 0x40, 0x22, 0x04, 0x02, 0x27, 0x40, 0x46, 0x40, 0x40, 0x40, 0x0f, ++ 0x46, 0x5e, 0x5a, 0x03, 0x60, 0x5e, 0x5c, 0x59, 0x59, 0x07, 0x07, 0x0e, 0x4c, 0x01, 0x58, 0x07, ++ 0x62, 0x27, 0x42, 0x16, 0x40, 0x4e, 0x1a, 0x40, 0x40, 0x40, 0x46, 0x46, 0x54, 0x5a, 0x58, 0x5a, ++ 0x60, 0x5e, 0x54, 0x62, 0x5a, 0x56, 0x5a, 0x62, 0x62, 0x60, 0x58, 0x4a, 0x44, 0x4a, 0x54, 0x5a, ++ 0x58, 0x5a, 0x60, 0x5e, 0x54, 0x62, 0x5a, 0x56, 0x5a, 0x62, 0x62, 0x60, 0x58, 0x4a, 0x44, 0x4a, ++ 0x0b, 0x4e, 0x4c, 0x40, 0x48, 0x40, 0x46, 0x07, 0x46, 0x44, 0x44, 0x5c, 0x07, 0x1e, 0x14, 0x4e, ++ 0x11, 0x07, 0x40, 0x1e, 0x14, 0x4e, 0x11, 0x07, 0x40, 0x1e, 0x14, 0x4e, 0x11, 0x07, 0x40, 0x41, ++ 0x07, 0x44, 0x44, 0x42, 0x0b, 0x42, 0x0b, 0x16, 0x17, 0x14, 0x4e, 0x17, 0x14, 0x4e, 0x40, 0x40, ++ 0x40, 0x2a, 0x2a, 0x16, 0x40, 0x0f, 0x16, 0x1c, 0x1c, 0x21, 0x27, 0x11, 0x07, 0x0b, 0x11, 0x09, ++ 0x06, 0x3a, 0x1e, 0x16, 0x40, 0x16, 0x09, 0x1c, 0x42, 0x16, 0x40, 0x03, 0x42, 0x16, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x03, 0x41, 0x45, 0x5b, 0x40, 0x21, 0x03, 0x01, 0x27, 0x40, 0x45, 0x40, 0x40, 0x40, 0x0f, ++ 0x45, 0x5d, 0x59, 0x04, 0x5f, 0x5d, 0x5a, 0x56, 0x56, 0x07, 0x07, 0x0d, 0x4b, 0x02, 0x57, 0x07, ++ 0x61, 0x27, 0x41, 0x15, 0x40, 0x4d, 0x19, 0x40, 0x40, 0x40, 0x45, 0x45, 0x53, 0x59, 0x57, 0x59, ++ 0x5f, 0x5d, 0x53, 0x61, 0x59, 0x55, 0x59, 0x61, 0x61, 0x5f, 0x57, 0x49, 0x43, 0x49, 0x53, 0x59, ++ 0x57, 0x59, 0x5f, 0x5d, 0x53, 0x61, 0x59, 0x55, 0x59, 0x61, 0x61, 0x5f, 0x57, 0x49, 0x43, 0x49, ++ 0x0c, 0x4d, 0x4a, 0x40, 0x48, 0x40, 0x45, 0x07, 0x45, 0x43, 0x43, 0x5a, 0x07, 0x1d, 0x13, 0x4d, ++ 0x12, 0x07, 0x40, 0x1d, 0x13, 0x4d, 0x12, 0x07, 0x40, 0x1d, 0x13, 0x4d, 0x12, 0x07, 0x40, 0x42, ++ 0x07, 0x43, 0x43, 0x41, 0x0c, 0x41, 0x0c, 0x15, 0x17, 0x13, 0x4d, 0x17, 0x13, 0x4d, 0x40, 0x40, ++ 0x40, 0x29, 0x29, 0x15, 0x40, 0x0f, 0x15, 0x1b, 0x1b, 0x22, 0x27, 0x12, 0x07, 0x0c, 0x12, 0x0a, ++ 0x05, 0x39, 0x1d, 0x15, 0x40, 0x15, 0x0a, 0x1b, 0x41, 0x15, 0x00, 0x04, 0x41, 0x15, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x02, 0x40, 0x45, 0x5b, 0x40, 0x20, 0x02, 0x00, 0x27, 0x40, 0x45, 0x40, 0x40, 0x40, 0x0f, ++ 0x45, 0x5b, 0x58, 0x04, 0x5e, 0x5b, 0x59, 0x54, 0x54, 0x07, 0x07, 0x0d, 0x4b, 0x02, 0x56, 0x07, ++ 0x60, 0x27, 0x40, 0x15, 0x40, 0x4d, 0x18, 0x40, 0x40, 0x40, 0x45, 0x45, 0x53, 0x58, 0x56, 0x58, ++ 0x5e, 0x5b, 0x53, 0x60, 0x58, 0x53, 0x58, 0x60, 0x60, 0x5e, 0x56, 0x48, 0x43, 0x48, 0x53, 0x58, ++ 0x56, 0x58, 0x5e, 0x5b, 0x53, 0x60, 0x58, 0x53, 0x58, 0x60, 0x60, 0x5e, 0x56, 0x48, 0x43, 0x48, ++ 0x0c, 0x4d, 0x49, 0x40, 0x48, 0x40, 0x45, 0x07, 0x45, 0x43, 0x43, 0x59, 0x07, 0x1d, 0x12, 0x4d, ++ 0x12, 0x07, 0x40, 0x1d, 0x12, 0x4d, 0x12, 0x07, 0x40, 0x1d, 0x12, 0x4d, 0x12, 0x07, 0x40, 0x42, ++ 0x07, 0x43, 0x43, 0x40, 0x0c, 0x40, 0x0c, 0x15, 0x17, 0x12, 0x4d, 0x17, 0x12, 0x4d, 0x40, 0x40, ++ 0x40, 0x28, 0x28, 0x15, 0x40, 0x0f, 0x15, 0x1a, 0x1a, 0x22, 0x27, 0x12, 0x07, 0x0c, 0x12, 0x0a, ++ 0x05, 0x38, 0x1d, 0x15, 0x40, 0x15, 0x0a, 0x1a, 0x40, 0x15, 0x01, 0x04, 0x40, 0x15, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x02, 0x00, 0x45, 0x5a, 0x40, 0x1f, 0x02, 0x40, 0x27, 0x40, 0x45, 0x40, 0x40, 0x40, 0x0f, ++ 0x45, 0x59, 0x57, 0x05, 0x5c, 0x59, 0x57, 0x51, 0x51, 0x07, 0x07, 0x0d, 0x4a, 0x02, 0x54, 0x07, ++ 0x5f, 0x27, 0x00, 0x15, 0x40, 0x4d, 0x17, 0x40, 0x40, 0x40, 0x45, 0x45, 0x52, 0x57, 0x54, 0x57, ++ 0x5c, 0x59, 0x52, 0x5f, 0x57, 0x51, 0x57, 0x5f, 0x5f, 0x5c, 0x54, 0x47, 0x42, 0x47, 0x52, 0x57, ++ 0x54, 0x57, 0x5c, 0x59, 0x52, 0x5f, 0x57, 0x51, 0x57, 0x5f, 0x5f, 0x5c, 0x54, 0x47, 0x42, 0x47, ++ 0x0d, 0x4d, 0x47, 0x40, 0x48, 0x40, 0x45, 0x07, 0x45, 0x42, 0x42, 0x57, 0x07, 0x1d, 0x12, 0x4d, ++ 0x12, 0x07, 0x40, 0x1d, 0x12, 0x4d, 0x12, 0x07, 0x40, 0x1d, 0x12, 0x4d, 0x12, 0x07, 0x40, 0x42, ++ 0x07, 0x42, 0x42, 0x00, 0x0d, 0x00, 0x0d, 0x15, 0x17, 0x12, 0x4d, 0x17, 0x12, 0x4d, 0x40, 0x40, ++ 0x40, 0x27, 0x27, 0x15, 0x40, 0x0f, 0x15, 0x1a, 0x1a, 0x22, 0x27, 0x12, 0x07, 0x0d, 0x12, 0x0a, ++ 0x05, 0x37, 0x1d, 0x15, 0x40, 0x15, 0x0a, 0x1a, 0x00, 0x15, 0x03, 0x05, 0x00, 0x15, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x01, 0x01, 0x44, 0x59, 0x40, 0x1e, 0x01, 0x41, 0x27, 0x40, 0x44, 0x40, 0x40, 0x40, 0x0f, ++ 0x44, 0x58, 0x56, 0x06, 0x5b, 0x58, 0x55, 0x4f, 0x4f, 0x07, 0x07, 0x0c, 0x49, 0x03, 0x53, 0x07, ++ 0x5e, 0x27, 0x01, 0x14, 0x40, 0x4c, 0x16, 0x40, 0x40, 0x40, 0x44, 0x44, 0x51, 0x56, 0x53, 0x56, ++ 0x5b, 0x58, 0x51, 0x5e, 0x56, 0x50, 0x56, 0x5e, 0x5e, 0x5b, 0x53, 0x46, 0x41, 0x46, 0x51, 0x56, ++ 0x53, 0x56, 0x5b, 0x58, 0x51, 0x5e, 0x56, 0x50, 0x56, 0x5e, 0x5e, 0x5b, 0x53, 0x46, 0x41, 0x46, ++ 0x0e, 0x4c, 0x45, 0x40, 0x48, 0x40, 0x44, 0x07, 0x44, 0x41, 0x41, 0x55, 0x07, 0x1c, 0x11, 0x4c, ++ 0x13, 0x07, 0x40, 0x1c, 0x11, 0x4c, 0x13, 0x07, 0x40, 0x1c, 0x11, 0x4c, 0x13, 0x07, 0x40, 0x43, ++ 0x07, 0x41, 0x41, 0x01, 0x0e, 0x01, 0x0e, 0x14, 0x17, 0x11, 0x4c, 0x17, 0x11, 0x4c, 0x40, 0x40, ++ 0x40, 0x26, 0x26, 0x14, 0x40, 0x0f, 0x14, 0x19, 0x19, 0x23, 0x27, 0x13, 0x07, 0x0e, 0x13, 0x0b, ++ 0x04, 0x36, 0x1c, 0x14, 0x40, 0x14, 0x0b, 0x19, 0x01, 0x14, 0x04, 0x06, 0x01, 0x14, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x01, 0x02, 0x44, 0x59, 0x40, 0x1d, 0x01, 0x42, 0x27, 0x40, 0x44, 0x40, 0x40, 0x40, 0x0f, ++ 0x44, 0x56, 0x55, 0x06, 0x5a, 0x56, 0x53, 0x4c, 0x4c, 0x07, 0x07, 0x0c, 0x49, 0x03, 0x52, 0x07, ++ 0x5d, 0x27, 0x02, 0x14, 0x40, 0x4c, 0x15, 0x40, 0x40, 0x40, 0x44, 0x44, 0x51, 0x55, 0x52, 0x55, ++ 0x5a, 0x56, 0x51, 0x5d, 0x55, 0x4e, 0x55, 0x5d, 0x5d, 0x5a, 0x52, 0x45, 0x41, 0x45, 0x51, 0x55, ++ 0x52, 0x55, 0x5a, 0x56, 0x51, 0x5d, 0x55, 0x4e, 0x55, 0x5d, 0x5d, 0x5a, 0x52, 0x45, 0x41, 0x45, ++ 0x0e, 0x4c, 0x43, 0x40, 0x48, 0x40, 0x44, 0x07, 0x44, 0x41, 0x41, 0x53, 0x07, 0x1c, 0x11, 0x4c, ++ 0x13, 0x07, 0x40, 0x1c, 0x11, 0x4c, 0x13, 0x07, 0x40, 0x1c, 0x11, 0x4c, 0x13, 0x07, 0x40, 0x43, ++ 0x07, 0x41, 0x41, 0x02, 0x0e, 0x02, 0x0e, 0x14, 0x17, 0x11, 0x4c, 0x17, 0x11, 0x4c, 0x40, 0x40, ++ 0x40, 0x25, 0x25, 0x14, 0x40, 0x0f, 0x14, 0x19, 0x19, 0x23, 0x27, 0x13, 0x07, 0x0e, 0x13, 0x0b, ++ 0x04, 0x35, 0x1c, 0x14, 0x40, 0x14, 0x0b, 0x19, 0x02, 0x14, 0x05, 0x06, 0x02, 0x14, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x00, 0x03, 0x44, 0x58, 0x40, 0x1c, 0x00, 0x43, 0x27, 0x40, 0x44, 0x40, 0x40, 0x40, 0x0f, ++ 0x44, 0x55, 0x54, 0x07, 0x59, 0x55, 0x51, 0x4a, 0x4a, 0x07, 0x07, 0x0c, 0x48, 0x03, 0x51, 0x07, ++ 0x5c, 0x27, 0x03, 0x14, 0x40, 0x4c, 0x14, 0x40, 0x40, 0x40, 0x44, 0x44, 0x50, 0x54, 0x51, 0x54, ++ 0x59, 0x55, 0x50, 0x5c, 0x54, 0x4d, 0x54, 0x5c, 0x5c, 0x59, 0x51, 0x44, 0x40, 0x44, 0x50, 0x54, ++ 0x51, 0x54, 0x59, 0x55, 0x50, 0x5c, 0x54, 0x4d, 0x54, 0x5c, 0x5c, 0x59, 0x51, 0x44, 0x40, 0x44, ++ 0x0f, 0x4c, 0x41, 0x40, 0x48, 0x40, 0x44, 0x07, 0x44, 0x40, 0x40, 0x51, 0x07, 0x1c, 0x10, 0x4c, ++ 0x13, 0x07, 0x40, 0x1c, 0x10, 0x4c, 0x13, 0x07, 0x40, 0x1c, 0x10, 0x4c, 0x13, 0x07, 0x40, 0x43, ++ 0x07, 0x40, 0x40, 0x03, 0x0f, 0x03, 0x0f, 0x14, 0x17, 0x10, 0x4c, 0x17, 0x10, 0x4c, 0x40, 0x40, ++ 0x40, 0x24, 0x24, 0x14, 0x40, 0x0f, 0x14, 0x18, 0x18, 0x23, 0x27, 0x13, 0x07, 0x0f, 0x13, 0x0b, ++ 0x04, 0x34, 0x1c, 0x14, 0x40, 0x14, 0x0b, 0x18, 0x03, 0x14, 0x06, 0x07, 0x03, 0x14, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x40, 0x04, 0x43, 0x57, 0x40, 0x1b, 0x40, 0x44, 0x27, 0x40, 0x43, 0x40, 0x40, 0x40, 0x0f, ++ 0x43, 0x53, 0x53, 0x08, 0x57, 0x53, 0x4f, 0x47, 0x47, 0x07, 0x07, 0x0b, 0x47, 0x04, 0x4f, 0x07, ++ 0x5b, 0x27, 0x04, 0x13, 0x40, 0x4b, 0x13, 0x40, 0x40, 0x40, 0x43, 0x43, 0x4f, 0x53, 0x4f, 0x53, ++ 0x57, 0x53, 0x4f, 0x5b, 0x53, 0x4b, 0x53, 0x5b, 0x5b, 0x57, 0x4f, 0x43, 0x00, 0x43, 0x4f, 0x53, ++ 0x4f, 0x53, 0x57, 0x53, 0x4f, 0x5b, 0x53, 0x4b, 0x53, 0x5b, 0x5b, 0x57, 0x4f, 0x43, 0x00, 0x43, ++ 0x10, 0x4b, 0x00, 0x40, 0x48, 0x40, 0x43, 0x07, 0x43, 0x00, 0x00, 0x4f, 0x07, 0x1b, 0x0f, 0x4b, ++ 0x14, 0x07, 0x40, 0x1b, 0x0f, 0x4b, 0x14, 0x07, 0x40, 0x1b, 0x0f, 0x4b, 0x14, 0x07, 0x40, 0x44, ++ 0x07, 0x00, 0x00, 0x04, 0x10, 0x04, 0x10, 0x13, 0x17, 0x0f, 0x4b, 0x17, 0x0f, 0x4b, 0x40, 0x40, ++ 0x40, 0x23, 0x23, 0x13, 0x40, 0x0f, 0x13, 0x17, 0x17, 0x24, 0x27, 0x14, 0x07, 0x10, 0x14, 0x0c, ++ 0x03, 0x33, 0x1b, 0x13, 0x40, 0x13, 0x0c, 0x17, 0x04, 0x13, 0x08, 0x08, 0x04, 0x13, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x40, 0x05, 0x43, 0x57, 0x40, 0x1a, 0x40, 0x45, 0x27, 0x40, 0x43, 0x40, 0x40, 0x40, 0x0f, ++ 0x43, 0x52, 0x52, 0x08, 0x56, 0x52, 0x4d, 0x45, 0x45, 0x07, 0x07, 0x0b, 0x47, 0x04, 0x4e, 0x07, ++ 0x5a, 0x27, 0x05, 0x13, 0x40, 0x4b, 0x12, 0x40, 0x40, 0x40, 0x43, 0x43, 0x4f, 0x52, 0x4e, 0x52, ++ 0x56, 0x52, 0x4f, 0x5a, 0x52, 0x4a, 0x52, 0x5a, 0x5a, 0x56, 0x4e, 0x42, 0x00, 0x42, 0x4f, 0x52, ++ 0x4e, 0x52, 0x56, 0x52, 0x4f, 0x5a, 0x52, 0x4a, 0x52, 0x5a, 0x5a, 0x56, 0x4e, 0x42, 0x00, 0x42, ++ 0x10, 0x4b, 0x02, 0x40, 0x48, 0x40, 0x43, 0x07, 0x43, 0x00, 0x00, 0x4d, 0x07, 0x1b, 0x0f, 0x4b, ++ 0x14, 0x07, 0x40, 0x1b, 0x0f, 0x4b, 0x14, 0x07, 0x40, 0x1b, 0x0f, 0x4b, 0x14, 0x07, 0x40, 0x44, ++ 0x07, 0x00, 0x00, 0x05, 0x10, 0x05, 0x10, 0x13, 0x17, 0x0f, 0x4b, 0x17, 0x0f, 0x4b, 0x40, 0x40, ++ 0x40, 0x22, 0x22, 0x13, 0x40, 0x0f, 0x13, 0x17, 0x17, 0x24, 0x27, 0x14, 0x07, 0x10, 0x14, 0x0c, ++ 0x03, 0x32, 0x1b, 0x13, 0x40, 0x13, 0x0c, 0x17, 0x05, 0x13, 0x09, 0x08, 0x05, 0x13, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x41, 0x06, 0x43, 0x56, 0x40, 0x19, 0x41, 0x46, 0x27, 0x40, 0x43, 0x40, 0x40, 0x40, 0x0f, ++ 0x43, 0x50, 0x51, 0x09, 0x55, 0x50, 0x4b, 0x42, 0x42, 0x07, 0x07, 0x0b, 0x46, 0x04, 0x4d, 0x07, ++ 0x59, 0x27, 0x06, 0x13, 0x40, 0x4b, 0x11, 0x40, 0x40, 0x40, 0x43, 0x43, 0x4e, 0x51, 0x4d, 0x51, ++ 0x55, 0x50, 0x4e, 0x59, 0x51, 0x48, 0x51, 0x59, 0x59, 0x55, 0x4d, 0x41, 0x01, 0x41, 0x4e, 0x51, ++ 0x4d, 0x51, 0x55, 0x50, 0x4e, 0x59, 0x51, 0x48, 0x51, 0x59, 0x59, 0x55, 0x4d, 0x41, 0x01, 0x41, ++ 0x11, 0x4b, 0x04, 0x40, 0x48, 0x40, 0x43, 0x07, 0x43, 0x01, 0x01, 0x4b, 0x07, 0x1b, 0x0e, 0x4b, ++ 0x14, 0x07, 0x40, 0x1b, 0x0e, 0x4b, 0x14, 0x07, 0x40, 0x1b, 0x0e, 0x4b, 0x14, 0x07, 0x40, 0x44, ++ 0x07, 0x01, 0x01, 0x06, 0x11, 0x06, 0x11, 0x13, 0x17, 0x0e, 0x4b, 0x17, 0x0e, 0x4b, 0x40, 0x40, ++ 0x40, 0x21, 0x21, 0x13, 0x40, 0x0f, 0x13, 0x16, 0x16, 0x24, 0x27, 0x14, 0x07, 0x11, 0x14, 0x0c, ++ 0x03, 0x31, 0x1b, 0x13, 0x40, 0x13, 0x0c, 0x16, 0x06, 0x13, 0x0a, 0x09, 0x06, 0x13, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x42, 0x06, 0x43, 0x56, 0x40, 0x18, 0x42, 0x47, 0x27, 0x40, 0x43, 0x40, 0x40, 0x40, 0x0f, ++ 0x43, 0x4f, 0x51, 0x09, 0x54, 0x4f, 0x4a, 0x40, 0x40, 0x07, 0x07, 0x0a, 0x46, 0x04, 0x4c, 0x07, ++ 0x59, 0x27, 0x06, 0x12, 0x40, 0x4b, 0x10, 0x40, 0x40, 0x40, 0x43, 0x43, 0x4e, 0x51, 0x4c, 0x51, ++ 0x54, 0x4f, 0x4e, 0x59, 0x51, 0x47, 0x51, 0x59, 0x59, 0x54, 0x4c, 0x41, 0x01, 0x41, 0x4e, 0x51, ++ 0x4c, 0x51, 0x54, 0x4f, 0x4e, 0x59, 0x51, 0x47, 0x51, 0x59, 0x59, 0x54, 0x4c, 0x41, 0x01, 0x41, ++ 0x11, 0x4b, 0x05, 0x40, 0x48, 0x40, 0x43, 0x07, 0x43, 0x01, 0x01, 0x4a, 0x07, 0x1a, 0x0d, 0x4b, ++ 0x14, 0x07, 0x40, 0x1a, 0x0d, 0x4b, 0x14, 0x07, 0x40, 0x1a, 0x0d, 0x4b, 0x14, 0x07, 0x40, 0x45, ++ 0x07, 0x01, 0x01, 0x06, 0x11, 0x06, 0x11, 0x12, 0x17, 0x0d, 0x4b, 0x17, 0x0d, 0x4b, 0x40, 0x40, ++ 0x40, 0x20, 0x20, 0x12, 0x40, 0x0f, 0x12, 0x15, 0x15, 0x24, 0x27, 0x14, 0x07, 0x11, 0x14, 0x0c, ++ 0x02, 0x30, 0x1a, 0x12, 0x40, 0x12, 0x0c, 0x15, 0x06, 0x12, 0x0b, 0x09, 0x06, 0x12, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x42, 0x07, 0x42, 0x55, 0x40, 0x18, 0x42, 0x47, 0x27, 0x40, 0x42, 0x40, 0x40, 0x40, 0x0f, ++ 0x42, 0x4d, 0x50, 0x0a, 0x52, 0x4d, 0x48, 0x02, 0x02, 0x07, 0x07, 0x0a, 0x45, 0x05, 0x4a, 0x07, ++ 0x58, 0x27, 0x07, 0x12, 0x40, 0x4a, 0x10, 0x40, 0x40, 0x40, 0x42, 0x42, 0x4d, 0x50, 0x4a, 0x50, ++ 0x52, 0x4d, 0x4d, 0x58, 0x50, 0x45, 0x50, 0x58, 0x58, 0x52, 0x4a, 0x40, 0x02, 0x40, 0x4d, 0x50, ++ 0x4a, 0x50, 0x52, 0x4d, 0x4d, 0x58, 0x50, 0x45, 0x50, 0x58, 0x58, 0x52, 0x4a, 0x40, 0x02, 0x40, ++ 0x12, 0x4a, 0x07, 0x40, 0x48, 0x40, 0x42, 0x07, 0x42, 0x02, 0x02, 0x48, 0x07, 0x1a, 0x0d, 0x4a, ++ 0x15, 0x07, 0x40, 0x1a, 0x0d, 0x4a, 0x15, 0x07, 0x40, 0x1a, 0x0d, 0x4a, 0x15, 0x07, 0x40, 0x45, ++ 0x07, 0x02, 0x02, 0x07, 0x12, 0x07, 0x12, 0x12, 0x17, 0x0d, 0x4a, 0x17, 0x0d, 0x4a, 0x40, 0x40, ++ 0x40, 0x20, 0x20, 0x12, 0x40, 0x0f, 0x12, 0x15, 0x15, 0x25, 0x27, 0x15, 0x07, 0x12, 0x15, 0x0d, ++ 0x02, 0x30, 0x1a, 0x12, 0x40, 0x12, 0x0d, 0x15, 0x07, 0x12, 0x0d, 0x0a, 0x07, 0x12, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x43, 0x08, 0x42, 0x54, 0x40, 0x17, 0x43, 0x48, 0x27, 0x40, 0x42, 0x40, 0x40, 0x40, 0x0f, ++ 0x42, 0x4b, 0x4f, 0x0b, 0x51, 0x4b, 0x46, 0x04, 0x04, 0x07, 0x07, 0x0a, 0x44, 0x05, 0x49, 0x07, ++ 0x57, 0x27, 0x08, 0x12, 0x40, 0x4a, 0x0f, 0x40, 0x40, 0x40, 0x42, 0x42, 0x4c, 0x4f, 0x49, 0x4f, ++ 0x51, 0x4b, 0x4c, 0x57, 0x4f, 0x43, 0x4f, 0x57, 0x57, 0x51, 0x49, 0x00, 0x03, 0x00, 0x4c, 0x4f, ++ 0x49, 0x4f, 0x51, 0x4b, 0x4c, 0x57, 0x4f, 0x43, 0x4f, 0x57, 0x57, 0x51, 0x49, 0x00, 0x03, 0x00, ++ 0x13, 0x4a, 0x09, 0x40, 0x48, 0x40, 0x42, 0x07, 0x42, 0x03, 0x03, 0x46, 0x07, 0x1a, 0x0c, 0x4a, ++ 0x15, 0x07, 0x40, 0x1a, 0x0c, 0x4a, 0x15, 0x07, 0x40, 0x1a, 0x0c, 0x4a, 0x15, 0x07, 0x40, 0x45, ++ 0x07, 0x03, 0x03, 0x08, 0x13, 0x08, 0x13, 0x12, 0x17, 0x0c, 0x4a, 0x17, 0x0c, 0x4a, 0x40, 0x40, ++ 0x40, 0x1f, 0x1f, 0x12, 0x40, 0x0f, 0x12, 0x14, 0x14, 0x25, 0x27, 0x15, 0x07, 0x13, 0x15, 0x0d, ++ 0x02, 0x2f, 0x1a, 0x12, 0x40, 0x12, 0x0d, 0x14, 0x08, 0x12, 0x0e, 0x0b, 0x08, 0x12, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x43, 0x09, 0x42, 0x54, 0x40, 0x16, 0x43, 0x49, 0x27, 0x40, 0x42, 0x40, 0x40, 0x40, 0x0f, ++ 0x42, 0x4a, 0x4e, 0x0b, 0x50, 0x4a, 0x44, 0x07, 0x07, 0x07, 0x07, 0x0a, 0x44, 0x05, 0x48, 0x07, ++ 0x56, 0x27, 0x09, 0x12, 0x40, 0x4a, 0x0e, 0x40, 0x40, 0x40, 0x42, 0x42, 0x4c, 0x4e, 0x48, 0x4e, ++ 0x50, 0x4a, 0x4c, 0x56, 0x4e, 0x42, 0x4e, 0x56, 0x56, 0x50, 0x48, 0x01, 0x03, 0x01, 0x4c, 0x4e, ++ 0x48, 0x4e, 0x50, 0x4a, 0x4c, 0x56, 0x4e, 0x42, 0x4e, 0x56, 0x56, 0x50, 0x48, 0x01, 0x03, 0x01, ++ 0x13, 0x4a, 0x0b, 0x40, 0x48, 0x40, 0x42, 0x07, 0x42, 0x03, 0x03, 0x44, 0x07, 0x1a, 0x0c, 0x4a, ++ 0x15, 0x07, 0x40, 0x1a, 0x0c, 0x4a, 0x15, 0x07, 0x40, 0x1a, 0x0c, 0x4a, 0x15, 0x07, 0x40, 0x45, ++ 0x07, 0x03, 0x03, 0x09, 0x13, 0x09, 0x13, 0x12, 0x17, 0x0c, 0x4a, 0x17, 0x0c, 0x4a, 0x40, 0x40, ++ 0x40, 0x1e, 0x1e, 0x12, 0x40, 0x0f, 0x12, 0x14, 0x14, 0x25, 0x27, 0x15, 0x07, 0x13, 0x15, 0x0d, ++ 0x02, 0x2e, 0x1a, 0x12, 0x40, 0x12, 0x0d, 0x14, 0x09, 0x12, 0x0f, 0x0b, 0x09, 0x12, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x44, 0x0a, 0x41, 0x53, 0x40, 0x15, 0x44, 0x4a, 0x27, 0x40, 0x41, 0x40, 0x40, 0x40, 0x0f, ++ 0x41, 0x48, 0x4d, 0x0c, 0x4f, 0x48, 0x42, 0x09, 0x09, 0x07, 0x07, 0x09, 0x43, 0x06, 0x47, 0x07, ++ 0x55, 0x27, 0x0a, 0x11, 0x40, 0x49, 0x0d, 0x40, 0x40, 0x40, 0x41, 0x41, 0x4b, 0x4d, 0x47, 0x4d, ++ 0x4f, 0x48, 0x4b, 0x55, 0x4d, 0x40, 0x4d, 0x55, 0x55, 0x4f, 0x47, 0x02, 0x04, 0x02, 0x4b, 0x4d, ++ 0x47, 0x4d, 0x4f, 0x48, 0x4b, 0x55, 0x4d, 0x40, 0x4d, 0x55, 0x55, 0x4f, 0x47, 0x02, 0x04, 0x02, ++ 0x14, 0x49, 0x0d, 0x40, 0x48, 0x40, 0x41, 0x07, 0x41, 0x04, 0x04, 0x42, 0x07, 0x19, 0x0b, 0x49, ++ 0x16, 0x07, 0x40, 0x19, 0x0b, 0x49, 0x16, 0x07, 0x40, 0x19, 0x0b, 0x49, 0x16, 0x07, 0x40, 0x46, ++ 0x07, 0x04, 0x04, 0x0a, 0x14, 0x0a, 0x14, 0x11, 0x17, 0x0b, 0x49, 0x17, 0x0b, 0x49, 0x40, 0x40, ++ 0x40, 0x1d, 0x1d, 0x11, 0x40, 0x0f, 0x11, 0x13, 0x13, 0x26, 0x27, 0x16, 0x07, 0x14, 0x16, 0x0e, ++ 0x01, 0x2d, 0x19, 0x11, 0x40, 0x11, 0x0e, 0x13, 0x0a, 0x11, 0x10, 0x0c, 0x0a, 0x11, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x45, 0x0b, 0x41, 0x52, 0x40, 0x14, 0x45, 0x4b, 0x27, 0x40, 0x41, 0x40, 0x40, 0x40, 0x0f, ++ 0x41, 0x47, 0x4c, 0x0d, 0x4d, 0x47, 0x40, 0x0c, 0x0c, 0x07, 0x07, 0x09, 0x42, 0x06, 0x45, 0x07, ++ 0x54, 0x27, 0x0b, 0x11, 0x40, 0x49, 0x0c, 0x40, 0x40, 0x40, 0x41, 0x41, 0x4a, 0x4c, 0x45, 0x4c, ++ 0x4d, 0x47, 0x4a, 0x54, 0x4c, 0x00, 0x4c, 0x54, 0x54, 0x4d, 0x45, 0x03, 0x05, 0x03, 0x4a, 0x4c, ++ 0x45, 0x4c, 0x4d, 0x47, 0x4a, 0x54, 0x4c, 0x00, 0x4c, 0x54, 0x54, 0x4d, 0x45, 0x03, 0x05, 0x03, ++ 0x15, 0x49, 0x0f, 0x40, 0x48, 0x40, 0x41, 0x07, 0x41, 0x05, 0x05, 0x40, 0x07, 0x19, 0x0a, 0x49, ++ 0x16, 0x07, 0x40, 0x19, 0x0a, 0x49, 0x16, 0x07, 0x40, 0x19, 0x0a, 0x49, 0x16, 0x07, 0x40, 0x46, ++ 0x07, 0x05, 0x05, 0x0b, 0x15, 0x0b, 0x15, 0x11, 0x17, 0x0a, 0x49, 0x17, 0x0a, 0x49, 0x40, 0x40, ++ 0x40, 0x1c, 0x1c, 0x11, 0x40, 0x0f, 0x11, 0x12, 0x12, 0x26, 0x27, 0x16, 0x07, 0x15, 0x16, 0x0e, ++ 0x01, 0x2c, 0x19, 0x11, 0x40, 0x11, 0x0e, 0x12, 0x0b, 0x11, 0x12, 0x0d, 0x0b, 0x11, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x45, 0x0c, 0x41, 0x52, 0x40, 0x13, 0x45, 0x4c, 0x27, 0x40, 0x41, 0x40, 0x40, 0x40, 0x0f, ++ 0x41, 0x45, 0x4b, 0x0d, 0x4c, 0x45, 0x01, 0x0e, 0x0e, 0x07, 0x07, 0x09, 0x42, 0x06, 0x44, 0x07, ++ 0x53, 0x27, 0x0c, 0x11, 0x40, 0x49, 0x0b, 0x40, 0x40, 0x40, 0x41, 0x41, 0x4a, 0x4b, 0x44, 0x4b, ++ 0x4c, 0x45, 0x4a, 0x53, 0x4b, 0x02, 0x4b, 0x53, 0x53, 0x4c, 0x44, 0x04, 0x05, 0x04, 0x4a, 0x4b, ++ 0x44, 0x4b, 0x4c, 0x45, 0x4a, 0x53, 0x4b, 0x02, 0x4b, 0x53, 0x53, 0x4c, 0x44, 0x04, 0x05, 0x04, ++ 0x15, 0x49, 0x11, 0x40, 0x48, 0x40, 0x41, 0x07, 0x41, 0x05, 0x05, 0x01, 0x07, 0x19, 0x0a, 0x49, ++ 0x16, 0x07, 0x40, 0x19, 0x0a, 0x49, 0x16, 0x07, 0x40, 0x19, 0x0a, 0x49, 0x16, 0x07, 0x40, 0x46, ++ 0x07, 0x05, 0x05, 0x0c, 0x15, 0x0c, 0x15, 0x11, 0x17, 0x0a, 0x49, 0x17, 0x0a, 0x49, 0x40, 0x40, ++ 0x40, 0x1b, 0x1b, 0x11, 0x40, 0x0f, 0x11, 0x12, 0x12, 0x26, 0x27, 0x16, 0x07, 0x15, 0x16, 0x0e, ++ 0x01, 0x2b, 0x19, 0x11, 0x40, 0x11, 0x0e, 0x12, 0x0c, 0x11, 0x13, 0x0d, 0x0c, 0x11, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x46, 0x0d, 0x40, 0x51, 0x40, 0x12, 0x46, 0x4d, 0x27, 0x40, 0x40, 0x40, 0x40, 0x40, 0x0f, ++ 0x40, 0x44, 0x4a, 0x0e, 0x4b, 0x44, 0x03, 0x11, 0x11, 0x07, 0x07, 0x08, 0x41, 0x07, 0x43, 0x07, ++ 0x52, 0x27, 0x0d, 0x10, 0x40, 0x48, 0x0a, 0x40, 0x40, 0x40, 0x40, 0x40, 0x49, 0x4a, 0x43, 0x4a, ++ 0x4b, 0x44, 0x49, 0x52, 0x4a, 0x03, 0x4a, 0x52, 0x52, 0x4b, 0x43, 0x05, 0x06, 0x05, 0x49, 0x4a, ++ 0x43, 0x4a, 0x4b, 0x44, 0x49, 0x52, 0x4a, 0x03, 0x4a, 0x52, 0x52, 0x4b, 0x43, 0x05, 0x06, 0x05, ++ 0x16, 0x48, 0x13, 0x40, 0x48, 0x40, 0x40, 0x07, 0x40, 0x06, 0x06, 0x03, 0x07, 0x18, 0x09, 0x48, ++ 0x17, 0x07, 0x40, 0x18, 0x09, 0x48, 0x17, 0x07, 0x40, 0x18, 0x09, 0x48, 0x17, 0x07, 0x40, 0x47, ++ 0x07, 0x06, 0x06, 0x0d, 0x16, 0x0d, 0x16, 0x10, 0x17, 0x09, 0x48, 0x17, 0x09, 0x48, 0x40, 0x40, ++ 0x40, 0x1a, 0x1a, 0x10, 0x40, 0x0f, 0x10, 0x11, 0x11, 0x27, 0x27, 0x17, 0x07, 0x16, 0x17, 0x0f, ++ 0x00, 0x2a, 0x18, 0x10, 0x40, 0x10, 0x0f, 0x11, 0x0d, 0x10, 0x14, 0x0e, 0x0d, 0x10, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x47, 0x0e, 0x40, 0x51, 0x40, 0x11, 0x47, 0x4e, 0x27, 0x40, 0x40, 0x40, 0x40, 0x40, 0x0f, ++ 0x40, 0x42, 0x49, 0x0e, 0x4a, 0x42, 0x04, 0x13, 0x13, 0x07, 0x07, 0x08, 0x41, 0x07, 0x42, 0x07, ++ 0x51, 0x27, 0x0e, 0x10, 0x40, 0x48, 0x09, 0x40, 0x40, 0x40, 0x40, 0x40, 0x49, 0x49, 0x42, 0x49, ++ 0x4a, 0x42, 0x49, 0x51, 0x49, 0x05, 0x49, 0x51, 0x51, 0x4a, 0x42, 0x06, 0x06, 0x06, 0x49, 0x49, ++ 0x42, 0x49, 0x4a, 0x42, 0x49, 0x51, 0x49, 0x05, 0x49, 0x51, 0x51, 0x4a, 0x42, 0x06, 0x06, 0x06, ++ 0x16, 0x48, 0x14, 0x40, 0x48, 0x40, 0x40, 0x07, 0x40, 0x06, 0x06, 0x04, 0x07, 0x18, 0x08, 0x48, ++ 0x17, 0x07, 0x40, 0x18, 0x08, 0x48, 0x17, 0x07, 0x40, 0x18, 0x08, 0x48, 0x17, 0x07, 0x40, 0x47, ++ 0x07, 0x06, 0x06, 0x0e, 0x16, 0x0e, 0x16, 0x10, 0x17, 0x08, 0x48, 0x17, 0x08, 0x48, 0x40, 0x40, ++ 0x40, 0x19, 0x19, 0x10, 0x40, 0x0f, 0x10, 0x10, 0x10, 0x27, 0x27, 0x17, 0x07, 0x16, 0x17, 0x0f, ++ 0x00, 0x29, 0x18, 0x10, 0x40, 0x10, 0x0f, 0x10, 0x0e, 0x10, 0x15, 0x0e, 0x0e, 0x10, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x47, 0x0f, 0x40, 0x50, 0x40, 0x10, 0x47, 0x4f, 0x27, 0x40, 0x40, 0x40, 0x40, 0x40, 0x0f, ++ 0x40, 0x40, 0x48, 0x0f, 0x48, 0x40, 0x06, 0x16, 0x16, 0x07, 0x07, 0x08, 0x40, 0x07, 0x40, 0x07, ++ 0x50, 0x27, 0x0f, 0x10, 0x40, 0x48, 0x08, 0x40, 0x40, 0x40, 0x40, 0x40, 0x48, 0x48, 0x40, 0x48, ++ 0x48, 0x40, 0x48, 0x50, 0x48, 0x07, 0x48, 0x50, 0x50, 0x48, 0x40, 0x07, 0x07, 0x07, 0x48, 0x48, ++ 0x40, 0x48, 0x48, 0x40, 0x48, 0x50, 0x48, 0x07, 0x48, 0x50, 0x50, 0x48, 0x40, 0x07, 0x07, 0x07, ++ 0x17, 0x48, 0x16, 0x40, 0x48, 0x40, 0x40, 0x07, 0x40, 0x07, 0x07, 0x06, 0x07, 0x18, 0x08, 0x48, ++ 0x17, 0x07, 0x40, 0x18, 0x08, 0x48, 0x17, 0x07, 0x40, 0x18, 0x08, 0x48, 0x17, 0x07, 0x40, 0x47, ++ 0x07, 0x07, 0x07, 0x0f, 0x17, 0x0f, 0x17, 0x10, 0x17, 0x08, 0x48, 0x17, 0x08, 0x48, 0x40, 0x40, ++ 0x40, 0x18, 0x18, 0x10, 0x40, 0x0f, 0x10, 0x10, 0x10, 0x27, 0x27, 0x17, 0x07, 0x17, 0x17, 0x0f, ++ 0x00, 0x28, 0x18, 0x10, 0x40, 0x10, 0x0f, 0x10, 0x0f, 0x10, 0x17, 0x0f, 0x0f, 0x10, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x48, 0x10, 0x00, 0x4f, 0x40, 0x0f, 0x48, 0x50, 0x27, 0x40, 0x00, 0x40, 0x40, 0x40, 0x0f, ++ 0x00, 0x00, 0x47, 0x10, 0x47, 0x00, 0x08, 0x18, 0x18, 0x07, 0x07, 0x07, 0x00, 0x08, 0x00, 0x07, ++ 0x4f, 0x27, 0x10, 0x0f, 0x40, 0x47, 0x07, 0x40, 0x40, 0x40, 0x00, 0x00, 0x47, 0x47, 0x00, 0x47, ++ 0x47, 0x00, 0x47, 0x4f, 0x47, 0x08, 0x47, 0x4f, 0x4f, 0x47, 0x00, 0x08, 0x08, 0x08, 0x47, 0x47, ++ 0x00, 0x47, 0x47, 0x00, 0x47, 0x4f, 0x47, 0x08, 0x47, 0x4f, 0x4f, 0x47, 0x00, 0x08, 0x08, 0x08, ++ 0x18, 0x47, 0x18, 0x40, 0x48, 0x40, 0x00, 0x07, 0x00, 0x08, 0x08, 0x08, 0x07, 0x17, 0x07, 0x47, ++ 0x18, 0x07, 0x40, 0x17, 0x07, 0x47, 0x18, 0x07, 0x40, 0x17, 0x07, 0x47, 0x18, 0x07, 0x40, 0x48, ++ 0x07, 0x08, 0x08, 0x10, 0x18, 0x10, 0x18, 0x0f, 0x17, 0x07, 0x47, 0x17, 0x07, 0x47, 0x40, 0x40, ++ 0x40, 0x17, 0x17, 0x0f, 0x40, 0x0f, 0x0f, 0x0f, 0x0f, 0x28, 0x27, 0x18, 0x07, 0x18, 0x18, 0x10, ++ 0x40, 0x27, 0x17, 0x0f, 0x40, 0x0f, 0x10, 0x0f, 0x10, 0x0f, 0x18, 0x10, 0x10, 0x0f, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x48, 0x11, 0x00, 0x4f, 0x40, 0x0e, 0x48, 0x51, 0x27, 0x40, 0x00, 0x40, 0x40, 0x40, 0x0f, ++ 0x00, 0x02, 0x46, 0x10, 0x46, 0x02, 0x0a, 0x1b, 0x1b, 0x07, 0x07, 0x07, 0x00, 0x08, 0x01, 0x07, ++ 0x4e, 0x27, 0x11, 0x0f, 0x40, 0x47, 0x06, 0x40, 0x40, 0x40, 0x00, 0x00, 0x47, 0x46, 0x01, 0x46, ++ 0x46, 0x02, 0x47, 0x4e, 0x46, 0x0a, 0x46, 0x4e, 0x4e, 0x46, 0x01, 0x09, 0x08, 0x09, 0x47, 0x46, ++ 0x01, 0x46, 0x46, 0x02, 0x47, 0x4e, 0x46, 0x0a, 0x46, 0x4e, 0x4e, 0x46, 0x01, 0x09, 0x08, 0x09, ++ 0x18, 0x47, 0x1a, 0x40, 0x48, 0x40, 0x00, 0x07, 0x00, 0x08, 0x08, 0x0a, 0x07, 0x17, 0x07, 0x47, ++ 0x18, 0x07, 0x40, 0x17, 0x07, 0x47, 0x18, 0x07, 0x40, 0x17, 0x07, 0x47, 0x18, 0x07, 0x40, 0x48, ++ 0x07, 0x08, 0x08, 0x11, 0x18, 0x11, 0x18, 0x0f, 0x17, 0x07, 0x47, 0x17, 0x07, 0x47, 0x40, 0x40, ++ 0x40, 0x16, 0x16, 0x0f, 0x40, 0x0f, 0x0f, 0x0f, 0x0f, 0x28, 0x27, 0x18, 0x07, 0x18, 0x18, 0x10, ++ 0x40, 0x26, 0x17, 0x0f, 0x40, 0x0f, 0x10, 0x0f, 0x11, 0x0f, 0x19, 0x10, 0x11, 0x0f, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x49, 0x12, 0x00, 0x4e, 0x40, 0x0d, 0x49, 0x52, 0x27, 0x40, 0x00, 0x40, 0x40, 0x40, 0x0f, ++ 0x00, 0x03, 0x45, 0x11, 0x45, 0x03, 0x0c, 0x1d, 0x1d, 0x07, 0x07, 0x07, 0x01, 0x08, 0x02, 0x07, ++ 0x4d, 0x27, 0x12, 0x0f, 0x40, 0x47, 0x05, 0x40, 0x40, 0x40, 0x00, 0x00, 0x46, 0x45, 0x02, 0x45, ++ 0x45, 0x03, 0x46, 0x4d, 0x45, 0x0b, 0x45, 0x4d, 0x4d, 0x45, 0x02, 0x0a, 0x09, 0x0a, 0x46, 0x45, ++ 0x02, 0x45, 0x45, 0x03, 0x46, 0x4d, 0x45, 0x0b, 0x45, 0x4d, 0x4d, 0x45, 0x02, 0x0a, 0x09, 0x0a, ++ 0x19, 0x47, 0x1c, 0x40, 0x48, 0x40, 0x00, 0x07, 0x00, 0x09, 0x09, 0x0c, 0x07, 0x17, 0x06, 0x47, ++ 0x18, 0x07, 0x40, 0x17, 0x06, 0x47, 0x18, 0x07, 0x40, 0x17, 0x06, 0x47, 0x18, 0x07, 0x40, 0x48, ++ 0x07, 0x09, 0x09, 0x12, 0x19, 0x12, 0x19, 0x0f, 0x17, 0x06, 0x47, 0x17, 0x06, 0x47, 0x40, 0x40, ++ 0x40, 0x15, 0x15, 0x0f, 0x40, 0x0f, 0x0f, 0x0e, 0x0e, 0x28, 0x27, 0x18, 0x07, 0x19, 0x18, 0x10, ++ 0x40, 0x25, 0x17, 0x0f, 0x40, 0x0f, 0x10, 0x0e, 0x12, 0x0f, 0x1a, 0x11, 0x12, 0x0f, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x4a, 0x13, 0x01, 0x4d, 0x40, 0x0c, 0x4a, 0x53, 0x27, 0x40, 0x01, 0x40, 0x40, 0x40, 0x0f, ++ 0x01, 0x05, 0x44, 0x12, 0x43, 0x05, 0x0e, 0x20, 0x20, 0x07, 0x07, 0x06, 0x02, 0x09, 0x04, 0x07, ++ 0x4c, 0x27, 0x13, 0x0e, 0x40, 0x46, 0x04, 0x40, 0x40, 0x40, 0x01, 0x01, 0x45, 0x44, 0x04, 0x44, ++ 0x43, 0x05, 0x45, 0x4c, 0x44, 0x0d, 0x44, 0x4c, 0x4c, 0x43, 0x04, 0x0b, 0x0a, 0x0b, 0x45, 0x44, ++ 0x04, 0x44, 0x43, 0x05, 0x45, 0x4c, 0x44, 0x0d, 0x44, 0x4c, 0x4c, 0x43, 0x04, 0x0b, 0x0a, 0x0b, ++ 0x1a, 0x46, 0x1e, 0x40, 0x48, 0x40, 0x01, 0x07, 0x01, 0x0a, 0x0a, 0x0e, 0x07, 0x16, 0x05, 0x46, ++ 0x19, 0x07, 0x40, 0x16, 0x05, 0x46, 0x19, 0x07, 0x40, 0x16, 0x05, 0x46, 0x19, 0x07, 0x40, 0x49, ++ 0x07, 0x0a, 0x0a, 0x13, 0x1a, 0x13, 0x1a, 0x0e, 0x17, 0x05, 0x46, 0x17, 0x05, 0x46, 0x40, 0x40, ++ 0x40, 0x14, 0x14, 0x0e, 0x40, 0x0f, 0x0e, 0x0d, 0x0d, 0x29, 0x27, 0x19, 0x07, 0x1a, 0x19, 0x11, ++ 0x41, 0x24, 0x16, 0x0e, 0x40, 0x0e, 0x11, 0x0d, 0x13, 0x0e, 0x1c, 0x12, 0x13, 0x0e, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x4a, 0x14, 0x01, 0x4d, 0x40, 0x0b, 0x4a, 0x54, 0x27, 0x40, 0x01, 0x40, 0x40, 0x40, 0x0f, ++ 0x01, 0x06, 0x43, 0x12, 0x42, 0x06, 0x10, 0x22, 0x22, 0x07, 0x07, 0x06, 0x02, 0x09, 0x05, 0x07, ++ 0x4b, 0x27, 0x14, 0x0e, 0x40, 0x46, 0x03, 0x40, 0x40, 0x40, 0x01, 0x01, 0x45, 0x43, 0x05, 0x43, ++ 0x42, 0x06, 0x45, 0x4b, 0x43, 0x0e, 0x43, 0x4b, 0x4b, 0x42, 0x05, 0x0c, 0x0a, 0x0c, 0x45, 0x43, ++ 0x05, 0x43, 0x42, 0x06, 0x45, 0x4b, 0x43, 0x0e, 0x43, 0x4b, 0x4b, 0x42, 0x05, 0x0c, 0x0a, 0x0c, ++ 0x1a, 0x46, 0x20, 0x40, 0x48, 0x40, 0x01, 0x07, 0x01, 0x0a, 0x0a, 0x10, 0x07, 0x16, 0x05, 0x46, ++ 0x19, 0x07, 0x40, 0x16, 0x05, 0x46, 0x19, 0x07, 0x40, 0x16, 0x05, 0x46, 0x19, 0x07, 0x40, 0x49, ++ 0x07, 0x0a, 0x0a, 0x14, 0x1a, 0x14, 0x1a, 0x0e, 0x17, 0x05, 0x46, 0x17, 0x05, 0x46, 0x40, 0x40, ++ 0x40, 0x13, 0x13, 0x0e, 0x40, 0x0f, 0x0e, 0x0d, 0x0d, 0x29, 0x27, 0x19, 0x07, 0x1a, 0x19, 0x11, ++ 0x41, 0x23, 0x16, 0x0e, 0x40, 0x0e, 0x11, 0x0d, 0x14, 0x0e, 0x1d, 0x12, 0x14, 0x0e, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x4b, 0x15, 0x01, 0x4c, 0x40, 0x0a, 0x4b, 0x55, 0x27, 0x40, 0x01, 0x40, 0x40, 0x40, 0x0f, ++ 0x01, 0x08, 0x42, 0x13, 0x41, 0x08, 0x12, 0x25, 0x25, 0x07, 0x07, 0x06, 0x03, 0x09, 0x06, 0x07, ++ 0x4a, 0x27, 0x15, 0x0e, 0x40, 0x46, 0x02, 0x40, 0x40, 0x40, 0x01, 0x01, 0x44, 0x42, 0x06, 0x42, ++ 0x41, 0x08, 0x44, 0x4a, 0x42, 0x10, 0x42, 0x4a, 0x4a, 0x41, 0x06, 0x0d, 0x0b, 0x0d, 0x44, 0x42, ++ 0x06, 0x42, 0x41, 0x08, 0x44, 0x4a, 0x42, 0x10, 0x42, 0x4a, 0x4a, 0x41, 0x06, 0x0d, 0x0b, 0x0d, ++ 0x1b, 0x46, 0x22, 0x40, 0x48, 0x40, 0x01, 0x07, 0x01, 0x0b, 0x0b, 0x12, 0x07, 0x16, 0x04, 0x46, ++ 0x19, 0x07, 0x40, 0x16, 0x04, 0x46, 0x19, 0x07, 0x40, 0x16, 0x04, 0x46, 0x19, 0x07, 0x40, 0x49, ++ 0x07, 0x0b, 0x0b, 0x15, 0x1b, 0x15, 0x1b, 0x0e, 0x17, 0x04, 0x46, 0x17, 0x04, 0x46, 0x40, 0x40, ++ 0x40, 0x12, 0x12, 0x0e, 0x40, 0x0f, 0x0e, 0x0c, 0x0c, 0x29, 0x27, 0x19, 0x07, 0x1b, 0x19, 0x11, ++ 0x41, 0x22, 0x16, 0x0e, 0x40, 0x0e, 0x11, 0x0c, 0x15, 0x0e, 0x1e, 0x13, 0x15, 0x0e, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x4c, 0x15, 0x01, 0x4c, 0x40, 0x09, 0x4c, 0x56, 0x27, 0x40, 0x01, 0x40, 0x40, 0x40, 0x0f, ++ 0x01, 0x09, 0x42, 0x13, 0x40, 0x09, 0x13, 0x27, 0x27, 0x07, 0x07, 0x05, 0x03, 0x09, 0x07, 0x07, ++ 0x4a, 0x27, 0x15, 0x0d, 0x40, 0x46, 0x01, 0x40, 0x40, 0x40, 0x01, 0x01, 0x44, 0x42, 0x07, 0x42, ++ 0x40, 0x09, 0x44, 0x4a, 0x42, 0x11, 0x42, 0x4a, 0x4a, 0x40, 0x07, 0x0d, 0x0b, 0x0d, 0x44, 0x42, ++ 0x07, 0x42, 0x40, 0x09, 0x44, 0x4a, 0x42, 0x11, 0x42, 0x4a, 0x4a, 0x40, 0x07, 0x0d, 0x0b, 0x0d, ++ 0x1b, 0x46, 0x23, 0x40, 0x48, 0x40, 0x01, 0x07, 0x01, 0x0b, 0x0b, 0x13, 0x07, 0x15, 0x03, 0x46, ++ 0x19, 0x07, 0x40, 0x15, 0x03, 0x46, 0x19, 0x07, 0x40, 0x15, 0x03, 0x46, 0x19, 0x07, 0x40, 0x4a, ++ 0x07, 0x0b, 0x0b, 0x15, 0x1b, 0x15, 0x1b, 0x0d, 0x17, 0x03, 0x46, 0x17, 0x03, 0x46, 0x40, 0x40, ++ 0x40, 0x11, 0x11, 0x0d, 0x40, 0x0f, 0x0d, 0x0b, 0x0b, 0x29, 0x27, 0x19, 0x07, 0x1b, 0x19, 0x11, ++ 0x42, 0x21, 0x15, 0x0d, 0x40, 0x0d, 0x11, 0x0b, 0x15, 0x0d, 0x1f, 0x13, 0x15, 0x0d, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x4c, 0x16, 0x02, 0x4b, 0x40, 0x09, 0x4c, 0x56, 0x27, 0x40, 0x02, 0x40, 0x40, 0x40, 0x0f, ++ 0x02, 0x0b, 0x41, 0x14, 0x01, 0x0b, 0x15, 0x2a, 0x2a, 0x07, 0x07, 0x05, 0x04, 0x0a, 0x09, 0x07, ++ 0x49, 0x27, 0x16, 0x0d, 0x40, 0x45, 0x01, 0x40, 0x40, 0x40, 0x02, 0x02, 0x43, 0x41, 0x09, 0x41, ++ 0x01, 0x0b, 0x43, 0x49, 0x41, 0x13, 0x41, 0x49, 0x49, 0x01, 0x09, 0x0e, 0x0c, 0x0e, 0x43, 0x41, ++ 0x09, 0x41, 0x01, 0x0b, 0x43, 0x49, 0x41, 0x13, 0x41, 0x49, 0x49, 0x01, 0x09, 0x0e, 0x0c, 0x0e, ++ 0x1c, 0x45, 0x25, 0x40, 0x48, 0x40, 0x02, 0x07, 0x02, 0x0c, 0x0c, 0x15, 0x07, 0x15, 0x03, 0x45, ++ 0x1a, 0x07, 0x40, 0x15, 0x03, 0x45, 0x1a, 0x07, 0x40, 0x15, 0x03, 0x45, 0x1a, 0x07, 0x40, 0x4a, ++ 0x07, 0x0c, 0x0c, 0x16, 0x1c, 0x16, 0x1c, 0x0d, 0x17, 0x03, 0x45, 0x17, 0x03, 0x45, 0x40, 0x40, ++ 0x40, 0x11, 0x11, 0x0d, 0x40, 0x0f, 0x0d, 0x0b, 0x0b, 0x2a, 0x27, 0x1a, 0x07, 0x1c, 0x1a, 0x12, ++ 0x42, 0x21, 0x15, 0x0d, 0x40, 0x0d, 0x12, 0x0b, 0x16, 0x0d, 0x21, 0x14, 0x16, 0x0d, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x4d, 0x17, 0x02, 0x4a, 0x40, 0x08, 0x4d, 0x57, 0x27, 0x40, 0x02, 0x40, 0x40, 0x40, 0x0f, ++ 0x02, 0x0d, 0x40, 0x15, 0x02, 0x0d, 0x17, 0x2c, 0x2c, 0x07, 0x07, 0x05, 0x05, 0x0a, 0x0a, 0x07, ++ 0x48, 0x27, 0x17, 0x0d, 0x40, 0x45, 0x00, 0x40, 0x40, 0x40, 0x02, 0x02, 0x42, 0x40, 0x0a, 0x40, ++ 0x02, 0x0d, 0x42, 0x48, 0x40, 0x15, 0x40, 0x48, 0x48, 0x02, 0x0a, 0x0f, 0x0d, 0x0f, 0x42, 0x40, ++ 0x0a, 0x40, 0x02, 0x0d, 0x42, 0x48, 0x40, 0x15, 0x40, 0x48, 0x48, 0x02, 0x0a, 0x0f, 0x0d, 0x0f, ++ 0x1d, 0x45, 0x27, 0x40, 0x48, 0x40, 0x02, 0x07, 0x02, 0x0d, 0x0d, 0x17, 0x07, 0x15, 0x02, 0x45, ++ 0x1a, 0x07, 0x40, 0x15, 0x02, 0x45, 0x1a, 0x07, 0x40, 0x15, 0x02, 0x45, 0x1a, 0x07, 0x40, 0x4a, ++ 0x07, 0x0d, 0x0d, 0x17, 0x1d, 0x17, 0x1d, 0x0d, 0x17, 0x02, 0x45, 0x17, 0x02, 0x45, 0x40, 0x40, ++ 0x40, 0x10, 0x10, 0x0d, 0x40, 0x0f, 0x0d, 0x0a, 0x0a, 0x2a, 0x27, 0x1a, 0x07, 0x1d, 0x1a, 0x12, ++ 0x42, 0x20, 0x15, 0x0d, 0x40, 0x0d, 0x12, 0x0a, 0x17, 0x0d, 0x22, 0x15, 0x17, 0x0d, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x4d, 0x18, 0x02, 0x4a, 0x40, 0x07, 0x4d, 0x58, 0x27, 0x40, 0x02, 0x40, 0x40, 0x40, 0x0f, ++ 0x02, 0x0e, 0x00, 0x15, 0x03, 0x0e, 0x19, 0x2f, 0x2f, 0x07, 0x07, 0x05, 0x05, 0x0a, 0x0b, 0x07, ++ 0x47, 0x27, 0x18, 0x0d, 0x40, 0x45, 0x40, 0x40, 0x40, 0x40, 0x02, 0x02, 0x42, 0x00, 0x0b, 0x00, ++ 0x03, 0x0e, 0x42, 0x47, 0x00, 0x16, 0x00, 0x47, 0x47, 0x03, 0x0b, 0x10, 0x0d, 0x10, 0x42, 0x00, ++ 0x0b, 0x00, 0x03, 0x0e, 0x42, 0x47, 0x00, 0x16, 0x00, 0x47, 0x47, 0x03, 0x0b, 0x10, 0x0d, 0x10, ++ 0x1d, 0x45, 0x29, 0x40, 0x48, 0x40, 0x02, 0x07, 0x02, 0x0d, 0x0d, 0x19, 0x07, 0x15, 0x02, 0x45, ++ 0x1a, 0x07, 0x40, 0x15, 0x02, 0x45, 0x1a, 0x07, 0x40, 0x15, 0x02, 0x45, 0x1a, 0x07, 0x40, 0x4a, ++ 0x07, 0x0d, 0x0d, 0x18, 0x1d, 0x18, 0x1d, 0x0d, 0x17, 0x02, 0x45, 0x17, 0x02, 0x45, 0x40, 0x40, ++ 0x40, 0x0f, 0x0f, 0x0d, 0x40, 0x0f, 0x0d, 0x0a, 0x0a, 0x2a, 0x27, 0x1a, 0x07, 0x1d, 0x1a, 0x12, ++ 0x42, 0x1f, 0x15, 0x0d, 0x40, 0x0d, 0x12, 0x0a, 0x18, 0x0d, 0x23, 0x15, 0x18, 0x0d, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x4e, 0x19, 0x03, 0x49, 0x40, 0x06, 0x4e, 0x59, 0x27, 0x40, 0x03, 0x40, 0x40, 0x40, 0x0f, ++ 0x03, 0x10, 0x01, 0x16, 0x04, 0x10, 0x1b, 0x31, 0x31, 0x07, 0x07, 0x04, 0x06, 0x0b, 0x0c, 0x07, ++ 0x46, 0x27, 0x19, 0x0c, 0x40, 0x44, 0x41, 0x40, 0x40, 0x40, 0x03, 0x03, 0x41, 0x01, 0x0c, 0x01, ++ 0x04, 0x10, 0x41, 0x46, 0x01, 0x18, 0x01, 0x46, 0x46, 0x04, 0x0c, 0x11, 0x0e, 0x11, 0x41, 0x01, ++ 0x0c, 0x01, 0x04, 0x10, 0x41, 0x46, 0x01, 0x18, 0x01, 0x46, 0x46, 0x04, 0x0c, 0x11, 0x0e, 0x11, ++ 0x1e, 0x44, 0x2b, 0x40, 0x48, 0x40, 0x03, 0x07, 0x03, 0x0e, 0x0e, 0x1b, 0x07, 0x14, 0x01, 0x44, ++ 0x1b, 0x07, 0x40, 0x14, 0x01, 0x44, 0x1b, 0x07, 0x40, 0x14, 0x01, 0x44, 0x1b, 0x07, 0x40, 0x4b, ++ 0x07, 0x0e, 0x0e, 0x19, 0x1e, 0x19, 0x1e, 0x0c, 0x17, 0x01, 0x44, 0x17, 0x01, 0x44, 0x40, 0x40, ++ 0x40, 0x0e, 0x0e, 0x0c, 0x40, 0x0f, 0x0c, 0x09, 0x09, 0x2b, 0x27, 0x1b, 0x07, 0x1e, 0x1b, 0x13, ++ 0x43, 0x1e, 0x14, 0x0c, 0x40, 0x0c, 0x13, 0x09, 0x19, 0x0c, 0x24, 0x16, 0x19, 0x0c, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x4f, 0x1a, 0x03, 0x48, 0x40, 0x05, 0x4f, 0x5a, 0x27, 0x40, 0x03, 0x40, 0x40, 0x40, 0x0f, ++ 0x03, 0x11, 0x02, 0x17, 0x06, 0x11, 0x1d, 0x34, 0x34, 0x07, 0x07, 0x04, 0x07, 0x0b, 0x0e, 0x07, ++ 0x45, 0x27, 0x1a, 0x0c, 0x40, 0x44, 0x42, 0x40, 0x40, 0x40, 0x03, 0x03, 0x40, 0x02, 0x0e, 0x02, ++ 0x06, 0x11, 0x40, 0x45, 0x02, 0x19, 0x02, 0x45, 0x45, 0x06, 0x0e, 0x12, 0x0f, 0x12, 0x40, 0x02, ++ 0x0e, 0x02, 0x06, 0x11, 0x40, 0x45, 0x02, 0x19, 0x02, 0x45, 0x45, 0x06, 0x0e, 0x12, 0x0f, 0x12, ++ 0x1f, 0x44, 0x2d, 0x40, 0x48, 0x40, 0x03, 0x07, 0x03, 0x0f, 0x0f, 0x1d, 0x07, 0x14, 0x00, 0x44, ++ 0x1b, 0x07, 0x40, 0x14, 0x00, 0x44, 0x1b, 0x07, 0x40, 0x14, 0x00, 0x44, 0x1b, 0x07, 0x40, 0x4b, ++ 0x07, 0x0f, 0x0f, 0x1a, 0x1f, 0x1a, 0x1f, 0x0c, 0x17, 0x00, 0x44, 0x17, 0x00, 0x44, 0x40, 0x40, ++ 0x40, 0x0d, 0x0d, 0x0c, 0x40, 0x0f, 0x0c, 0x08, 0x08, 0x2b, 0x27, 0x1b, 0x07, 0x1f, 0x1b, 0x13, ++ 0x43, 0x1d, 0x14, 0x0c, 0x40, 0x0c, 0x13, 0x08, 0x1a, 0x0c, 0x26, 0x17, 0x1a, 0x0c, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x4f, 0x1b, 0x03, 0x48, 0x40, 0x04, 0x4f, 0x5b, 0x27, 0x40, 0x03, 0x40, 0x40, 0x40, 0x0f, ++ 0x03, 0x13, 0x03, 0x17, 0x07, 0x13, 0x1f, 0x36, 0x36, 0x07, 0x07, 0x04, 0x07, 0x0b, 0x0f, 0x07, ++ 0x44, 0x27, 0x1b, 0x0c, 0x40, 0x44, 0x43, 0x40, 0x40, 0x40, 0x03, 0x03, 0x40, 0x03, 0x0f, 0x03, ++ 0x07, 0x13, 0x40, 0x44, 0x03, 0x1b, 0x03, 0x44, 0x44, 0x07, 0x0f, 0x13, 0x0f, 0x13, 0x40, 0x03, ++ 0x0f, 0x03, 0x07, 0x13, 0x40, 0x44, 0x03, 0x1b, 0x03, 0x44, 0x44, 0x07, 0x0f, 0x13, 0x0f, 0x13, ++ 0x1f, 0x44, 0x2f, 0x40, 0x48, 0x40, 0x03, 0x07, 0x03, 0x0f, 0x0f, 0x1f, 0x07, 0x14, 0x00, 0x44, ++ 0x1b, 0x07, 0x40, 0x14, 0x00, 0x44, 0x1b, 0x07, 0x40, 0x14, 0x00, 0x44, 0x1b, 0x07, 0x40, 0x4b, ++ 0x07, 0x0f, 0x0f, 0x1b, 0x1f, 0x1b, 0x1f, 0x0c, 0x17, 0x00, 0x44, 0x17, 0x00, 0x44, 0x40, 0x40, ++ 0x40, 0x0c, 0x0c, 0x0c, 0x40, 0x0f, 0x0c, 0x08, 0x08, 0x2b, 0x27, 0x1b, 0x07, 0x1f, 0x1b, 0x13, ++ 0x43, 0x1c, 0x14, 0x0c, 0x40, 0x0c, 0x13, 0x08, 0x1b, 0x0c, 0x27, 0x17, 0x1b, 0x0c, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x50, 0x1c, 0x04, 0x47, 0x40, 0x03, 0x50, 0x5c, 0x27, 0x40, 0x04, 0x40, 0x40, 0x40, 0x0f, ++ 0x04, 0x14, 0x04, 0x18, 0x08, 0x14, 0x21, 0x39, 0x39, 0x07, 0x07, 0x03, 0x08, 0x0c, 0x10, 0x07, ++ 0x43, 0x27, 0x1c, 0x0b, 0x40, 0x43, 0x44, 0x40, 0x40, 0x40, 0x04, 0x04, 0x00, 0x04, 0x10, 0x04, ++ 0x08, 0x14, 0x00, 0x43, 0x04, 0x1c, 0x04, 0x43, 0x43, 0x08, 0x10, 0x14, 0x10, 0x14, 0x00, 0x04, ++ 0x10, 0x04, 0x08, 0x14, 0x00, 0x43, 0x04, 0x1c, 0x04, 0x43, 0x43, 0x08, 0x10, 0x14, 0x10, 0x14, ++ 0x20, 0x43, 0x31, 0x40, 0x48, 0x40, 0x04, 0x07, 0x04, 0x10, 0x10, 0x21, 0x07, 0x13, 0x40, 0x43, ++ 0x1c, 0x07, 0x40, 0x13, 0x40, 0x43, 0x1c, 0x07, 0x40, 0x13, 0x40, 0x43, 0x1c, 0x07, 0x40, 0x4c, ++ 0x07, 0x10, 0x10, 0x1c, 0x20, 0x1c, 0x20, 0x0b, 0x17, 0x40, 0x43, 0x17, 0x40, 0x43, 0x40, 0x40, ++ 0x40, 0x0b, 0x0b, 0x0b, 0x40, 0x0f, 0x0b, 0x07, 0x07, 0x2c, 0x27, 0x1c, 0x07, 0x20, 0x1c, 0x14, ++ 0x44, 0x1b, 0x13, 0x0b, 0x40, 0x0b, 0x14, 0x07, 0x1c, 0x0b, 0x28, 0x18, 0x1c, 0x0b, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x51, 0x1d, 0x04, 0x47, 0x40, 0x02, 0x51, 0x5d, 0x27, 0x40, 0x04, 0x40, 0x40, 0x40, 0x0f, ++ 0x04, 0x16, 0x05, 0x18, 0x09, 0x16, 0x22, 0x3b, 0x3b, 0x07, 0x07, 0x03, 0x08, 0x0c, 0x11, 0x07, ++ 0x42, 0x27, 0x1d, 0x0b, 0x40, 0x43, 0x45, 0x40, 0x40, 0x40, 0x04, 0x04, 0x00, 0x05, 0x11, 0x05, ++ 0x09, 0x16, 0x00, 0x42, 0x05, 0x1e, 0x05, 0x42, 0x42, 0x09, 0x11, 0x15, 0x10, 0x15, 0x00, 0x05, ++ 0x11, 0x05, 0x09, 0x16, 0x00, 0x42, 0x05, 0x1e, 0x05, 0x42, 0x42, 0x09, 0x11, 0x15, 0x10, 0x15, ++ 0x20, 0x43, 0x32, 0x40, 0x48, 0x40, 0x04, 0x07, 0x04, 0x10, 0x10, 0x22, 0x07, 0x13, 0x41, 0x43, ++ 0x1c, 0x07, 0x40, 0x13, 0x41, 0x43, 0x1c, 0x07, 0x40, 0x13, 0x41, 0x43, 0x1c, 0x07, 0x40, 0x4c, ++ 0x07, 0x10, 0x10, 0x1d, 0x20, 0x1d, 0x20, 0x0b, 0x17, 0x41, 0x43, 0x17, 0x41, 0x43, 0x40, 0x40, ++ 0x40, 0x0a, 0x0a, 0x0b, 0x40, 0x0f, 0x0b, 0x06, 0x06, 0x2c, 0x27, 0x1c, 0x07, 0x20, 0x1c, 0x14, ++ 0x44, 0x1a, 0x13, 0x0b, 0x40, 0x0b, 0x14, 0x06, 0x1d, 0x0b, 0x29, 0x18, 0x1d, 0x0b, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x51, 0x1e, 0x04, 0x46, 0x40, 0x01, 0x51, 0x5e, 0x27, 0x40, 0x04, 0x40, 0x40, 0x40, 0x0f, ++ 0x04, 0x18, 0x06, 0x19, 0x0b, 0x18, 0x24, 0x3e, 0x3e, 0x07, 0x07, 0x03, 0x09, 0x0c, 0x13, 0x07, ++ 0x41, 0x27, 0x1e, 0x0b, 0x40, 0x43, 0x46, 0x40, 0x40, 0x40, 0x04, 0x04, 0x01, 0x06, 0x13, 0x06, ++ 0x0b, 0x18, 0x01, 0x41, 0x06, 0x20, 0x06, 0x41, 0x41, 0x0b, 0x13, 0x16, 0x11, 0x16, 0x01, 0x06, ++ 0x13, 0x06, 0x0b, 0x18, 0x01, 0x41, 0x06, 0x20, 0x06, 0x41, 0x41, 0x0b, 0x13, 0x16, 0x11, 0x16, ++ 0x21, 0x43, 0x34, 0x40, 0x48, 0x40, 0x04, 0x07, 0x04, 0x11, 0x11, 0x24, 0x07, 0x13, 0x41, 0x43, ++ 0x1c, 0x07, 0x40, 0x13, 0x41, 0x43, 0x1c, 0x07, 0x40, 0x13, 0x41, 0x43, 0x1c, 0x07, 0x40, 0x4c, ++ 0x07, 0x11, 0x11, 0x1e, 0x21, 0x1e, 0x21, 0x0b, 0x17, 0x41, 0x43, 0x17, 0x41, 0x43, 0x40, 0x40, ++ 0x40, 0x09, 0x09, 0x0b, 0x40, 0x0f, 0x0b, 0x06, 0x06, 0x2c, 0x27, 0x1c, 0x07, 0x21, 0x1c, 0x14, ++ 0x44, 0x19, 0x13, 0x0b, 0x40, 0x0b, 0x14, 0x06, 0x1e, 0x0b, 0x2b, 0x19, 0x1e, 0x0b, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x52, 0x1f, 0x05, 0x45, 0x40, 0x00, 0x52, 0x5f, 0x27, 0x40, 0x05, 0x40, 0x40, 0x40, 0x0f, ++ 0x05, 0x19, 0x07, 0x1a, 0x0c, 0x19, 0x26, 0x3e, 0x3e, 0x07, 0x07, 0x02, 0x0a, 0x0d, 0x14, 0x07, ++ 0x40, 0x27, 0x1f, 0x0a, 0x40, 0x42, 0x47, 0x40, 0x40, 0x40, 0x05, 0x05, 0x02, 0x07, 0x14, 0x07, ++ 0x0c, 0x19, 0x02, 0x40, 0x07, 0x21, 0x07, 0x40, 0x40, 0x0c, 0x14, 0x17, 0x12, 0x17, 0x02, 0x07, ++ 0x14, 0x07, 0x0c, 0x19, 0x02, 0x40, 0x07, 0x21, 0x07, 0x40, 0x40, 0x0c, 0x14, 0x17, 0x12, 0x17, ++ 0x22, 0x42, 0x36, 0x40, 0x48, 0x40, 0x05, 0x07, 0x05, 0x12, 0x12, 0x26, 0x07, 0x12, 0x42, 0x42, ++ 0x1d, 0x07, 0x40, 0x12, 0x42, 0x42, 0x1d, 0x07, 0x40, 0x12, 0x42, 0x42, 0x1d, 0x07, 0x40, 0x4d, ++ 0x07, 0x12, 0x12, 0x1f, 0x22, 0x1f, 0x22, 0x0a, 0x17, 0x42, 0x42, 0x17, 0x42, 0x42, 0x40, 0x40, ++ 0x40, 0x08, 0x08, 0x0a, 0x40, 0x0f, 0x0a, 0x05, 0x05, 0x2d, 0x27, 0x1d, 0x07, 0x22, 0x1d, 0x15, ++ 0x45, 0x18, 0x12, 0x0a, 0x40, 0x0a, 0x15, 0x05, 0x1f, 0x0a, 0x2c, 0x1a, 0x1f, 0x0a, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x52, 0x20, 0x05, 0x45, 0x40, 0x40, 0x52, 0x60, 0x27, 0x40, 0x05, 0x40, 0x40, 0x40, 0x0f, ++ 0x05, 0x1b, 0x08, 0x1a, 0x0d, 0x1b, 0x28, 0x3e, 0x3e, 0x07, 0x07, 0x02, 0x0a, 0x0d, 0x15, 0x07, ++ 0x00, 0x27, 0x20, 0x0a, 0x40, 0x42, 0x48, 0x40, 0x40, 0x40, 0x05, 0x05, 0x02, 0x08, 0x15, 0x08, ++ 0x0d, 0x1b, 0x02, 0x00, 0x08, 0x23, 0x08, 0x00, 0x00, 0x0d, 0x15, 0x18, 0x12, 0x18, 0x02, 0x08, ++ 0x15, 0x08, 0x0d, 0x1b, 0x02, 0x00, 0x08, 0x23, 0x08, 0x00, 0x00, 0x0d, 0x15, 0x18, 0x12, 0x18, ++ 0x22, 0x42, 0x38, 0x40, 0x48, 0x40, 0x05, 0x07, 0x05, 0x12, 0x12, 0x28, 0x07, 0x12, 0x42, 0x42, ++ 0x1d, 0x07, 0x40, 0x12, 0x42, 0x42, 0x1d, 0x07, 0x40, 0x12, 0x42, 0x42, 0x1d, 0x07, 0x40, 0x4d, ++ 0x07, 0x12, 0x12, 0x20, 0x22, 0x20, 0x22, 0x0a, 0x17, 0x42, 0x42, 0x17, 0x42, 0x42, 0x40, 0x40, ++ 0x40, 0x07, 0x07, 0x0a, 0x40, 0x0f, 0x0a, 0x05, 0x05, 0x2d, 0x27, 0x1d, 0x07, 0x22, 0x1d, 0x15, ++ 0x45, 0x17, 0x12, 0x0a, 0x40, 0x0a, 0x15, 0x05, 0x20, 0x0a, 0x2d, 0x1a, 0x20, 0x0a, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x53, 0x21, 0x05, 0x44, 0x40, 0x41, 0x53, 0x61, 0x27, 0x40, 0x05, 0x40, 0x40, 0x40, 0x0f, ++ 0x05, 0x1c, 0x09, 0x1b, 0x0e, 0x1c, 0x2a, 0x3e, 0x3e, 0x07, 0x07, 0x02, 0x0b, 0x0d, 0x16, 0x07, ++ 0x01, 0x27, 0x21, 0x0a, 0x40, 0x42, 0x49, 0x40, 0x40, 0x40, 0x05, 0x05, 0x03, 0x09, 0x16, 0x09, ++ 0x0e, 0x1c, 0x03, 0x01, 0x09, 0x24, 0x09, 0x01, 0x01, 0x0e, 0x16, 0x19, 0x13, 0x19, 0x03, 0x09, ++ 0x16, 0x09, 0x0e, 0x1c, 0x03, 0x01, 0x09, 0x24, 0x09, 0x01, 0x01, 0x0e, 0x16, 0x19, 0x13, 0x19, ++ 0x23, 0x42, 0x3a, 0x40, 0x48, 0x40, 0x05, 0x07, 0x05, 0x13, 0x13, 0x2a, 0x07, 0x12, 0x43, 0x42, ++ 0x1d, 0x07, 0x40, 0x12, 0x43, 0x42, 0x1d, 0x07, 0x40, 0x12, 0x43, 0x42, 0x1d, 0x07, 0x40, 0x4d, ++ 0x07, 0x13, 0x13, 0x21, 0x23, 0x21, 0x23, 0x0a, 0x17, 0x43, 0x42, 0x17, 0x43, 0x42, 0x40, 0x40, ++ 0x40, 0x06, 0x06, 0x0a, 0x40, 0x0f, 0x0a, 0x04, 0x04, 0x2d, 0x27, 0x1d, 0x07, 0x23, 0x1d, 0x15, ++ 0x45, 0x16, 0x12, 0x0a, 0x40, 0x0a, 0x15, 0x04, 0x21, 0x0a, 0x2e, 0x1b, 0x21, 0x0a, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x54, 0x22, 0x06, 0x43, 0x40, 0x42, 0x54, 0x62, 0x27, 0x40, 0x06, 0x40, 0x40, 0x40, 0x0f, ++ 0x06, 0x1e, 0x0a, 0x1c, 0x10, 0x1e, 0x2c, 0x3e, 0x3e, 0x07, 0x07, 0x01, 0x0c, 0x0e, 0x18, 0x07, ++ 0x02, 0x27, 0x22, 0x09, 0x40, 0x41, 0x4a, 0x40, 0x40, 0x40, 0x06, 0x06, 0x04, 0x0a, 0x18, 0x0a, ++ 0x10, 0x1e, 0x04, 0x02, 0x0a, 0x26, 0x0a, 0x02, 0x02, 0x10, 0x18, 0x1a, 0x14, 0x1a, 0x04, 0x0a, ++ 0x18, 0x0a, 0x10, 0x1e, 0x04, 0x02, 0x0a, 0x26, 0x0a, 0x02, 0x02, 0x10, 0x18, 0x1a, 0x14, 0x1a, ++ 0x24, 0x41, 0x3c, 0x40, 0x48, 0x40, 0x06, 0x07, 0x06, 0x14, 0x14, 0x2c, 0x07, 0x11, 0x44, 0x41, ++ 0x1e, 0x07, 0x40, 0x11, 0x44, 0x41, 0x1e, 0x07, 0x40, 0x11, 0x44, 0x41, 0x1e, 0x07, 0x40, 0x4e, ++ 0x07, 0x14, 0x14, 0x22, 0x24, 0x22, 0x24, 0x09, 0x17, 0x44, 0x41, 0x17, 0x44, 0x41, 0x40, 0x40, ++ 0x40, 0x05, 0x05, 0x09, 0x40, 0x0f, 0x09, 0x03, 0x03, 0x2e, 0x27, 0x1e, 0x07, 0x24, 0x1e, 0x16, ++ 0x46, 0x15, 0x11, 0x09, 0x40, 0x09, 0x16, 0x03, 0x22, 0x09, 0x30, 0x1c, 0x22, 0x09, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x54, 0x23, 0x06, 0x43, 0x40, 0x43, 0x54, 0x63, 0x27, 0x40, 0x06, 0x40, 0x40, 0x40, 0x0f, ++ 0x06, 0x1f, 0x0b, 0x1c, 0x11, 0x1f, 0x2e, 0x3e, 0x3e, 0x07, 0x07, 0x01, 0x0c, 0x0e, 0x19, 0x07, ++ 0x03, 0x27, 0x23, 0x09, 0x40, 0x41, 0x4b, 0x40, 0x40, 0x40, 0x06, 0x06, 0x04, 0x0b, 0x19, 0x0b, ++ 0x11, 0x1f, 0x04, 0x03, 0x0b, 0x27, 0x0b, 0x03, 0x03, 0x11, 0x19, 0x1b, 0x14, 0x1b, 0x04, 0x0b, ++ 0x19, 0x0b, 0x11, 0x1f, 0x04, 0x03, 0x0b, 0x27, 0x0b, 0x03, 0x03, 0x11, 0x19, 0x1b, 0x14, 0x1b, ++ 0x24, 0x41, 0x3e, 0x40, 0x48, 0x40, 0x06, 0x07, 0x06, 0x14, 0x14, 0x2e, 0x07, 0x11, 0x44, 0x41, ++ 0x1e, 0x07, 0x40, 0x11, 0x44, 0x41, 0x1e, 0x07, 0x40, 0x11, 0x44, 0x41, 0x1e, 0x07, 0x40, 0x4e, ++ 0x07, 0x14, 0x14, 0x23, 0x24, 0x23, 0x24, 0x09, 0x17, 0x44, 0x41, 0x17, 0x44, 0x41, 0x40, 0x40, ++ 0x40, 0x04, 0x04, 0x09, 0x40, 0x0f, 0x09, 0x03, 0x03, 0x2e, 0x27, 0x1e, 0x07, 0x24, 0x1e, 0x16, ++ 0x46, 0x14, 0x11, 0x09, 0x40, 0x09, 0x16, 0x03, 0x23, 0x09, 0x31, 0x1c, 0x23, 0x09, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x55, 0x24, 0x06, 0x42, 0x40, 0x44, 0x55, 0x64, 0x27, 0x40, 0x06, 0x40, 0x40, 0x40, 0x0f, ++ 0x06, 0x21, 0x0c, 0x1d, 0x12, 0x21, 0x30, 0x3e, 0x3e, 0x07, 0x07, 0x01, 0x0d, 0x0e, 0x1a, 0x07, ++ 0x04, 0x27, 0x24, 0x09, 0x40, 0x41, 0x4c, 0x40, 0x40, 0x40, 0x06, 0x06, 0x05, 0x0c, 0x1a, 0x0c, ++ 0x12, 0x21, 0x05, 0x04, 0x0c, 0x29, 0x0c, 0x04, 0x04, 0x12, 0x1a, 0x1c, 0x15, 0x1c, 0x05, 0x0c, ++ 0x1a, 0x0c, 0x12, 0x21, 0x05, 0x04, 0x0c, 0x29, 0x0c, 0x04, 0x04, 0x12, 0x1a, 0x1c, 0x15, 0x1c, ++ 0x25, 0x41, 0x3e, 0x40, 0x48, 0x40, 0x06, 0x07, 0x06, 0x15, 0x15, 0x30, 0x07, 0x11, 0x45, 0x41, ++ 0x1e, 0x07, 0x40, 0x11, 0x45, 0x41, 0x1e, 0x07, 0x40, 0x11, 0x45, 0x41, 0x1e, 0x07, 0x40, 0x4e, ++ 0x07, 0x15, 0x15, 0x24, 0x25, 0x24, 0x25, 0x09, 0x17, 0x45, 0x41, 0x17, 0x45, 0x41, 0x40, 0x40, ++ 0x40, 0x03, 0x03, 0x09, 0x40, 0x0f, 0x09, 0x02, 0x02, 0x2e, 0x27, 0x1e, 0x07, 0x25, 0x1e, 0x16, ++ 0x46, 0x13, 0x11, 0x09, 0x40, 0x09, 0x16, 0x02, 0x24, 0x09, 0x32, 0x1d, 0x24, 0x09, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x56, 0x24, 0x06, 0x42, 0x40, 0x45, 0x56, 0x65, 0x27, 0x40, 0x06, 0x40, 0x40, 0x40, 0x0f, ++ 0x06, 0x22, 0x0c, 0x1d, 0x13, 0x22, 0x31, 0x3e, 0x3e, 0x07, 0x07, 0x00, 0x0d, 0x0e, 0x1b, 0x07, ++ 0x04, 0x27, 0x24, 0x08, 0x40, 0x41, 0x4d, 0x40, 0x40, 0x40, 0x06, 0x06, 0x05, 0x0c, 0x1b, 0x0c, ++ 0x13, 0x22, 0x05, 0x04, 0x0c, 0x2a, 0x0c, 0x04, 0x04, 0x13, 0x1b, 0x1c, 0x15, 0x1c, 0x05, 0x0c, ++ 0x1b, 0x0c, 0x13, 0x22, 0x05, 0x04, 0x0c, 0x2a, 0x0c, 0x04, 0x04, 0x13, 0x1b, 0x1c, 0x15, 0x1c, ++ 0x25, 0x41, 0x3e, 0x40, 0x48, 0x40, 0x06, 0x07, 0x06, 0x15, 0x15, 0x31, 0x07, 0x10, 0x46, 0x41, ++ 0x1e, 0x07, 0x40, 0x10, 0x46, 0x41, 0x1e, 0x07, 0x40, 0x10, 0x46, 0x41, 0x1e, 0x07, 0x40, 0x4f, ++ 0x07, 0x15, 0x15, 0x24, 0x25, 0x24, 0x25, 0x08, 0x17, 0x46, 0x41, 0x17, 0x46, 0x41, 0x40, 0x40, ++ 0x40, 0x02, 0x02, 0x08, 0x40, 0x0f, 0x08, 0x01, 0x01, 0x2e, 0x27, 0x1e, 0x07, 0x25, 0x1e, 0x16, ++ 0x47, 0x12, 0x10, 0x08, 0x40, 0x08, 0x16, 0x01, 0x24, 0x08, 0x33, 0x1d, 0x24, 0x08, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x56, 0x25, 0x07, 0x41, 0x40, 0x45, 0x56, 0x65, 0x27, 0x40, 0x07, 0x40, 0x40, 0x40, 0x0f, ++ 0x07, 0x24, 0x0d, 0x1e, 0x15, 0x24, 0x33, 0x3e, 0x3e, 0x07, 0x07, 0x00, 0x0e, 0x0f, 0x1d, 0x07, ++ 0x05, 0x27, 0x25, 0x08, 0x40, 0x40, 0x4d, 0x40, 0x40, 0x40, 0x07, 0x07, 0x06, 0x0d, 0x1d, 0x0d, ++ 0x15, 0x24, 0x06, 0x05, 0x0d, 0x2c, 0x0d, 0x05, 0x05, 0x15, 0x1d, 0x1d, 0x16, 0x1d, 0x06, 0x0d, ++ 0x1d, 0x0d, 0x15, 0x24, 0x06, 0x05, 0x0d, 0x2c, 0x0d, 0x05, 0x05, 0x15, 0x1d, 0x1d, 0x16, 0x1d, ++ 0x26, 0x40, 0x3e, 0x40, 0x48, 0x40, 0x07, 0x07, 0x07, 0x16, 0x16, 0x33, 0x07, 0x10, 0x46, 0x40, ++ 0x1f, 0x07, 0x40, 0x10, 0x46, 0x40, 0x1f, 0x07, 0x40, 0x10, 0x46, 0x40, 0x1f, 0x07, 0x40, 0x4f, ++ 0x07, 0x16, 0x16, 0x25, 0x26, 0x25, 0x26, 0x08, 0x17, 0x46, 0x40, 0x17, 0x46, 0x40, 0x40, 0x40, ++ 0x40, 0x02, 0x02, 0x08, 0x40, 0x0f, 0x08, 0x01, 0x01, 0x2f, 0x27, 0x1f, 0x07, 0x26, 0x1f, 0x17, ++ 0x47, 0x12, 0x10, 0x08, 0x40, 0x08, 0x17, 0x01, 0x25, 0x08, 0x35, 0x1e, 0x25, 0x08, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x57, 0x26, 0x07, 0x40, 0x40, 0x46, 0x57, 0x66, 0x27, 0x40, 0x07, 0x40, 0x40, 0x40, 0x0f, ++ 0x07, 0x26, 0x0e, 0x1f, 0x16, 0x26, 0x35, 0x3e, 0x3e, 0x07, 0x07, 0x00, 0x0f, 0x0f, 0x1e, 0x07, ++ 0x06, 0x27, 0x26, 0x08, 0x40, 0x40, 0x4e, 0x40, 0x40, 0x40, 0x07, 0x07, 0x07, 0x0e, 0x1e, 0x0e, ++ 0x16, 0x26, 0x07, 0x06, 0x0e, 0x2e, 0x0e, 0x06, 0x06, 0x16, 0x1e, 0x1e, 0x17, 0x1e, 0x07, 0x0e, ++ 0x1e, 0x0e, 0x16, 0x26, 0x07, 0x06, 0x0e, 0x2e, 0x0e, 0x06, 0x06, 0x16, 0x1e, 0x1e, 0x17, 0x1e, ++ 0x27, 0x40, 0x3e, 0x40, 0x48, 0x40, 0x07, 0x07, 0x07, 0x17, 0x17, 0x35, 0x07, 0x10, 0x47, 0x40, ++ 0x1f, 0x07, 0x40, 0x10, 0x47, 0x40, 0x1f, 0x07, 0x40, 0x10, 0x47, 0x40, 0x1f, 0x07, 0x40, 0x4f, ++ 0x07, 0x17, 0x17, 0x26, 0x27, 0x26, 0x27, 0x08, 0x17, 0x47, 0x40, 0x17, 0x47, 0x40, 0x40, 0x40, ++ 0x40, 0x01, 0x01, 0x08, 0x40, 0x0f, 0x08, 0x00, 0x00, 0x2f, 0x27, 0x1f, 0x07, 0x27, 0x1f, 0x17, ++ 0x47, 0x11, 0x10, 0x08, 0x40, 0x08, 0x17, 0x00, 0x26, 0x08, 0x36, 0x1f, 0x26, 0x08, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x57, 0x27, 0x07, 0x40, 0x40, 0x47, 0x57, 0x67, 0x27, 0x40, 0x07, 0x40, 0x40, 0x40, 0x0f, ++ 0x07, 0x27, 0x0f, 0x1f, 0x17, 0x27, 0x37, 0x3e, 0x3e, 0x07, 0x07, 0x00, 0x0f, 0x0f, 0x1f, 0x07, ++ 0x07, 0x27, 0x27, 0x08, 0x40, 0x40, 0x4f, 0x40, 0x40, 0x40, 0x07, 0x07, 0x07, 0x0f, 0x1f, 0x0f, ++ 0x17, 0x27, 0x07, 0x07, 0x0f, 0x2f, 0x0f, 0x07, 0x07, 0x17, 0x1f, 0x1f, 0x17, 0x1f, 0x07, 0x0f, ++ 0x1f, 0x0f, 0x17, 0x27, 0x07, 0x07, 0x0f, 0x2f, 0x0f, 0x07, 0x07, 0x17, 0x1f, 0x1f, 0x17, 0x1f, ++ 0x27, 0x40, 0x3e, 0x40, 0x48, 0x40, 0x07, 0x07, 0x07, 0x17, 0x17, 0x37, 0x07, 0x10, 0x47, 0x40, ++ 0x1f, 0x07, 0x40, 0x10, 0x47, 0x40, 0x1f, 0x07, 0x40, 0x10, 0x47, 0x40, 0x1f, 0x07, 0x40, 0x4f, ++ 0x07, 0x17, 0x17, 0x27, 0x27, 0x27, 0x27, 0x08, 0x17, 0x47, 0x40, 0x17, 0x47, 0x40, 0x40, 0x40, ++ 0x40, 0x00, 0x00, 0x08, 0x40, 0x0f, 0x08, 0x00, 0x00, 0x2f, 0x27, 0x1f, 0x07, 0x27, 0x1f, 0x17, ++ 0x47, 0x10, 0x10, 0x08, 0x40, 0x08, 0x17, 0x00, 0x27, 0x08, 0x37, 0x1f, 0x27, 0x08, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x3e, 0x48, 0x48, 0x60, 0x40, 0x27, 0x07, 0x07, 0x1f, 0x40, 0x48, 0x40, 0x40, 0x17, 0x0f, ++ 0x48, 0x68, 0x40, 0x07, 0x68, 0x68, 0x68, 0x68, 0x68, 0x07, 0x07, 0x0f, 0x3e, 0x17, 0x40, 0x07, ++ 0x68, 0x27, 0x50, 0x17, 0x40, 0x07, 0x1f, 0x40, 0x40, 0x40, 0x48, 0x48, 0x58, 0x60, 0x50, 0x60, ++ 0x68, 0x60, 0x58, 0x68, 0x68, 0x68, 0x58, 0x60, 0x68, 0x68, 0x68, 0x50, 0x48, 0x58, 0x58, 0x60, ++ 0x50, 0x60, 0x68, 0x60, 0x58, 0x68, 0x68, 0x68, 0x58, 0x60, 0x68, 0x68, 0x68, 0x50, 0x48, 0x58, ++ 0x07, 0x50, 0x58, 0x40, 0x40, 0x40, 0x48, 0x07, 0x48, 0x48, 0x48, 0x68, 0x50, 0x1f, 0x17, 0x50, ++ 0x0f, 0x07, 0x40, 0x1f, 0x17, 0x50, 0x0f, 0x07, 0x40, 0x1f, 0x17, 0x50, 0x0f, 0x07, 0x40, 0x40, ++ 0x07, 0x40, 0x40, 0x40, 0x07, 0x40, 0x07, 0x17, 0x17, 0x17, 0x50, 0x17, 0x17, 0x50, 0x40, 0x40, ++ 0x40, 0x2f, 0x17, 0x17, 0x40, 0x0f, 0x17, 0x1f, 0x1f, 0x1f, 0x27, 0x0f, 0x07, 0x07, 0x0f, 0x40, ++ 0x07, 0x3e, 0x1f, 0x17, 0x40, 0x0f, 0x17, 0x1f, 0x48, 0x17, 0x48, 0x48, 0x48, 0x17, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x3e, 0x47, 0x47, 0x5f, 0x40, 0x27, 0x07, 0x07, 0x20, 0x40, 0x47, 0x40, 0x40, 0x17, 0x0f, ++ 0x47, 0x66, 0x40, 0x08, 0x66, 0x66, 0x66, 0x65, 0x65, 0x07, 0x07, 0x0f, 0x3e, 0x17, 0x00, 0x07, ++ 0x67, 0x27, 0x4e, 0x17, 0x40, 0x07, 0x1f, 0x40, 0x40, 0x40, 0x47, 0x47, 0x57, 0x5f, 0x4f, 0x5f, ++ 0x66, 0x5e, 0x57, 0x67, 0x67, 0x66, 0x57, 0x5f, 0x67, 0x67, 0x66, 0x4f, 0x47, 0x56, 0x57, 0x5f, ++ 0x4f, 0x5f, 0x66, 0x5e, 0x57, 0x67, 0x67, 0x66, 0x57, 0x5f, 0x67, 0x67, 0x66, 0x4f, 0x47, 0x56, ++ 0x08, 0x4f, 0x56, 0x40, 0x40, 0x40, 0x47, 0x07, 0x47, 0x47, 0x47, 0x66, 0x4f, 0x1f, 0x17, 0x4f, ++ 0x10, 0x07, 0x40, 0x1f, 0x17, 0x4f, 0x10, 0x07, 0x40, 0x1f, 0x17, 0x4f, 0x10, 0x07, 0x40, 0x40, ++ 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x08, 0x17, 0x17, 0x17, 0x4f, 0x17, 0x17, 0x4f, 0x40, 0x40, ++ 0x40, 0x2f, 0x17, 0x17, 0x40, 0x0f, 0x17, 0x1f, 0x1f, 0x20, 0x27, 0x10, 0x07, 0x08, 0x10, 0x00, ++ 0x07, 0x3e, 0x1f, 0x17, 0x40, 0x0f, 0x17, 0x1f, 0x47, 0x17, 0x46, 0x47, 0x47, 0x17, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x3e, 0x46, 0x47, 0x5e, 0x40, 0x26, 0x06, 0x06, 0x20, 0x40, 0x47, 0x40, 0x40, 0x16, 0x0f, ++ 0x47, 0x64, 0x40, 0x08, 0x65, 0x64, 0x64, 0x63, 0x63, 0x07, 0x07, 0x0f, 0x3e, 0x17, 0x01, 0x07, ++ 0x66, 0x27, 0x4d, 0x17, 0x40, 0x07, 0x1e, 0x40, 0x40, 0x40, 0x47, 0x47, 0x56, 0x5e, 0x4e, 0x5e, ++ 0x65, 0x5d, 0x56, 0x66, 0x66, 0x64, 0x56, 0x5e, 0x66, 0x66, 0x64, 0x4e, 0x46, 0x55, 0x56, 0x5e, ++ 0x4e, 0x5e, 0x65, 0x5d, 0x56, 0x66, 0x66, 0x64, 0x56, 0x5e, 0x66, 0x66, 0x64, 0x4e, 0x46, 0x55, ++ 0x09, 0x4f, 0x54, 0x40, 0x40, 0x40, 0x47, 0x07, 0x47, 0x46, 0x46, 0x64, 0x4e, 0x1f, 0x16, 0x4f, ++ 0x10, 0x07, 0x40, 0x1f, 0x16, 0x4f, 0x10, 0x07, 0x40, 0x1f, 0x16, 0x4f, 0x10, 0x07, 0x40, 0x40, ++ 0x07, 0x00, 0x00, 0x01, 0x09, 0x01, 0x09, 0x17, 0x17, 0x16, 0x4f, 0x17, 0x16, 0x4f, 0x40, 0x40, ++ 0x40, 0x2e, 0x17, 0x17, 0x40, 0x0f, 0x17, 0x1e, 0x1e, 0x20, 0x27, 0x10, 0x07, 0x09, 0x10, 0x01, ++ 0x07, 0x3e, 0x1f, 0x17, 0x40, 0x0f, 0x17, 0x1e, 0x46, 0x17, 0x45, 0x46, 0x46, 0x17, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x3e, 0x45, 0x47, 0x5e, 0x40, 0x25, 0x06, 0x05, 0x20, 0x40, 0x47, 0x40, 0x40, 0x16, 0x0f, ++ 0x47, 0x63, 0x40, 0x08, 0x64, 0x63, 0x62, 0x60, 0x60, 0x07, 0x07, 0x0f, 0x3e, 0x17, 0x01, 0x07, ++ 0x65, 0x27, 0x4c, 0x17, 0x40, 0x07, 0x1d, 0x40, 0x40, 0x40, 0x47, 0x47, 0x56, 0x5d, 0x4e, 0x5d, ++ 0x64, 0x5c, 0x56, 0x65, 0x65, 0x63, 0x56, 0x5e, 0x65, 0x65, 0x63, 0x4d, 0x46, 0x54, 0x56, 0x5d, ++ 0x4e, 0x5d, 0x64, 0x5c, 0x56, 0x65, 0x65, 0x63, 0x56, 0x5e, 0x65, 0x65, 0x63, 0x4d, 0x46, 0x54, ++ 0x09, 0x4f, 0x52, 0x40, 0x40, 0x40, 0x47, 0x07, 0x47, 0x46, 0x46, 0x62, 0x4e, 0x1f, 0x16, 0x4f, ++ 0x10, 0x07, 0x40, 0x1f, 0x16, 0x4f, 0x10, 0x07, 0x40, 0x1f, 0x16, 0x4f, 0x10, 0x07, 0x40, 0x40, ++ 0x07, 0x00, 0x00, 0x01, 0x09, 0x01, 0x09, 0x17, 0x17, 0x16, 0x4f, 0x17, 0x16, 0x4f, 0x40, 0x40, ++ 0x40, 0x2d, 0x17, 0x17, 0x40, 0x0f, 0x17, 0x1e, 0x1e, 0x20, 0x27, 0x10, 0x07, 0x09, 0x10, 0x01, ++ 0x07, 0x3e, 0x1f, 0x17, 0x40, 0x0f, 0x17, 0x1e, 0x45, 0x17, 0x44, 0x45, 0x45, 0x17, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x3e, 0x44, 0x46, 0x5d, 0x40, 0x24, 0x05, 0x04, 0x21, 0x40, 0x46, 0x40, 0x40, 0x15, 0x0f, ++ 0x46, 0x61, 0x40, 0x09, 0x63, 0x61, 0x60, 0x5e, 0x5e, 0x07, 0x07, 0x0e, 0x3e, 0x16, 0x02, 0x07, ++ 0x64, 0x27, 0x4b, 0x16, 0x40, 0x06, 0x1c, 0x40, 0x40, 0x40, 0x46, 0x46, 0x55, 0x5c, 0x4d, 0x5c, ++ 0x63, 0x5b, 0x55, 0x64, 0x64, 0x61, 0x55, 0x5d, 0x64, 0x64, 0x61, 0x4c, 0x45, 0x53, 0x55, 0x5c, ++ 0x4d, 0x5c, 0x63, 0x5b, 0x55, 0x64, 0x64, 0x61, 0x55, 0x5d, 0x64, 0x64, 0x61, 0x4c, 0x45, 0x53, ++ 0x0a, 0x4e, 0x50, 0x40, 0x41, 0x40, 0x46, 0x07, 0x46, 0x45, 0x45, 0x60, 0x4d, 0x1e, 0x15, 0x4e, ++ 0x11, 0x07, 0x40, 0x1e, 0x15, 0x4e, 0x11, 0x07, 0x40, 0x1e, 0x15, 0x4e, 0x11, 0x07, 0x40, 0x41, ++ 0x07, 0x01, 0x01, 0x02, 0x0a, 0x02, 0x0a, 0x16, 0x17, 0x15, 0x4e, 0x17, 0x15, 0x4e, 0x40, 0x40, ++ 0x40, 0x2c, 0x16, 0x16, 0x40, 0x0f, 0x16, 0x1d, 0x1d, 0x21, 0x27, 0x11, 0x07, 0x0a, 0x11, 0x02, ++ 0x06, 0x3e, 0x1e, 0x16, 0x40, 0x0f, 0x16, 0x1d, 0x44, 0x16, 0x43, 0x44, 0x44, 0x16, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x3e, 0x43, 0x46, 0x5c, 0x40, 0x23, 0x04, 0x03, 0x21, 0x40, 0x46, 0x40, 0x40, 0x14, 0x0f, ++ 0x46, 0x60, 0x40, 0x09, 0x61, 0x60, 0x5e, 0x5b, 0x5b, 0x07, 0x07, 0x0e, 0x3e, 0x16, 0x03, 0x07, ++ 0x63, 0x27, 0x49, 0x16, 0x40, 0x06, 0x1b, 0x40, 0x40, 0x40, 0x46, 0x46, 0x54, 0x5b, 0x4c, 0x5b, ++ 0x61, 0x59, 0x54, 0x63, 0x63, 0x60, 0x54, 0x5c, 0x63, 0x63, 0x60, 0x4b, 0x44, 0x51, 0x54, 0x5b, ++ 0x4c, 0x5b, 0x61, 0x59, 0x54, 0x63, 0x63, 0x60, 0x54, 0x5c, 0x63, 0x63, 0x60, 0x4b, 0x44, 0x51, ++ 0x0b, 0x4e, 0x4e, 0x40, 0x41, 0x40, 0x46, 0x07, 0x46, 0x44, 0x44, 0x5e, 0x4c, 0x1e, 0x14, 0x4e, ++ 0x11, 0x07, 0x40, 0x1e, 0x14, 0x4e, 0x11, 0x07, 0x40, 0x1e, 0x14, 0x4e, 0x11, 0x07, 0x40, 0x41, ++ 0x07, 0x01, 0x01, 0x03, 0x0b, 0x03, 0x0b, 0x16, 0x17, 0x14, 0x4e, 0x17, 0x14, 0x4e, 0x40, 0x40, ++ 0x40, 0x2b, 0x16, 0x16, 0x40, 0x0f, 0x16, 0x1c, 0x1c, 0x21, 0x27, 0x11, 0x07, 0x0b, 0x11, 0x03, ++ 0x06, 0x3e, 0x1e, 0x16, 0x40, 0x0f, 0x16, 0x1c, 0x43, 0x16, 0x41, 0x43, 0x43, 0x16, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x3e, 0x42, 0x46, 0x5c, 0x40, 0x22, 0x04, 0x02, 0x21, 0x40, 0x46, 0x40, 0x40, 0x14, 0x0f, ++ 0x46, 0x5e, 0x40, 0x09, 0x60, 0x5e, 0x5c, 0x59, 0x59, 0x07, 0x07, 0x0e, 0x3e, 0x16, 0x03, 0x07, ++ 0x62, 0x27, 0x48, 0x16, 0x40, 0x06, 0x1a, 0x40, 0x40, 0x40, 0x46, 0x46, 0x54, 0x5a, 0x4c, 0x5a, ++ 0x60, 0x58, 0x54, 0x62, 0x62, 0x5e, 0x54, 0x5c, 0x62, 0x62, 0x5e, 0x4a, 0x44, 0x50, 0x54, 0x5a, ++ 0x4c, 0x5a, 0x60, 0x58, 0x54, 0x62, 0x62, 0x5e, 0x54, 0x5c, 0x62, 0x62, 0x5e, 0x4a, 0x44, 0x50, ++ 0x0b, 0x4e, 0x4c, 0x40, 0x41, 0x40, 0x46, 0x07, 0x46, 0x44, 0x44, 0x5c, 0x4c, 0x1e, 0x14, 0x4e, ++ 0x11, 0x07, 0x40, 0x1e, 0x14, 0x4e, 0x11, 0x07, 0x40, 0x1e, 0x14, 0x4e, 0x11, 0x07, 0x40, 0x41, ++ 0x07, 0x01, 0x01, 0x03, 0x0b, 0x03, 0x0b, 0x16, 0x17, 0x14, 0x4e, 0x17, 0x14, 0x4e, 0x40, 0x40, ++ 0x40, 0x2a, 0x16, 0x16, 0x40, 0x0f, 0x16, 0x1c, 0x1c, 0x21, 0x27, 0x11, 0x07, 0x0b, 0x11, 0x03, ++ 0x06, 0x3e, 0x1e, 0x16, 0x40, 0x0f, 0x16, 0x1c, 0x42, 0x16, 0x40, 0x42, 0x42, 0x16, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x3e, 0x41, 0x45, 0x5b, 0x40, 0x21, 0x03, 0x01, 0x22, 0x40, 0x45, 0x40, 0x40, 0x13, 0x0f, ++ 0x45, 0x5d, 0x40, 0x0a, 0x5f, 0x5d, 0x5a, 0x56, 0x56, 0x07, 0x07, 0x0d, 0x3e, 0x15, 0x04, 0x07, ++ 0x61, 0x27, 0x47, 0x15, 0x40, 0x05, 0x19, 0x40, 0x40, 0x40, 0x45, 0x45, 0x53, 0x59, 0x4b, 0x59, ++ 0x5f, 0x57, 0x53, 0x61, 0x61, 0x5d, 0x53, 0x5b, 0x61, 0x61, 0x5d, 0x49, 0x43, 0x4f, 0x53, 0x59, ++ 0x4b, 0x59, 0x5f, 0x57, 0x53, 0x61, 0x61, 0x5d, 0x53, 0x5b, 0x61, 0x61, 0x5d, 0x49, 0x43, 0x4f, ++ 0x0c, 0x4d, 0x4a, 0x40, 0x42, 0x40, 0x45, 0x07, 0x45, 0x43, 0x43, 0x5a, 0x4b, 0x1d, 0x13, 0x4d, ++ 0x12, 0x07, 0x40, 0x1d, 0x13, 0x4d, 0x12, 0x07, 0x40, 0x1d, 0x13, 0x4d, 0x12, 0x07, 0x40, 0x42, ++ 0x07, 0x02, 0x02, 0x04, 0x0c, 0x04, 0x0c, 0x15, 0x17, 0x13, 0x4d, 0x17, 0x13, 0x4d, 0x40, 0x40, ++ 0x40, 0x29, 0x15, 0x15, 0x40, 0x0f, 0x15, 0x1b, 0x1b, 0x22, 0x27, 0x12, 0x07, 0x0c, 0x12, 0x04, ++ 0x05, 0x3e, 0x1d, 0x15, 0x40, 0x0f, 0x15, 0x1b, 0x41, 0x15, 0x00, 0x41, 0x41, 0x15, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x3e, 0x40, 0x45, 0x5b, 0x40, 0x20, 0x02, 0x00, 0x22, 0x40, 0x45, 0x40, 0x40, 0x12, 0x0f, ++ 0x45, 0x5b, 0x40, 0x0a, 0x5e, 0x5b, 0x59, 0x54, 0x54, 0x07, 0x07, 0x0d, 0x3e, 0x15, 0x04, 0x07, ++ 0x60, 0x27, 0x46, 0x15, 0x40, 0x05, 0x18, 0x40, 0x40, 0x40, 0x45, 0x45, 0x53, 0x58, 0x4b, 0x58, ++ 0x5e, 0x56, 0x53, 0x60, 0x60, 0x5b, 0x53, 0x5b, 0x60, 0x60, 0x5b, 0x48, 0x43, 0x4e, 0x53, 0x58, ++ 0x4b, 0x58, 0x5e, 0x56, 0x53, 0x60, 0x60, 0x5b, 0x53, 0x5b, 0x60, 0x60, 0x5b, 0x48, 0x43, 0x4e, ++ 0x0c, 0x4d, 0x49, 0x40, 0x42, 0x40, 0x45, 0x07, 0x45, 0x43, 0x43, 0x59, 0x4b, 0x1d, 0x12, 0x4d, ++ 0x12, 0x07, 0x40, 0x1d, 0x12, 0x4d, 0x12, 0x07, 0x40, 0x1d, 0x12, 0x4d, 0x12, 0x07, 0x40, 0x42, ++ 0x07, 0x02, 0x02, 0x04, 0x0c, 0x04, 0x0c, 0x15, 0x17, 0x12, 0x4d, 0x17, 0x12, 0x4d, 0x40, 0x40, ++ 0x40, 0x28, 0x15, 0x15, 0x40, 0x0f, 0x15, 0x1a, 0x1a, 0x22, 0x27, 0x12, 0x07, 0x0c, 0x12, 0x04, ++ 0x05, 0x3e, 0x1d, 0x15, 0x40, 0x0f, 0x15, 0x1a, 0x40, 0x15, 0x01, 0x40, 0x40, 0x15, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x3e, 0x00, 0x45, 0x5a, 0x40, 0x1f, 0x02, 0x40, 0x22, 0x40, 0x45, 0x40, 0x40, 0x12, 0x0f, ++ 0x45, 0x59, 0x40, 0x0a, 0x5c, 0x59, 0x57, 0x51, 0x51, 0x07, 0x07, 0x0d, 0x3e, 0x15, 0x05, 0x07, ++ 0x5f, 0x27, 0x44, 0x15, 0x40, 0x05, 0x17, 0x40, 0x40, 0x40, 0x45, 0x45, 0x52, 0x57, 0x4a, 0x57, ++ 0x5c, 0x54, 0x52, 0x5f, 0x5f, 0x59, 0x52, 0x5a, 0x5f, 0x5f, 0x59, 0x47, 0x42, 0x4c, 0x52, 0x57, ++ 0x4a, 0x57, 0x5c, 0x54, 0x52, 0x5f, 0x5f, 0x59, 0x52, 0x5a, 0x5f, 0x5f, 0x59, 0x47, 0x42, 0x4c, ++ 0x0d, 0x4d, 0x47, 0x40, 0x42, 0x40, 0x45, 0x07, 0x45, 0x42, 0x42, 0x57, 0x4a, 0x1d, 0x12, 0x4d, ++ 0x12, 0x07, 0x40, 0x1d, 0x12, 0x4d, 0x12, 0x07, 0x40, 0x1d, 0x12, 0x4d, 0x12, 0x07, 0x40, 0x42, ++ 0x07, 0x02, 0x02, 0x05, 0x0d, 0x05, 0x0d, 0x15, 0x17, 0x12, 0x4d, 0x17, 0x12, 0x4d, 0x40, 0x40, ++ 0x40, 0x27, 0x15, 0x15, 0x40, 0x0f, 0x15, 0x1a, 0x1a, 0x22, 0x27, 0x12, 0x07, 0x0d, 0x12, 0x05, ++ 0x05, 0x3e, 0x1d, 0x15, 0x40, 0x0f, 0x15, 0x1a, 0x00, 0x15, 0x03, 0x00, 0x00, 0x15, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x3e, 0x01, 0x44, 0x59, 0x40, 0x1e, 0x01, 0x41, 0x23, 0x40, 0x44, 0x40, 0x40, 0x11, 0x0f, ++ 0x44, 0x58, 0x40, 0x0b, 0x5b, 0x58, 0x55, 0x4f, 0x4f, 0x07, 0x07, 0x0c, 0x3e, 0x14, 0x06, 0x07, ++ 0x5e, 0x27, 0x43, 0x14, 0x40, 0x04, 0x16, 0x40, 0x40, 0x40, 0x44, 0x44, 0x51, 0x56, 0x49, 0x56, ++ 0x5b, 0x53, 0x51, 0x5e, 0x5e, 0x58, 0x51, 0x59, 0x5e, 0x5e, 0x58, 0x46, 0x41, 0x4b, 0x51, 0x56, ++ 0x49, 0x56, 0x5b, 0x53, 0x51, 0x5e, 0x5e, 0x58, 0x51, 0x59, 0x5e, 0x5e, 0x58, 0x46, 0x41, 0x4b, ++ 0x0e, 0x4c, 0x45, 0x40, 0x43, 0x40, 0x44, 0x07, 0x44, 0x41, 0x41, 0x55, 0x49, 0x1c, 0x11, 0x4c, ++ 0x13, 0x07, 0x40, 0x1c, 0x11, 0x4c, 0x13, 0x07, 0x40, 0x1c, 0x11, 0x4c, 0x13, 0x07, 0x40, 0x43, ++ 0x07, 0x03, 0x03, 0x06, 0x0e, 0x06, 0x0e, 0x14, 0x17, 0x11, 0x4c, 0x17, 0x11, 0x4c, 0x40, 0x40, ++ 0x40, 0x26, 0x14, 0x14, 0x40, 0x0f, 0x14, 0x19, 0x19, 0x23, 0x27, 0x13, 0x07, 0x0e, 0x13, 0x06, ++ 0x04, 0x3e, 0x1c, 0x14, 0x40, 0x0f, 0x14, 0x19, 0x01, 0x14, 0x04, 0x01, 0x01, 0x14, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x3e, 0x02, 0x44, 0x59, 0x40, 0x1d, 0x01, 0x42, 0x23, 0x40, 0x44, 0x40, 0x40, 0x11, 0x0f, ++ 0x44, 0x56, 0x40, 0x0b, 0x5a, 0x56, 0x53, 0x4c, 0x4c, 0x07, 0x07, 0x0c, 0x3e, 0x14, 0x06, 0x07, ++ 0x5d, 0x27, 0x42, 0x14, 0x40, 0x04, 0x15, 0x40, 0x40, 0x40, 0x44, 0x44, 0x51, 0x55, 0x49, 0x55, ++ 0x5a, 0x52, 0x51, 0x5d, 0x5d, 0x56, 0x51, 0x59, 0x5d, 0x5d, 0x56, 0x45, 0x41, 0x4a, 0x51, 0x55, ++ 0x49, 0x55, 0x5a, 0x52, 0x51, 0x5d, 0x5d, 0x56, 0x51, 0x59, 0x5d, 0x5d, 0x56, 0x45, 0x41, 0x4a, ++ 0x0e, 0x4c, 0x43, 0x40, 0x43, 0x40, 0x44, 0x07, 0x44, 0x41, 0x41, 0x53, 0x49, 0x1c, 0x11, 0x4c, ++ 0x13, 0x07, 0x40, 0x1c, 0x11, 0x4c, 0x13, 0x07, 0x40, 0x1c, 0x11, 0x4c, 0x13, 0x07, 0x40, 0x43, ++ 0x07, 0x03, 0x03, 0x06, 0x0e, 0x06, 0x0e, 0x14, 0x17, 0x11, 0x4c, 0x17, 0x11, 0x4c, 0x40, 0x40, ++ 0x40, 0x25, 0x14, 0x14, 0x40, 0x0f, 0x14, 0x19, 0x19, 0x23, 0x27, 0x13, 0x07, 0x0e, 0x13, 0x06, ++ 0x04, 0x3e, 0x1c, 0x14, 0x40, 0x0f, 0x14, 0x19, 0x02, 0x14, 0x05, 0x02, 0x02, 0x14, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x3e, 0x03, 0x44, 0x58, 0x40, 0x1c, 0x00, 0x43, 0x23, 0x40, 0x44, 0x40, 0x40, 0x10, 0x0f, ++ 0x44, 0x55, 0x40, 0x0b, 0x59, 0x55, 0x51, 0x4a, 0x4a, 0x07, 0x07, 0x0c, 0x3d, 0x14, 0x07, 0x07, ++ 0x5c, 0x27, 0x41, 0x14, 0x40, 0x04, 0x14, 0x40, 0x40, 0x40, 0x44, 0x44, 0x50, 0x54, 0x48, 0x54, ++ 0x59, 0x51, 0x50, 0x5c, 0x5c, 0x55, 0x50, 0x58, 0x5c, 0x5c, 0x55, 0x44, 0x40, 0x49, 0x50, 0x54, ++ 0x48, 0x54, 0x59, 0x51, 0x50, 0x5c, 0x5c, 0x55, 0x50, 0x58, 0x5c, 0x5c, 0x55, 0x44, 0x40, 0x49, ++ 0x0f, 0x4c, 0x41, 0x40, 0x43, 0x40, 0x44, 0x07, 0x44, 0x40, 0x40, 0x51, 0x48, 0x1c, 0x10, 0x4c, ++ 0x13, 0x07, 0x40, 0x1c, 0x10, 0x4c, 0x13, 0x07, 0x40, 0x1c, 0x10, 0x4c, 0x13, 0x07, 0x40, 0x43, ++ 0x07, 0x03, 0x03, 0x07, 0x0f, 0x07, 0x0f, 0x14, 0x17, 0x10, 0x4c, 0x17, 0x10, 0x4c, 0x40, 0x40, ++ 0x40, 0x24, 0x14, 0x14, 0x40, 0x0f, 0x14, 0x18, 0x18, 0x23, 0x27, 0x13, 0x07, 0x0f, 0x13, 0x07, ++ 0x04, 0x3e, 0x1c, 0x14, 0x40, 0x0f, 0x14, 0x18, 0x03, 0x14, 0x06, 0x03, 0x03, 0x14, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x3e, 0x04, 0x43, 0x57, 0x40, 0x1b, 0x40, 0x44, 0x24, 0x40, 0x43, 0x40, 0x40, 0x0f, 0x0f, ++ 0x43, 0x53, 0x40, 0x0c, 0x57, 0x53, 0x4f, 0x47, 0x47, 0x07, 0x07, 0x0b, 0x3b, 0x13, 0x08, 0x07, ++ 0x5b, 0x27, 0x00, 0x13, 0x40, 0x03, 0x13, 0x40, 0x40, 0x40, 0x43, 0x43, 0x4f, 0x53, 0x47, 0x53, ++ 0x57, 0x4f, 0x4f, 0x5b, 0x5b, 0x53, 0x4f, 0x57, 0x5b, 0x5b, 0x53, 0x43, 0x00, 0x47, 0x4f, 0x53, ++ 0x47, 0x53, 0x57, 0x4f, 0x4f, 0x5b, 0x5b, 0x53, 0x4f, 0x57, 0x5b, 0x5b, 0x53, 0x43, 0x00, 0x47, ++ 0x10, 0x4b, 0x00, 0x40, 0x44, 0x40, 0x43, 0x07, 0x43, 0x00, 0x00, 0x4f, 0x47, 0x1b, 0x0f, 0x4b, ++ 0x14, 0x07, 0x40, 0x1b, 0x0f, 0x4b, 0x14, 0x07, 0x40, 0x1b, 0x0f, 0x4b, 0x14, 0x07, 0x40, 0x44, ++ 0x07, 0x04, 0x04, 0x08, 0x10, 0x08, 0x10, 0x13, 0x17, 0x0f, 0x4b, 0x17, 0x0f, 0x4b, 0x40, 0x40, ++ 0x40, 0x23, 0x13, 0x13, 0x40, 0x0f, 0x13, 0x17, 0x17, 0x24, 0x27, 0x14, 0x07, 0x10, 0x14, 0x08, ++ 0x03, 0x3e, 0x1b, 0x13, 0x40, 0x0f, 0x13, 0x17, 0x04, 0x13, 0x08, 0x04, 0x04, 0x13, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x3e, 0x05, 0x43, 0x57, 0x40, 0x1a, 0x40, 0x45, 0x24, 0x40, 0x43, 0x40, 0x40, 0x0f, 0x0f, ++ 0x43, 0x52, 0x40, 0x0c, 0x56, 0x52, 0x4d, 0x45, 0x45, 0x07, 0x07, 0x0b, 0x3a, 0x13, 0x08, 0x07, ++ 0x5a, 0x27, 0x01, 0x13, 0x40, 0x03, 0x12, 0x40, 0x40, 0x40, 0x43, 0x43, 0x4f, 0x52, 0x47, 0x52, ++ 0x56, 0x4e, 0x4f, 0x5a, 0x5a, 0x52, 0x4f, 0x57, 0x5a, 0x5a, 0x52, 0x42, 0x00, 0x46, 0x4f, 0x52, ++ 0x47, 0x52, 0x56, 0x4e, 0x4f, 0x5a, 0x5a, 0x52, 0x4f, 0x57, 0x5a, 0x5a, 0x52, 0x42, 0x00, 0x46, ++ 0x10, 0x4b, 0x02, 0x40, 0x44, 0x40, 0x43, 0x07, 0x43, 0x00, 0x00, 0x4d, 0x47, 0x1b, 0x0f, 0x4b, ++ 0x14, 0x07, 0x40, 0x1b, 0x0f, 0x4b, 0x14, 0x07, 0x40, 0x1b, 0x0f, 0x4b, 0x14, 0x07, 0x40, 0x44, ++ 0x07, 0x04, 0x04, 0x08, 0x10, 0x08, 0x10, 0x13, 0x17, 0x0f, 0x4b, 0x17, 0x0f, 0x4b, 0x40, 0x40, ++ 0x40, 0x22, 0x13, 0x13, 0x40, 0x0f, 0x13, 0x17, 0x17, 0x24, 0x27, 0x14, 0x07, 0x10, 0x14, 0x08, ++ 0x03, 0x3e, 0x1b, 0x13, 0x40, 0x0f, 0x13, 0x17, 0x05, 0x13, 0x09, 0x05, 0x05, 0x13, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x3e, 0x06, 0x43, 0x56, 0x40, 0x19, 0x41, 0x46, 0x24, 0x40, 0x43, 0x40, 0x40, 0x0e, 0x0f, ++ 0x43, 0x50, 0x40, 0x0c, 0x55, 0x50, 0x4b, 0x42, 0x42, 0x07, 0x07, 0x0b, 0x38, 0x13, 0x09, 0x07, ++ 0x59, 0x27, 0x02, 0x13, 0x40, 0x03, 0x11, 0x40, 0x40, 0x40, 0x43, 0x43, 0x4e, 0x51, 0x46, 0x51, ++ 0x55, 0x4d, 0x4e, 0x59, 0x59, 0x50, 0x4e, 0x56, 0x59, 0x59, 0x50, 0x41, 0x01, 0x45, 0x4e, 0x51, ++ 0x46, 0x51, 0x55, 0x4d, 0x4e, 0x59, 0x59, 0x50, 0x4e, 0x56, 0x59, 0x59, 0x50, 0x41, 0x01, 0x45, ++ 0x11, 0x4b, 0x04, 0x40, 0x44, 0x40, 0x43, 0x07, 0x43, 0x01, 0x01, 0x4b, 0x46, 0x1b, 0x0e, 0x4b, ++ 0x14, 0x07, 0x40, 0x1b, 0x0e, 0x4b, 0x14, 0x07, 0x40, 0x1b, 0x0e, 0x4b, 0x14, 0x07, 0x40, 0x44, ++ 0x07, 0x04, 0x04, 0x09, 0x11, 0x09, 0x11, 0x13, 0x17, 0x0e, 0x4b, 0x17, 0x0e, 0x4b, 0x40, 0x40, ++ 0x40, 0x21, 0x13, 0x13, 0x40, 0x0f, 0x13, 0x16, 0x16, 0x24, 0x27, 0x14, 0x07, 0x11, 0x14, 0x09, ++ 0x03, 0x3d, 0x1b, 0x13, 0x40, 0x0f, 0x13, 0x16, 0x06, 0x13, 0x0a, 0x06, 0x06, 0x13, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x3e, 0x06, 0x43, 0x56, 0x40, 0x18, 0x42, 0x47, 0x24, 0x40, 0x43, 0x40, 0x40, 0x0d, 0x0f, ++ 0x43, 0x4f, 0x40, 0x0c, 0x54, 0x4f, 0x4a, 0x40, 0x40, 0x07, 0x07, 0x0a, 0x36, 0x12, 0x09, 0x07, ++ 0x59, 0x27, 0x03, 0x12, 0x40, 0x02, 0x10, 0x40, 0x40, 0x40, 0x43, 0x43, 0x4e, 0x51, 0x46, 0x51, ++ 0x54, 0x4c, 0x4e, 0x59, 0x59, 0x4f, 0x4e, 0x56, 0x59, 0x59, 0x4f, 0x41, 0x01, 0x44, 0x4e, 0x51, ++ 0x46, 0x51, 0x54, 0x4c, 0x4e, 0x59, 0x59, 0x4f, 0x4e, 0x56, 0x59, 0x59, 0x4f, 0x41, 0x01, 0x44, ++ 0x11, 0x4b, 0x05, 0x40, 0x45, 0x40, 0x43, 0x07, 0x43, 0x01, 0x01, 0x4a, 0x46, 0x1a, 0x0d, 0x4b, ++ 0x14, 0x07, 0x40, 0x1a, 0x0d, 0x4b, 0x14, 0x07, 0x40, 0x1a, 0x0d, 0x4b, 0x14, 0x07, 0x40, 0x45, ++ 0x07, 0x04, 0x04, 0x09, 0x11, 0x09, 0x11, 0x12, 0x17, 0x0d, 0x4b, 0x17, 0x0d, 0x4b, 0x40, 0x40, ++ 0x40, 0x20, 0x12, 0x12, 0x40, 0x0f, 0x12, 0x15, 0x15, 0x24, 0x27, 0x14, 0x07, 0x11, 0x14, 0x09, ++ 0x02, 0x3b, 0x1a, 0x12, 0x40, 0x0f, 0x12, 0x15, 0x06, 0x12, 0x0b, 0x06, 0x06, 0x12, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x3e, 0x07, 0x42, 0x55, 0x40, 0x18, 0x42, 0x47, 0x25, 0x40, 0x42, 0x40, 0x40, 0x0d, 0x0f, ++ 0x42, 0x4d, 0x40, 0x0d, 0x52, 0x4d, 0x48, 0x02, 0x02, 0x07, 0x07, 0x0a, 0x35, 0x12, 0x0a, 0x07, ++ 0x58, 0x27, 0x05, 0x12, 0x40, 0x02, 0x10, 0x40, 0x40, 0x40, 0x42, 0x42, 0x4d, 0x50, 0x45, 0x50, ++ 0x52, 0x4a, 0x4d, 0x58, 0x58, 0x4d, 0x4d, 0x55, 0x58, 0x58, 0x4d, 0x40, 0x02, 0x42, 0x4d, 0x50, ++ 0x45, 0x50, 0x52, 0x4a, 0x4d, 0x58, 0x58, 0x4d, 0x4d, 0x55, 0x58, 0x58, 0x4d, 0x40, 0x02, 0x42, ++ 0x12, 0x4a, 0x07, 0x40, 0x45, 0x40, 0x42, 0x07, 0x42, 0x02, 0x02, 0x48, 0x45, 0x1a, 0x0d, 0x4a, ++ 0x15, 0x07, 0x40, 0x1a, 0x0d, 0x4a, 0x15, 0x07, 0x40, 0x1a, 0x0d, 0x4a, 0x15, 0x07, 0x40, 0x45, ++ 0x07, 0x05, 0x05, 0x0a, 0x12, 0x0a, 0x12, 0x12, 0x17, 0x0d, 0x4a, 0x17, 0x0d, 0x4a, 0x40, 0x40, ++ 0x40, 0x20, 0x12, 0x12, 0x40, 0x0f, 0x12, 0x15, 0x15, 0x25, 0x27, 0x15, 0x07, 0x12, 0x15, 0x0a, ++ 0x02, 0x3a, 0x1a, 0x12, 0x40, 0x0f, 0x12, 0x15, 0x07, 0x12, 0x0d, 0x07, 0x07, 0x12, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x3e, 0x08, 0x42, 0x54, 0x40, 0x17, 0x43, 0x48, 0x25, 0x40, 0x42, 0x40, 0x40, 0x0c, 0x0f, ++ 0x42, 0x4b, 0x40, 0x0d, 0x51, 0x4b, 0x46, 0x04, 0x04, 0x07, 0x07, 0x0a, 0x33, 0x12, 0x0b, 0x07, ++ 0x57, 0x27, 0x06, 0x12, 0x40, 0x02, 0x0f, 0x40, 0x40, 0x40, 0x42, 0x42, 0x4c, 0x4f, 0x44, 0x4f, ++ 0x51, 0x49, 0x4c, 0x57, 0x57, 0x4b, 0x4c, 0x54, 0x57, 0x57, 0x4b, 0x00, 0x03, 0x41, 0x4c, 0x4f, ++ 0x44, 0x4f, 0x51, 0x49, 0x4c, 0x57, 0x57, 0x4b, 0x4c, 0x54, 0x57, 0x57, 0x4b, 0x00, 0x03, 0x41, ++ 0x13, 0x4a, 0x09, 0x40, 0x45, 0x40, 0x42, 0x07, 0x42, 0x03, 0x03, 0x46, 0x44, 0x1a, 0x0c, 0x4a, ++ 0x15, 0x07, 0x40, 0x1a, 0x0c, 0x4a, 0x15, 0x07, 0x40, 0x1a, 0x0c, 0x4a, 0x15, 0x07, 0x40, 0x45, ++ 0x07, 0x05, 0x05, 0x0b, 0x13, 0x0b, 0x13, 0x12, 0x17, 0x0c, 0x4a, 0x17, 0x0c, 0x4a, 0x40, 0x40, ++ 0x40, 0x1f, 0x12, 0x12, 0x40, 0x0f, 0x12, 0x14, 0x14, 0x25, 0x27, 0x15, 0x07, 0x13, 0x15, 0x0b, ++ 0x02, 0x39, 0x1a, 0x12, 0x40, 0x0f, 0x12, 0x14, 0x08, 0x12, 0x0e, 0x08, 0x08, 0x12, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x3e, 0x09, 0x42, 0x54, 0x40, 0x16, 0x43, 0x49, 0x25, 0x40, 0x42, 0x40, 0x40, 0x0c, 0x0f, ++ 0x42, 0x4a, 0x40, 0x0d, 0x50, 0x4a, 0x44, 0x07, 0x07, 0x07, 0x07, 0x0a, 0x32, 0x12, 0x0b, 0x07, ++ 0x56, 0x27, 0x07, 0x12, 0x40, 0x02, 0x0e, 0x40, 0x40, 0x40, 0x42, 0x42, 0x4c, 0x4e, 0x44, 0x4e, ++ 0x50, 0x48, 0x4c, 0x56, 0x56, 0x4a, 0x4c, 0x54, 0x56, 0x56, 0x4a, 0x01, 0x03, 0x40, 0x4c, 0x4e, ++ 0x44, 0x4e, 0x50, 0x48, 0x4c, 0x56, 0x56, 0x4a, 0x4c, 0x54, 0x56, 0x56, 0x4a, 0x01, 0x03, 0x40, ++ 0x13, 0x4a, 0x0b, 0x40, 0x45, 0x40, 0x42, 0x07, 0x42, 0x03, 0x03, 0x44, 0x44, 0x1a, 0x0c, 0x4a, ++ 0x15, 0x07, 0x40, 0x1a, 0x0c, 0x4a, 0x15, 0x07, 0x40, 0x1a, 0x0c, 0x4a, 0x15, 0x07, 0x40, 0x45, ++ 0x07, 0x05, 0x05, 0x0b, 0x13, 0x0b, 0x13, 0x12, 0x17, 0x0c, 0x4a, 0x17, 0x0c, 0x4a, 0x40, 0x40, ++ 0x40, 0x1e, 0x12, 0x12, 0x40, 0x0f, 0x12, 0x14, 0x14, 0x25, 0x27, 0x15, 0x07, 0x13, 0x15, 0x0b, ++ 0x02, 0x38, 0x1a, 0x12, 0x40, 0x0f, 0x12, 0x14, 0x09, 0x12, 0x0f, 0x09, 0x09, 0x12, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x3e, 0x0a, 0x41, 0x53, 0x40, 0x15, 0x44, 0x4a, 0x26, 0x40, 0x41, 0x40, 0x40, 0x0b, 0x0f, ++ 0x41, 0x48, 0x40, 0x0e, 0x4f, 0x48, 0x42, 0x09, 0x09, 0x07, 0x07, 0x09, 0x30, 0x11, 0x0c, 0x07, ++ 0x55, 0x27, 0x08, 0x11, 0x40, 0x01, 0x0d, 0x40, 0x40, 0x40, 0x41, 0x41, 0x4b, 0x4d, 0x43, 0x4d, ++ 0x4f, 0x47, 0x4b, 0x55, 0x55, 0x48, 0x4b, 0x53, 0x55, 0x55, 0x48, 0x02, 0x04, 0x00, 0x4b, 0x4d, ++ 0x43, 0x4d, 0x4f, 0x47, 0x4b, 0x55, 0x55, 0x48, 0x4b, 0x53, 0x55, 0x55, 0x48, 0x02, 0x04, 0x00, ++ 0x14, 0x49, 0x0d, 0x40, 0x46, 0x40, 0x41, 0x07, 0x41, 0x04, 0x04, 0x42, 0x43, 0x19, 0x0b, 0x49, ++ 0x16, 0x07, 0x40, 0x19, 0x0b, 0x49, 0x16, 0x07, 0x40, 0x19, 0x0b, 0x49, 0x16, 0x07, 0x40, 0x46, ++ 0x07, 0x06, 0x06, 0x0c, 0x14, 0x0c, 0x14, 0x11, 0x17, 0x0b, 0x49, 0x17, 0x0b, 0x49, 0x40, 0x40, ++ 0x40, 0x1d, 0x11, 0x11, 0x40, 0x0f, 0x11, 0x13, 0x13, 0x26, 0x27, 0x16, 0x07, 0x14, 0x16, 0x0c, ++ 0x01, 0x36, 0x19, 0x11, 0x40, 0x0f, 0x11, 0x13, 0x0a, 0x11, 0x10, 0x0a, 0x0a, 0x11, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x3e, 0x0b, 0x41, 0x52, 0x40, 0x14, 0x45, 0x4b, 0x26, 0x40, 0x41, 0x40, 0x40, 0x0a, 0x0f, ++ 0x41, 0x47, 0x40, 0x0e, 0x4d, 0x47, 0x40, 0x0c, 0x0c, 0x07, 0x07, 0x09, 0x2f, 0x11, 0x0d, 0x07, ++ 0x54, 0x27, 0x0a, 0x11, 0x40, 0x01, 0x0c, 0x40, 0x40, 0x40, 0x41, 0x41, 0x4a, 0x4c, 0x42, 0x4c, ++ 0x4d, 0x45, 0x4a, 0x54, 0x54, 0x47, 0x4a, 0x52, 0x54, 0x54, 0x47, 0x03, 0x05, 0x02, 0x4a, 0x4c, ++ 0x42, 0x4c, 0x4d, 0x45, 0x4a, 0x54, 0x54, 0x47, 0x4a, 0x52, 0x54, 0x54, 0x47, 0x03, 0x05, 0x02, ++ 0x15, 0x49, 0x0f, 0x40, 0x46, 0x40, 0x41, 0x07, 0x41, 0x05, 0x05, 0x40, 0x42, 0x19, 0x0a, 0x49, ++ 0x16, 0x07, 0x40, 0x19, 0x0a, 0x49, 0x16, 0x07, 0x40, 0x19, 0x0a, 0x49, 0x16, 0x07, 0x40, 0x46, ++ 0x07, 0x06, 0x06, 0x0d, 0x15, 0x0d, 0x15, 0x11, 0x17, 0x0a, 0x49, 0x17, 0x0a, 0x49, 0x40, 0x40, ++ 0x40, 0x1c, 0x11, 0x11, 0x40, 0x0f, 0x11, 0x12, 0x12, 0x26, 0x27, 0x16, 0x07, 0x15, 0x16, 0x0d, ++ 0x01, 0x35, 0x19, 0x11, 0x40, 0x0f, 0x11, 0x12, 0x0b, 0x11, 0x12, 0x0b, 0x0b, 0x11, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x3e, 0x0c, 0x41, 0x52, 0x40, 0x13, 0x45, 0x4c, 0x26, 0x40, 0x41, 0x40, 0x40, 0x0a, 0x0f, ++ 0x41, 0x45, 0x40, 0x0e, 0x4c, 0x45, 0x01, 0x0e, 0x0e, 0x07, 0x07, 0x09, 0x2d, 0x11, 0x0d, 0x07, ++ 0x53, 0x27, 0x0b, 0x11, 0x40, 0x01, 0x0b, 0x40, 0x40, 0x40, 0x41, 0x41, 0x4a, 0x4b, 0x42, 0x4b, ++ 0x4c, 0x44, 0x4a, 0x53, 0x53, 0x45, 0x4a, 0x52, 0x53, 0x53, 0x45, 0x04, 0x05, 0x03, 0x4a, 0x4b, ++ 0x42, 0x4b, 0x4c, 0x44, 0x4a, 0x53, 0x53, 0x45, 0x4a, 0x52, 0x53, 0x53, 0x45, 0x04, 0x05, 0x03, ++ 0x15, 0x49, 0x11, 0x40, 0x46, 0x40, 0x41, 0x07, 0x41, 0x05, 0x05, 0x01, 0x42, 0x19, 0x0a, 0x49, ++ 0x16, 0x07, 0x40, 0x19, 0x0a, 0x49, 0x16, 0x07, 0x40, 0x19, 0x0a, 0x49, 0x16, 0x07, 0x40, 0x46, ++ 0x07, 0x06, 0x06, 0x0d, 0x15, 0x0d, 0x15, 0x11, 0x17, 0x0a, 0x49, 0x17, 0x0a, 0x49, 0x40, 0x40, ++ 0x40, 0x1b, 0x11, 0x11, 0x40, 0x0f, 0x11, 0x12, 0x12, 0x26, 0x27, 0x16, 0x07, 0x15, 0x16, 0x0d, ++ 0x01, 0x34, 0x19, 0x11, 0x40, 0x0f, 0x11, 0x12, 0x0c, 0x11, 0x13, 0x0c, 0x0c, 0x11, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x3e, 0x0d, 0x40, 0x51, 0x40, 0x12, 0x46, 0x4d, 0x27, 0x40, 0x40, 0x40, 0x40, 0x09, 0x0f, ++ 0x40, 0x44, 0x40, 0x0f, 0x4b, 0x44, 0x03, 0x11, 0x11, 0x07, 0x07, 0x08, 0x2c, 0x10, 0x0e, 0x07, ++ 0x52, 0x27, 0x0c, 0x10, 0x40, 0x00, 0x0a, 0x40, 0x40, 0x40, 0x40, 0x40, 0x49, 0x4a, 0x41, 0x4a, ++ 0x4b, 0x43, 0x49, 0x52, 0x52, 0x44, 0x49, 0x51, 0x52, 0x52, 0x44, 0x05, 0x06, 0x04, 0x49, 0x4a, ++ 0x41, 0x4a, 0x4b, 0x43, 0x49, 0x52, 0x52, 0x44, 0x49, 0x51, 0x52, 0x52, 0x44, 0x05, 0x06, 0x04, ++ 0x16, 0x48, 0x13, 0x40, 0x47, 0x40, 0x40, 0x07, 0x40, 0x06, 0x06, 0x03, 0x41, 0x18, 0x09, 0x48, ++ 0x17, 0x07, 0x40, 0x18, 0x09, 0x48, 0x17, 0x07, 0x40, 0x18, 0x09, 0x48, 0x17, 0x07, 0x40, 0x47, ++ 0x07, 0x07, 0x07, 0x0e, 0x16, 0x0e, 0x16, 0x10, 0x17, 0x09, 0x48, 0x17, 0x09, 0x48, 0x40, 0x40, ++ 0x40, 0x1a, 0x10, 0x10, 0x40, 0x0f, 0x10, 0x11, 0x11, 0x27, 0x27, 0x17, 0x07, 0x16, 0x17, 0x0e, ++ 0x00, 0x33, 0x18, 0x10, 0x40, 0x0f, 0x10, 0x11, 0x0d, 0x10, 0x14, 0x0d, 0x0d, 0x10, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x3e, 0x0e, 0x40, 0x51, 0x40, 0x11, 0x47, 0x4e, 0x27, 0x40, 0x40, 0x40, 0x40, 0x08, 0x0f, ++ 0x40, 0x42, 0x40, 0x0f, 0x4a, 0x42, 0x04, 0x13, 0x13, 0x07, 0x07, 0x08, 0x2a, 0x10, 0x0e, 0x07, ++ 0x51, 0x27, 0x0d, 0x10, 0x40, 0x00, 0x09, 0x40, 0x40, 0x40, 0x40, 0x40, 0x49, 0x49, 0x41, 0x49, ++ 0x4a, 0x42, 0x49, 0x51, 0x51, 0x42, 0x49, 0x51, 0x51, 0x51, 0x42, 0x06, 0x06, 0x05, 0x49, 0x49, ++ 0x41, 0x49, 0x4a, 0x42, 0x49, 0x51, 0x51, 0x42, 0x49, 0x51, 0x51, 0x51, 0x42, 0x06, 0x06, 0x05, ++ 0x16, 0x48, 0x14, 0x40, 0x47, 0x40, 0x40, 0x07, 0x40, 0x06, 0x06, 0x04, 0x41, 0x18, 0x08, 0x48, ++ 0x17, 0x07, 0x40, 0x18, 0x08, 0x48, 0x17, 0x07, 0x40, 0x18, 0x08, 0x48, 0x17, 0x07, 0x40, 0x47, ++ 0x07, 0x07, 0x07, 0x0e, 0x16, 0x0e, 0x16, 0x10, 0x17, 0x08, 0x48, 0x17, 0x08, 0x48, 0x40, 0x40, ++ 0x40, 0x19, 0x10, 0x10, 0x40, 0x0f, 0x10, 0x10, 0x10, 0x27, 0x27, 0x17, 0x07, 0x16, 0x17, 0x0e, ++ 0x00, 0x31, 0x18, 0x10, 0x40, 0x0f, 0x10, 0x10, 0x0e, 0x10, 0x15, 0x0e, 0x0e, 0x10, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x3e, 0x0f, 0x40, 0x50, 0x40, 0x10, 0x47, 0x4f, 0x27, 0x40, 0x40, 0x40, 0x40, 0x08, 0x0f, ++ 0x40, 0x40, 0x40, 0x0f, 0x48, 0x40, 0x06, 0x16, 0x16, 0x07, 0x07, 0x08, 0x28, 0x10, 0x0f, 0x07, ++ 0x50, 0x27, 0x0f, 0x10, 0x40, 0x00, 0x08, 0x40, 0x40, 0x40, 0x40, 0x40, 0x48, 0x48, 0x40, 0x48, ++ 0x48, 0x40, 0x48, 0x50, 0x50, 0x40, 0x48, 0x50, 0x50, 0x50, 0x40, 0x07, 0x07, 0x07, 0x48, 0x48, ++ 0x40, 0x48, 0x48, 0x40, 0x48, 0x50, 0x50, 0x40, 0x48, 0x50, 0x50, 0x50, 0x40, 0x07, 0x07, 0x07, ++ 0x17, 0x48, 0x16, 0x40, 0x47, 0x40, 0x40, 0x07, 0x40, 0x07, 0x07, 0x06, 0x40, 0x18, 0x08, 0x48, ++ 0x17, 0x07, 0x40, 0x18, 0x08, 0x48, 0x17, 0x07, 0x40, 0x18, 0x08, 0x48, 0x17, 0x07, 0x40, 0x47, ++ 0x07, 0x07, 0x07, 0x0f, 0x17, 0x0f, 0x17, 0x10, 0x17, 0x08, 0x48, 0x17, 0x08, 0x48, 0x40, 0x40, ++ 0x40, 0x18, 0x10, 0x10, 0x40, 0x0f, 0x10, 0x10, 0x10, 0x27, 0x27, 0x17, 0x07, 0x17, 0x17, 0x0f, ++ 0x00, 0x30, 0x18, 0x10, 0x40, 0x0f, 0x10, 0x10, 0x0f, 0x10, 0x17, 0x0f, 0x0f, 0x10, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x3e, 0x10, 0x00, 0x4f, 0x40, 0x0f, 0x48, 0x50, 0x28, 0x40, 0x00, 0x40, 0x40, 0x07, 0x0f, ++ 0x00, 0x00, 0x40, 0x10, 0x47, 0x00, 0x08, 0x18, 0x18, 0x07, 0x07, 0x07, 0x27, 0x0f, 0x10, 0x07, ++ 0x4f, 0x27, 0x10, 0x0f, 0x40, 0x40, 0x07, 0x40, 0x40, 0x40, 0x00, 0x00, 0x47, 0x47, 0x00, 0x47, ++ 0x47, 0x00, 0x47, 0x4f, 0x4f, 0x00, 0x47, 0x4f, 0x4f, 0x4f, 0x00, 0x08, 0x08, 0x08, 0x47, 0x47, ++ 0x00, 0x47, 0x47, 0x00, 0x47, 0x4f, 0x4f, 0x00, 0x47, 0x4f, 0x4f, 0x4f, 0x00, 0x08, 0x08, 0x08, ++ 0x18, 0x47, 0x18, 0x40, 0x48, 0x40, 0x00, 0x07, 0x00, 0x08, 0x08, 0x08, 0x00, 0x17, 0x07, 0x47, ++ 0x18, 0x07, 0x40, 0x17, 0x07, 0x47, 0x18, 0x07, 0x40, 0x17, 0x07, 0x47, 0x18, 0x07, 0x40, 0x48, ++ 0x07, 0x08, 0x08, 0x10, 0x18, 0x10, 0x18, 0x0f, 0x17, 0x07, 0x47, 0x17, 0x07, 0x47, 0x40, 0x40, ++ 0x40, 0x17, 0x0f, 0x0f, 0x40, 0x0f, 0x0f, 0x0f, 0x0f, 0x28, 0x27, 0x18, 0x07, 0x18, 0x18, 0x10, ++ 0x40, 0x2f, 0x17, 0x0f, 0x40, 0x0f, 0x0f, 0x0f, 0x10, 0x0f, 0x18, 0x10, 0x10, 0x0f, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x3e, 0x11, 0x00, 0x4f, 0x40, 0x0e, 0x48, 0x51, 0x28, 0x40, 0x00, 0x40, 0x40, 0x07, 0x0f, ++ 0x00, 0x02, 0x40, 0x10, 0x46, 0x02, 0x0a, 0x1b, 0x1b, 0x07, 0x07, 0x07, 0x25, 0x0f, 0x10, 0x07, ++ 0x4e, 0x27, 0x11, 0x0f, 0x40, 0x40, 0x06, 0x40, 0x40, 0x40, 0x00, 0x00, 0x47, 0x46, 0x00, 0x46, ++ 0x46, 0x01, 0x47, 0x4e, 0x4e, 0x02, 0x47, 0x4f, 0x4e, 0x4e, 0x02, 0x09, 0x08, 0x09, 0x47, 0x46, ++ 0x00, 0x46, 0x46, 0x01, 0x47, 0x4e, 0x4e, 0x02, 0x47, 0x4f, 0x4e, 0x4e, 0x02, 0x09, 0x08, 0x09, ++ 0x18, 0x47, 0x1a, 0x40, 0x48, 0x40, 0x00, 0x07, 0x00, 0x08, 0x08, 0x0a, 0x00, 0x17, 0x07, 0x47, ++ 0x18, 0x07, 0x40, 0x17, 0x07, 0x47, 0x18, 0x07, 0x40, 0x17, 0x07, 0x47, 0x18, 0x07, 0x40, 0x48, ++ 0x07, 0x08, 0x08, 0x10, 0x18, 0x10, 0x18, 0x0f, 0x17, 0x07, 0x47, 0x17, 0x07, 0x47, 0x40, 0x40, ++ 0x40, 0x16, 0x0f, 0x0f, 0x40, 0x0f, 0x0f, 0x0f, 0x0f, 0x28, 0x27, 0x18, 0x07, 0x18, 0x18, 0x10, ++ 0x40, 0x2e, 0x17, 0x0f, 0x40, 0x0f, 0x0f, 0x0f, 0x11, 0x0f, 0x19, 0x11, 0x11, 0x0f, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x3e, 0x12, 0x00, 0x4e, 0x40, 0x0d, 0x49, 0x52, 0x28, 0x40, 0x00, 0x40, 0x40, 0x06, 0x0f, ++ 0x00, 0x03, 0x40, 0x10, 0x45, 0x03, 0x0c, 0x1d, 0x1d, 0x07, 0x07, 0x07, 0x24, 0x0f, 0x11, 0x07, ++ 0x4d, 0x27, 0x12, 0x0f, 0x40, 0x40, 0x05, 0x40, 0x40, 0x40, 0x00, 0x00, 0x46, 0x45, 0x01, 0x45, ++ 0x45, 0x02, 0x46, 0x4d, 0x4d, 0x03, 0x46, 0x4e, 0x4d, 0x4d, 0x03, 0x0a, 0x09, 0x0a, 0x46, 0x45, ++ 0x01, 0x45, 0x45, 0x02, 0x46, 0x4d, 0x4d, 0x03, 0x46, 0x4e, 0x4d, 0x4d, 0x03, 0x0a, 0x09, 0x0a, ++ 0x19, 0x47, 0x1c, 0x40, 0x48, 0x40, 0x00, 0x07, 0x00, 0x09, 0x09, 0x0c, 0x01, 0x17, 0x06, 0x47, ++ 0x18, 0x07, 0x40, 0x17, 0x06, 0x47, 0x18, 0x07, 0x40, 0x17, 0x06, 0x47, 0x18, 0x07, 0x40, 0x48, ++ 0x07, 0x08, 0x08, 0x11, 0x19, 0x11, 0x19, 0x0f, 0x17, 0x06, 0x47, 0x17, 0x06, 0x47, 0x40, 0x40, ++ 0x40, 0x15, 0x0f, 0x0f, 0x40, 0x0f, 0x0f, 0x0e, 0x0e, 0x28, 0x27, 0x18, 0x07, 0x19, 0x18, 0x11, ++ 0x40, 0x2c, 0x17, 0x0f, 0x40, 0x0f, 0x0f, 0x0e, 0x12, 0x0f, 0x1a, 0x12, 0x12, 0x0f, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x3e, 0x13, 0x01, 0x4d, 0x40, 0x0c, 0x4a, 0x53, 0x29, 0x40, 0x01, 0x40, 0x40, 0x05, 0x0f, ++ 0x01, 0x05, 0x40, 0x11, 0x43, 0x05, 0x0e, 0x20, 0x20, 0x07, 0x07, 0x06, 0x22, 0x0e, 0x12, 0x07, ++ 0x4c, 0x27, 0x14, 0x0e, 0x40, 0x41, 0x04, 0x40, 0x40, 0x40, 0x01, 0x01, 0x45, 0x44, 0x02, 0x44, ++ 0x43, 0x04, 0x45, 0x4c, 0x4c, 0x05, 0x45, 0x4d, 0x4c, 0x4c, 0x05, 0x0b, 0x0a, 0x0c, 0x45, 0x44, ++ 0x02, 0x44, 0x43, 0x04, 0x45, 0x4c, 0x4c, 0x05, 0x45, 0x4d, 0x4c, 0x4c, 0x05, 0x0b, 0x0a, 0x0c, ++ 0x1a, 0x46, 0x1e, 0x40, 0x49, 0x40, 0x01, 0x07, 0x01, 0x0a, 0x0a, 0x0e, 0x02, 0x16, 0x05, 0x46, ++ 0x19, 0x07, 0x40, 0x16, 0x05, 0x46, 0x19, 0x07, 0x40, 0x16, 0x05, 0x46, 0x19, 0x07, 0x40, 0x49, ++ 0x07, 0x09, 0x09, 0x12, 0x1a, 0x12, 0x1a, 0x0e, 0x17, 0x05, 0x46, 0x17, 0x05, 0x46, 0x40, 0x40, ++ 0x40, 0x14, 0x0e, 0x0e, 0x40, 0x0f, 0x0e, 0x0d, 0x0d, 0x29, 0x27, 0x19, 0x07, 0x1a, 0x19, 0x12, ++ 0x41, 0x2b, 0x16, 0x0e, 0x40, 0x0f, 0x0e, 0x0d, 0x13, 0x0e, 0x1c, 0x13, 0x13, 0x0e, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x3e, 0x14, 0x01, 0x4d, 0x40, 0x0b, 0x4a, 0x54, 0x29, 0x40, 0x01, 0x40, 0x40, 0x05, 0x0f, ++ 0x01, 0x06, 0x40, 0x11, 0x42, 0x06, 0x10, 0x22, 0x22, 0x07, 0x07, 0x06, 0x21, 0x0e, 0x12, 0x07, ++ 0x4b, 0x27, 0x15, 0x0e, 0x40, 0x41, 0x03, 0x40, 0x40, 0x40, 0x01, 0x01, 0x45, 0x43, 0x02, 0x43, ++ 0x42, 0x05, 0x45, 0x4b, 0x4b, 0x06, 0x45, 0x4d, 0x4b, 0x4b, 0x06, 0x0c, 0x0a, 0x0d, 0x45, 0x43, ++ 0x02, 0x43, 0x42, 0x05, 0x45, 0x4b, 0x4b, 0x06, 0x45, 0x4d, 0x4b, 0x4b, 0x06, 0x0c, 0x0a, 0x0d, ++ 0x1a, 0x46, 0x20, 0x40, 0x49, 0x40, 0x01, 0x07, 0x01, 0x0a, 0x0a, 0x10, 0x02, 0x16, 0x05, 0x46, ++ 0x19, 0x07, 0x40, 0x16, 0x05, 0x46, 0x19, 0x07, 0x40, 0x16, 0x05, 0x46, 0x19, 0x07, 0x40, 0x49, ++ 0x07, 0x09, 0x09, 0x12, 0x1a, 0x12, 0x1a, 0x0e, 0x17, 0x05, 0x46, 0x17, 0x05, 0x46, 0x40, 0x40, ++ 0x40, 0x13, 0x0e, 0x0e, 0x40, 0x0f, 0x0e, 0x0d, 0x0d, 0x29, 0x27, 0x19, 0x07, 0x1a, 0x19, 0x12, ++ 0x41, 0x2a, 0x16, 0x0e, 0x40, 0x0f, 0x0e, 0x0d, 0x14, 0x0e, 0x1d, 0x14, 0x14, 0x0e, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x3e, 0x15, 0x01, 0x4c, 0x40, 0x0a, 0x4b, 0x55, 0x29, 0x40, 0x01, 0x40, 0x40, 0x04, 0x0f, ++ 0x01, 0x08, 0x40, 0x11, 0x41, 0x08, 0x12, 0x25, 0x25, 0x07, 0x07, 0x06, 0x1f, 0x0e, 0x13, 0x07, ++ 0x4a, 0x27, 0x16, 0x0e, 0x40, 0x41, 0x02, 0x40, 0x40, 0x40, 0x01, 0x01, 0x44, 0x42, 0x03, 0x42, ++ 0x41, 0x06, 0x44, 0x4a, 0x4a, 0x08, 0x44, 0x4c, 0x4a, 0x4a, 0x08, 0x0d, 0x0b, 0x0e, 0x44, 0x42, ++ 0x03, 0x42, 0x41, 0x06, 0x44, 0x4a, 0x4a, 0x08, 0x44, 0x4c, 0x4a, 0x4a, 0x08, 0x0d, 0x0b, 0x0e, ++ 0x1b, 0x46, 0x22, 0x40, 0x49, 0x40, 0x01, 0x07, 0x01, 0x0b, 0x0b, 0x12, 0x03, 0x16, 0x04, 0x46, ++ 0x19, 0x07, 0x40, 0x16, 0x04, 0x46, 0x19, 0x07, 0x40, 0x16, 0x04, 0x46, 0x19, 0x07, 0x40, 0x49, ++ 0x07, 0x09, 0x09, 0x13, 0x1b, 0x13, 0x1b, 0x0e, 0x17, 0x04, 0x46, 0x17, 0x04, 0x46, 0x40, 0x40, ++ 0x40, 0x12, 0x0e, 0x0e, 0x40, 0x0f, 0x0e, 0x0c, 0x0c, 0x29, 0x27, 0x19, 0x07, 0x1b, 0x19, 0x13, ++ 0x41, 0x29, 0x16, 0x0e, 0x40, 0x0f, 0x0e, 0x0c, 0x15, 0x0e, 0x1e, 0x15, 0x15, 0x0e, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x3e, 0x15, 0x01, 0x4c, 0x40, 0x09, 0x4c, 0x56, 0x29, 0x40, 0x01, 0x40, 0x40, 0x03, 0x0f, ++ 0x01, 0x09, 0x40, 0x11, 0x40, 0x09, 0x13, 0x27, 0x27, 0x07, 0x07, 0x05, 0x1d, 0x0d, 0x13, 0x07, ++ 0x4a, 0x27, 0x17, 0x0d, 0x40, 0x42, 0x01, 0x40, 0x40, 0x40, 0x01, 0x01, 0x44, 0x42, 0x03, 0x42, ++ 0x40, 0x07, 0x44, 0x4a, 0x4a, 0x09, 0x44, 0x4c, 0x4a, 0x4a, 0x09, 0x0d, 0x0b, 0x0f, 0x44, 0x42, ++ 0x03, 0x42, 0x40, 0x07, 0x44, 0x4a, 0x4a, 0x09, 0x44, 0x4c, 0x4a, 0x4a, 0x09, 0x0d, 0x0b, 0x0f, ++ 0x1b, 0x46, 0x23, 0x40, 0x4a, 0x40, 0x01, 0x07, 0x01, 0x0b, 0x0b, 0x13, 0x03, 0x15, 0x03, 0x46, ++ 0x19, 0x07, 0x40, 0x15, 0x03, 0x46, 0x19, 0x07, 0x40, 0x15, 0x03, 0x46, 0x19, 0x07, 0x40, 0x4a, ++ 0x07, 0x09, 0x09, 0x13, 0x1b, 0x13, 0x1b, 0x0d, 0x17, 0x03, 0x46, 0x17, 0x03, 0x46, 0x40, 0x40, ++ 0x40, 0x11, 0x0d, 0x0d, 0x40, 0x0f, 0x0d, 0x0b, 0x0b, 0x29, 0x27, 0x19, 0x07, 0x1b, 0x19, 0x13, ++ 0x42, 0x27, 0x15, 0x0d, 0x40, 0x0f, 0x0d, 0x0b, 0x15, 0x0d, 0x1f, 0x15, 0x15, 0x0d, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x3e, 0x16, 0x02, 0x4b, 0x40, 0x09, 0x4c, 0x56, 0x2a, 0x40, 0x02, 0x40, 0x40, 0x03, 0x0f, ++ 0x02, 0x0b, 0x40, 0x12, 0x01, 0x0b, 0x15, 0x2a, 0x2a, 0x07, 0x07, 0x05, 0x1c, 0x0d, 0x14, 0x07, ++ 0x49, 0x27, 0x19, 0x0d, 0x40, 0x42, 0x01, 0x40, 0x40, 0x40, 0x02, 0x02, 0x43, 0x41, 0x04, 0x41, ++ 0x01, 0x09, 0x43, 0x49, 0x49, 0x0b, 0x43, 0x4b, 0x49, 0x49, 0x0b, 0x0e, 0x0c, 0x11, 0x43, 0x41, ++ 0x04, 0x41, 0x01, 0x09, 0x43, 0x49, 0x49, 0x0b, 0x43, 0x4b, 0x49, 0x49, 0x0b, 0x0e, 0x0c, 0x11, ++ 0x1c, 0x45, 0x25, 0x40, 0x4a, 0x40, 0x02, 0x07, 0x02, 0x0c, 0x0c, 0x15, 0x04, 0x15, 0x03, 0x45, ++ 0x1a, 0x07, 0x40, 0x15, 0x03, 0x45, 0x1a, 0x07, 0x40, 0x15, 0x03, 0x45, 0x1a, 0x07, 0x40, 0x4a, ++ 0x07, 0x0a, 0x0a, 0x14, 0x1c, 0x14, 0x1c, 0x0d, 0x17, 0x03, 0x45, 0x17, 0x03, 0x45, 0x40, 0x40, ++ 0x40, 0x11, 0x0d, 0x0d, 0x40, 0x0f, 0x0d, 0x0b, 0x0b, 0x2a, 0x27, 0x1a, 0x07, 0x1c, 0x1a, 0x14, ++ 0x42, 0x26, 0x15, 0x0d, 0x40, 0x0f, 0x0d, 0x0b, 0x16, 0x0d, 0x21, 0x16, 0x16, 0x0d, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x3e, 0x17, 0x02, 0x4a, 0x40, 0x08, 0x4d, 0x57, 0x2a, 0x40, 0x02, 0x40, 0x40, 0x02, 0x0f, ++ 0x02, 0x0d, 0x40, 0x12, 0x02, 0x0d, 0x17, 0x2c, 0x2c, 0x07, 0x07, 0x05, 0x1a, 0x0d, 0x15, 0x07, ++ 0x48, 0x27, 0x1a, 0x0d, 0x40, 0x42, 0x00, 0x40, 0x40, 0x40, 0x02, 0x02, 0x42, 0x40, 0x05, 0x40, ++ 0x02, 0x0a, 0x42, 0x48, 0x48, 0x0d, 0x42, 0x4a, 0x48, 0x48, 0x0d, 0x0f, 0x0d, 0x12, 0x42, 0x40, ++ 0x05, 0x40, 0x02, 0x0a, 0x42, 0x48, 0x48, 0x0d, 0x42, 0x4a, 0x48, 0x48, 0x0d, 0x0f, 0x0d, 0x12, ++ 0x1d, 0x45, 0x27, 0x40, 0x4a, 0x40, 0x02, 0x07, 0x02, 0x0d, 0x0d, 0x17, 0x05, 0x15, 0x02, 0x45, ++ 0x1a, 0x07, 0x40, 0x15, 0x02, 0x45, 0x1a, 0x07, 0x40, 0x15, 0x02, 0x45, 0x1a, 0x07, 0x40, 0x4a, ++ 0x07, 0x0a, 0x0a, 0x15, 0x1d, 0x15, 0x1d, 0x0d, 0x17, 0x02, 0x45, 0x17, 0x02, 0x45, 0x40, 0x40, ++ 0x40, 0x10, 0x0d, 0x0d, 0x40, 0x0f, 0x0d, 0x0a, 0x0a, 0x2a, 0x27, 0x1a, 0x07, 0x1d, 0x1a, 0x15, ++ 0x42, 0x25, 0x15, 0x0d, 0x40, 0x0f, 0x0d, 0x0a, 0x17, 0x0d, 0x22, 0x17, 0x17, 0x0d, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x3e, 0x18, 0x02, 0x4a, 0x40, 0x07, 0x4d, 0x58, 0x2a, 0x40, 0x02, 0x40, 0x40, 0x02, 0x0f, ++ 0x02, 0x0e, 0x40, 0x12, 0x03, 0x0e, 0x19, 0x2f, 0x2f, 0x07, 0x07, 0x05, 0x19, 0x0d, 0x15, 0x07, ++ 0x47, 0x27, 0x1b, 0x0d, 0x40, 0x42, 0x40, 0x40, 0x40, 0x40, 0x02, 0x02, 0x42, 0x00, 0x05, 0x00, ++ 0x03, 0x0b, 0x42, 0x47, 0x47, 0x0e, 0x42, 0x4a, 0x47, 0x47, 0x0e, 0x10, 0x0d, 0x13, 0x42, 0x00, ++ 0x05, 0x00, 0x03, 0x0b, 0x42, 0x47, 0x47, 0x0e, 0x42, 0x4a, 0x47, 0x47, 0x0e, 0x10, 0x0d, 0x13, ++ 0x1d, 0x45, 0x29, 0x40, 0x4a, 0x40, 0x02, 0x07, 0x02, 0x0d, 0x0d, 0x19, 0x05, 0x15, 0x02, 0x45, ++ 0x1a, 0x07, 0x40, 0x15, 0x02, 0x45, 0x1a, 0x07, 0x40, 0x15, 0x02, 0x45, 0x1a, 0x07, 0x40, 0x4a, ++ 0x07, 0x0a, 0x0a, 0x15, 0x1d, 0x15, 0x1d, 0x0d, 0x17, 0x02, 0x45, 0x17, 0x02, 0x45, 0x40, 0x40, ++ 0x40, 0x0f, 0x0d, 0x0d, 0x40, 0x0f, 0x0d, 0x0a, 0x0a, 0x2a, 0x27, 0x1a, 0x07, 0x1d, 0x1a, 0x15, ++ 0x42, 0x24, 0x15, 0x0d, 0x40, 0x0f, 0x0d, 0x0a, 0x18, 0x0d, 0x23, 0x18, 0x18, 0x0d, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x3e, 0x19, 0x03, 0x49, 0x40, 0x06, 0x4e, 0x59, 0x2b, 0x40, 0x03, 0x40, 0x40, 0x01, 0x0f, ++ 0x03, 0x10, 0x40, 0x13, 0x04, 0x10, 0x1b, 0x31, 0x31, 0x07, 0x07, 0x04, 0x17, 0x0c, 0x16, 0x07, ++ 0x46, 0x27, 0x1c, 0x0c, 0x40, 0x43, 0x41, 0x40, 0x40, 0x40, 0x03, 0x03, 0x41, 0x01, 0x06, 0x01, ++ 0x04, 0x0c, 0x41, 0x46, 0x46, 0x10, 0x41, 0x49, 0x46, 0x46, 0x10, 0x11, 0x0e, 0x14, 0x41, 0x01, ++ 0x06, 0x01, 0x04, 0x0c, 0x41, 0x46, 0x46, 0x10, 0x41, 0x49, 0x46, 0x46, 0x10, 0x11, 0x0e, 0x14, ++ 0x1e, 0x44, 0x2b, 0x40, 0x4b, 0x40, 0x03, 0x07, 0x03, 0x0e, 0x0e, 0x1b, 0x06, 0x14, 0x01, 0x44, ++ 0x1b, 0x07, 0x40, 0x14, 0x01, 0x44, 0x1b, 0x07, 0x40, 0x14, 0x01, 0x44, 0x1b, 0x07, 0x40, 0x4b, ++ 0x07, 0x0b, 0x0b, 0x16, 0x1e, 0x16, 0x1e, 0x0c, 0x17, 0x01, 0x44, 0x17, 0x01, 0x44, 0x40, 0x40, ++ 0x40, 0x0e, 0x0c, 0x0c, 0x40, 0x0f, 0x0c, 0x09, 0x09, 0x2b, 0x27, 0x1b, 0x07, 0x1e, 0x1b, 0x16, ++ 0x43, 0x22, 0x14, 0x0c, 0x40, 0x0f, 0x0c, 0x09, 0x19, 0x0c, 0x24, 0x19, 0x19, 0x0c, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x3e, 0x1a, 0x03, 0x48, 0x40, 0x05, 0x4f, 0x5a, 0x2b, 0x40, 0x03, 0x40, 0x40, 0x00, 0x0f, ++ 0x03, 0x11, 0x40, 0x13, 0x06, 0x11, 0x1d, 0x34, 0x34, 0x07, 0x07, 0x04, 0x16, 0x0c, 0x17, 0x07, ++ 0x45, 0x27, 0x1e, 0x0c, 0x40, 0x43, 0x42, 0x40, 0x40, 0x40, 0x03, 0x03, 0x40, 0x02, 0x07, 0x02, ++ 0x06, 0x0e, 0x40, 0x45, 0x45, 0x11, 0x40, 0x48, 0x45, 0x45, 0x11, 0x12, 0x0f, 0x16, 0x40, 0x02, ++ 0x07, 0x02, 0x06, 0x0e, 0x40, 0x45, 0x45, 0x11, 0x40, 0x48, 0x45, 0x45, 0x11, 0x12, 0x0f, 0x16, ++ 0x1f, 0x44, 0x2d, 0x40, 0x4b, 0x40, 0x03, 0x07, 0x03, 0x0f, 0x0f, 0x1d, 0x07, 0x14, 0x00, 0x44, ++ 0x1b, 0x07, 0x40, 0x14, 0x00, 0x44, 0x1b, 0x07, 0x40, 0x14, 0x00, 0x44, 0x1b, 0x07, 0x40, 0x4b, ++ 0x07, 0x0b, 0x0b, 0x17, 0x1f, 0x17, 0x1f, 0x0c, 0x17, 0x00, 0x44, 0x17, 0x00, 0x44, 0x40, 0x40, ++ 0x40, 0x0d, 0x0c, 0x0c, 0x40, 0x0f, 0x0c, 0x08, 0x08, 0x2b, 0x27, 0x1b, 0x07, 0x1f, 0x1b, 0x17, ++ 0x43, 0x21, 0x14, 0x0c, 0x40, 0x0f, 0x0c, 0x08, 0x1a, 0x0c, 0x26, 0x1a, 0x1a, 0x0c, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x3e, 0x1b, 0x03, 0x48, 0x40, 0x04, 0x4f, 0x5b, 0x2b, 0x40, 0x03, 0x40, 0x40, 0x00, 0x0f, ++ 0x03, 0x13, 0x40, 0x13, 0x07, 0x13, 0x1f, 0x36, 0x36, 0x07, 0x07, 0x04, 0x14, 0x0c, 0x17, 0x07, ++ 0x44, 0x27, 0x1f, 0x0c, 0x40, 0x43, 0x43, 0x40, 0x40, 0x40, 0x03, 0x03, 0x40, 0x03, 0x07, 0x03, ++ 0x07, 0x0f, 0x40, 0x44, 0x44, 0x13, 0x40, 0x48, 0x44, 0x44, 0x13, 0x13, 0x0f, 0x17, 0x40, 0x03, ++ 0x07, 0x03, 0x07, 0x0f, 0x40, 0x44, 0x44, 0x13, 0x40, 0x48, 0x44, 0x44, 0x13, 0x13, 0x0f, 0x17, ++ 0x1f, 0x44, 0x2f, 0x40, 0x4b, 0x40, 0x03, 0x07, 0x03, 0x0f, 0x0f, 0x1f, 0x07, 0x14, 0x00, 0x44, ++ 0x1b, 0x07, 0x40, 0x14, 0x00, 0x44, 0x1b, 0x07, 0x40, 0x14, 0x00, 0x44, 0x1b, 0x07, 0x40, 0x4b, ++ 0x07, 0x0b, 0x0b, 0x17, 0x1f, 0x17, 0x1f, 0x0c, 0x17, 0x00, 0x44, 0x17, 0x00, 0x44, 0x40, 0x40, ++ 0x40, 0x0c, 0x0c, 0x0c, 0x40, 0x0f, 0x0c, 0x08, 0x08, 0x2b, 0x27, 0x1b, 0x07, 0x1f, 0x1b, 0x17, ++ 0x43, 0x20, 0x14, 0x0c, 0x40, 0x0f, 0x0c, 0x08, 0x1b, 0x0c, 0x27, 0x1b, 0x1b, 0x0c, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x3e, 0x1c, 0x04, 0x47, 0x40, 0x03, 0x50, 0x5c, 0x2c, 0x40, 0x04, 0x40, 0x40, 0x40, 0x0f, ++ 0x04, 0x14, 0x40, 0x14, 0x08, 0x14, 0x21, 0x39, 0x39, 0x07, 0x07, 0x03, 0x13, 0x0b, 0x18, 0x07, ++ 0x43, 0x27, 0x20, 0x0b, 0x40, 0x44, 0x44, 0x40, 0x40, 0x40, 0x04, 0x04, 0x00, 0x04, 0x08, 0x04, ++ 0x08, 0x10, 0x00, 0x43, 0x43, 0x14, 0x00, 0x47, 0x43, 0x43, 0x14, 0x14, 0x10, 0x18, 0x00, 0x04, ++ 0x08, 0x04, 0x08, 0x10, 0x00, 0x43, 0x43, 0x14, 0x00, 0x47, 0x43, 0x43, 0x14, 0x14, 0x10, 0x18, ++ 0x20, 0x43, 0x31, 0x40, 0x4c, 0x40, 0x04, 0x07, 0x04, 0x10, 0x10, 0x21, 0x08, 0x13, 0x40, 0x43, ++ 0x1c, 0x07, 0x40, 0x13, 0x40, 0x43, 0x1c, 0x07, 0x40, 0x13, 0x40, 0x43, 0x1c, 0x07, 0x40, 0x4c, ++ 0x07, 0x0c, 0x0c, 0x18, 0x20, 0x18, 0x20, 0x0b, 0x17, 0x40, 0x43, 0x17, 0x40, 0x43, 0x40, 0x40, ++ 0x40, 0x0b, 0x0b, 0x0b, 0x40, 0x0f, 0x0b, 0x07, 0x07, 0x2c, 0x27, 0x1c, 0x07, 0x20, 0x1c, 0x18, ++ 0x44, 0x1f, 0x13, 0x0b, 0x40, 0x0f, 0x0b, 0x07, 0x1c, 0x0b, 0x28, 0x1c, 0x1c, 0x0b, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x3e, 0x1d, 0x04, 0x47, 0x40, 0x02, 0x51, 0x5d, 0x2c, 0x40, 0x04, 0x40, 0x40, 0x41, 0x0f, ++ 0x04, 0x16, 0x40, 0x14, 0x09, 0x16, 0x22, 0x3b, 0x3b, 0x07, 0x07, 0x03, 0x11, 0x0b, 0x18, 0x07, ++ 0x42, 0x27, 0x21, 0x0b, 0x40, 0x44, 0x45, 0x40, 0x40, 0x40, 0x04, 0x04, 0x00, 0x05, 0x08, 0x05, ++ 0x09, 0x11, 0x00, 0x42, 0x42, 0x16, 0x00, 0x47, 0x42, 0x42, 0x16, 0x15, 0x10, 0x19, 0x00, 0x05, ++ 0x08, 0x05, 0x09, 0x11, 0x00, 0x42, 0x42, 0x16, 0x00, 0x47, 0x42, 0x42, 0x16, 0x15, 0x10, 0x19, ++ 0x20, 0x43, 0x32, 0x40, 0x4c, 0x40, 0x04, 0x07, 0x04, 0x10, 0x10, 0x22, 0x08, 0x13, 0x41, 0x43, ++ 0x1c, 0x07, 0x40, 0x13, 0x41, 0x43, 0x1c, 0x07, 0x40, 0x13, 0x41, 0x43, 0x1c, 0x07, 0x40, 0x4c, ++ 0x07, 0x0c, 0x0c, 0x18, 0x20, 0x18, 0x20, 0x0b, 0x17, 0x41, 0x43, 0x17, 0x41, 0x43, 0x40, 0x40, ++ 0x40, 0x0a, 0x0b, 0x0b, 0x40, 0x0f, 0x0b, 0x06, 0x06, 0x2c, 0x27, 0x1c, 0x07, 0x20, 0x1c, 0x18, ++ 0x44, 0x1d, 0x13, 0x0b, 0x40, 0x0f, 0x0b, 0x06, 0x1d, 0x0b, 0x29, 0x1d, 0x1d, 0x0b, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x3e, 0x1e, 0x04, 0x46, 0x40, 0x01, 0x51, 0x5e, 0x2c, 0x40, 0x04, 0x40, 0x40, 0x41, 0x0f, ++ 0x04, 0x18, 0x40, 0x14, 0x0b, 0x18, 0x24, 0x3e, 0x3e, 0x07, 0x07, 0x03, 0x0f, 0x0b, 0x19, 0x07, ++ 0x41, 0x27, 0x23, 0x0b, 0x40, 0x44, 0x46, 0x40, 0x40, 0x40, 0x04, 0x04, 0x01, 0x06, 0x09, 0x06, ++ 0x0b, 0x13, 0x01, 0x41, 0x41, 0x18, 0x01, 0x46, 0x41, 0x41, 0x18, 0x16, 0x11, 0x1b, 0x01, 0x06, ++ 0x09, 0x06, 0x0b, 0x13, 0x01, 0x41, 0x41, 0x18, 0x01, 0x46, 0x41, 0x41, 0x18, 0x16, 0x11, 0x1b, ++ 0x21, 0x43, 0x34, 0x40, 0x4c, 0x40, 0x04, 0x07, 0x04, 0x11, 0x11, 0x24, 0x09, 0x13, 0x41, 0x43, ++ 0x1c, 0x07, 0x40, 0x13, 0x41, 0x43, 0x1c, 0x07, 0x40, 0x13, 0x41, 0x43, 0x1c, 0x07, 0x40, 0x4c, ++ 0x07, 0x0c, 0x0c, 0x19, 0x21, 0x19, 0x21, 0x0b, 0x17, 0x41, 0x43, 0x17, 0x41, 0x43, 0x40, 0x40, ++ 0x40, 0x09, 0x0b, 0x0b, 0x40, 0x0f, 0x0b, 0x06, 0x06, 0x2c, 0x27, 0x1c, 0x07, 0x21, 0x1c, 0x19, ++ 0x44, 0x1c, 0x13, 0x0b, 0x40, 0x0f, 0x0b, 0x06, 0x1e, 0x0b, 0x2b, 0x1e, 0x1e, 0x0b, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x3e, 0x1f, 0x05, 0x45, 0x40, 0x00, 0x52, 0x5f, 0x2d, 0x40, 0x05, 0x40, 0x40, 0x42, 0x0f, ++ 0x05, 0x19, 0x40, 0x15, 0x0c, 0x19, 0x26, 0x3e, 0x3e, 0x07, 0x07, 0x02, 0x0e, 0x0a, 0x1a, 0x07, ++ 0x40, 0x27, 0x24, 0x0a, 0x40, 0x45, 0x47, 0x40, 0x40, 0x40, 0x05, 0x05, 0x02, 0x07, 0x0a, 0x07, ++ 0x0c, 0x14, 0x02, 0x40, 0x40, 0x19, 0x02, 0x45, 0x40, 0x40, 0x19, 0x17, 0x12, 0x1c, 0x02, 0x07, ++ 0x0a, 0x07, 0x0c, 0x14, 0x02, 0x40, 0x40, 0x19, 0x02, 0x45, 0x40, 0x40, 0x19, 0x17, 0x12, 0x1c, ++ 0x22, 0x42, 0x36, 0x40, 0x4d, 0x40, 0x05, 0x07, 0x05, 0x12, 0x12, 0x26, 0x0a, 0x12, 0x42, 0x42, ++ 0x1d, 0x07, 0x40, 0x12, 0x42, 0x42, 0x1d, 0x07, 0x40, 0x12, 0x42, 0x42, 0x1d, 0x07, 0x40, 0x4d, ++ 0x07, 0x0d, 0x0d, 0x1a, 0x22, 0x1a, 0x22, 0x0a, 0x17, 0x42, 0x42, 0x17, 0x42, 0x42, 0x40, 0x40, ++ 0x40, 0x08, 0x0a, 0x0a, 0x40, 0x0f, 0x0a, 0x05, 0x05, 0x2d, 0x27, 0x1d, 0x07, 0x22, 0x1d, 0x1a, ++ 0x45, 0x1b, 0x12, 0x0a, 0x40, 0x0f, 0x0a, 0x05, 0x1f, 0x0a, 0x2c, 0x1f, 0x1f, 0x0a, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x3e, 0x20, 0x05, 0x45, 0x40, 0x40, 0x52, 0x60, 0x2d, 0x40, 0x05, 0x40, 0x40, 0x42, 0x0f, ++ 0x05, 0x1b, 0x40, 0x15, 0x0d, 0x1b, 0x28, 0x3e, 0x3e, 0x07, 0x07, 0x02, 0x0c, 0x0a, 0x1a, 0x07, ++ 0x00, 0x27, 0x25, 0x0a, 0x40, 0x45, 0x48, 0x40, 0x40, 0x40, 0x05, 0x05, 0x02, 0x08, 0x0a, 0x08, ++ 0x0d, 0x15, 0x02, 0x00, 0x00, 0x1b, 0x02, 0x45, 0x00, 0x00, 0x1b, 0x18, 0x12, 0x1d, 0x02, 0x08, ++ 0x0a, 0x08, 0x0d, 0x15, 0x02, 0x00, 0x00, 0x1b, 0x02, 0x45, 0x00, 0x00, 0x1b, 0x18, 0x12, 0x1d, ++ 0x22, 0x42, 0x38, 0x40, 0x4d, 0x40, 0x05, 0x07, 0x05, 0x12, 0x12, 0x28, 0x0a, 0x12, 0x42, 0x42, ++ 0x1d, 0x07, 0x40, 0x12, 0x42, 0x42, 0x1d, 0x07, 0x40, 0x12, 0x42, 0x42, 0x1d, 0x07, 0x40, 0x4d, ++ 0x07, 0x0d, 0x0d, 0x1a, 0x22, 0x1a, 0x22, 0x0a, 0x17, 0x42, 0x42, 0x17, 0x42, 0x42, 0x40, 0x40, ++ 0x40, 0x07, 0x0a, 0x0a, 0x40, 0x0f, 0x0a, 0x05, 0x05, 0x2d, 0x27, 0x1d, 0x07, 0x22, 0x1d, 0x1a, ++ 0x45, 0x1a, 0x12, 0x0a, 0x40, 0x0f, 0x0a, 0x05, 0x20, 0x0a, 0x2d, 0x20, 0x20, 0x0a, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x3e, 0x21, 0x05, 0x44, 0x40, 0x41, 0x53, 0x61, 0x2d, 0x40, 0x05, 0x40, 0x40, 0x43, 0x0f, ++ 0x05, 0x1c, 0x40, 0x15, 0x0e, 0x1c, 0x2a, 0x3e, 0x3e, 0x07, 0x07, 0x02, 0x0b, 0x0a, 0x1b, 0x07, ++ 0x01, 0x27, 0x26, 0x0a, 0x40, 0x45, 0x49, 0x40, 0x40, 0x40, 0x05, 0x05, 0x03, 0x09, 0x0b, 0x09, ++ 0x0e, 0x16, 0x03, 0x01, 0x01, 0x1c, 0x03, 0x44, 0x01, 0x01, 0x1c, 0x19, 0x13, 0x1e, 0x03, 0x09, ++ 0x0b, 0x09, 0x0e, 0x16, 0x03, 0x01, 0x01, 0x1c, 0x03, 0x44, 0x01, 0x01, 0x1c, 0x19, 0x13, 0x1e, ++ 0x23, 0x42, 0x3a, 0x40, 0x4d, 0x40, 0x05, 0x07, 0x05, 0x13, 0x13, 0x2a, 0x0b, 0x12, 0x43, 0x42, ++ 0x1d, 0x07, 0x40, 0x12, 0x43, 0x42, 0x1d, 0x07, 0x40, 0x12, 0x43, 0x42, 0x1d, 0x07, 0x40, 0x4d, ++ 0x07, 0x0d, 0x0d, 0x1b, 0x23, 0x1b, 0x23, 0x0a, 0x17, 0x43, 0x42, 0x17, 0x43, 0x42, 0x40, 0x40, ++ 0x40, 0x06, 0x0a, 0x0a, 0x40, 0x0f, 0x0a, 0x04, 0x04, 0x2d, 0x27, 0x1d, 0x07, 0x23, 0x1d, 0x1b, ++ 0x45, 0x18, 0x12, 0x0a, 0x40, 0x0f, 0x0a, 0x04, 0x21, 0x0a, 0x2e, 0x21, 0x21, 0x0a, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x3e, 0x22, 0x06, 0x43, 0x40, 0x42, 0x54, 0x62, 0x2e, 0x40, 0x06, 0x40, 0x40, 0x44, 0x0f, ++ 0x06, 0x1e, 0x40, 0x16, 0x10, 0x1e, 0x2c, 0x3e, 0x3e, 0x07, 0x07, 0x01, 0x09, 0x09, 0x1c, 0x07, ++ 0x02, 0x27, 0x28, 0x09, 0x40, 0x46, 0x4a, 0x40, 0x40, 0x40, 0x06, 0x06, 0x04, 0x0a, 0x0c, 0x0a, ++ 0x10, 0x18, 0x04, 0x02, 0x02, 0x1e, 0x04, 0x43, 0x02, 0x02, 0x1e, 0x1a, 0x14, 0x20, 0x04, 0x0a, ++ 0x0c, 0x0a, 0x10, 0x18, 0x04, 0x02, 0x02, 0x1e, 0x04, 0x43, 0x02, 0x02, 0x1e, 0x1a, 0x14, 0x20, ++ 0x24, 0x41, 0x3c, 0x40, 0x4e, 0x40, 0x06, 0x07, 0x06, 0x14, 0x14, 0x2c, 0x0c, 0x11, 0x44, 0x41, ++ 0x1e, 0x07, 0x40, 0x11, 0x44, 0x41, 0x1e, 0x07, 0x40, 0x11, 0x44, 0x41, 0x1e, 0x07, 0x40, 0x4e, ++ 0x07, 0x0e, 0x0e, 0x1c, 0x24, 0x1c, 0x24, 0x09, 0x17, 0x44, 0x41, 0x17, 0x44, 0x41, 0x40, 0x40, ++ 0x40, 0x05, 0x09, 0x09, 0x40, 0x0f, 0x09, 0x03, 0x03, 0x2e, 0x27, 0x1e, 0x07, 0x24, 0x1e, 0x1c, ++ 0x46, 0x17, 0x11, 0x09, 0x40, 0x0f, 0x09, 0x03, 0x22, 0x09, 0x30, 0x22, 0x22, 0x09, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x3e, 0x23, 0x06, 0x43, 0x40, 0x43, 0x54, 0x63, 0x2e, 0x40, 0x06, 0x40, 0x40, 0x44, 0x0f, ++ 0x06, 0x1f, 0x40, 0x16, 0x11, 0x1f, 0x2e, 0x3e, 0x3e, 0x07, 0x07, 0x01, 0x08, 0x09, 0x1c, 0x07, ++ 0x03, 0x27, 0x29, 0x09, 0x40, 0x46, 0x4b, 0x40, 0x40, 0x40, 0x06, 0x06, 0x04, 0x0b, 0x0c, 0x0b, ++ 0x11, 0x19, 0x04, 0x03, 0x03, 0x1f, 0x04, 0x43, 0x03, 0x03, 0x1f, 0x1b, 0x14, 0x21, 0x04, 0x0b, ++ 0x0c, 0x0b, 0x11, 0x19, 0x04, 0x03, 0x03, 0x1f, 0x04, 0x43, 0x03, 0x03, 0x1f, 0x1b, 0x14, 0x21, ++ 0x24, 0x41, 0x3e, 0x40, 0x4e, 0x40, 0x06, 0x07, 0x06, 0x14, 0x14, 0x2e, 0x0c, 0x11, 0x44, 0x41, ++ 0x1e, 0x07, 0x40, 0x11, 0x44, 0x41, 0x1e, 0x07, 0x40, 0x11, 0x44, 0x41, 0x1e, 0x07, 0x40, 0x4e, ++ 0x07, 0x0e, 0x0e, 0x1c, 0x24, 0x1c, 0x24, 0x09, 0x17, 0x44, 0x41, 0x17, 0x44, 0x41, 0x40, 0x40, ++ 0x40, 0x04, 0x09, 0x09, 0x40, 0x0f, 0x09, 0x03, 0x03, 0x2e, 0x27, 0x1e, 0x07, 0x24, 0x1e, 0x1c, ++ 0x46, 0x16, 0x11, 0x09, 0x40, 0x0f, 0x09, 0x03, 0x23, 0x09, 0x31, 0x23, 0x23, 0x09, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x3e, 0x24, 0x06, 0x42, 0x40, 0x44, 0x55, 0x64, 0x2e, 0x40, 0x06, 0x40, 0x40, 0x45, 0x0f, ++ 0x06, 0x21, 0x40, 0x16, 0x12, 0x21, 0x30, 0x3e, 0x3e, 0x07, 0x07, 0x01, 0x06, 0x09, 0x1d, 0x07, ++ 0x04, 0x27, 0x2a, 0x09, 0x40, 0x46, 0x4c, 0x40, 0x40, 0x40, 0x06, 0x06, 0x05, 0x0c, 0x0d, 0x0c, ++ 0x12, 0x1a, 0x05, 0x04, 0x04, 0x21, 0x05, 0x42, 0x04, 0x04, 0x21, 0x1c, 0x15, 0x22, 0x05, 0x0c, ++ 0x0d, 0x0c, 0x12, 0x1a, 0x05, 0x04, 0x04, 0x21, 0x05, 0x42, 0x04, 0x04, 0x21, 0x1c, 0x15, 0x22, ++ 0x25, 0x41, 0x3e, 0x40, 0x4e, 0x40, 0x06, 0x07, 0x06, 0x15, 0x15, 0x30, 0x0d, 0x11, 0x45, 0x41, ++ 0x1e, 0x07, 0x40, 0x11, 0x45, 0x41, 0x1e, 0x07, 0x40, 0x11, 0x45, 0x41, 0x1e, 0x07, 0x40, 0x4e, ++ 0x07, 0x0e, 0x0e, 0x1d, 0x25, 0x1d, 0x25, 0x09, 0x17, 0x45, 0x41, 0x17, 0x45, 0x41, 0x40, 0x40, ++ 0x40, 0x03, 0x09, 0x09, 0x40, 0x0f, 0x09, 0x02, 0x02, 0x2e, 0x27, 0x1e, 0x07, 0x25, 0x1e, 0x1d, ++ 0x46, 0x15, 0x11, 0x09, 0x40, 0x0f, 0x09, 0x02, 0x24, 0x09, 0x32, 0x24, 0x24, 0x09, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x3e, 0x24, 0x06, 0x42, 0x40, 0x45, 0x56, 0x65, 0x2e, 0x40, 0x06, 0x40, 0x40, 0x46, 0x0f, ++ 0x06, 0x22, 0x40, 0x16, 0x13, 0x22, 0x31, 0x3e, 0x3e, 0x07, 0x07, 0x00, 0x04, 0x08, 0x1d, 0x07, ++ 0x04, 0x27, 0x2b, 0x08, 0x40, 0x47, 0x4d, 0x40, 0x40, 0x40, 0x06, 0x06, 0x05, 0x0c, 0x0d, 0x0c, ++ 0x13, 0x1b, 0x05, 0x04, 0x04, 0x22, 0x05, 0x42, 0x04, 0x04, 0x22, 0x1c, 0x15, 0x23, 0x05, 0x0c, ++ 0x0d, 0x0c, 0x13, 0x1b, 0x05, 0x04, 0x04, 0x22, 0x05, 0x42, 0x04, 0x04, 0x22, 0x1c, 0x15, 0x23, ++ 0x25, 0x41, 0x3e, 0x40, 0x4f, 0x40, 0x06, 0x07, 0x06, 0x15, 0x15, 0x31, 0x0d, 0x10, 0x46, 0x41, ++ 0x1e, 0x07, 0x40, 0x10, 0x46, 0x41, 0x1e, 0x07, 0x40, 0x10, 0x46, 0x41, 0x1e, 0x07, 0x40, 0x4f, ++ 0x07, 0x0e, 0x0e, 0x1d, 0x25, 0x1d, 0x25, 0x08, 0x17, 0x46, 0x41, 0x17, 0x46, 0x41, 0x40, 0x40, ++ 0x40, 0x02, 0x08, 0x08, 0x40, 0x0f, 0x08, 0x01, 0x01, 0x2e, 0x27, 0x1e, 0x07, 0x25, 0x1e, 0x1d, ++ 0x47, 0x13, 0x10, 0x08, 0x40, 0x0f, 0x08, 0x01, 0x24, 0x08, 0x33, 0x24, 0x24, 0x08, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x3e, 0x25, 0x07, 0x41, 0x40, 0x45, 0x56, 0x65, 0x2f, 0x40, 0x07, 0x40, 0x40, 0x46, 0x0f, ++ 0x07, 0x24, 0x40, 0x17, 0x15, 0x24, 0x33, 0x3e, 0x3e, 0x07, 0x07, 0x00, 0x03, 0x08, 0x1e, 0x07, ++ 0x05, 0x27, 0x2d, 0x08, 0x40, 0x47, 0x4d, 0x40, 0x40, 0x40, 0x07, 0x07, 0x06, 0x0d, 0x0e, 0x0d, ++ 0x15, 0x1d, 0x06, 0x05, 0x05, 0x24, 0x06, 0x41, 0x05, 0x05, 0x24, 0x1d, 0x16, 0x25, 0x06, 0x0d, ++ 0x0e, 0x0d, 0x15, 0x1d, 0x06, 0x05, 0x05, 0x24, 0x06, 0x41, 0x05, 0x05, 0x24, 0x1d, 0x16, 0x25, ++ 0x26, 0x40, 0x3e, 0x40, 0x4f, 0x40, 0x07, 0x07, 0x07, 0x16, 0x16, 0x33, 0x0e, 0x10, 0x46, 0x40, ++ 0x1f, 0x07, 0x40, 0x10, 0x46, 0x40, 0x1f, 0x07, 0x40, 0x10, 0x46, 0x40, 0x1f, 0x07, 0x40, 0x4f, ++ 0x07, 0x0f, 0x0f, 0x1e, 0x26, 0x1e, 0x26, 0x08, 0x17, 0x46, 0x40, 0x17, 0x46, 0x40, 0x40, 0x40, ++ 0x40, 0x02, 0x08, 0x08, 0x40, 0x0f, 0x08, 0x01, 0x01, 0x2f, 0x27, 0x1f, 0x07, 0x26, 0x1f, 0x1e, ++ 0x47, 0x12, 0x10, 0x08, 0x40, 0x0f, 0x08, 0x01, 0x25, 0x08, 0x35, 0x25, 0x25, 0x08, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x3e, 0x26, 0x07, 0x40, 0x40, 0x46, 0x57, 0x66, 0x2f, 0x40, 0x07, 0x40, 0x40, 0x47, 0x0f, ++ 0x07, 0x26, 0x40, 0x17, 0x16, 0x26, 0x35, 0x3e, 0x3e, 0x07, 0x07, 0x00, 0x01, 0x08, 0x1f, 0x07, ++ 0x06, 0x27, 0x2e, 0x08, 0x40, 0x47, 0x4e, 0x40, 0x40, 0x40, 0x07, 0x07, 0x07, 0x0e, 0x0f, 0x0e, ++ 0x16, 0x1e, 0x07, 0x06, 0x06, 0x26, 0x07, 0x40, 0x06, 0x06, 0x26, 0x1e, 0x17, 0x26, 0x07, 0x0e, ++ 0x0f, 0x0e, 0x16, 0x1e, 0x07, 0x06, 0x06, 0x26, 0x07, 0x40, 0x06, 0x06, 0x26, 0x1e, 0x17, 0x26, ++ 0x27, 0x40, 0x3e, 0x40, 0x4f, 0x40, 0x07, 0x07, 0x07, 0x17, 0x17, 0x35, 0x0f, 0x10, 0x47, 0x40, ++ 0x1f, 0x07, 0x40, 0x10, 0x47, 0x40, 0x1f, 0x07, 0x40, 0x10, 0x47, 0x40, 0x1f, 0x07, 0x40, 0x4f, ++ 0x07, 0x0f, 0x0f, 0x1f, 0x27, 0x1f, 0x27, 0x08, 0x17, 0x47, 0x40, 0x17, 0x47, 0x40, 0x40, 0x40, ++ 0x40, 0x01, 0x08, 0x08, 0x40, 0x0f, 0x08, 0x00, 0x00, 0x2f, 0x27, 0x1f, 0x07, 0x27, 0x1f, 0x1f, ++ 0x47, 0x11, 0x10, 0x08, 0x40, 0x0f, 0x08, 0x00, 0x26, 0x08, 0x36, 0x26, 0x26, 0x08, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x3e, 0x27, 0x07, 0x40, 0x40, 0x47, 0x57, 0x67, 0x2f, 0x40, 0x07, 0x40, 0x40, 0x47, 0x0f, ++ 0x07, 0x27, 0x40, 0x17, 0x17, 0x27, 0x37, 0x3e, 0x3e, 0x07, 0x07, 0x00, 0x00, 0x08, 0x1f, 0x07, ++ 0x07, 0x27, 0x2f, 0x08, 0x40, 0x47, 0x4f, 0x40, 0x40, 0x40, 0x07, 0x07, 0x07, 0x0f, 0x0f, 0x0f, ++ 0x17, 0x1f, 0x07, 0x07, 0x07, 0x27, 0x07, 0x40, 0x07, 0x07, 0x27, 0x1f, 0x17, 0x27, 0x07, 0x0f, ++ 0x0f, 0x0f, 0x17, 0x1f, 0x07, 0x07, 0x07, 0x27, 0x07, 0x40, 0x07, 0x07, 0x27, 0x1f, 0x17, 0x27, ++ 0x27, 0x40, 0x3e, 0x40, 0x4f, 0x40, 0x07, 0x07, 0x07, 0x17, 0x17, 0x37, 0x0f, 0x10, 0x47, 0x40, ++ 0x1f, 0x07, 0x40, 0x10, 0x47, 0x40, 0x1f, 0x07, 0x40, 0x10, 0x47, 0x40, 0x1f, 0x07, 0x40, 0x4f, ++ 0x07, 0x0f, 0x0f, 0x1f, 0x27, 0x1f, 0x27, 0x08, 0x17, 0x47, 0x40, 0x17, 0x47, 0x40, 0x40, 0x40, ++ 0x40, 0x00, 0x08, 0x08, 0x40, 0x0f, 0x08, 0x00, 0x00, 0x2f, 0x27, 0x1f, 0x07, 0x27, 0x1f, 0x1f, ++ 0x47, 0x10, 0x10, 0x08, 0x40, 0x0f, 0x08, 0x00, 0x27, 0x08, 0x37, 0x27, 0x27, 0x08, 0x40, 0x40, ++ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++}; ++ ++static void set_ps_field(u32 *buf, struct rkvdec_ps_field field, u32 value) ++{ ++ u8 bit = field.offset % 32, word = field.offset / 32; ++ u64 mask = GENMASK_ULL(bit + field.len - 1, bit); ++ u64 val = ((u64)value << bit) & mask; ++ ++ buf[word] &= ~mask; ++ buf[word] |= val; ++ if (bit + field.len > 32) { ++ buf[word + 1] &= ~(mask >> 32); ++ buf[word + 1] |= val >> 32; ++ } ++} ++ ++static void assemble_hw_pps(struct rkvdec_ctx *ctx, ++ struct rkvdec_hevc_run *run) ++{ ++ struct rkvdec_hevc_ctx *hevc_ctx = ctx->priv; ++ const struct v4l2_ctrl_hevc_sps *sps = run->sps; ++ const struct v4l2_ctrl_hevc_pps *pps = run->pps; ++ struct rkvdec_hevc_priv_tbl *priv_tbl = hevc_ctx->priv_tbl.cpu; ++ struct rkvdec_sps_pps_packet *hw_ps; ++ u32 min_cb_log2_size_y, ctb_log2_size_y, ctb_size_y; ++ u32 log2_min_cu_qp_delta_size; ++ dma_addr_t scaling_list_address; ++ u32 scaling_distance; ++ int i; ++ ++ /* ++ * HW read the SPS/PPS information from PPS packet index by PPS id. ++ * offset from the base can be calculated by PPS_id * 80 (size per PPS ++ * packet unit). so the driver copy SPS/PPS information to the exact PPS ++ * packet unit for HW accessing. ++ */ ++ hw_ps = &priv_tbl->param_set[pps->pic_parameter_set_id]; ++ memset(hw_ps, 0, sizeof(*hw_ps)); ++ ++ min_cb_log2_size_y = sps->log2_min_luma_coding_block_size_minus3 + 3; ++ ctb_log2_size_y = min_cb_log2_size_y + ++ sps->log2_diff_max_min_luma_coding_block_size; ++ ctb_size_y = 1 << ctb_log2_size_y; ++ ++#define WRITE_PPS(value, field) set_ps_field(hw_ps->info, field, value) ++ /* write sps */ ++ WRITE_PPS(sps->video_parameter_set_id, VIDEO_PARAMETER_SET_ID); ++ WRITE_PPS(sps->seq_parameter_set_id, SEQ_PARAMETER_SET_ID); ++ WRITE_PPS(1, CHROMA_FORMAT_IDC); ++ WRITE_PPS(sps->pic_width_in_luma_samples, PIC_WIDTH_IN_LUMA_SAMPLES); ++ WRITE_PPS(sps->pic_height_in_luma_samples, PIC_HEIGHT_IN_LUMA_SAMPLES); ++ WRITE_PPS(sps->bit_depth_luma_minus8 + 8, BIT_DEPTH_LUMA); ++ WRITE_PPS(sps->bit_depth_chroma_minus8 + 8, BIT_DEPTH_CHROMA); ++ WRITE_PPS(sps->log2_max_pic_order_cnt_lsb_minus4 + 4, ++ LOG2_MAX_PIC_ORDER_CNT_LSB); ++ WRITE_PPS(sps->log2_diff_max_min_luma_coding_block_size, ++ LOG2_DIFF_MAX_MIN_LUMA_CODING_BLOCK_SIZE); ++ WRITE_PPS(sps->log2_min_luma_coding_block_size_minus3 + 3, ++ LOG2_MIN_LUMA_CODING_BLOCK_SIZE); ++ WRITE_PPS(sps->log2_min_luma_transform_block_size_minus2 + 2, ++ LOG2_MIN_TRANSFORM_BLOCK_SIZE); ++ WRITE_PPS(sps->log2_diff_max_min_luma_transform_block_size, ++ LOG2_DIFF_MAX_MIN_LUMA_TRANSFORM_BLOCK_SIZE); ++ WRITE_PPS(sps->max_transform_hierarchy_depth_inter, ++ MAX_TRANSFORM_HIERARCHY_DEPTH_INTER); ++ WRITE_PPS(sps->max_transform_hierarchy_depth_intra, ++ MAX_TRANSFORM_HIERARCHY_DEPTH_INTRA); ++ WRITE_PPS(!!(sps->flags & V4L2_HEVC_SPS_FLAG_SCALING_LIST_ENABLED), ++ SCALING_LIST_ENABLED_FLAG); ++ WRITE_PPS(!!(sps->flags & V4L2_HEVC_SPS_FLAG_AMP_ENABLED), ++ AMP_ENABLED_FLAG); ++ WRITE_PPS(!!(sps->flags & V4L2_HEVC_SPS_FLAG_SAMPLE_ADAPTIVE_OFFSET), ++ SAMPLE_ADAPTIVE_OFFSET_ENABLED_FLAG); ++ if (sps->flags & V4L2_HEVC_SPS_FLAG_PCM_ENABLED) { ++ WRITE_PPS(1, PCM_ENABLED_FLAG); ++ WRITE_PPS(sps->pcm_sample_bit_depth_luma_minus1 + 1, ++ PCM_SAMPLE_BIT_DEPTH_LUMA); ++ WRITE_PPS(sps->pcm_sample_bit_depth_chroma_minus1 + 1, ++ PCM_SAMPLE_BIT_DEPTH_CHROMA); ++ WRITE_PPS(!!(sps->flags & V4L2_HEVC_SPS_FLAG_PCM_LOOP_FILTER_DISABLED), ++ PCM_LOOP_FILTER_DISABLED_FLAG); ++ WRITE_PPS(sps->log2_diff_max_min_pcm_luma_coding_block_size, ++ LOG2_DIFF_MAX_MIN_PCM_LUMA_CODING_BLOCK_SIZE); ++ WRITE_PPS(sps->log2_min_pcm_luma_coding_block_size_minus3 + 3, ++ LOG2_MIN_PCM_LUMA_CODING_BLOCK_SIZE); ++ } ++ WRITE_PPS(sps->num_short_term_ref_pic_sets, NUM_SHORT_TERM_REF_PIC_SETS); ++ WRITE_PPS(!!(sps->flags & V4L2_HEVC_SPS_FLAG_LONG_TERM_REF_PICS_PRESENT), ++ LONG_TERM_REF_PICS_PRESENT_FLAG); ++ WRITE_PPS(sps->num_long_term_ref_pics_sps, NUM_LONG_TERM_REF_PICS_SPS); ++ WRITE_PPS(!!(sps->flags & V4L2_HEVC_SPS_FLAG_SPS_TEMPORAL_MVP_ENABLED), ++ SPS_TEMPORAL_MVP_ENABLED_FLAG); ++ WRITE_PPS(!!(sps->flags & V4L2_HEVC_SPS_FLAG_STRONG_INTRA_SMOOTHING_ENABLED), ++ STRONG_INTRA_SMOOTHING_ENABLED_FLAG); ++ //WRITE_PPS(0, PS_FIELD(100, 7)); ++ //WRITE_PPS(0x1fffff, PS_FIELD(107, 21)); ++ ++ /* write pps */ ++ WRITE_PPS(pps->pic_parameter_set_id, PIC_PARAMETER_SET_ID); ++ WRITE_PPS(sps->seq_parameter_set_id, PPS_SEQ_PARAMETER_SET_ID); ++ WRITE_PPS(!!(pps->flags & V4L2_HEVC_PPS_FLAG_DEPENDENT_SLICE_SEGMENT), ++ DEPENDENT_SLICE_SEGMENTS_ENABLED_FLAG); ++ WRITE_PPS(!!(pps->flags & V4L2_HEVC_PPS_FLAG_OUTPUT_FLAG_PRESENT), ++ OUTPUT_FLAG_PRESENT_FLAG); ++ WRITE_PPS(pps->num_extra_slice_header_bits, NUM_EXTRA_SLICE_HEADER_BITS); ++ WRITE_PPS(!!(pps->flags & V4L2_HEVC_PPS_FLAG_SIGN_DATA_HIDING_ENABLED), ++ SIGN_DATA_HIDING_ENABLED_FLAG); ++ WRITE_PPS(!!(pps->flags & V4L2_HEVC_PPS_FLAG_CABAC_INIT_PRESENT), ++ CABAC_INIT_PRESENT_FLAG); ++ WRITE_PPS(pps->num_ref_idx_l0_default_active_minus1 + 1, ++ NUM_REF_IDX_L0_DEFAULT_ACTIVE); ++ WRITE_PPS(pps->num_ref_idx_l1_default_active_minus1 + 1, ++ NUM_REF_IDX_L1_DEFAULT_ACTIVE); ++ WRITE_PPS(pps->init_qp_minus26, INIT_QP_MINUS26); ++ WRITE_PPS(!!(pps->flags & V4L2_HEVC_PPS_FLAG_CONSTRAINED_INTRA_PRED), ++ CONSTRAINED_INTRA_PRED_FLAG); ++ WRITE_PPS(!!(pps->flags & V4L2_HEVC_PPS_FLAG_TRANSFORM_SKIP_ENABLED), ++ TRANSFORM_SKIP_ENABLED_FLAG); ++ WRITE_PPS(!!(pps->flags & V4L2_HEVC_PPS_FLAG_CU_QP_DELTA_ENABLED), ++ CU_QP_DELTA_ENABLED_FLAG); ++ ++ log2_min_cu_qp_delta_size = ctb_log2_size_y - pps->diff_cu_qp_delta_depth; ++ WRITE_PPS(log2_min_cu_qp_delta_size, LOG2_MIN_CU_QP_DELTA_SIZE); ++ ++ WRITE_PPS(pps->pps_cb_qp_offset, PPS_CB_QP_OFFSET); ++ WRITE_PPS(pps->pps_cr_qp_offset, PPS_CR_QP_OFFSET); ++ WRITE_PPS(!!(pps->flags & V4L2_HEVC_PPS_FLAG_PPS_SLICE_CHROMA_QP_OFFSETS_PRESENT), ++ PPS_SLICE_CHROMA_QP_OFFSETS_PRESENT_FLAG); ++ WRITE_PPS(!!(pps->flags & V4L2_HEVC_PPS_FLAG_WEIGHTED_PRED), ++ WEIGHTED_PRED_FLAG); ++ WRITE_PPS(!!(pps->flags & V4L2_HEVC_PPS_FLAG_WEIGHTED_BIPRED), ++ WEIGHTED_BIPRED_FLAG); ++ WRITE_PPS(!!(pps->flags & V4L2_HEVC_PPS_FLAG_TRANSQUANT_BYPASS_ENABLED), ++ TRANSQUANT_BYPASS_ENABLED_FLAG); ++ WRITE_PPS(!!(pps->flags & V4L2_HEVC_PPS_FLAG_TILES_ENABLED), ++ TILES_ENABLED_FLAG); ++ WRITE_PPS(!!(pps->flags & V4L2_HEVC_PPS_FLAG_ENTROPY_CODING_SYNC_ENABLED), ++ ENTROPY_CODING_SYNC_ENABLED_FLAG); ++ WRITE_PPS(!!(pps->flags & V4L2_HEVC_PPS_FLAG_PPS_LOOP_FILTER_ACROSS_SLICES_ENABLED), ++ PPS_LOOP_FILTER_ACROSS_SLICES_ENABLED_FLAG); ++ WRITE_PPS(!!(pps->flags & V4L2_HEVC_PPS_FLAG_LOOP_FILTER_ACROSS_TILES_ENABLED), ++ LOOP_FILTER_ACROSS_TILES_ENABLED_FLAG); ++ WRITE_PPS(!!(pps->flags & V4L2_HEVC_PPS_FLAG_DEBLOCKING_FILTER_OVERRIDE_ENABLED), ++ DEBLOCKING_FILTER_OVERRIDE_ENABLED_FLAG); ++ WRITE_PPS(!!(pps->flags & V4L2_HEVC_PPS_FLAG_PPS_DISABLE_DEBLOCKING_FILTER), ++ PPS_DEBLOCKING_FILTER_DISABLED_FLAG); ++ WRITE_PPS(pps->pps_beta_offset_div2, PPS_BETA_OFFSET_DIV2); ++ WRITE_PPS(pps->pps_tc_offset_div2, PPS_TC_OFFSET_DIV2); ++ WRITE_PPS(!!(pps->flags & V4L2_HEVC_PPS_FLAG_LISTS_MODIFICATION_PRESENT), ++ LISTS_MODIFICATION_PRESENT_FLAG); ++ WRITE_PPS(pps->log2_parallel_merge_level_minus2 + 2, LOG2_PARALLEL_MERGE_LEVEL); ++ WRITE_PPS(!!(pps->flags & V4L2_HEVC_PPS_FLAG_SLICE_SEGMENT_HEADER_EXTENSION_PRESENT), ++ SLICE_SEGMENT_HEADER_EXTENSION_PRESENT_FLAG); ++ //WRITE_PPS(0, PS_FIELD(209, 3)); ++ WRITE_PPS(pps->num_tile_columns_minus1 + 1, NUM_TILE_COLUMNS); ++ WRITE_PPS(pps->num_tile_rows_minus1 + 1, NUM_TILE_ROWS); ++ //WRITE_PPS(0x2, PS_FIELD(222, 2)); ++ //WRITE_PPS(0xffffffff, PS_FIELD(224, 32)); ++ ++ if (pps->flags & V4L2_HEVC_PPS_FLAG_TILES_ENABLED) { ++ for (i = 0; i <= pps->num_tile_columns_minus1; i++) ++ WRITE_PPS(pps->column_width_minus1[i], COLUMN_WIDTH(i)); ++ for (i = 0; i <= pps->num_tile_rows_minus1; i++) ++ WRITE_PPS(pps->row_height_minus1[i], ROW_HEIGHT(i)); ++ } else { ++ WRITE_PPS(round_up(sps->pic_width_in_luma_samples, ctb_size_y) - 1, ++ COLUMN_WIDTH(0)); ++ WRITE_PPS(round_up(sps->pic_height_in_luma_samples, ctb_size_y) - 1, ++ ROW_HEIGHT(0)); ++ } ++ ++ scaling_distance = offsetof(struct rkvdec_hevc_priv_tbl, scaling_list); ++ scaling_list_address = hevc_ctx->priv_tbl.dma + scaling_distance; ++ WRITE_PPS(scaling_list_address, SCALING_LIST_ADDRESS); ++ //WRITE_PPS(0xffff, PS_FIELD(624, 16)); ++} ++ ++static void assemble_hw_rps(struct rkvdec_ctx *ctx, ++ struct rkvdec_hevc_run *run) ++{ ++ const struct v4l2_ctrl_hevc_slice_params *sl_params; ++ const struct v4l2_hevc_dpb_entry *dpb; ++ struct rkvdec_hevc_ctx *hevc_ctx = ctx->priv; ++ struct rkvdec_hevc_priv_tbl *priv_tbl = hevc_ctx->priv_tbl.cpu; ++ struct rkvdec_rps_packet *hw_ps; ++ int i, j; ++ ++#define WRITE_RPS(value, field) set_ps_field(hw_ps->info, field, value) ++ ++#define REF_PIC_LONG_TERM_L0(i) PS_FIELD(i * 5, 1) ++#define REF_PIC_IDX_L0(i) PS_FIELD(1 + (i * 5), 4) ++#define REF_PIC_LONG_TERM_L1(i) PS_FIELD((i < 5 ? 75 : 132) + (i * 5), 1) ++#define REF_PIC_IDX_L1(i) PS_FIELD((i < 4 ? 76 : 128) + (i * 5), 4) ++ ++#define LOWDELAY PS_FIELD(182, 1) ++#define SHORT_TERM_REF_PIC_SET_SIZE PS_FIELD(183, 10) ++#define LONG_TERM_REF_PIC_SET_SIZE PS_FIELD(193, 9) ++#define NUM_RPS_POC PS_FIELD(202, 4) ++ ++ for (j = 0; j < run->num_slices; j++) { ++ sl_params = &run->slices_params[j]; ++ dpb = sl_params->dpb; ++ ++ hw_ps = &priv_tbl->rps[j]; ++ memset(hw_ps, 0, sizeof(*hw_ps)); ++ ++ for (i = 0; i <= sl_params->num_ref_idx_l0_active_minus1; i++) { ++ WRITE_RPS(!!(dpb[sl_params->ref_idx_l0[i]].rps == V4L2_HEVC_DPB_ENTRY_RPS_LT_CURR), ++ REF_PIC_LONG_TERM_L0(i)); ++ WRITE_RPS(sl_params->ref_idx_l0[i], REF_PIC_IDX_L0(i)); ++ } ++ ++ for (i = 0; i <= sl_params->num_ref_idx_l1_active_minus1; i++) { ++ WRITE_RPS(!!(dpb[sl_params->ref_idx_l1[i]].rps == V4L2_HEVC_DPB_ENTRY_RPS_LT_CURR), ++ REF_PIC_LONG_TERM_L1(i)); ++ WRITE_RPS(sl_params->ref_idx_l1[i], REF_PIC_IDX_L1(i)); ++ } ++ ++ //WRITE_RPS(0xffffffff, PS_FIELD(96, 32)); ++ ++ // TODO: lowdelay ++ WRITE_RPS(0, LOWDELAY); ++ ++ // NOTE: these two differs from mpp ++ WRITE_RPS(sl_params->short_term_ref_pic_set_size, ++ SHORT_TERM_REF_PIC_SET_SIZE); ++ WRITE_RPS(sl_params->long_term_ref_pic_set_size, ++ LONG_TERM_REF_PIC_SET_SIZE); ++ ++ WRITE_RPS(sl_params->num_rps_poc_st_curr_before + ++ sl_params->num_rps_poc_st_curr_after + ++ sl_params->num_rps_poc_lt_curr, ++ NUM_RPS_POC); ++ ++ //WRITE_RPS(0x3ffff, PS_FIELD(206, 18)); ++ //WRITE_RPS(0xffffffff, PS_FIELD(224, 32)); ++ } ++} ++ ++static void assemble_hw_scaling_list(struct rkvdec_ctx *ctx, ++ struct rkvdec_hevc_run *run) ++{ ++ const struct v4l2_ctrl_hevc_scaling_matrix *scaling = run->scaling_matrix; ++ struct rkvdec_hevc_ctx *hevc_ctx = ctx->priv; ++ struct rkvdec_hevc_priv_tbl *tbl = hevc_ctx->priv_tbl.cpu; ++ u8 *dst; ++ scalingList_t sl; ++ int i, j; ++ ++ if (!memcmp((void*)&hevc_ctx->scaling_matrix_cache, scaling, ++ sizeof(struct v4l2_ctrl_hevc_scaling_matrix))) ++ return; ++ ++ memset(&sl, 0, sizeof(scalingList_t)); ++ ++ for (i = 0; i < 6; i++) { ++ for (j = 0; j < 16; j++) ++ sl.sl[0][i][j] = scaling->scaling_list_4x4[i][j]; ++ for (j = 0; j < 64; j++) { ++ sl.sl[1][i][j] = scaling->scaling_list_8x8[i][j]; ++ sl.sl[2][i][j] = scaling->scaling_list_16x16[i][j]; ++ if (i < 2) ++ sl.sl[3][i][j] = scaling->scaling_list_32x32[i][j]; ++ } ++ sl.sl_dc[0][i] = scaling->scaling_list_dc_coef_16x16[i]; ++ if (i < 2) ++ sl.sl_dc[1][i] = scaling->scaling_list_dc_coef_32x32[i]; ++ } ++ ++ dst = tbl->scaling_list; ++ hal_record_scaling_list((scalingFactor_t *)dst, &sl); ++ ++ memcpy((void*)&hevc_ctx->scaling_matrix_cache, scaling, ++ sizeof(struct v4l2_ctrl_hevc_scaling_matrix)); ++} ++ ++static struct vb2_buffer * ++get_ref_buf(struct rkvdec_ctx *ctx, struct rkvdec_hevc_run *run, ++ unsigned int dpb_idx) ++{ ++ struct v4l2_m2m_ctx *m2m_ctx = ctx->fh.m2m_ctx; ++ const struct v4l2_ctrl_hevc_slice_params *sl_params = &run->slices_params[0]; ++ const struct v4l2_hevc_dpb_entry *dpb = sl_params->dpb; ++ struct vb2_queue *cap_q = &m2m_ctx->cap_q_ctx.q; ++ int buf_idx = -1; ++ ++ if (dpb_idx < sl_params->num_active_dpb_entries) ++ buf_idx = vb2_find_timestamp(cap_q, ++ dpb[dpb_idx].timestamp, 0); ++ ++ /* ++ * If a DPB entry is unused or invalid, address of current destination ++ * buffer is returned. ++ */ ++ if (buf_idx < 0) ++ return &run->base.bufs.dst->vb2_buf; ++ ++ return vb2_get_buffer(cap_q, buf_idx); ++} ++ ++static void config_registers(struct rkvdec_ctx *ctx, ++ struct rkvdec_hevc_run *run) ++{ ++ struct rkvdec_dev *rkvdec = ctx->dev; ++ const struct v4l2_ctrl_hevc_slice_params *sl_params = &run->slices_params[0]; ++ const struct v4l2_hevc_dpb_entry *dpb = sl_params->dpb; ++ struct rkvdec_hevc_ctx *hevc_ctx = ctx->priv; ++ dma_addr_t priv_start_addr = hevc_ctx->priv_tbl.dma; ++ const struct v4l2_pix_format_mplane *dst_fmt; ++ struct vb2_v4l2_buffer *src_buf = run->base.bufs.src; ++ struct vb2_v4l2_buffer *dst_buf = run->base.bufs.dst; ++ const struct v4l2_format *f; ++ dma_addr_t rlc_addr; ++ dma_addr_t refer_addr; ++ u32 rlc_len; ++ u32 hor_virstride; ++ u32 ver_virstride; ++ u32 y_virstride; ++ u32 uv_virstride; ++ u32 yuv_virstride; ++ u32 offset; ++ dma_addr_t dst_addr; ++ u32 reg, i; ++ ++ reg = RKVDEC_MODE(RKVDEC_MODE_HEVC); ++ writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_SYSCTRL); ++ ++ f = &ctx->decoded_fmt; ++ dst_fmt = &f->fmt.pix_mp; ++ hor_virstride = dst_fmt->plane_fmt[0].bytesperline; ++ ver_virstride = dst_fmt->height; ++ y_virstride = hor_virstride * ver_virstride; ++ uv_virstride = y_virstride / 2; ++ yuv_virstride = y_virstride + uv_virstride; ++ ++ reg = RKVDEC_Y_HOR_VIRSTRIDE(hor_virstride / 16) | ++ RKVDEC_UV_HOR_VIRSTRIDE(hor_virstride / 16) | ++ RKVDEC_SLICE_NUM_LOWBITS(run->num_slices); ++ writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_PICPAR); ++ ++ /* config rlc base address */ ++ rlc_addr = vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, 0); ++ writel_relaxed(rlc_addr, rkvdec->regs + RKVDEC_REG_STRM_RLC_BASE); ++ ++ rlc_len = vb2_get_plane_payload(&src_buf->vb2_buf, 0); ++ reg = RKVDEC_STRM_LEN(round_up(rlc_len, 16) + 64); ++ writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_STRM_LEN); ++ ++ /* config cabac table */ ++ offset = offsetof(struct rkvdec_hevc_priv_tbl, cabac_table); ++ writel_relaxed(priv_start_addr + offset, ++ rkvdec->regs + RKVDEC_REG_CABACTBL_PROB_BASE); ++ ++ /* config output base address */ ++ dst_addr = vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 0); ++ writel_relaxed(dst_addr, rkvdec->regs + RKVDEC_REG_DECOUT_BASE); ++ ++ reg = RKVDEC_Y_VIRSTRIDE(y_virstride / 16); ++ writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_Y_VIRSTRIDE); ++ ++ reg = RKVDEC_YUV_VIRSTRIDE(yuv_virstride / 16); ++ writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_YUV_VIRSTRIDE); ++ ++ /* config ref pic address */ ++ for (i = 0; i < 15; i++) { ++ struct vb2_buffer *vb_buf = get_ref_buf(ctx, run, i); ++ ++ if (i < 4 && sl_params->num_active_dpb_entries) { ++ reg = GENMASK(sl_params->num_active_dpb_entries - 1, 0); ++ reg = (reg >> (i * 4)) & 0xf; ++ } else ++ reg = 0; ++ ++ refer_addr = vb2_dma_contig_plane_dma_addr(vb_buf, 0); ++ writel_relaxed(refer_addr | reg, ++ rkvdec->regs + RKVDEC_REG_H264_BASE_REFER(i)); ++ ++ reg = RKVDEC_POC_REFER(i < sl_params->num_active_dpb_entries ? dpb[i].pic_order_cnt[0] : 0); ++ writel_relaxed(reg, ++ rkvdec->regs + RKVDEC_REG_H264_POC_REFER0(i)); ++ } ++ ++ reg = RKVDEC_CUR_POC(sl_params->slice_pic_order_cnt); ++ writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_CUR_POC0); ++ ++ /* config hw pps address */ ++ offset = offsetof(struct rkvdec_hevc_priv_tbl, param_set); ++ writel_relaxed(priv_start_addr + offset, ++ rkvdec->regs + RKVDEC_REG_PPS_BASE); ++ ++ /* config hw rps address */ ++ offset = offsetof(struct rkvdec_hevc_priv_tbl, rps); ++ writel_relaxed(priv_start_addr + offset, ++ rkvdec->regs + RKVDEC_REG_RPS_BASE); ++ ++ reg = RKVDEC_AXI_DDR_RDATA(0); ++ writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_AXI_DDR_RDATA); ++ ++ reg = RKVDEC_AXI_DDR_WDATA(0); ++ writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_AXI_DDR_WDATA); ++} ++ ++#define RKVDEC_HEVC_MAX_DEPTH_IN_BYTES 2 ++ ++static int rkvdec_hevc_adjust_fmt(struct rkvdec_ctx *ctx, ++ struct v4l2_format *f) ++{ ++ struct v4l2_pix_format_mplane *fmt = &f->fmt.pix_mp; ++ ++ fmt->num_planes = 1; ++ if (!fmt->plane_fmt[0].sizeimage) ++ fmt->plane_fmt[0].sizeimage = fmt->width * fmt->height * ++ RKVDEC_HEVC_MAX_DEPTH_IN_BYTES; ++ return 0; ++} ++ ++static int rkvdec_hevc_start(struct rkvdec_ctx *ctx) ++{ ++ struct rkvdec_dev *rkvdec = ctx->dev; ++ struct rkvdec_hevc_priv_tbl *priv_tbl; ++ struct rkvdec_hevc_ctx *hevc_ctx; ++ int ret; ++ ++ hevc_ctx = kzalloc(sizeof(*hevc_ctx), GFP_KERNEL); ++ if (!hevc_ctx) ++ return -ENOMEM; ++ ++ priv_tbl = dma_alloc_coherent(rkvdec->dev, sizeof(*priv_tbl), ++ &hevc_ctx->priv_tbl.dma, GFP_KERNEL); ++ if (!priv_tbl) { ++ ret = -ENOMEM; ++ goto err_free_ctx; ++ } ++ ++ hevc_ctx->priv_tbl.size = sizeof(*priv_tbl); ++ hevc_ctx->priv_tbl.cpu = priv_tbl; ++ memset(priv_tbl, 0, sizeof(*priv_tbl)); ++ memcpy(priv_tbl->cabac_table, rkvdec_hevc_cabac_table, ++ sizeof(rkvdec_hevc_cabac_table)); ++ ++ ctx->priv = hevc_ctx; ++ return 0; ++ ++err_free_ctx: ++ kfree(hevc_ctx); ++ return ret; ++} ++ ++static void rkvdec_hevc_stop(struct rkvdec_ctx *ctx) ++{ ++ struct rkvdec_hevc_ctx *hevc_ctx = ctx->priv; ++ struct rkvdec_dev *rkvdec = ctx->dev; ++ ++ dma_free_coherent(rkvdec->dev, hevc_ctx->priv_tbl.size, ++ hevc_ctx->priv_tbl.cpu, hevc_ctx->priv_tbl.dma); ++ kfree(hevc_ctx); ++} ++ ++static void rkvdec_hevc_run_preamble(struct rkvdec_ctx *ctx, ++ struct rkvdec_hevc_run *run) ++{ ++ struct v4l2_ctrl *ctrl; ++ ++ ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl, ++ V4L2_CID_MPEG_VIDEO_HEVC_SLICE_PARAMS); ++ run->slices_params = ctrl ? ctrl->p_cur.p : NULL; ++ ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl, ++ V4L2_CID_MPEG_VIDEO_HEVC_SPS); ++ run->sps = ctrl ? ctrl->p_cur.p : NULL; ++ ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl, ++ V4L2_CID_MPEG_VIDEO_HEVC_PPS); ++ run->pps = ctrl ? ctrl->p_cur.p : NULL; ++ ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl, ++ V4L2_CID_MPEG_VIDEO_HEVC_SCALING_MATRIX); ++ run->scaling_matrix = ctrl ? ctrl->p_cur.p : NULL; ++ ++ rkvdec_run_preamble(ctx, &run->base); ++ ++ // HACK: we need num slices from somewhere ++ run->num_slices = run->sps->num_slices; ++} ++ ++static int rkvdec_hevc_run(struct rkvdec_ctx *ctx) ++{ ++ struct rkvdec_dev *rkvdec = ctx->dev; ++ struct rkvdec_hevc_run run; ++ ++ rkvdec_hevc_run_preamble(ctx, &run); ++ ++ assemble_hw_scaling_list(ctx, &run); ++ assemble_hw_pps(ctx, &run); ++ assemble_hw_rps(ctx, &run); ++ config_registers(ctx, &run); ++ ++ rkvdec_run_postamble(ctx, &run.base); ++ ++ // sw_cabac_error_e - cabac error enable ++ writel_relaxed(0xfdfffffd, rkvdec->regs + RKVDEC_REG_STRMD_ERR_EN); ++ // slice end error enable = BIT(28) ++ // frame end error enable = BIT(29) ++ writel_relaxed(0x30000000, rkvdec->regs + RKVDEC_REG_H264_ERR_E); ++ ++ schedule_delayed_work(&rkvdec->watchdog_work, msecs_to_jiffies(2000)); ++ ++ writel(1, rkvdec->regs + RKVDEC_REG_PREF_LUMA_CACHE_COMMAND); ++ writel(1, rkvdec->regs + RKVDEC_REG_PREF_CHR_CACHE_COMMAND); ++ ++ /* Start decoding! */ ++ writel(RKVDEC_INTERRUPT_DEC_E | RKVDEC_CONFIG_DEC_CLK_GATE_E | ++ RKVDEC_TIMEOUT_E | RKVDEC_BUF_EMPTY_E, ++ rkvdec->regs + RKVDEC_REG_INTERRUPT); ++ ++ return 0; ++} ++ ++const struct rkvdec_coded_fmt_ops rkvdec_hevc_fmt_ops = { ++ .adjust_fmt = rkvdec_hevc_adjust_fmt, ++ .start = rkvdec_hevc_start, ++ .stop = rkvdec_hevc_stop, ++ .run = rkvdec_hevc_run, ++}; +diff --git a/drivers/staging/media/rkvdec/rkvdec-regs.h b/drivers/staging/media/rkvdec/rkvdec-regs.h +index 15b9bee92016..83bf790ed9b7 100644 +--- a/drivers/staging/media/rkvdec/rkvdec-regs.h ++++ b/drivers/staging/media/rkvdec/rkvdec-regs.h +@@ -43,6 +43,7 @@ + #define RKVDEC_RLC_MODE BIT(11) + #define RKVDEC_STRM_START_BIT(x) (((x) & 0x7f) << 12) + #define RKVDEC_MODE(x) (((x) & 0x03) << 20) ++#define RKVDEC_MODE_HEVC 0 + #define RKVDEC_MODE_H264 1 + #define RKVDEC_MODE_VP9 2 + #define RKVDEC_RPS_MODE BIT(24) +diff --git a/drivers/staging/media/rkvdec/rkvdec.c b/drivers/staging/media/rkvdec/rkvdec.c +index 658fb6028e72..2141633c7437 100644 +--- a/drivers/staging/media/rkvdec/rkvdec.c ++++ b/drivers/staging/media/rkvdec/rkvdec.c +@@ -159,6 +159,61 @@ static const u32 rkvdec_h264_decoded_fmts[] = { + V4L2_PIX_FMT_NV20, + }; + ++static const struct rkvdec_ctrl_desc rkvdec_hevc_ctrl_descs[] = { ++ { ++ .mandatory = true, ++ .cfg.id = V4L2_CID_MPEG_VIDEO_HEVC_SLICE_PARAMS, ++ // HACK: match ffmpeg v4l2 request api hwaccel size, ++ // we should support variable length up to 600 slices ++ .cfg.dims = { 16 }, ++ }, ++ { ++ .mandatory = true, ++ .cfg.id = V4L2_CID_MPEG_VIDEO_HEVC_SPS, ++ }, ++ { ++ .mandatory = true, ++ .cfg.id = V4L2_CID_MPEG_VIDEO_HEVC_PPS, ++ }, ++ { ++ .mandatory = true, ++ .cfg.id = V4L2_CID_MPEG_VIDEO_HEVC_SCALING_MATRIX, ++ }, ++ { ++ .cfg.id = V4L2_CID_MPEG_VIDEO_HEVC_DECODE_MODE, ++ .cfg.min = V4L2_MPEG_VIDEO_HEVC_DECODE_MODE_FRAME_BASED, ++ .cfg.max = V4L2_MPEG_VIDEO_HEVC_DECODE_MODE_FRAME_BASED, ++ .cfg.def = V4L2_MPEG_VIDEO_HEVC_DECODE_MODE_FRAME_BASED, ++ }, ++ { ++ .cfg.id = V4L2_CID_MPEG_VIDEO_HEVC_START_CODE, ++ .cfg.min = V4L2_MPEG_VIDEO_HEVC_START_CODE_ANNEX_B, ++ .cfg.def = V4L2_MPEG_VIDEO_HEVC_START_CODE_ANNEX_B, ++ .cfg.max = V4L2_MPEG_VIDEO_HEVC_START_CODE_ANNEX_B, ++ }, ++ { ++ .cfg.id = V4L2_CID_MPEG_VIDEO_HEVC_PROFILE, ++ .cfg.min = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN, ++ .cfg.max = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10, ++ .cfg.def = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN, ++ }, ++ { ++ .cfg.id = V4L2_CID_MPEG_VIDEO_HEVC_LEVEL, ++ .cfg.min = V4L2_MPEG_VIDEO_HEVC_LEVEL_1, ++ .cfg.max = V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1, ++ }, ++}; ++ ++static const struct rkvdec_ctrls rkvdec_hevc_ctrls = { ++ .ctrls = rkvdec_hevc_ctrl_descs, ++ .num_ctrls = ARRAY_SIZE(rkvdec_hevc_ctrl_descs), ++}; ++ ++static const u32 rkvdec_hevc_decoded_fmts[] = { ++ V4L2_PIX_FMT_NV12, ++ V4L2_PIX_FMT_NV15, ++}; ++ + static const struct rkvdec_ctrl_desc rkvdec_vp9_ctrl_descs[] = { + { + .mandatory = true, +@@ -209,6 +264,21 @@ static const struct rkvdec_coded_fmt_desc rkvdec_coded_fmts[] = { + .num_decoded_fmts = ARRAY_SIZE(rkvdec_h264_decoded_fmts), + .decoded_fmts = rkvdec_h264_decoded_fmts, + }, ++ { ++ .fourcc = V4L2_PIX_FMT_HEVC_SLICE, ++ .frmsize = { ++ .min_width = 64, ++ .max_width = 4096, ++ .step_width = 64, ++ .min_height = 64, ++ .max_height = 2304, ++ .step_height = 16, ++ }, ++ .ctrls = &rkvdec_hevc_ctrls, ++ .ops = &rkvdec_hevc_fmt_ops, ++ .num_decoded_fmts = ARRAY_SIZE(rkvdec_hevc_decoded_fmts), ++ .decoded_fmts = rkvdec_hevc_decoded_fmts, ++ }, + { + .fourcc = V4L2_PIX_FMT_VP9_FRAME, + .frmsize = { +diff --git a/drivers/staging/media/rkvdec/rkvdec.h b/drivers/staging/media/rkvdec/rkvdec.h +index 5f66f07acac5..d5600c6a4c17 100644 +--- a/drivers/staging/media/rkvdec/rkvdec.h ++++ b/drivers/staging/media/rkvdec/rkvdec.h +@@ -123,6 +123,7 @@ void rkvdec_run_preamble(struct rkvdec_ctx *ctx, struct rkvdec_run *run); + void rkvdec_run_postamble(struct rkvdec_ctx *ctx, struct rkvdec_run *run); + + extern const struct rkvdec_coded_fmt_ops rkvdec_h264_fmt_ops; ++extern const struct rkvdec_coded_fmt_ops rkvdec_hevc_fmt_ops; + extern const struct rkvdec_coded_fmt_ops rkvdec_vp9_fmt_ops; + + #endif /* RKVDEC_H_ */ + +From 42bf64d9be3b320b3ff6617a63b177f6dae206fb Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Sat, 1 Aug 2020 12:24:58 +0000 +Subject: [PATCH] WIP: media: rkvdec: add HEVC format validation + +--- + drivers/staging/media/rkvdec/rkvdec-hevc.c | 11 +++++++++++ + drivers/staging/media/rkvdec/rkvdec.c | 23 +++++++++++++++++++++- + 2 files changed, 33 insertions(+), 1 deletion(-) + +diff --git a/drivers/staging/media/rkvdec/rkvdec-hevc.c b/drivers/staging/media/rkvdec/rkvdec-hevc.c +index 03ba848411c6..b8ad7fc2271c 100644 +--- a/drivers/staging/media/rkvdec/rkvdec-hevc.c ++++ b/drivers/staging/media/rkvdec/rkvdec-hevc.c +@@ -2415,6 +2415,16 @@ static int rkvdec_hevc_adjust_fmt(struct rkvdec_ctx *ctx, + return 0; + } + ++static u32 rkvdec_hevc_valid_fmt(struct rkvdec_ctx *ctx, struct v4l2_ctrl *ctrl) ++{ ++ const struct v4l2_ctrl_hevc_sps *sps = ctrl->p_new.p_hevc_sps; ++ ++ if (sps->bit_depth_luma_minus8 == 2) ++ return V4L2_PIX_FMT_NV15; ++ else ++ return V4L2_PIX_FMT_NV12; ++} ++ + static int rkvdec_hevc_start(struct rkvdec_ctx *ctx) + { + struct rkvdec_dev *rkvdec = ctx->dev; +@@ -2516,6 +2526,7 @@ static int rkvdec_hevc_run(struct rkvdec_ctx *ctx) + + const struct rkvdec_coded_fmt_ops rkvdec_hevc_fmt_ops = { + .adjust_fmt = rkvdec_hevc_adjust_fmt, ++ .valid_fmt = rkvdec_hevc_valid_fmt, + .start = rkvdec_hevc_start, + .stop = rkvdec_hevc_stop, + .run = rkvdec_hevc_run, +diff --git a/drivers/staging/media/rkvdec/rkvdec.c b/drivers/staging/media/rkvdec/rkvdec.c +index 2141633c7437..869275a411c8 100644 +--- a/drivers/staging/media/rkvdec/rkvdec.c ++++ b/drivers/staging/media/rkvdec/rkvdec.c +@@ -76,6 +76,26 @@ static int rkvdec_try_ctrl(struct v4l2_ctrl *ctrl) + if (width > ctx->coded_fmt.fmt.pix_mp.width || + height > ctx->coded_fmt.fmt.pix_mp.height) + return -EINVAL; ++ } else if (ctrl->id == V4L2_CID_MPEG_VIDEO_HEVC_SPS) { ++ const struct v4l2_ctrl_hevc_sps *sps = ctrl->p_new.p_hevc_sps; ++ ++ if (sps->chroma_format_idc > 1) ++ /* Only 4:0:0 and 4:2:0 are supported */ ++ return -EINVAL; ++ if (sps->bit_depth_luma_minus8 != sps->bit_depth_chroma_minus8) ++ /* Luma and chroma bit depth mismatch */ ++ return -EINVAL; ++ if (sps->bit_depth_luma_minus8 != 0 && sps->bit_depth_luma_minus8 != 2) ++ /* Only 8-bit and 10-bit is supported */ ++ return -EINVAL; ++ ++ if (ctx->valid_fmt && ctx->valid_fmt != rkvdec_valid_fmt(ctx, ctrl)) ++ /* Only current valid format */ ++ return -EINVAL; ++ ++ if (sps->pic_width_in_luma_samples > ctx->coded_fmt.fmt.pix_mp.width || ++ sps->pic_height_in_luma_samples > ctx->coded_fmt.fmt.pix_mp.height) ++ return -EINVAL; + } + return 0; + } +@@ -84,7 +104,7 @@ static int rkvdec_s_ctrl(struct v4l2_ctrl *ctrl) + { + struct rkvdec_ctx *ctx = container_of(ctrl->handler, struct rkvdec_ctx, ctrl_hdl); + +- if (ctrl->id == V4L2_CID_MPEG_VIDEO_H264_SPS && !ctx->valid_fmt) { ++ if (!ctx->valid_fmt) { + ctx->valid_fmt = rkvdec_valid_fmt(ctx, ctrl); + if (ctx->valid_fmt) { + struct v4l2_pix_format_mplane *pix_mp; +@@ -170,6 +190,7 @@ static const struct rkvdec_ctrl_desc rkvdec_hevc_ctrl_descs[] = { + { + .mandatory = true, + .cfg.id = V4L2_CID_MPEG_VIDEO_HEVC_SPS, ++ .cfg.ops = &rkvdec_ctrl_ops, + }, + { + .mandatory = true, + +From d37481b9f7f915f93efaee842548a4b42b2da4ce Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Tue, 29 Oct 2019 01:26:02 +0000 +Subject: [PATCH] RFC: media: hantro: Fix H264 decoding of field encoded + content + +This still need code cleanup and formatting + +Signed-off-by: Jonas Karlman +--- + .../staging/media/hantro/hantro_g1_h264_dec.c | 17 +--- + drivers/staging/media/hantro/hantro_h264.c | 81 ++++++++++++++++--- + drivers/staging/media/hantro/hantro_hw.h | 2 + + 3 files changed, 74 insertions(+), 26 deletions(-) + +diff --git a/drivers/staging/media/hantro/hantro_g1_h264_dec.c b/drivers/staging/media/hantro/hantro_g1_h264_dec.c +index 845bef73d218..869ee261a5db 100644 +--- a/drivers/staging/media/hantro/hantro_g1_h264_dec.c ++++ b/drivers/staging/media/hantro/hantro_g1_h264_dec.c +@@ -130,25 +130,12 @@ static void set_ref(struct hantro_ctx *ctx) + struct v4l2_h264_dpb_entry *dpb = ctx->h264_dec.dpb; + const u8 *b0_reflist, *b1_reflist, *p_reflist; + struct hantro_dev *vpu = ctx->dev; +- u32 dpb_longterm = 0; +- u32 dpb_valid = 0; + int reg_num; + u32 reg; + int i; + +- /* +- * Set up bit maps of valid and long term DPBs. +- * NOTE: The bits are reversed, i.e. MSb is DPB 0. +- */ +- for (i = 0; i < HANTRO_H264_DPB_SIZE; ++i) { +- if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE) +- dpb_valid |= BIT(HANTRO_H264_DPB_SIZE - 1 - i); +- +- if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM) +- dpb_longterm |= BIT(HANTRO_H264_DPB_SIZE - 1 - i); +- } +- vdpu_write_relaxed(vpu, dpb_valid << 16, G1_REG_VALID_REF); +- vdpu_write_relaxed(vpu, dpb_longterm << 16, G1_REG_LT_REF); ++ vdpu_write_relaxed(vpu, ctx->h264_dec.dpb_valid, G1_REG_VALID_REF); ++ vdpu_write_relaxed(vpu, ctx->h264_dec.dpb_longterm, G1_REG_LT_REF); + + /* + * Set up reference frame picture numbers. +diff --git a/drivers/staging/media/hantro/hantro_h264.c b/drivers/staging/media/hantro/hantro_h264.c +index b1bdc00ac262..bc2af450a94c 100644 +--- a/drivers/staging/media/hantro/hantro_h264.c ++++ b/drivers/staging/media/hantro/hantro_h264.c +@@ -227,17 +227,67 @@ static void prepare_table(struct hantro_ctx *ctx) + { + const struct hantro_h264_dec_ctrls *ctrls = &ctx->h264_dec.ctrls; + const struct v4l2_ctrl_h264_decode_params *dec_param = ctrls->decode; ++ const struct v4l2_ctrl_h264_sps *sps = ctrls->sps; + struct hantro_h264_dec_priv_tbl *tbl = ctx->h264_dec.priv.cpu; + const struct v4l2_h264_dpb_entry *dpb = ctx->h264_dec.dpb; ++ u32 dpb_longterm = 0; ++ u32 dpb_valid = 0; + int i; + ++ /* ++ * Set up bit maps of valid and long term DPBs. ++ * NOTE: The bits are reversed, i.e. MSb is DPB 0. ++ */ ++ if ((dec_param->flags & V4L2_H264_DECODE_PARAM_FLAG_FIELD_PIC) || (sps->flags & V4L2_H264_SPS_FLAG_MB_ADAPTIVE_FRAME_FIELD)) { ++ for (i = 0; i < HANTRO_H264_DPB_SIZE * 2; ++i) { ++ // check for correct reference use ++ enum v4l2_h264_field_reference parity = (i & 0x1) ? ++ V4L2_H264_BOTTOM_FIELD_REF : V4L2_H264_TOP_FIELD_REF; ++ if (dpb[i / 2].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE && ++ dpb[i / 2].reference & parity) ++ dpb_valid |= BIT(HANTRO_H264_DPB_SIZE * 2 - 1 - i); ++ ++ if (dpb[i / 2].flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM) ++ dpb_longterm |= BIT(HANTRO_H264_DPB_SIZE * 2 - 1 - i); ++ } ++ ++ ctx->h264_dec.dpb_valid = dpb_valid; ++ ctx->h264_dec.dpb_longterm = dpb_longterm; ++ } else { ++ for (i = 0; i < HANTRO_H264_DPB_SIZE; ++i) { ++ if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE) ++ dpb_valid |= BIT(HANTRO_H264_DPB_SIZE - 1 - i); ++ ++ if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM) ++ dpb_longterm |= BIT(HANTRO_H264_DPB_SIZE - 1 - i); ++ } ++ ++ ctx->h264_dec.dpb_valid = dpb_valid << 16; ++ ctx->h264_dec.dpb_longterm = dpb_longterm << 16; ++ } ++ + for (i = 0; i < HANTRO_H264_DPB_SIZE; ++i) { +- tbl->poc[i * 2] = dpb[i].top_field_order_cnt; +- tbl->poc[i * 2 + 1] = dpb[i].bottom_field_order_cnt; ++ if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE) { ++ tbl->poc[i * 2] = dpb[i].top_field_order_cnt; ++ tbl->poc[i * 2 + 1] = dpb[i].bottom_field_order_cnt; ++ } else { ++ tbl->poc[i * 2] = 0; ++ tbl->poc[i * 2 + 1] = 0; ++ } + } + +- tbl->poc[32] = dec_param->top_field_order_cnt; +- tbl->poc[33] = dec_param->bottom_field_order_cnt; ++ if ((dec_param->flags & V4L2_H264_DECODE_PARAM_FLAG_FIELD_PIC) || !(sps->flags & V4L2_H264_SPS_FLAG_MB_ADAPTIVE_FRAME_FIELD)) { ++ if ((dec_param->flags & V4L2_H264_DECODE_PARAM_FLAG_FIELD_PIC)) ++ tbl->poc[32] = (dec_param->flags & V4L2_H264_DECODE_PARAM_FLAG_BOTTOM_FIELD) ? ++ dec_param->bottom_field_order_cnt : ++ dec_param->top_field_order_cnt; ++ else ++ tbl->poc[32] = min(dec_param->top_field_order_cnt, dec_param->bottom_field_order_cnt); ++ tbl->poc[33] = 0; ++ } else { ++ tbl->poc[32] = dec_param->top_field_order_cnt; ++ tbl->poc[33] = dec_param->bottom_field_order_cnt; ++ } + + assemble_scaling_list(ctx); + } +@@ -245,8 +295,7 @@ static void prepare_table(struct hantro_ctx *ctx) + static bool dpb_entry_match(const struct v4l2_h264_dpb_entry *a, + const struct v4l2_h264_dpb_entry *b) + { +- return a->top_field_order_cnt == b->top_field_order_cnt && +- a->bottom_field_order_cnt == b->bottom_field_order_cnt; ++ return a->reference_ts == b->reference_ts; + } + + static void update_dpb(struct hantro_ctx *ctx) +@@ -260,13 +309,13 @@ static void update_dpb(struct hantro_ctx *ctx) + + /* Disable all entries by default. */ + for (i = 0; i < ARRAY_SIZE(ctx->h264_dec.dpb); i++) +- ctx->h264_dec.dpb[i].flags &= ~V4L2_H264_DPB_ENTRY_FLAG_ACTIVE; ++ ctx->h264_dec.dpb[i].flags = 0; + + /* Try to match new DPB entries with existing ones by their POCs. */ + for (i = 0; i < ARRAY_SIZE(dec_param->dpb); i++) { + const struct v4l2_h264_dpb_entry *ndpb = &dec_param->dpb[i]; + +- if (!(ndpb->flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE)) ++ if (!(ndpb->flags & V4L2_H264_DPB_ENTRY_FLAG_VALID)) + continue; + + /* +@@ -277,8 +326,7 @@ static void update_dpb(struct hantro_ctx *ctx) + struct v4l2_h264_dpb_entry *cdpb; + + cdpb = &ctx->h264_dec.dpb[j]; +- if (cdpb->flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE || +- !dpb_entry_match(cdpb, ndpb)) ++ if (!dpb_entry_match(cdpb, ndpb)) + continue; + + *cdpb = *ndpb; +@@ -314,7 +362,10 @@ dma_addr_t hantro_h264_get_ref_buf(struct hantro_ctx *ctx, + unsigned int dpb_idx) + { + struct v4l2_h264_dpb_entry *dpb = ctx->h264_dec.dpb; ++ const struct v4l2_ctrl_h264_decode_params *dec_param = ctx->h264_dec.ctrls.decode; + dma_addr_t dma_addr = 0; ++ s32 cur_poc; ++ u32 flags; + + if (dpb[dpb_idx].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE) + dma_addr = hantro_get_ref(ctx, dpb[dpb_idx].reference_ts); +@@ -332,7 +383,15 @@ dma_addr_t hantro_h264_get_ref_buf(struct hantro_ctx *ctx, + dma_addr = hantro_get_dec_buf_addr(ctx, buf); + } + +- return dma_addr; ++ cur_poc = dec_param->flags & V4L2_H264_DECODE_PARAM_FLAG_BOTTOM_FIELD ? ++ dec_param->bottom_field_order_cnt : ++ dec_param->top_field_order_cnt; ++ flags = dpb[dpb_idx].flags & V4L2_H264_DPB_ENTRY_FLAG_FIELD ? 0x2 : 0; ++ flags |= abs(dpb[dpb_idx].top_field_order_cnt - cur_poc) < ++ abs(dpb[dpb_idx].bottom_field_order_cnt - cur_poc) ? ++ 0x1 : 0; ++ ++ return dma_addr | flags; + } + + int hantro_h264_dec_prepare_run(struct hantro_ctx *ctx) +diff --git a/drivers/staging/media/hantro/hantro_hw.h b/drivers/staging/media/hantro/hantro_hw.h +index 219283a06f52..7e35140a4f22 100644 +--- a/drivers/staging/media/hantro/hantro_hw.h ++++ b/drivers/staging/media/hantro/hantro_hw.h +@@ -90,6 +90,8 @@ struct hantro_h264_dec_hw_ctx { + struct v4l2_h264_dpb_entry dpb[HANTRO_H264_DPB_SIZE]; + struct hantro_h264_dec_reflists reflists; + struct hantro_h264_dec_ctrls ctrls; ++ u32 dpb_longterm; ++ u32 dpb_valid; + }; + + /** + +From badc3bfbfabd4fd01837498a4dd6bc84420bea79 Mon Sep 17 00:00:00 2001 +From: Randy Li +Date: Sun, 6 Jan 2019 01:48:37 +0800 +Subject: [PATCH] soc: rockchip: power-domain: export idle request + +We need to put the power status of HEVC IP into IDLE unless +we can't reset that IP or the SoC would crash down. +rockchip_pmu_idle_request(dev, true)---> enter idle +rockchip_pmu_idle_request(dev, false)---> exit idle + +Signed-off-by: Caesar Wang +Signed-off-by: Jeffy Chen +Signed-off-by: Randy Li +--- + drivers/soc/rockchip/pm_domains.c | 23 +++++++++++++++++++++++ + include/linux/rockchip_pmu.h | 15 +++++++++++++++ + include/soc/rockchip/pm_domains.h | 18 ++++++++++++++++++ + 3 files changed, 56 insertions(+) + create mode 100644 include/linux/rockchip_pmu.h + create mode 100644 include/soc/rockchip/pm_domains.h + +diff --git a/drivers/soc/rockchip/pm_domains.c b/drivers/soc/rockchip/pm_domains.c +index 54eb6cfc5d5b..727af107e6d3 100644 +--- a/drivers/soc/rockchip/pm_domains.c ++++ b/drivers/soc/rockchip/pm_domains.c +@@ -196,6 +196,29 @@ static int rockchip_pmu_set_idle_request(struct rockchip_pm_domain *pd, + return 0; + } + ++int rockchip_pmu_idle_request(struct device *dev, bool idle) ++{ ++ struct generic_pm_domain *genpd; ++ struct rockchip_pm_domain *pd; ++ int ret; ++ ++ if (IS_ERR_OR_NULL(dev)) ++ return -EINVAL; ++ ++ if (IS_ERR_OR_NULL(dev->pm_domain)) ++ return -EINVAL; ++ ++ genpd = pd_to_genpd(dev->pm_domain); ++ pd = to_rockchip_pd(genpd); ++ ++ mutex_lock(&pd->pmu->mutex); ++ ret = rockchip_pmu_set_idle_request(pd, idle); ++ mutex_unlock(&pd->pmu->mutex); ++ ++ return ret; ++} ++EXPORT_SYMBOL(rockchip_pmu_idle_request); ++ + static int rockchip_pmu_save_qos(struct rockchip_pm_domain *pd) + { + int i; +diff --git a/include/linux/rockchip_pmu.h b/include/linux/rockchip_pmu.h +new file mode 100644 +index 000000000000..720b3314e71a +--- /dev/null ++++ b/include/linux/rockchip_pmu.h +@@ -0,0 +1,15 @@ ++/* ++ * pm_domain.h - Definitions and headers related to device power domains. ++ * ++ * Copyright (C) 2017 Randy Li . ++ * ++ * This file is released under the GPLv2. ++ */ ++ ++#ifndef _LINUX_ROCKCHIP_PM_H ++#define _LINUX_ROCKCHIP_PM_H ++#include ++ ++int rockchip_pmu_idle_request(struct device *dev, bool idle); ++ ++#endif /* _LINUX_ROCKCHIP_PM_H */ +diff --git a/include/soc/rockchip/pm_domains.h b/include/soc/rockchip/pm_domains.h +new file mode 100644 +index 000000000000..690db6118636 +--- /dev/null ++++ b/include/soc/rockchip/pm_domains.h +@@ -0,0 +1,18 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++#ifndef __SOC_ROCKCHIP_PM_DOMAINS_H ++#define __SOC_ROCKCHIP_PM_DOMAINS_H ++ ++#include ++ ++struct device; ++ ++#ifdef CONFIG_ROCKCHIP_PM_DOMAINS ++int rockchip_pmu_idle_request(struct device *dev, bool idle); ++#else ++static inline int rockchip_pmu_idle_request(struct device *dev, bool idle) ++{ ++ return -ENOTSUPP; ++} ++#endif ++ ++#endif + +From 495e11bbb264dfb5f1d8b319ed647901fc91dc11 Mon Sep 17 00:00:00 2001 +From: Alex Bee +Date: Wed, 20 May 2020 17:04:47 +0200 +Subject: [PATCH] media: rkvdec: implement reset controls + +--- + .../bindings/media/rockchip,vdec.yaml | 19 ++++++ + drivers/staging/media/rkvdec/rkvdec-regs.h | 5 ++ + drivers/staging/media/rkvdec/rkvdec.c | 60 +++++++++++++++++++ + drivers/staging/media/rkvdec/rkvdec.h | 11 +++- + 4 files changed, 94 insertions(+), 1 deletion(-) + +diff --git a/Documentation/devicetree/bindings/media/rockchip,vdec.yaml b/Documentation/devicetree/bindings/media/rockchip,vdec.yaml +index 8d35c327018b..1e8cfd8e032b 100644 +--- a/Documentation/devicetree/bindings/media/rockchip,vdec.yaml ++++ b/Documentation/devicetree/bindings/media/rockchip,vdec.yaml +@@ -43,6 +43,18 @@ properties: + iommus: + maxItems: 1 + ++ resets: ++ maxItems: 6 ++ ++ reset-names: ++ items: ++ - const: video_h ++ - const: video_a ++ - const: video_core ++ - const: video_cabac ++ - const: niu_a ++ - const: niu_h ++ + required: + - compatible + - reg +@@ -50,6 +62,8 @@ required: + - clocks + - clock-names + - power-domains ++ - resets ++ - reset-names + + additionalProperties: false + +@@ -68,6 +82,11 @@ examples: + clock-names = "axi", "ahb", "cabac", "core"; + power-domains = <&power RK3399_PD_VDU>; + iommus = <&vdec_mmu>; ++ resets = <&cru SRST_H_VDU>, <&cru SRST_A_VDU>, ++ <&cru SRST_VDU_CORE>, <&cru SRST_VDU_CA>, ++ <&cru SRST_A_VDU_NOC>, <&cru SRST_H_VDU_NOC>; ++ reset-names = "video_h", "video_a", "video_core", "video_cabac", ++ "niu_a", "niu_h" + }; + + ... +diff --git a/drivers/staging/media/rkvdec/rkvdec-regs.h b/drivers/staging/media/rkvdec/rkvdec-regs.h +index 83bf790ed9b7..4addfaefdfb4 100644 +--- a/drivers/staging/media/rkvdec/rkvdec-regs.h ++++ b/drivers/staging/media/rkvdec/rkvdec-regs.h +@@ -28,6 +28,11 @@ + #define RKVDEC_SOFTRST_EN_P BIT(20) + #define RKVDEC_FORCE_SOFTRESET_VALID BIT(21) + #define RKVDEC_SOFTRESET_RDY BIT(22) ++#define RKVDEC_ERR_MASK (RKVDEC_BUS_STA \ ++ | RKVDEC_ERR_STA \ ++ | RKVDEC_TIMEOUT_STA \ ++ | RKVDEC_BUF_EMPTY_STA \ ++ | RKVDEC_COLMV_REF_ERR_STA ) + + #define RKVDEC_REG_SYSCTRL 0x008 + #define RKVDEC_IN_ENDIAN BIT(0) +diff --git a/drivers/staging/media/rkvdec/rkvdec.c b/drivers/staging/media/rkvdec/rkvdec.c +index 869275a411c8..74f566e65413 100644 +--- a/drivers/staging/media/rkvdec/rkvdec.c ++++ b/drivers/staging/media/rkvdec/rkvdec.c +@@ -10,12 +10,15 @@ + */ + + #include ++#include + #include + #include + #include + #include + #include + #include ++#include ++#include + #include + #include + #include +@@ -871,6 +874,11 @@ static void rkvdec_job_finish(struct rkvdec_ctx *ctx, + + pm_runtime_mark_last_busy(rkvdec->dev); + pm_runtime_put_autosuspend(rkvdec->dev); ++ ++ if (result == VB2_BUF_STATE_ERROR && ++ rkvdec->reset_mask == RESET_NONE) ++ rkvdec->reset_mask |= RESET_SOFT; ++ + rkvdec_job_finish_no_pm(ctx, result); + } + +@@ -908,6 +916,40 @@ static void rkvdec_device_run(void *priv) + + if (WARN_ON(!desc)) + return; ++ if (rkvdec->reset_mask != RESET_NONE) { ++ ++ if (rkvdec->reset_mask & RESET_SOFT) { ++ writel(RKVDEC_SOFTRST_EN_P, ++ rkvdec->regs + RKVDEC_REG_INTERRUPT); ++ udelay(RKVDEC_RESET_DELAY); ++ if (readl(rkvdec->regs + RKVDEC_REG_INTERRUPT) ++ & RKVDEC_SOFTRESET_RDY) ++ dev_info_ratelimited(rkvdec->dev, ++ "softreset failed\n"); ++ else ++ dev_notice_ratelimited(rkvdec->dev, ++ "softreset done\n"); ++ } ++ ++ if (rkvdec->reset_mask & RESET_HARD) { ++ pm_runtime_suspend(rkvdec->dev); ++ rockchip_pmu_idle_request(rkvdec->dev, true); ++ ret = reset_control_assert(rkvdec->rstc); ++ if (!ret) { ++ udelay(RKVDEC_RESET_DELAY); ++ ret = reset_control_deassert(rkvdec->rstc); ++ } ++ rockchip_pmu_idle_request(rkvdec->dev, false); ++ if (ret) ++ dev_notice_ratelimited(rkvdec->dev, ++ "hardreset failed\n"); ++ else ++ dev_notice_ratelimited(rkvdec->dev, ++ "hardreset done\n"); ++ } ++ ++ rkvdec->reset_mask = RESET_NONE; ++ } + + ret = pm_runtime_get_sync(rkvdec->dev); + if (ret < 0) { +@@ -1175,6 +1217,11 @@ static irqreturn_t rkvdec_irq_handler(int irq, void *priv) + if (cancel_delayed_work(&rkvdec->watchdog_work)) { + struct rkvdec_ctx *ctx; + ++ if (state == VB2_BUF_STATE_ERROR) { ++ rkvdec->reset_mask |= (status & RKVDEC_ERR_MASK) ? ++ RESET_HARD : RESET_SOFT; ++ } ++ + ctx = v4l2_m2m_get_curr_priv(rkvdec->m2m_dev); + rkvdec_job_finish(ctx, state); + } +@@ -1192,6 +1239,7 @@ static void rkvdec_watchdog_func(struct work_struct *work) + ctx = v4l2_m2m_get_curr_priv(rkvdec->m2m_dev); + if (ctx) { + dev_err(rkvdec->dev, "Frame processing timed out!\n"); ++ rkvdec->reset_mask |= RESET_HARD; + writel(RKVDEC_CONFIG_DEC_CLK_GATE_E | RKVDEC_IRQ_DIS, + rkvdec->regs + RKVDEC_REG_INTERRUPT); + writel(0, rkvdec->regs + RKVDEC_REG_SYSCTRL); +@@ -1271,6 +1319,18 @@ static int rkvdec_probe(struct platform_device *pdev) + return ret; + } + ++ ++ rkvdec->rstc = devm_reset_control_array_get(&pdev->dev, false, true); ++ if (IS_ERR(rkvdec->rstc)) { ++ dev_err(&pdev->dev, ++ "get resets failed %ld\n", PTR_ERR(rkvdec->rstc)); ++ return PTR_ERR(rkvdec->rstc); ++ } else { ++ dev_dbg(&pdev->dev, ++ "requested %d resets\n", ++ reset_control_get_count(&pdev->dev)); ++ } ++ + pm_runtime_set_autosuspend_delay(&pdev->dev, 100); + pm_runtime_use_autosuspend(&pdev->dev); + pm_runtime_enable(&pdev->dev); +diff --git a/drivers/staging/media/rkvdec/rkvdec.h b/drivers/staging/media/rkvdec/rkvdec.h +index d5600c6a4c17..975fe4b5dd68 100644 +--- a/drivers/staging/media/rkvdec/rkvdec.h ++++ b/drivers/staging/media/rkvdec/rkvdec.h +@@ -11,10 +11,11 @@ + #ifndef RKVDEC_H_ + #define RKVDEC_H_ + ++#include + #include ++#include + #include + #include +-#include + + #include + #include +@@ -22,6 +23,12 @@ + #include + #include + ++#define RESET_NONE 0 ++#define RESET_SOFT BIT(0) ++#define RESET_HARD BIT(1) ++ ++#define RKVDEC_RESET_DELAY 5 ++ + struct rkvdec_ctx; + + struct rkvdec_ctrl_desc { +@@ -95,6 +102,8 @@ struct rkvdec_dev { + void __iomem *regs; + struct mutex vdev_lock; /* serializes ioctls */ + struct delayed_work watchdog_work; ++ struct reset_control *rstc; ++ u8 reset_mask; + }; + + struct rkvdec_ctx { + +From 0f3ef2d452750f5688292c232b6c7d28ce2b0095 Mon Sep 17 00:00:00 2001 +From: Alex Bee +Date: Tue, 18 Aug 2020 11:38:04 +0200 +Subject: [PATCH] WIP: arm64: dts: add resets to vdec for RK3399 + +--- + arch/arm64/boot/dts/rockchip/rk3399.dtsi | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/arch/arm64/boot/dts/rockchip/rk3399.dtsi b/arch/arm64/boot/dts/rockchip/rk3399.dtsi +index 8973bf68d652..1efe2c916508 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3399.dtsi ++++ b/arch/arm64/boot/dts/rockchip/rk3399.dtsi +@@ -1281,6 +1281,11 @@ vdec: video-codec@ff660000 { + clock-names = "axi", "ahb", "cabac", "core"; + iommus = <&vdec_mmu>; + power-domains = <&power RK3399_PD_VDU>; ++ resets = <&cru SRST_H_VDU>, <&cru SRST_A_VDU>, ++ <&cru SRST_VDU_CORE>, <&cru SRST_VDU_CA>, ++ <&cru SRST_A_VDU_NOC>, <&cru SRST_H_VDU_NOC>; ++ reset-names = "video_h", "video_a", "video_core", "video_cabac", ++ "niu_a", "niu_h" + }; + + vdec_mmu: iommu@ff660480 { + +From 98eac32dca51c74be1d223854976b834ac2d9587 Mon Sep 17 00:00:00 2001 +From: Alex Bee +Date: Fri, 24 Apr 2020 12:36:13 +0200 +Subject: [PATCH] media: hantro: add Rockchip RK3228 + +RK3228 has the same VPU IP-Block as RK3399 has and at the current state +the driver can be taken as is. +This adds just a new compatible string to bindings file if any future +ajustment for this SoC is necessary. +--- + Documentation/devicetree/bindings/media/rockchip-vpu.yaml | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/Documentation/devicetree/bindings/media/rockchip-vpu.yaml b/Documentation/devicetree/bindings/media/rockchip-vpu.yaml +index 2b629456d75f..4509891a0f0f 100644 +--- a/Documentation/devicetree/bindings/media/rockchip-vpu.yaml ++++ b/Documentation/devicetree/bindings/media/rockchip-vpu.yaml +@@ -16,6 +16,7 @@ description: + properties: + compatible: + enum: ++ - rockchip,rk3228-vpu + - rockchip,rk3288-vpu + - rockchip,rk3328-vpu + - rockchip,rk3399-vpu + +From e47b8ed20a45dcb324b997e5fa74586f71fc71cc Mon Sep 17 00:00:00 2001 +From: Alex Bee +Date: Fri, 24 Apr 2020 12:38:24 +0200 +Subject: [PATCH] ARM: dts: rockchip: add vpu node for RK322x + +This adds VPU node to RK3228. While at it also add the required power-domain +controller and qos node to make the VPU work on this SoC. +--- + arch/arm/boot/dts/rk322x.dtsi | 35 +++++++++++++++++++++++++++++++++-- + 1 file changed, 33 insertions(+), 2 deletions(-) + +diff --git a/arch/arm/boot/dts/rk322x.dtsi b/arch/arm/boot/dts/rk322x.dtsi +index b69b5be110c3..0586a89d24d3 100644 +--- a/arch/arm/boot/dts/rk322x.dtsi ++++ b/arch/arm/boot/dts/rk322x.dtsi +@@ -6,6 +6,7 @@ + #include + #include + #include ++#include + + / { + #address-cells = <1>; +@@ -208,6 +209,19 @@ io_domains: io-domains { + status = "disabled"; + }; + ++ power: power-controller { ++ compatible = "rockchip,rk3228-power-controller"; ++ #power-domain-cells = <1>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ pd_vpu@RK3228_PD_VPU { ++ reg = ; ++ clocks = <&cru ACLK_VPU>, <&cru HCLK_VPU>; ++ pm_qos = <&qos_vpu>; ++ }; ++ }; ++ + u2phy0: usb2-phy@760 { + compatible = "rockchip,rk3228-usb2phy"; + reg = <0x0760 0x0c>; +@@ -561,6 +575,18 @@ gpu: gpu@20000000 { + status = "disabled"; + }; + ++ vpu: video-codec@20020000 { ++ compatible = "rockchip,rk3228-vpu", "rockchip,rk3399-vpu"; ++ reg = <0x20020000 0x800>; ++ interrupts = , ++ ; ++ interrupt-names = "vepu", "vdpu"; ++ clocks = <&cru ACLK_VPU>, <&cru HCLK_VPU>; ++ clock-names = "aclk", "hclk"; ++ iommus = <&vpu_mmu>; ++ power-domains = <&power RK3228_PD_VPU>; ++ }; ++ + vpu_mmu: iommu@20020800 { + compatible = "rockchip,iommu"; + reg = <0x20020800 0x100>; +@@ -568,8 +594,8 @@ vpu_mmu: iommu@20020800 { + interrupt-names = "vpu_mmu"; + clocks = <&cru ACLK_VPU>, <&cru HCLK_VPU>; + clock-names = "aclk", "iface"; +- iommu-cells = <0>; +- status = "disabled"; ++ power-domains = <&power RK3228_PD_VPU>; ++ #iommu-cells = <0>; + }; + + vdec_mmu: iommu@20030480 { +@@ -807,6 +833,11 @@ gmac: ethernet@30200000 { + status = "disabled"; + }; + ++ qos_vpu: qos@31040000 { ++ compatible = "syscon"; ++ reg = <0x31040000 0x20>; ++ }; ++ + gic: interrupt-controller@32010000 { + compatible = "arm,gic-400"; + interrupt-controller; + +From 70feb241848426de731a1f8bc5ad0d9c45bf5bfa Mon Sep 17 00:00:00 2001 +From: Alex Bee +Date: Tue, 26 May 2020 14:11:57 +0200 +Subject: [PATCH] media: hantro: add support for RK3188 + +RK3188s VPU IP-Block is the predecessor from what RK3288 has. + +While most of the registers match in the current state of the driver +there are some HW differences: + - supports resultion up to 1920x1088 only + - has one aclk and one hclk per vdpu/vepu + - doesn't have the 'G1_REG_SOFT_RESET' register + - ACLKs can be clocked up to 300 MHz only + - no MMU for VPU +These make it necessary to add another variant to the driver. + +This should be also reuseable for RK3066 but has not been tested, +so I'm not adding it here. +--- + .../bindings/media/rockchip-vpu.yaml | 7 +- + drivers/staging/media/hantro/hantro_drv.c | 1 + + drivers/staging/media/hantro/hantro_hw.h | 1 + + drivers/staging/media/hantro/rk3288_vpu_hw.c | 116 ++++++++++++++++++ + 4 files changed, 124 insertions(+), 1 deletion(-) + +diff --git a/Documentation/devicetree/bindings/media/rockchip-vpu.yaml b/Documentation/devicetree/bindings/media/rockchip-vpu.yaml +index 4509891a0f0f..d95274bf3b0f 100644 +--- a/Documentation/devicetree/bindings/media/rockchip-vpu.yaml ++++ b/Documentation/devicetree/bindings/media/rockchip-vpu.yaml +@@ -16,6 +16,7 @@ description: + properties: + compatible: + enum: ++ - rockchip,rk3188-vpu + - rockchip,rk3228-vpu + - rockchip,rk3288-vpu + - rockchip,rk3328-vpu +@@ -36,12 +37,16 @@ properties: + - const: vdpu + + clocks: +- maxItems: 2 ++ maxItems: 4 + + clock-names: + items: + - const: aclk ++ - const: aclk_vdpu ++ - const: aclk_vepu + - const: hclk ++ - const: hclk_vdpu ++ - const: hclk_vepu + + power-domains: + maxItems: 1 +diff --git a/drivers/staging/media/hantro/hantro_drv.c b/drivers/staging/media/hantro/hantro_drv.c +index 3cd00cc0a364..ecc0938b7f35 100644 +--- a/drivers/staging/media/hantro/hantro_drv.c ++++ b/drivers/staging/media/hantro/hantro_drv.c +@@ -475,6 +475,7 @@ static const struct of_device_id of_hantro_match[] = { + { .compatible = "rockchip,rk3399-vpu", .data = &rk3399_vpu_variant, }, + { .compatible = "rockchip,rk3328-vpu", .data = &rk3328_vpu_variant, }, + { .compatible = "rockchip,rk3288-vpu", .data = &rk3288_vpu_variant, }, ++ { .compatible = "rockchip,rk3188-vpu", .data = &rk3188_vpu_variant, }, + #endif + #ifdef CONFIG_VIDEO_HANTRO_IMX8M + { .compatible = "nxp,imx8mq-vpu", .data = &imx8mq_vpu_variant, }, +diff --git a/drivers/staging/media/hantro/hantro_hw.h b/drivers/staging/media/hantro/hantro_hw.h +index 7e35140a4f22..22b0ed01f673 100644 +--- a/drivers/staging/media/hantro/hantro_hw.h ++++ b/drivers/staging/media/hantro/hantro_hw.h +@@ -152,6 +152,7 @@ enum hantro_enc_fmt { + RK3288_VPU_ENC_FMT_UYVY422 = 3, + }; + ++extern const struct hantro_variant rk3188_vpu_variant; + extern const struct hantro_variant rk3399_vpu_variant; + extern const struct hantro_variant rk3328_vpu_variant; + extern const struct hantro_variant rk3288_vpu_variant; +diff --git a/drivers/staging/media/hantro/rk3288_vpu_hw.c b/drivers/staging/media/hantro/rk3288_vpu_hw.c +index 7b299ee3e93d..1ac00695a864 100644 +--- a/drivers/staging/media/hantro/rk3288_vpu_hw.c ++++ b/drivers/staging/media/hantro/rk3288_vpu_hw.c +@@ -13,6 +13,7 @@ + #include "hantro_g1_regs.h" + #include "hantro_h1_regs.h" + ++#define RK3188_ACLK_MAX_FREQ (300 * 1000 * 1000) + #define RK3288_ACLK_MAX_FREQ (400 * 1000 * 1000) + + /* +@@ -63,6 +64,52 @@ static const struct hantro_fmt rk3288_vpu_postproc_fmts[] = { + }, + }; + ++static const struct hantro_fmt rk3188_vpu_dec_fmts[] = { ++ { ++ .fourcc = V4L2_PIX_FMT_NV12, ++ .codec_mode = HANTRO_MODE_NONE, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_H264_SLICE, ++ .codec_mode = HANTRO_MODE_H264_DEC, ++ .max_depth = 2, ++ .frmsize = { ++ .min_width = 48, ++ .max_width = 1920, ++ .step_width = MB_DIM, ++ .min_height = 48, ++ .max_height = 1088, ++ .step_height = MB_DIM, ++ }, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_MPEG2_SLICE, ++ .codec_mode = HANTRO_MODE_MPEG2_DEC, ++ .max_depth = 2, ++ .frmsize = { ++ .min_width = 48, ++ .max_width = 1920, ++ .step_width = MB_DIM, ++ .min_height = 48, ++ .max_height = 1088, ++ .step_height = MB_DIM, ++ }, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_VP8_FRAME, ++ .codec_mode = HANTRO_MODE_VP8_DEC, ++ .max_depth = 2, ++ .frmsize = { ++ .min_width = 48, ++ .max_width = 1920, ++ .step_width = MB_DIM, ++ .min_height = 48, ++ .max_height = 1088, ++ .step_height = MB_DIM, ++ }, ++ }, ++}; ++ + static const struct hantro_fmt rk3288_vpu_dec_fmts[] = { + { + .fourcc = V4L2_PIX_FMT_NV12, +@@ -145,6 +192,14 @@ static irqreturn_t rk3288_vdpu_irq(int irq, void *dev_id) + return IRQ_HANDLED; + } + ++static int rk3188_vpu_hw_init(struct hantro_dev *vpu) ++{ ++ /* Bump ACLKs to max. possible freq. to improve performance. */ ++ clk_set_rate(vpu->clocks[0].clk, RK3188_ACLK_MAX_FREQ); ++ clk_set_rate(vpu->clocks[2].clk, RK3188_ACLK_MAX_FREQ); ++ return 0; ++} ++ + static int rk3288_vpu_hw_init(struct hantro_dev *vpu) + { + /* Bump ACLK to max. possible freq. to improve performance. */ +@@ -161,6 +216,15 @@ static void rk3288_vpu_enc_reset(struct hantro_ctx *ctx) + vepu_write(vpu, 0, H1_REG_AXI_CTRL); + } + ++ ++static void rk3188_vpu_dec_reset(struct hantro_ctx *ctx) ++{ ++ struct hantro_dev *vpu = ctx->dev; ++ ++ vdpu_write(vpu, G1_REG_INTERRUPT_DEC_IRQ_DIS, G1_REG_INTERRUPT); ++ vdpu_write(vpu, G1_REG_CONFIG_DEC_CLK_GATE_E, G1_REG_CONFIG); ++} ++ + static void rk3288_vpu_dec_reset(struct hantro_ctx *ctx) + { + struct hantro_dev *vpu = ctx->dev; +@@ -174,6 +238,33 @@ static void rk3288_vpu_dec_reset(struct hantro_ctx *ctx) + * Supported codec ops. + */ + ++static const struct hantro_codec_ops rk3188_vpu_codec_ops[] = { ++ [HANTRO_MODE_JPEG_ENC] = { ++ .run = hantro_h1_jpeg_enc_run, ++ .reset = rk3288_vpu_enc_reset, ++ .init = hantro_jpeg_enc_init, ++ .exit = hantro_jpeg_enc_exit, ++ }, ++ [HANTRO_MODE_H264_DEC] = { ++ .run = hantro_g1_h264_dec_run, ++ .reset = rk3188_vpu_dec_reset, ++ .init = hantro_h264_dec_init, ++ .exit = hantro_h264_dec_exit, ++ }, ++ [HANTRO_MODE_MPEG2_DEC] = { ++ .run = hantro_g1_mpeg2_dec_run, ++ .reset = rk3188_vpu_dec_reset, ++ .init = hantro_mpeg2_dec_init, ++ .exit = hantro_mpeg2_dec_exit, ++ }, ++ [HANTRO_MODE_VP8_DEC] = { ++ .run = hantro_g1_vp8_dec_run, ++ .reset = rk3188_vpu_dec_reset, ++ .init = hantro_vp8_dec_init, ++ .exit = hantro_vp8_dec_exit, ++ }, ++}; ++ + static const struct hantro_codec_ops rk3288_vpu_codec_ops[] = { + [HANTRO_MODE_JPEG_ENC] = { + .run = hantro_h1_jpeg_enc_run, +@@ -211,10 +302,35 @@ static const struct hantro_irq rk3288_irqs[] = { + { "vdpu", rk3288_vdpu_irq }, + }; + ++static const char * const rk3188_clk_names[] = { ++ "aclk_vdpu", "hclk_vdpu", ++ "aclk_vepu", "hclk_vepu", ++}; ++ + static const char * const rk3288_clk_names[] = { + "aclk", "hclk" + }; + ++const struct hantro_variant rk3188_vpu_variant = { ++ .enc_offset = 0x0, ++ .enc_fmts = rk3288_vpu_enc_fmts, ++ .num_enc_fmts = ARRAY_SIZE(rk3288_vpu_enc_fmts), ++ .dec_offset = 0x400, ++ .dec_fmts = rk3188_vpu_dec_fmts, ++ .num_dec_fmts = ARRAY_SIZE(rk3188_vpu_dec_fmts), ++ .postproc_fmts = rk3288_vpu_postproc_fmts, ++ .num_postproc_fmts = ARRAY_SIZE(rk3288_vpu_postproc_fmts), ++ .postproc_regs = &hantro_g1_postproc_regs, ++ .codec = HANTRO_JPEG_ENCODER | HANTRO_MPEG2_DECODER | ++ HANTRO_VP8_DECODER | HANTRO_H264_DECODER, ++ .codec_ops = rk3188_vpu_codec_ops, ++ .irqs = rk3288_irqs, ++ .num_irqs = ARRAY_SIZE(rk3288_irqs), ++ .init = rk3188_vpu_hw_init, ++ .clk_names = rk3188_clk_names, ++ .num_clocks = ARRAY_SIZE(rk3188_clk_names) ++}; ++ + const struct hantro_variant rk3288_vpu_variant = { + .enc_offset = 0x0, + .enc_fmts = rk3288_vpu_enc_fmts, + +From 134592088d9c703169c9daff5793e0321ecc245d Mon Sep 17 00:00:00 2001 +From: Alex Bee +Date: Tue, 26 May 2020 14:12:35 +0200 +Subject: [PATCH] ARM: dts: rockchip: add vpu node for RK3188 + +Add VPU node to RK3188s dtsi. +--- + arch/arm/boot/dts/rk3188.dtsi | 13 +++++++++++++ + 1 file changed, 13 insertions(+) + +diff --git a/arch/arm/boot/dts/rk3188.dtsi b/arch/arm/boot/dts/rk3188.dtsi +index 2298a8d840ba..b6c1699345d0 100644 +--- a/arch/arm/boot/dts/rk3188.dtsi ++++ b/arch/arm/boot/dts/rk3188.dtsi +@@ -112,6 +112,19 @@ smp-sram@0 { + }; + }; + ++ vpu: video-codec@10104000 { ++ compatible = "rockchip,rk3188-vpu"; ++ reg = <0x10104000 0x800>; ++ interrupts = , ++ ; ++ interrupt-names = "vepu", "vdpu"; ++ clocks = <&cru ACLK_VDPU>, <&cru HCLK_VDPU>, ++ <&cru ACLK_VEPU>, <&cru HCLK_VEPU>; ++ clock-names = "aclk_vdpu", "hclk_vdpu", ++ "aclk_vepu", "hclk_vepu"; ++ power-domains = <&power RK3188_PD_VIDEO>; ++ }; ++ + vop0: vop@1010c000 { + compatible = "rockchip,rk3188-vop"; + reg = <0x1010c000 0x1000>; + +From 573413b3e49d1ca7676c976aa3e7d6bb65e497ed Mon Sep 17 00:00:00 2001 +From: Alex Bee +Date: Tue, 26 May 2020 17:24:12 +0200 +Subject: [PATCH] media: hantro: add support for Rockchip RK3036 + +RK3036 shares the hantro VPU IP Block with RK3288. +HW differences are: +- supports decoding up to 1920x1088 only +- ACLK can be clocked at max. 300MHz +This makes adding another variant to the driver necessary here also. + +However RK3036 TRM does not mention that it has an encoder also. I verfied +this on my devices and it worked for JPEG encoding. Since the identification +register share the id with RK3288 and the fact that it has an interrupt for +video encoding, makes me think that the encoding IP is the same. + +This variant could also be used for RK312x, but has not been tested. +--- + drivers/staging/media/hantro/hantro_drv.c | 1 + + drivers/staging/media/hantro/hantro_hw.h | 1 + + drivers/staging/media/hantro/rk3288_vpu_hw.c | 27 ++++++++++++++++++++ + 3 files changed, 29 insertions(+) + +diff --git a/drivers/staging/media/hantro/hantro_drv.c b/drivers/staging/media/hantro/hantro_drv.c +index ecc0938b7f35..ee59fad9a2f3 100644 +--- a/drivers/staging/media/hantro/hantro_drv.c ++++ b/drivers/staging/media/hantro/hantro_drv.c +@@ -476,6 +476,7 @@ static const struct of_device_id of_hantro_match[] = { + { .compatible = "rockchip,rk3328-vpu", .data = &rk3328_vpu_variant, }, + { .compatible = "rockchip,rk3288-vpu", .data = &rk3288_vpu_variant, }, + { .compatible = "rockchip,rk3188-vpu", .data = &rk3188_vpu_variant, }, ++ { .compatible = "rockchip,rk3036-vpu", .data = &rk3036_vpu_variant, }, + #endif + #ifdef CONFIG_VIDEO_HANTRO_IMX8M + { .compatible = "nxp,imx8mq-vpu", .data = &imx8mq_vpu_variant, }, +diff --git a/drivers/staging/media/hantro/hantro_hw.h b/drivers/staging/media/hantro/hantro_hw.h +index 22b0ed01f673..ede7acec5e9f 100644 +--- a/drivers/staging/media/hantro/hantro_hw.h ++++ b/drivers/staging/media/hantro/hantro_hw.h +@@ -152,6 +152,7 @@ enum hantro_enc_fmt { + RK3288_VPU_ENC_FMT_UYVY422 = 3, + }; + ++extern const struct hantro_variant rk3036_vpu_variant; + extern const struct hantro_variant rk3188_vpu_variant; + extern const struct hantro_variant rk3399_vpu_variant; + extern const struct hantro_variant rk3328_vpu_variant; +diff --git a/drivers/staging/media/hantro/rk3288_vpu_hw.c b/drivers/staging/media/hantro/rk3288_vpu_hw.c +index 1ac00695a864..b5887fdae250 100644 +--- a/drivers/staging/media/hantro/rk3288_vpu_hw.c ++++ b/drivers/staging/media/hantro/rk3288_vpu_hw.c +@@ -192,6 +192,13 @@ static irqreturn_t rk3288_vdpu_irq(int irq, void *dev_id) + return IRQ_HANDLED; + } + ++static int rk3036_vpu_hw_init(struct hantro_dev *vpu) ++{ ++ /* Bump ACLK to max. possible freq. to improve performance. */ ++ clk_set_rate(vpu->clocks[0].clk, RK3188_ACLK_MAX_FREQ); ++ return 0; ++} ++ + static int rk3188_vpu_hw_init(struct hantro_dev *vpu) + { + /* Bump ACLKs to max. possible freq. to improve performance. */ +@@ -311,6 +318,26 @@ static const char * const rk3288_clk_names[] = { + "aclk", "hclk" + }; + ++const struct hantro_variant rk3036_vpu_variant = { ++ .enc_offset = 0x0, ++ .enc_fmts = rk3288_vpu_enc_fmts, ++ .num_enc_fmts = ARRAY_SIZE(rk3288_vpu_enc_fmts), ++ .dec_offset = 0x400, ++ .dec_fmts = rk3188_vpu_dec_fmts, ++ .num_dec_fmts = ARRAY_SIZE(rk3188_vpu_dec_fmts), ++ .postproc_fmts = rk3288_vpu_postproc_fmts, ++ .num_postproc_fmts = ARRAY_SIZE(rk3288_vpu_postproc_fmts), ++ .postproc_regs = &hantro_g1_postproc_regs, ++ .codec = HANTRO_JPEG_ENCODER | HANTRO_MPEG2_DECODER | ++ HANTRO_VP8_DECODER | HANTRO_H264_DECODER, ++ .codec_ops = rk3288_vpu_codec_ops, ++ .irqs = rk3288_irqs, ++ .num_irqs = ARRAY_SIZE(rk3288_irqs), ++ .init = rk3036_vpu_hw_init, ++ .clk_names = rk3288_clk_names, ++ .num_clocks = ARRAY_SIZE(rk3288_clk_names) ++}; ++ + const struct hantro_variant rk3188_vpu_variant = { + .enc_offset = 0x0, + .enc_fmts = rk3288_vpu_enc_fmts, + +From 387d5e35e99f03bb0caed01163ef393e15b30362 Mon Sep 17 00:00:00 2001 +From: Alex Bee +Date: Tue, 26 May 2020 17:42:55 +0200 +Subject: [PATCH] ARM: dts: rockchip: add vpu node for RK3036 + +This adds VPU node to RK3036. While at it also add the required mmu, +power-domain controller and qos node to make the VPU work on this SoC. +--- + .../bindings/media/rockchip-vpu.yaml | 1 + + arch/arm/boot/dts/rk3036.dtsi | 44 +++++++++++++++++++ + 2 files changed, 45 insertions(+) + +diff --git a/Documentation/devicetree/bindings/media/rockchip-vpu.yaml b/Documentation/devicetree/bindings/media/rockchip-vpu.yaml +index d95274bf3b0f..15aeae3d1daf 100644 +--- a/Documentation/devicetree/bindings/media/rockchip-vpu.yaml ++++ b/Documentation/devicetree/bindings/media/rockchip-vpu.yaml +@@ -16,6 +16,7 @@ description: + properties: + compatible: + enum: ++ - rockchip,rk3036-vpu + - rockchip,rk3188-vpu + - rockchip,rk3228-vpu + - rockchip,rk3288-vpu +diff --git a/arch/arm/boot/dts/rk3036.dtsi b/arch/arm/boot/dts/rk3036.dtsi +index 6be6d9d134fe..10f15cdb932c 100644 +--- a/arch/arm/boot/dts/rk3036.dtsi ++++ b/arch/arm/boot/dts/rk3036.dtsi +@@ -6,6 +6,7 @@ + #include + #include + #include ++#include + + / { + #address-cells = <1>; +@@ -134,6 +135,29 @@ gpu: gpu@10090000 { + status = "disabled"; + }; + ++ vpu: video-codec@10108000 { ++ compatible = "rockchip,rk3036-vpu"; ++ reg = <0x10108000 0x800>; ++ interrupts = , ++ ; ++ interrupt-names = "vepu", "vdpu"; ++ clocks = <&cru ACLK_VCODEC>, <&cru HCLK_VCODEC>; ++ clock-names = "aclk", "hclk"; ++ iommus = <&vpu_mmu>; ++ power-domains = <&power RK3036_PD_VPU>; ++ }; ++ ++ vpu_mmu: iommu@10108800 { ++ compatible = "rockchip,iommu"; ++ reg = <0x10108800 0x100>; ++ interrupts = ; ++ interrupt-names = "vpu_mmu"; ++ clocks = <&cru ACLK_VCODEC>, <&cru HCLK_VCODEC>; ++ clock-names = "aclk", "iface"; ++ power-domains = <&power RK3036_PD_VPU>; ++ #iommu-cells = <0>; ++ }; ++ + vop: vop@10118000 { + compatible = "rockchip,rk3036-vop"; + reg = <0x10118000 0x19c>; +@@ -166,6 +190,11 @@ vop_mmu: iommu@10118300 { + status = "disabled"; + }; + ++ qos_vpu: qos@1012e000 { ++ compatible = "syscon"; ++ reg = <0x1012e000 0x20>; ++ }; ++ + gic: interrupt-controller@10139000 { + compatible = "arm,gic-400"; + interrupt-controller; +@@ -329,6 +358,21 @@ reboot-mode { + mode-bootloader = ; + mode-loader = ; + }; ++ ++ power: power-controller { ++ compatible = "rockchip,rk3036-power-controller"; ++ #power-domain-cells = <1>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ pd_vpu@RK3036_PD_VPU { ++ reg = ; ++ clocks = <&cru ACLK_VCODEC>, ++ <&cru HCLK_VCODEC>; ++ pm_qos = <&qos_vpu>; ++ }; ++ ++ }; + }; + + acodec: acodec-ana@20030000 { + +From 871a3ef06a4100a3d7ecc75d2751acf67269a07c Mon Sep 17 00:00:00 2001 +From: Alex Bee +Date: Tue, 26 May 2020 17:54:22 +0200 +Subject: [PATCH] media: hantro: adapt Kconfig help text + +Since help text line would get very long if all supported SoCs are mentioned +I shortend it to "Rockchip SoCs" +--- + drivers/staging/media/hantro/Kconfig | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/staging/media/hantro/Kconfig b/drivers/staging/media/hantro/Kconfig +index 5b6cf9f62b1a..d33f1ddbc9c9 100644 +--- a/drivers/staging/media/hantro/Kconfig ++++ b/drivers/staging/media/hantro/Kconfig +@@ -30,4 +30,4 @@ config VIDEO_HANTRO_ROCKCHIP + depends on ARCH_ROCKCHIP || COMPILE_TEST + default y + help +- Enable support for RK3288, RK3328, and RK3399 SoCs. ++ Enable support for Rockchip SoCs. + +From 83c9c3f037c52e8c4ada8b5b5f1269ccfa6f6f14 Mon Sep 17 00:00:00 2001 +From: Alex Bee +Date: Sat, 23 May 2020 14:22:54 +0200 +Subject: [PATCH] ARM: dts: rockchip: add vdec node for RK322x + +RK322x has the same VDEC IP block as RK3399 has and the driver in its +current state can be used as is. +Other than RK3399 its SCLKs have also to set to a fixed value to make it +work correctly. Rather than doing this in the driver it is done via +"assigned-clocks" in the vdec node. +--- + arch/arm/boot/dts/rk322x.dtsi | 42 +++++++++++++++++++++++++++++++++-- + 1 file changed, 40 insertions(+), 2 deletions(-) + +diff --git a/arch/arm/boot/dts/rk322x.dtsi b/arch/arm/boot/dts/rk322x.dtsi +index 0586a89d24d3..eec601fb4cd0 100644 +--- a/arch/arm/boot/dts/rk322x.dtsi ++++ b/arch/arm/boot/dts/rk322x.dtsi +@@ -220,6 +220,15 @@ pd_vpu@RK3228_PD_VPU { + clocks = <&cru ACLK_VPU>, <&cru HCLK_VPU>; + pm_qos = <&qos_vpu>; + }; ++ ++ pd_rkvdec@RK3228_PD_RKVDEC { ++ reg = ; ++ clocks = <&cru ACLK_RKVDEC>, ++ <&cru HCLK_RKVDEC>, ++ <&cru SCLK_VDEC_CABAC>, ++ <&cru SCLK_VDEC_CORE>; ++ pm_qos = <&qos_rkvdec_r>, <&qos_rkvdec_w>; ++ }; + }; + + u2phy0: usb2-phy@760 { +@@ -598,6 +607,25 @@ vpu_mmu: iommu@20020800 { + #iommu-cells = <0>; + }; + ++ vdec: video-codec@20030000 { ++ compatible = "rockchip,rk322x-vdec", "rockchip,rk3399-vdec"; ++ reg = <0x20030000 0x400>; ++ interrupts = ; ++ clocks = <&cru ACLK_RKVDEC>, <&cru HCLK_RKVDEC>, ++ <&cru SCLK_VDEC_CABAC>, <&cru SCLK_VDEC_CORE>; ++ clock-names = "axi", "ahb", "cabac", "core"; ++ assigned-clocks = <&cru ACLK_RKVDEC>, <&cru SCLK_VDEC_CABAC>, ++ <&cru SCLK_VDEC_CORE>; ++ assigned-clock-rates = <500000000>, <300000000>, <300000000>; ++ power-domains = <&power RK3228_PD_RKVDEC>; ++ resets = <&cru SRST_RKVDEC_H>, <&cru SRST_RKVDEC_A>, ++ <&cru SRST_RKVDEC_CORE>, <&cru SRST_RKVDEC_CABAC>, ++ <&cru SRST_RKVDEC_NOC_A>, <&cru SRST_RKVDEC_NOC_H>; ++ reset-names = "video_h", "video_a", "video_core", "video_cabac", ++ "niu_a", "niu_h"; ++ iommus = <&vdec_mmu>; ++ }; ++ + vdec_mmu: iommu@20030480 { + compatible = "rockchip,iommu"; + reg = <0x20030480 0x40>, <0x200304c0 0x40>; +@@ -605,8 +633,8 @@ vdec_mmu: iommu@20030480 { + interrupt-names = "vdec_mmu"; + clocks = <&cru ACLK_RKVDEC>, <&cru HCLK_RKVDEC>; + clock-names = "aclk", "iface"; +- iommu-cells = <0>; +- status = "disabled"; ++ power-domains = <&power RK3228_PD_RKVDEC>; ++ #iommu-cells = <0>; + }; + + vop: vop@20050000 { +@@ -838,6 +866,16 @@ qos_vpu: qos@31040000 { + reg = <0x31040000 0x20>; + }; + ++ qos_rkvdec_r: qos@31070000 { ++ compatible = "syscon"; ++ reg = <0x31070000 0x20>; ++ }; ++ ++ qos_rkvdec_w: qos@31070080 { ++ compatible = "syscon"; ++ reg = <0x31070080 0x20>; ++ }; ++ + gic: interrupt-controller@32010000 { + compatible = "arm,gic-400"; + interrupt-controller; diff --git a/patch/kernel/rk322x-dev/01-linux-4000-rockchip-linux-wip.patch b/patch/kernel/rk322x-dev/01-linux-4000-rockchip-linux-wip.patch new file mode 100644 index 000000000..2c2489b47 --- /dev/null +++ b/patch/kernel/rk322x-dev/01-linux-4000-rockchip-linux-wip.patch @@ -0,0 +1,1692 @@ +From a49884fc5063fb0eb3db69568b45e3b8ef5ea094 Mon Sep 17 00:00:00 2001 +From: Finley Xiao +Date: Thu, 22 Jun 2017 20:22:25 +0800 +Subject: [PATCH] clk: rockchip: rk3228: fix some PLL_NUX_CLKs' gates + +Some PLL_NUX_CLKs' gates is actually behind muxs according to latest TRM, +so move the gates to composite clocks and amend their parent clocks. + +Change-Id: Ib6043caa61e9df0473f2d0bdc756850968bb2a55 +Signed-off-by: Finley Xiao +--- + drivers/clk/rockchip/clk-rk3228.c | 53 ++++++++----------------------- + 1 file changed, 14 insertions(+), 39 deletions(-) + +diff --git a/drivers/clk/rockchip/clk-rk3228.c b/drivers/clk/rockchip/clk-rk3228.c +index dd414c8255e3..734126a2ad7e 100644 +--- a/drivers/clk/rockchip/clk-rk3228.c ++++ b/drivers/clk/rockchip/clk-rk3228.c +@@ -130,24 +130,22 @@ static const struct rockchip_cpuclk_reg_data rk3228_cpuclk_data = { + + PNAME(mux_pll_p) = { "clk_24m", "xin24m" }; + +-PNAME(mux_ddrphy_p) = { "dpll_ddr", "gpll_ddr", "apll_ddr" }; +-PNAME(mux_armclk_p) = { "apll_core", "gpll_core", "dpll_core" }; ++PNAME(mux_ddrphy_p) = { "dpll", "gpll", "apll" }; ++PNAME(mux_armclk_p) = { "apll", "gpll", "dpll" }; + PNAME(mux_usb480m_phy_p) = { "usb480m_phy0", "usb480m_phy1" }; + PNAME(mux_usb480m_p) = { "usb480m_phy", "xin24m" }; + PNAME(mux_hdmiphy_p) = { "hdmiphy_phy", "xin24m" }; +-PNAME(mux_aclk_cpu_src_p) = { "cpll_aclk_cpu", "gpll_aclk_cpu", "hdmiphy_aclk_cpu" }; + + PNAME(mux_pll_src_4plls_p) = { "cpll", "gpll", "hdmiphy" "usb480m" }; + PNAME(mux_pll_src_3plls_p) = { "cpll", "gpll", "hdmiphy" }; + PNAME(mux_pll_src_2plls_p) = { "cpll", "gpll" }; + PNAME(mux_sclk_hdmi_cec_p) = { "cpll", "gpll", "xin24m" }; +-PNAME(mux_aclk_peri_src_p) = { "cpll_peri", "gpll_peri", "hdmiphy_peri" }; + PNAME(mux_mmc_src_p) = { "cpll", "gpll", "xin24m", "usb480m" }; + PNAME(mux_pll_src_cpll_gpll_usb480m_p) = { "cpll", "gpll", "usb480m" }; + + PNAME(mux_sclk_rga_p) = { "gpll", "cpll", "sclk_rga_src" }; + +-PNAME(mux_sclk_vop_src_p) = { "gpll_vop", "cpll_vop" }; ++PNAME(mux_sclk_vop_src_p) = { "gpll", "cpll" }; + PNAME(mux_dclk_vop_p) = { "hdmiphy", "sclk_vop_pre" }; + + PNAME(mux_i2s0_p) = { "i2s0_src", "i2s0_frac", "ext_i2s", "xin12m" }; +@@ -216,27 +214,17 @@ static struct rockchip_clk_branch rk3228_clk_branches[] __initdata = { + RK2928_CLKSEL_CON(4), 8, 5, DFLAGS), + + /* PD_DDR */ +- GATE(0, "apll_ddr", "apll", CLK_IGNORE_UNUSED, ++ COMPOSITE(0, "clk_ddrphy_src", mux_ddrphy_p, CLK_IGNORE_UNUSED, ++ RK2928_CLKSEL_CON(26), 8, 2, MFLAGS, 0, 2, DFLAGS | CLK_DIVIDER_POWER_OF_TWO, + RK2928_CLKGATE_CON(0), 2, GFLAGS), +- GATE(0, "dpll_ddr", "dpll", CLK_IGNORE_UNUSED, +- RK2928_CLKGATE_CON(0), 2, GFLAGS), +- GATE(0, "gpll_ddr", "gpll", CLK_IGNORE_UNUSED, +- RK2928_CLKGATE_CON(0), 2, GFLAGS), +- COMPOSITE(0, "ddrphy4x", mux_ddrphy_p, CLK_IGNORE_UNUSED, +- RK2928_CLKSEL_CON(26), 8, 2, MFLAGS, 0, 3, DFLAGS | CLK_DIVIDER_POWER_OF_TWO, ++ GATE(0, "ddrphy4x", "clk_ddrphy_src", CLK_IGNORE_UNUSED, + RK2928_CLKGATE_CON(7), 1, GFLAGS), +- GATE(0, "ddrc", "ddrphy_pre", CLK_IGNORE_UNUSED, ++ FACTOR_GATE(0, "ddrc", "clk_ddrphy_src", CLK_IGNORE_UNUSED, 1, 4, + RK2928_CLKGATE_CON(8), 5, GFLAGS), +- FACTOR_GATE(0, "ddrphy", "ddrphy4x", CLK_IGNORE_UNUSED, 1, 4, ++ FACTOR_GATE(0, "ddrphy", "clk_ddrphy_src", CLK_IGNORE_UNUSED, 1, 4, + RK2928_CLKGATE_CON(7), 0, GFLAGS), + + /* PD_CORE */ +- GATE(0, "dpll_core", "dpll", CLK_IGNORE_UNUSED, +- RK2928_CLKGATE_CON(0), 6, GFLAGS), +- GATE(0, "apll_core", "apll", CLK_IGNORE_UNUSED, +- RK2928_CLKGATE_CON(0), 6, GFLAGS), +- GATE(0, "gpll_core", "gpll", CLK_IGNORE_UNUSED, +- RK2928_CLKGATE_CON(0), 6, GFLAGS), + COMPOSITE_NOMUX(0, "pclk_dbg", "armclk", CLK_IGNORE_UNUSED, + RK2928_CLKSEL_CON(1), 0, 4, DFLAGS | CLK_DIVIDER_READ_ONLY, + RK2928_CLKGATE_CON(4), 1, GFLAGS), +@@ -253,14 +241,9 @@ static struct rockchip_clk_branch rk3228_clk_branches[] __initdata = { + RK2928_MISC_CON, 15, 1, MFLAGS), + + /* PD_BUS */ +- GATE(0, "hdmiphy_aclk_cpu", "hdmiphy", CLK_IGNORE_UNUSED, +- RK2928_CLKGATE_CON(0), 1, GFLAGS), +- GATE(0, "gpll_aclk_cpu", "gpll", CLK_IGNORE_UNUSED, +- RK2928_CLKGATE_CON(0), 1, GFLAGS), +- GATE(0, "cpll_aclk_cpu", "cpll", CLK_IGNORE_UNUSED, ++ COMPOSITE(0, "aclk_cpu_src", mux_pll_src_3plls_p, 0, ++ RK2928_CLKSEL_CON(0), 13, 2, MFLAGS, 8, 5, DFLAGS, + RK2928_CLKGATE_CON(0), 1, GFLAGS), +- COMPOSITE_NOGATE(0, "aclk_cpu_src", mux_aclk_cpu_src_p, 0, +- RK2928_CLKSEL_CON(0), 13, 2, MFLAGS, 8, 5, DFLAGS), + GATE(ACLK_CPU, "aclk_cpu", "aclk_cpu_src", 0, + RK2928_CLKGATE_CON(6), 0, GFLAGS), + COMPOSITE_NOMUX(HCLK_CPU, "hclk_cpu", "aclk_cpu_src", 0, +@@ -333,14 +316,9 @@ static struct rockchip_clk_branch rk3228_clk_branches[] __initdata = { + RK2928_CLKGATE_CON(3), 8, GFLAGS), + + /* PD_PERI */ +- GATE(0, "cpll_peri", "cpll", CLK_IGNORE_UNUSED, ++ COMPOSITE(0, "aclk_peri_src", mux_pll_src_3plls_p, 0, ++ RK2928_CLKSEL_CON(10), 10, 2, MFLAGS, 0, 5, DFLAGS, + RK2928_CLKGATE_CON(2), 0, GFLAGS), +- GATE(0, "gpll_peri", "gpll", CLK_IGNORE_UNUSED, +- RK2928_CLKGATE_CON(2), 0, GFLAGS), +- GATE(0, "hdmiphy_peri", "hdmiphy", CLK_IGNORE_UNUSED, +- RK2928_CLKGATE_CON(2), 0, GFLAGS), +- COMPOSITE_NOGATE(0, "aclk_peri_src", mux_aclk_peri_src_p, 0, +- RK2928_CLKSEL_CON(10), 10, 2, MFLAGS, 0, 5, DFLAGS), + COMPOSITE_NOMUX(PCLK_PERI, "pclk_peri", "aclk_peri_src", 0, + RK2928_CLKSEL_CON(10), 12, 3, DFLAGS, + RK2928_CLKGATE_CON(5), 2, GFLAGS), +@@ -398,12 +376,9 @@ static struct rockchip_clk_branch rk3228_clk_branches[] __initdata = { + * Clock-Architecture Diagram 2 + */ + +- GATE(0, "gpll_vop", "gpll", 0, +- RK2928_CLKGATE_CON(3), 1, GFLAGS), +- GATE(0, "cpll_vop", "cpll", 0, ++ COMPOSITE_NODIV(0, "sclk_vop_src", mux_sclk_vop_src_p, 0, ++ RK2928_CLKSEL_CON(27), 0, 1, MFLAGS, + RK2928_CLKGATE_CON(3), 1, GFLAGS), +- MUX(0, "sclk_vop_src", mux_sclk_vop_src_p, 0, +- RK2928_CLKSEL_CON(27), 0, 1, MFLAGS), + DIV(DCLK_HDMI_PHY, "dclk_hdmiphy", "sclk_vop_src", 0, + RK2928_CLKSEL_CON(29), 0, 3, DFLAGS), + DIV(0, "sclk_vop_pre", "sclk_vop_src", 0, + +From 368824e53d6be0914927df4281bbce6da58a03ff Mon Sep 17 00:00:00 2001 +From: Finley Xiao +Date: Sun, 18 Mar 2018 21:41:43 +0800 +Subject: [PATCH] clk: rockchip: rk3228: Fix sclk_wifi div_width + +Change-Id: I8e216249fbd588ce55660eba9911fc59aedc920d +Signed-off-by: Finley Xiao +--- + drivers/clk/rockchip/clk-rk3228.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/clk/rockchip/clk-rk3228.c b/drivers/clk/rockchip/clk-rk3228.c +index 734126a2ad7e..90e5638d4e7e 100644 +--- a/drivers/clk/rockchip/clk-rk3228.c ++++ b/drivers/clk/rockchip/clk-rk3228.c +@@ -353,7 +353,7 @@ static struct rockchip_clk_branch rk3228_clk_branches[] __initdata = { + RK2928_CLKGATE_CON(10), 12, GFLAGS), + + COMPOSITE(SCLK_WIFI, "sclk_wifi", mux_pll_src_cpll_gpll_usb480m_p, 0, +- RK2928_CLKSEL_CON(23), 5, 2, MFLAGS, 0, 6, DFLAGS, ++ RK2928_CLKSEL_CON(23), 5, 2, MFLAGS, 0, 5, DFLAGS, + RK2928_CLKGATE_CON(2), 15, GFLAGS), + + COMPOSITE(SCLK_SDMMC, "sclk_sdmmc", mux_mmc_src_p, 0, + +From 06685aabce5c6147ca099bd1b1399f6a170f78e1 Mon Sep 17 00:00:00 2001 +From: Chen Lei +Date: Tue, 25 Dec 2018 18:29:04 +0800 +Subject: [PATCH] clk: rockchip: rk322x: fix wrong mmc phase shift for rk3228 + +mmc sample shift should be 1 for rk3228, or it will fail +if we enable mmc tuning for rk3228. + +Change-Id: I301c2a7d33de8d519d7c288aef03a82531016373 +Signed-off-by: Chen Lei +--- + drivers/clk/rockchip/clk-rk3228.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/clk/rockchip/clk-rk3228.c b/drivers/clk/rockchip/clk-rk3228.c +index 90e5638d4e7e..7fff74043766 100644 +--- a/drivers/clk/rockchip/clk-rk3228.c ++++ b/drivers/clk/rockchip/clk-rk3228.c +@@ -610,13 +610,13 @@ static struct rockchip_clk_branch rk3228_clk_branches[] __initdata = { + + /* PD_MMC */ + MMC(SCLK_SDMMC_DRV, "sdmmc_drv", "sclk_sdmmc", RK3228_SDMMC_CON0, 1), +- MMC(SCLK_SDMMC_SAMPLE, "sdmmc_sample", "sclk_sdmmc", RK3228_SDMMC_CON1, 0), ++ MMC(SCLK_SDMMC_SAMPLE, "sdmmc_sample", "sclk_sdmmc", RK3228_SDMMC_CON1, 1), + + MMC(SCLK_SDIO_DRV, "sdio_drv", "sclk_sdio", RK3228_SDIO_CON0, 1), +- MMC(SCLK_SDIO_SAMPLE, "sdio_sample", "sclk_sdio", RK3228_SDIO_CON1, 0), ++ MMC(SCLK_SDIO_SAMPLE, "sdio_sample", "sclk_sdio", RK3228_SDIO_CON1, 1), + + MMC(SCLK_EMMC_DRV, "emmc_drv", "sclk_emmc", RK3228_EMMC_CON0, 1), +- MMC(SCLK_EMMC_SAMPLE, "emmc_sample", "sclk_emmc", RK3228_EMMC_CON1, 0), ++ MMC(SCLK_EMMC_SAMPLE, "emmc_sample", "sclk_emmc", RK3228_EMMC_CON1, 1), + }; + + static const char *const rk3228_critical_clocks[] __initconst = { + +From a74448d0259e2fe4ad3d791d779ba7a85d31a08b Mon Sep 17 00:00:00 2001 +From: Finley Xiao +Date: Mon, 5 Feb 2018 10:04:15 +0800 +Subject: [PATCH] clk: rockchip: rk3228: Fix armclk parent + +Change-Id: I09830d96b37cca600f1782b9013b25e043467f97 +Signed-off-by: Finley Xiao +--- + drivers/clk/rockchip/clk-rk3228.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/drivers/clk/rockchip/clk-rk3228.c b/drivers/clk/rockchip/clk-rk3228.c +index 7fff74043766..00c5b8a1e295 100644 +--- a/drivers/clk/rockchip/clk-rk3228.c ++++ b/drivers/clk/rockchip/clk-rk3228.c +@@ -131,7 +131,7 @@ static const struct rockchip_cpuclk_reg_data rk3228_cpuclk_data = { + PNAME(mux_pll_p) = { "clk_24m", "xin24m" }; + + PNAME(mux_ddrphy_p) = { "dpll", "gpll", "apll" }; +-PNAME(mux_armclk_p) = { "apll", "gpll", "dpll" }; ++PNAME(mux_armclk_p) = { "apll_core", "gpll_core", "dpll_core" }; + PNAME(mux_usb480m_phy_p) = { "usb480m_phy0", "usb480m_phy1" }; + PNAME(mux_usb480m_p) = { "usb480m_phy", "xin24m" }; + PNAME(mux_hdmiphy_p) = { "hdmiphy_phy", "xin24m" }; +@@ -225,6 +225,12 @@ static struct rockchip_clk_branch rk3228_clk_branches[] __initdata = { + RK2928_CLKGATE_CON(7), 0, GFLAGS), + + /* PD_CORE */ ++ GATE(0, "apll_core", "apll", CLK_IGNORE_UNUSED, ++ PX30_CLKGATE_CON(0), 6, GFLAGS), ++ GATE(0, "gpll_core", "gpll", CLK_IGNORE_UNUSED, ++ PX30_CLKGATE_CON(0), 6, GFLAGS), ++ GATE(0, "dpll_core", "dpll", CLK_IGNORE_UNUSED, ++ PX30_CLKGATE_CON(0), 6, GFLAGS), + COMPOSITE_NOMUX(0, "pclk_dbg", "armclk", CLK_IGNORE_UNUSED, + RK2928_CLKSEL_CON(1), 0, 4, DFLAGS | CLK_DIVIDER_READ_ONLY, + RK2928_CLKGATE_CON(4), 1, GFLAGS), + +From bdbce1840c0b73a5e5c01576fb394d1719736ee8 Mon Sep 17 00:00:00 2001 +From: Finley Xiao +Date: Sun, 18 Mar 2018 21:42:22 +0800 +Subject: [PATCH] clk: rockchip: rk3228: remove the flag ROCKCHIP_PLL_SYNC_RATE + for GPLL + +To slove the display shaking, when uboot logo display to kernel show. + +Change-Id: Ifc97f72df27b4e8dbcd34ab8ed65ac027fd424d1 +Signed-off-by: Finley Xiao +--- + drivers/clk/rockchip/clk-rk3228.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/clk/rockchip/clk-rk3228.c b/drivers/clk/rockchip/clk-rk3228.c +index 00c5b8a1e295..5e9c6986e541 100644 +--- a/drivers/clk/rockchip/clk-rk3228.c ++++ b/drivers/clk/rockchip/clk-rk3228.c +@@ -170,7 +170,7 @@ static struct rockchip_pll_clock rk3228_pll_clks[] __initdata = { + [cpll] = PLL(pll_rk3036, PLL_CPLL, "cpll", mux_pll_p, 0, RK2928_PLL_CON(6), + RK2928_MODE_CON, 8, 8, 0, NULL), + [gpll] = PLL(pll_rk3036, PLL_GPLL, "gpll", mux_pll_p, 0, RK2928_PLL_CON(9), +- RK2928_MODE_CON, 12, 9, ROCKCHIP_PLL_SYNC_RATE, rk3228_pll_rates), ++ RK2928_MODE_CON, 12, 9, 0, rk3228_pll_rates), + }; + + #define MFLAGS CLK_MUX_HIWORD_MASK + +From 0b7003eb4fe6803d6f6071758f069fd7a63f096a Mon Sep 17 00:00:00 2001 +From: Elaine Zhang +Date: Tue, 25 Dec 2018 14:58:30 +0800 +Subject: [PATCH] clk: rockchip: rk322x: fix up the gate con description error + +Change-Id: I439314c590a7144fab6e33d1fb4f325530669842 +Signed-off-by: Elaine Zhang +--- + drivers/clk/rockchip/clk-rk3228.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/clk/rockchip/clk-rk3228.c b/drivers/clk/rockchip/clk-rk3228.c +index 5e9c6986e541..448b202bf4f3 100644 +--- a/drivers/clk/rockchip/clk-rk3228.c ++++ b/drivers/clk/rockchip/clk-rk3228.c +@@ -226,11 +226,11 @@ static struct rockchip_clk_branch rk3228_clk_branches[] __initdata = { + + /* PD_CORE */ + GATE(0, "apll_core", "apll", CLK_IGNORE_UNUSED, +- PX30_CLKGATE_CON(0), 6, GFLAGS), ++ RK2928_CLKGATE_CON(0), 6, GFLAGS), + GATE(0, "gpll_core", "gpll", CLK_IGNORE_UNUSED, +- PX30_CLKGATE_CON(0), 6, GFLAGS), ++ RK2928_CLKGATE_CON(0), 6, GFLAGS), + GATE(0, "dpll_core", "dpll", CLK_IGNORE_UNUSED, +- PX30_CLKGATE_CON(0), 6, GFLAGS), ++ RK2928_CLKGATE_CON(0), 6, GFLAGS), + COMPOSITE_NOMUX(0, "pclk_dbg", "armclk", CLK_IGNORE_UNUSED, + RK2928_CLKSEL_CON(1), 0, 4, DFLAGS | CLK_DIVIDER_READ_ONLY, + RK2928_CLKGATE_CON(4), 1, GFLAGS), + +From 8c78a060509051d135fceaaddd45aa8f3991298f Mon Sep 17 00:00:00 2001 +From: Alex Bee +Date: Sun, 16 Aug 2020 16:52:03 +0200 +Subject: [PATCH] clk: rockchip: add CLOCK_IGNORE_UNUSED to serval RK3228 clks + +Some clocks need the CLOCK_IGNORE_UNUSED flag in order to be prevented from being +disabled at boot time and to get respective devices working. +Has been taken from vendor kernel. +--- + drivers/clk/rockchip/clk-rk3228.c | 58 +++++++++++++++---------------- + 1 file changed, 29 insertions(+), 29 deletions(-) + +diff --git a/drivers/clk/rockchip/clk-rk3228.c b/drivers/clk/rockchip/clk-rk3228.c +index 448b202bf4f3..e6654938d6bd 100644 +--- a/drivers/clk/rockchip/clk-rk3228.c ++++ b/drivers/clk/rockchip/clk-rk3228.c +@@ -510,12 +510,12 @@ static struct rockchip_clk_branch rk3228_clk_branches[] __initdata = { + + /* PD_VOP */ + GATE(ACLK_RGA, "aclk_rga", "aclk_rga_pre", 0, RK2928_CLKGATE_CON(13), 0, GFLAGS), +- GATE(0, "aclk_rga_noc", "aclk_rga_pre", 0, RK2928_CLKGATE_CON(13), 11, GFLAGS), ++ GATE(0, "aclk_rga_noc", "aclk_rga_pre", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(13), 11, GFLAGS), + GATE(ACLK_IEP, "aclk_iep", "aclk_iep_pre", 0, RK2928_CLKGATE_CON(13), 2, GFLAGS), +- GATE(0, "aclk_iep_noc", "aclk_iep_pre", 0, RK2928_CLKGATE_CON(13), 9, GFLAGS), ++ GATE(0, "aclk_iep_noc", "aclk_iep_pre", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(13), 9, GFLAGS), + + GATE(ACLK_VOP, "aclk_vop", "aclk_vop_pre", 0, RK2928_CLKGATE_CON(13), 5, GFLAGS), +- GATE(0, "aclk_vop_noc", "aclk_vop_pre", 0, RK2928_CLKGATE_CON(13), 12, GFLAGS), ++ GATE(0, "aclk_vop_noc", "aclk_vop_pre", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(13), 12, GFLAGS), + + GATE(ACLK_HDCP, "aclk_hdcp", "aclk_hdcp_pre", 0, RK2928_CLKGATE_CON(14), 10, GFLAGS), + GATE(0, "aclk_hdcp_noc", "aclk_hdcp_pre", 0, RK2928_CLKGATE_CON(13), 10, GFLAGS), +@@ -523,13 +523,13 @@ static struct rockchip_clk_branch rk3228_clk_branches[] __initdata = { + GATE(HCLK_RGA, "hclk_rga", "hclk_vio_pre", 0, RK2928_CLKGATE_CON(13), 1, GFLAGS), + GATE(HCLK_IEP, "hclk_iep", "hclk_vio_pre", 0, RK2928_CLKGATE_CON(13), 3, GFLAGS), + GATE(HCLK_VOP, "hclk_vop", "hclk_vio_pre", 0, RK2928_CLKGATE_CON(13), 6, GFLAGS), +- GATE(0, "hclk_vio_ahb_arbi", "hclk_vio_pre", 0, RK2928_CLKGATE_CON(13), 7, GFLAGS), +- GATE(0, "hclk_vio_noc", "hclk_vio_pre", 0, RK2928_CLKGATE_CON(13), 8, GFLAGS), +- GATE(0, "hclk_vop_noc", "hclk_vio_pre", 0, RK2928_CLKGATE_CON(13), 13, GFLAGS), +- GATE(HCLK_VIO_H2P, "hclk_vio_h2p", "hclk_vio_pre", 0, RK2928_CLKGATE_CON(14), 7, GFLAGS), ++ GATE(0, "hclk_vio_ahb_arbi", "hclk_vio_pre", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(13), 7, GFLAGS), ++ GATE(0, "hclk_vio_noc", "hclk_vio_pre", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(13), 8, GFLAGS), ++ GATE(0, "hclk_vop_noc", "hclk_vio_pre", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(13), 13, GFLAGS), ++ GATE(HCLK_VIO_H2P, "hclk_vio_h2p", "hclk_vio_pre", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(14), 7, GFLAGS), + GATE(HCLK_HDCP_MMU, "hclk_hdcp_mmu", "hclk_vio_pre", 0, RK2928_CLKGATE_CON(14), 12, GFLAGS), + GATE(PCLK_HDMI_CTRL, "pclk_hdmi_ctrl", "hclk_vio_pre", 0, RK2928_CLKGATE_CON(14), 6, GFLAGS), +- GATE(PCLK_VIO_H2P, "pclk_vio_h2p", "hclk_vio_pre", 0, RK2928_CLKGATE_CON(14), 8, GFLAGS), ++ GATE(PCLK_VIO_H2P, "pclk_vio_h2p", "hclk_vio_pre", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(14), 8, GFLAGS), + GATE(PCLK_HDCP, "pclk_hdcp", "hclk_vio_pre", 0, RK2928_CLKGATE_CON(14), 11, GFLAGS), + + /* PD_PERI */ +@@ -541,13 +541,13 @@ static struct rockchip_clk_branch rk3228_clk_branches[] __initdata = { + GATE(HCLK_EMMC, "hclk_emmc", "hclk_peri", 0, RK2928_CLKGATE_CON(11), 2, GFLAGS), + GATE(HCLK_NANDC, "hclk_nandc", "hclk_peri", 0, RK2928_CLKGATE_CON(11), 3, GFLAGS), + GATE(HCLK_HOST0, "hclk_host0", "hclk_peri", 0, RK2928_CLKGATE_CON(11), 6, GFLAGS), +- GATE(0, "hclk_host0_arb", "hclk_peri", 0, RK2928_CLKGATE_CON(11), 7, GFLAGS), ++ GATE(0, "hclk_host0_arb", "hclk_peri", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(11), 7, GFLAGS), + GATE(HCLK_HOST1, "hclk_host1", "hclk_peri", 0, RK2928_CLKGATE_CON(11), 8, GFLAGS), +- GATE(0, "hclk_host1_arb", "hclk_peri", 0, RK2928_CLKGATE_CON(11), 9, GFLAGS), ++ GATE(0, "hclk_host1_arb", "hclk_peri", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(11), 9, GFLAGS), + GATE(HCLK_HOST2, "hclk_host2", "hclk_peri", 0, RK2928_CLKGATE_CON(11), 10, GFLAGS), + GATE(HCLK_OTG, "hclk_otg", "hclk_peri", 0, RK2928_CLKGATE_CON(11), 12, GFLAGS), +- GATE(0, "hclk_otg_pmu", "hclk_peri", 0, RK2928_CLKGATE_CON(11), 13, GFLAGS), +- GATE(0, "hclk_host2_arb", "hclk_peri", 0, RK2928_CLKGATE_CON(11), 14, GFLAGS), ++ GATE(0, "hclk_otg_pmu", "hclk_peri", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(11), 13, GFLAGS), ++ GATE(0, "hclk_host2_arb", "hclk_peri", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(11), 14, GFLAGS), + GATE(0, "hclk_peri_noc", "hclk_peri", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(12), 1, GFLAGS), + + GATE(PCLK_GMAC, "pclk_gmac", "pclk_peri", 0, RK2928_CLKGATE_CON(11), 5, GFLAGS), +@@ -555,15 +555,15 @@ static struct rockchip_clk_branch rk3228_clk_branches[] __initdata = { + + /* PD_GPU */ + GATE(ACLK_GPU, "aclk_gpu", "aclk_gpu_pre", 0, RK2928_CLKGATE_CON(7), 14, GFLAGS), +- GATE(0, "aclk_gpu_noc", "aclk_gpu_pre", 0, RK2928_CLKGATE_CON(7), 15, GFLAGS), ++ GATE(0, "aclk_gpu_noc", "aclk_gpu_pre", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(7), 15, GFLAGS), + + /* PD_BUS */ +- GATE(0, "sclk_initmem_mbist", "aclk_cpu", 0, RK2928_CLKGATE_CON(8), 1, GFLAGS), +- GATE(0, "aclk_initmem", "aclk_cpu", 0, RK2928_CLKGATE_CON(8), 0, GFLAGS), ++ GATE(0, "sclk_initmem_mbist", "aclk_cpu", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(8), 1, GFLAGS), ++ GATE(0, "aclk_initmem", "aclk_cpu", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(8), 0, GFLAGS), + GATE(ACLK_DMAC, "aclk_dmac_bus", "aclk_cpu", 0, RK2928_CLKGATE_CON(8), 2, GFLAGS), + GATE(0, "aclk_bus_noc", "aclk_cpu", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(10), 1, GFLAGS), + +- GATE(0, "hclk_rom", "hclk_cpu", 0, RK2928_CLKGATE_CON(8), 3, GFLAGS), ++ GATE(0, "hclk_rom", "hclk_cpu", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(8), 3, GFLAGS), + GATE(HCLK_I2S0_8CH, "hclk_i2s0_8ch", "hclk_cpu", 0, RK2928_CLKGATE_CON(8), 7, GFLAGS), + GATE(HCLK_I2S1_8CH, "hclk_i2s1_8ch", "hclk_cpu", 0, RK2928_CLKGATE_CON(8), 8, GFLAGS), + GATE(HCLK_I2S2_2CH, "hclk_i2s2_2ch", "hclk_cpu", 0, RK2928_CLKGATE_CON(8), 9, GFLAGS), +@@ -572,9 +572,9 @@ static struct rockchip_clk_branch rk3228_clk_branches[] __initdata = { + GATE(HCLK_M_CRYPTO, "hclk_crypto_mst", "hclk_cpu", 0, RK2928_CLKGATE_CON(8), 11, GFLAGS), + GATE(HCLK_S_CRYPTO, "hclk_crypto_slv", "hclk_cpu", 0, RK2928_CLKGATE_CON(8), 12, GFLAGS), + +- GATE(0, "pclk_ddrupctl", "pclk_ddr_pre", 0, RK2928_CLKGATE_CON(8), 4, GFLAGS), +- GATE(0, "pclk_ddrmon", "pclk_ddr_pre", 0, RK2928_CLKGATE_CON(8), 6, GFLAGS), +- GATE(0, "pclk_msch_noc", "pclk_ddr_pre", 0, RK2928_CLKGATE_CON(10), 2, GFLAGS), ++ GATE(0, "pclk_ddrupctl", "pclk_ddr_pre", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(8), 4, GFLAGS), ++ GATE(0, "pclk_ddrmon", "pclk_ddr_pre", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(8), 6, GFLAGS), ++ GATE(0, "pclk_msch_noc", "pclk_ddr_pre", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(10), 2, GFLAGS), + + GATE(PCLK_EFUSE_1024, "pclk_efuse_1024", "pclk_cpu", 0, RK2928_CLKGATE_CON(8), 13, GFLAGS), + GATE(PCLK_EFUSE_256, "pclk_efuse_256", "pclk_cpu", 0, RK2928_CLKGATE_CON(8), 14, GFLAGS), +@@ -583,7 +583,7 @@ static struct rockchip_clk_branch rk3228_clk_branches[] __initdata = { + GATE(PCLK_I2C2, "pclk_i2c2", "pclk_cpu", 0, RK2928_CLKGATE_CON(9), 1, GFLAGS), + GATE(PCLK_I2C3, "pclk_i2c3", "pclk_cpu", 0, RK2928_CLKGATE_CON(9), 2, GFLAGS), + GATE(PCLK_TIMER, "pclk_timer0", "pclk_cpu", 0, RK2928_CLKGATE_CON(9), 4, GFLAGS), +- GATE(0, "pclk_stimer", "pclk_cpu", 0, RK2928_CLKGATE_CON(9), 5, GFLAGS), ++ GATE(0, "pclk_stimer", "pclk_cpu", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(9), 5, GFLAGS), + GATE(PCLK_SPI0, "pclk_spi0", "pclk_cpu", 0, RK2928_CLKGATE_CON(9), 6, GFLAGS), + GATE(PCLK_PWM, "pclk_rk_pwm", "pclk_cpu", 0, RK2928_CLKGATE_CON(9), 7, GFLAGS), + GATE(PCLK_GPIO0, "pclk_gpio0", "pclk_cpu", 0, RK2928_CLKGATE_CON(9), 8, GFLAGS), +@@ -597,22 +597,22 @@ static struct rockchip_clk_branch rk3228_clk_branches[] __initdata = { + GATE(PCLK_GRF, "pclk_grf", "pclk_cpu", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(10), 0, GFLAGS), + GATE(0, "pclk_cru", "pclk_cpu", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(10), 1, GFLAGS), + GATE(0, "pclk_sgrf", "pclk_cpu", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(10), 2, GFLAGS), +- GATE(0, "pclk_sim", "pclk_cpu", 0, RK2928_CLKGATE_CON(10), 3, GFLAGS), ++ GATE(0, "pclk_sim", "pclk_cpu", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(10), 3, GFLAGS), + +- GATE(0, "pclk_ddrphy", "pclk_phy_pre", 0, RK2928_CLKGATE_CON(10), 3, GFLAGS), +- GATE(0, "pclk_acodecphy", "pclk_phy_pre", 0, RK2928_CLKGATE_CON(10), 5, GFLAGS), ++ GATE(0, "pclk_ddrphy", "pclk_phy_pre", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(10), 3, GFLAGS), ++ GATE(0, "pclk_acodecphy", "pclk_phy_pre", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(10), 5, GFLAGS), + GATE(PCLK_HDMI_PHY, "pclk_hdmiphy", "pclk_phy_pre", 0, RK2928_CLKGATE_CON(10), 7, GFLAGS), +- GATE(0, "pclk_vdacphy", "pclk_phy_pre", 0, RK2928_CLKGATE_CON(10), 8, GFLAGS), +- GATE(0, "pclk_phy_noc", "pclk_phy_pre", 0, RK2928_CLKGATE_CON(10), 9, GFLAGS), ++ GATE(0, "pclk_vdacphy", "pclk_phy_pre", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(10), 8, GFLAGS), ++ GATE(0, "pclk_phy_noc", "pclk_phy_pre", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(10), 9, GFLAGS), + + GATE(ACLK_VPU, "aclk_vpu", "aclk_vpu_pre", 0, RK2928_CLKGATE_CON(15), 0, GFLAGS), +- GATE(0, "aclk_vpu_noc", "aclk_vpu_pre", 0, RK2928_CLKGATE_CON(15), 4, GFLAGS), ++ GATE(0, "aclk_vpu_noc", "aclk_vpu_pre", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(15), 4, GFLAGS), + GATE(ACLK_RKVDEC, "aclk_rkvdec", "aclk_rkvdec_pre", 0, RK2928_CLKGATE_CON(15), 2, GFLAGS), +- GATE(0, "aclk_rkvdec_noc", "aclk_rkvdec_pre", 0, RK2928_CLKGATE_CON(15), 6, GFLAGS), ++ GATE(0, "aclk_rkvdec_noc", "aclk_rkvdec_pre", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(15), 6, GFLAGS), + GATE(HCLK_VPU, "hclk_vpu", "hclk_vpu_pre", 0, RK2928_CLKGATE_CON(15), 1, GFLAGS), +- GATE(0, "hclk_vpu_noc", "hclk_vpu_pre", 0, RK2928_CLKGATE_CON(15), 5, GFLAGS), ++ GATE(0, "hclk_vpu_noc", "hclk_vpu_pre", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(15), 5, GFLAGS), + GATE(HCLK_RKVDEC, "hclk_rkvdec", "hclk_rkvdec_pre", 0, RK2928_CLKGATE_CON(15), 3, GFLAGS), +- GATE(0, "hclk_rkvdec_noc", "hclk_rkvdec_pre", 0, RK2928_CLKGATE_CON(15), 7, GFLAGS), ++ GATE(0, "hclk_rkvdec_noc", "hclk_rkvdec_pre", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(15), 7, GFLAGS), + + /* PD_MMC */ + MMC(SCLK_SDMMC_DRV, "sdmmc_drv", "sclk_sdmmc", RK3228_SDMMC_CON0, 1), + +From facbc2eed0bab25a67e65387c9ac05d504fb886e Mon Sep 17 00:00:00 2001 +From: Alex Bee +Date: Sun, 16 Aug 2020 17:07:35 +0200 +Subject: [PATCH] clk: rockchip add aclk_rkvdec and hclk_rkvdec to RK3228 + critical clocks + +To be prevented from being disabled at any time add aclk_rkvdec and hclk_rkvdec +to RK3228 critical clocks +--- + drivers/clk/rockchip/clk-rk3228.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/clk/rockchip/clk-rk3228.c b/drivers/clk/rockchip/clk-rk3228.c +index e6654938d6bd..595ad0301ca6 100644 +--- a/drivers/clk/rockchip/clk-rk3228.c ++++ b/drivers/clk/rockchip/clk-rk3228.c +@@ -656,8 +656,10 @@ static const char *const rk3228_critical_clocks[] __initconst = { + "pclk_phy_noc", + "aclk_vpu_noc", + "aclk_rkvdec_noc", ++ "aclk_rkvdec", + "hclk_vpu_noc", + "hclk_rkvdec_noc", ++ "hclk_rkvdec", + }; + + static void __init rk3228_clk_init(struct device_node *np) + +From 4a3f15e1bc2fb7cb7c093e2814dbc9f447e82bbc Mon Sep 17 00:00:00 2001 +From: Alex Bee +Date: Fri, 24 Apr 2020 11:42:58 +0200 +Subject: [PATCH] soc: rockchip: Support powerdomains which don't need / + support to be switched on / off + +Taken from https://github.com/rockchip-linux/kernel/commit/5be2cb19cf8e678655b59ec70c6a5f66f08d9418 +--- + drivers/soc/rockchip/pm_domains.c | 23 +++++++++++++++++++++++ + 1 file changed, 23 insertions(+) + +diff --git a/drivers/soc/rockchip/pm_domains.c b/drivers/soc/rockchip/pm_domains.c +index 727af107e6d3..3688e9e67872 100644 +--- a/drivers/soc/rockchip/pm_domains.c ++++ b/drivers/soc/rockchip/pm_domains.c +@@ -71,6 +71,7 @@ struct rockchip_pm_domain { + struct regmap **qos_regmap; + u32 *qos_save_regs[MAX_QOS_REGS_NUM]; + int num_clks; ++ bool is_ignore_pwr; + struct clk_bulk_data *clks; + }; + +@@ -353,6 +354,9 @@ static int rockchip_pd_power_on(struct generic_pm_domain *domain) + { + struct rockchip_pm_domain *pd = to_rockchip_pd(domain); + ++ if (pd->is_ignore_pwr) ++ return 0; ++ + return rockchip_pd_power(pd, true); + } + +@@ -360,6 +364,9 @@ static int rockchip_pd_power_off(struct generic_pm_domain *domain) + { + struct rockchip_pm_domain *pd = to_rockchip_pd(domain); + ++ if (pd->is_ignore_pwr) ++ return 0; ++ + return rockchip_pd_power(pd, false); + } + +@@ -439,6 +446,9 @@ static int rockchip_pm_add_one_domain(struct rockchip_pmu *pmu, + pd->info = pd_info; + pd->pmu = pmu; + ++ if (!pd_info->pwr_mask) ++ pd->is_ignore_pwr = true; ++ + pd->num_clks = of_clk_get_parent_count(node); + if (pd->num_clks > 0) { + pd->clks = devm_kcalloc(pmu->dev, pd->num_clks, +@@ -589,6 +599,7 @@ static int rockchip_pm_add_subdomain(struct rockchip_pmu *pmu, + { + struct device_node *np; + struct generic_pm_domain *child_domain, *parent_domain; ++ struct rockchip_pm_domain *child_pd, *parent_pd; + int error; + + for_each_child_of_node(parent, np) { +@@ -629,6 +640,18 @@ static int rockchip_pm_add_subdomain(struct rockchip_pmu *pmu, + parent_domain->name, child_domain->name); + } + ++ /* ++ * If child_pd doesn't do idle request or power on/off, ++ * parent_pd may fail to do power on/off, so if parent_pd ++ * need to power on/off, child_pd can't ignore to do idle ++ * request and power on/off. ++ */ ++ child_pd = to_rockchip_pd(child_domain); ++ parent_pd = to_rockchip_pd(parent_domain); ++ if (!parent_pd->is_ignore_pwr) ++ child_pd->is_ignore_pwr = false; ++ ++ + rockchip_pm_add_subdomain(pmu, np); + } + + +From 02a2d327ebfce5e3b4ddd839c2cf3b9631c38b91 Mon Sep 17 00:00:00 2001 +From: Alex Bee +Date: Fri, 24 Apr 2020 13:01:07 +0200 +Subject: [PATCH] sound: soc: rockchip: use rouned rate for i2s + +--- + sound/soc/rockchip/rockchip_i2s.c | 9 +++++++-- + 1 file changed, 7 insertions(+), 2 deletions(-) + +diff --git a/sound/soc/rockchip/rockchip_i2s.c b/sound/soc/rockchip/rockchip_i2s.c +index 61c984f10d8e..efca853eba6b 100644 +--- a/sound/soc/rockchip/rockchip_i2s.c ++++ b/sound/soc/rockchip/rockchip_i2s.c +@@ -279,10 +279,13 @@ static int rockchip_i2s_hw_params(struct snd_pcm_substream *substream, + if (i2s->is_master_mode) { + mclk_rate = clk_get_rate(i2s->mclk); + bclk_rate = 2 * 32 * params_rate(params); +- if (bclk_rate && mclk_rate % bclk_rate) ++ if (!bclk_rate) { ++ dev_err(i2s->dev, "invalid bclk_rate: %d\n", ++ bclk_rate); + return -EINVAL; ++ } + +- div_bclk = mclk_rate / bclk_rate; ++ div_bclk = DIV_ROUND_CLOSEST(mclk_rate, bclk_rate); + div_lrck = bclk_rate / params_rate(params); + regmap_update_bits(i2s->regmap, I2S_CKR, + I2S_CKR_MDIV_MASK, +@@ -312,6 +315,8 @@ static int rockchip_i2s_hw_params(struct snd_pcm_substream *substream, + val |= I2S_TXCR_VDW(32); + break; + default: ++ dev_err(i2s->dev, "invalid format: %d\n", ++ params_format(params)); + return -EINVAL; + } + + +From 824bce392cfdaaf0037f33637078e722a9f757b9 Mon Sep 17 00:00:00 2001 +From: Alex Bee +Date: Fri, 24 Apr 2020 09:08:44 +0200 +Subject: [PATCH] phy: rockchip: hdmi: readout hdmi phy flag for RK3228 HDMI + phys + +Some RK3228 HDMI phys only get a stable pll on frequencies higher 33,75 MHz. +This is defined in a flag in efuse of those devices. +--- + arch/arm/boot/dts/rk322x.dtsi | 6 +++ + drivers/phy/rockchip/phy-rockchip-inno-hdmi.c | 38 ++++++++++++++++++- + 2 files changed, 42 insertions(+), 2 deletions(-) + +diff --git a/arch/arm/boot/dts/rk322x.dtsi b/arch/arm/boot/dts/rk322x.dtsi +index eec601fb4cd0..81dfdc8c864a 100644 +--- a/arch/arm/boot/dts/rk322x.dtsi ++++ b/arch/arm/boot/dts/rk322x.dtsi +@@ -340,6 +340,10 @@ efuse_id: id@7 { + cpu_leakage: cpu_leakage@17 { + reg = <0x17 0x1>; + }; ++ hdmi_phy_flag: hdmi-phy-flag@1d { ++ reg = <0x1d 0x1>; ++ bits = <1 1>; ++ }; + }; + + i2c0: i2c@11050000 { +@@ -559,6 +563,8 @@ hdmi_phy: hdmi-phy@12030000 { + clock-names = "sysclk", "refoclk", "refpclk"; + #clock-cells = <0>; + clock-output-names = "hdmiphy_phy"; ++ nvmem-cells = <&hdmi_phy_flag>; ++ nvmem-cell-names = "hdmi-phy-flag"; + #phy-cells = <0>; + status = "disabled"; + }; +diff --git a/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c b/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c +index bb8bdf5e3301..0c7a97352714 100644 +--- a/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c ++++ b/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c +@@ -237,6 +237,9 @@ struct inno_hdmi_phy { + struct clk *refoclk; + struct clk *refpclk; + ++ /* phy_flag flag */ ++ bool phy_flag; ++ + /* platform data */ + const struct inno_hdmi_phy_drv_data *plat_data; + int chip_version; +@@ -347,6 +350,7 @@ static const struct pre_pll_config pre_pll_cfg_table[] = { + static const struct post_pll_config post_pll_cfg_table[] = { + {33750000, 1, 40, 8, 1}, + {33750000, 1, 80, 8, 2}, ++ {33750000, 1, 10, 2, 4}, + {74250000, 1, 40, 8, 1}, + {74250000, 18, 80, 8, 2}, + {148500000, 2, 40, 4, 3}, +@@ -497,8 +501,11 @@ static int inno_hdmi_phy_power_on(struct phy *phy) + return -EINVAL; + + for (; cfg->tmdsclock != 0; cfg++) +- if (tmdsclock <= cfg->tmdsclock && +- cfg->version & inno->chip_version) ++ if (((!inno->phy_flag || tmdsclock > 33750000) ++ && tmdsclock <= cfg->tmdsclock ++ && cfg->version & inno->chip_version) || ++ (inno->phy_flag && tmdsclock <= 33750000 ++ && cfg->version & 4)) + break; + + for (; phy_cfg->tmdsclock != 0; phy_cfg++) +@@ -909,6 +916,10 @@ static int inno_hdmi_phy_clk_register(struct inno_hdmi_phy *inno) + + static int inno_hdmi_phy_rk3228_init(struct inno_hdmi_phy *inno) + { ++ struct nvmem_cell *cell; ++ unsigned char *efuse_buf; ++ size_t len; ++ + /* + * Use phy internal register control + * rxsense/poweron/pllpd/pdataen signal. +@@ -923,7 +934,28 @@ static int inno_hdmi_phy_rk3228_init(struct inno_hdmi_phy *inno) + inno_update_bits(inno, 0xaa, RK3228_POST_PLL_CTRL_MANUAL, + RK3228_POST_PLL_CTRL_MANUAL); + ++ + inno->chip_version = 1; ++ inno->phy_flag = false; ++ ++ cell = nvmem_cell_get(inno->dev, "hdmi-phy-flag"); ++ if (IS_ERR(cell)) { ++ if (PTR_ERR(cell) == -EPROBE_DEFER) ++ return -EPROBE_DEFER; ++ ++ return 0; ++ } ++ ++ efuse_buf = nvmem_cell_read(cell, &len); ++ nvmem_cell_put(cell); ++ ++ if (IS_ERR(efuse_buf)) ++ return 0; ++ if (len == 1) ++ inno->phy_flag = (efuse_buf[0] & BIT(1)) ? true : false; ++ kfree(efuse_buf); ++ ++ dev_info(inno->dev, "phy_flag is: %d\n", inno->phy_flag); + + return 0; + } +@@ -1023,6 +1055,8 @@ static int inno_hdmi_phy_rk3328_init(struct inno_hdmi_phy *inno) + + /* try to read the chip-version */ + inno->chip_version = 1; ++ inno->phy_flag = false; ++ + cell = nvmem_cell_get(inno->dev, "cpu-version"); + if (IS_ERR(cell)) { + if (PTR_ERR(cell) == -EPROBE_DEFER) + +From ac8834648e1e35703f6a0533b7c90b24d0d537da Mon Sep 17 00:00:00 2001 +From: Alex Bee +Date: Tue, 26 May 2020 14:41:39 +0200 +Subject: [PATCH] usb: dwc2: QUIRKS: rockchip host only controller needs longer + msleep to initialize + +--- + drivers/usb/dwc2/core.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/usb/dwc2/core.c b/drivers/usb/dwc2/core.c +index fec17a2d2447..eb55c64f63be 100644 +--- a/drivers/usb/dwc2/core.c ++++ b/drivers/usb/dwc2/core.c +@@ -663,7 +663,7 @@ void dwc2_force_dr_mode(struct dwc2_hsotg *hsotg) + * platforms on their host-only dwc2. + */ + if (!dwc2_hw_is_otg(hsotg)) +- msleep(50); ++ msleep(200); + + break; + case USB_DR_MODE_PERIPHERAL: + +From 98c3cfe4ee409e64edcb9dff8341637588c9e166 Mon Sep 17 00:00:00 2001 +From: Alex Bee +Date: Sun, 16 Aug 2020 17:35:43 +0200 +Subject: [PATCH] nvmem: rockchip-efuse: fix RK3188 efuse read + +In order to read from RK3188s efuse, the logic is slightly different from whats +done currently for RK3288 and also used for this SoC. +Logic, register mask and udelays have been taken from vendor kernel. +--- + drivers/nvmem/rockchip-efuse.c | 49 +++++++++++++++++++++++++++++++++- + 1 file changed, 48 insertions(+), 1 deletion(-) + +diff --git a/drivers/nvmem/rockchip-efuse.c b/drivers/nvmem/rockchip-efuse.c +index e4579de5d014..9afd71edf503 100644 +--- a/drivers/nvmem/rockchip-efuse.c ++++ b/drivers/nvmem/rockchip-efuse.c +@@ -17,6 +17,8 @@ + #include + #include + ++#define RK3188_A_MASK 0xff ++ + #define RK3288_A_SHIFT 6 + #define RK3288_A_MASK 0x3ff + #define RK3288_PGENB BIT(3) +@@ -52,6 +54,51 @@ struct rockchip_efuse_chip { + struct clk *clk; + }; + ++static int rockchip_rk3188_efuse_read(void *context, unsigned int offset, ++ void *val, size_t bytes) ++{ ++ struct rockchip_efuse_chip *efuse = context; ++ u8 *buf = val; ++ int ret; ++ ++ ret = clk_prepare_enable(efuse->clk); ++ if (ret < 0) { ++ dev_err(efuse->dev, "failed to prepare/enable efuse clk\n"); ++ return ret; ++ } ++ ++ writel(RK3288_CSB, efuse->base + REG_EFUSE_CTRL); ++ writel(RK3288_LOAD | RK3288_PGENB, efuse->base + REG_EFUSE_CTRL); ++ udelay(2); ++ ++ while (bytes--) { ++ writel(readl(efuse->base + REG_EFUSE_CTRL) & ++ (~(RK3188_A_MASK << RK3288_A_SHIFT)), ++ efuse->base + REG_EFUSE_CTRL); ++ writel(readl(efuse->base + REG_EFUSE_CTRL) | ++ ((offset++ & RK3188_A_MASK) << RK3288_A_SHIFT), ++ efuse->base + REG_EFUSE_CTRL); ++ udelay(2); ++ writel(readl(efuse->base + REG_EFUSE_CTRL) | ++ RK3288_STROBE, efuse->base + REG_EFUSE_CTRL); ++ udelay(2); ++ ++ *buf++ = readl(efuse->base + REG_EFUSE_DOUT); ++ writel(readl(efuse->base + REG_EFUSE_CTRL) & ++ (~RK3288_STROBE), efuse->base + REG_EFUSE_CTRL); ++ udelay(2); ++ } ++ ++ udelay(2); ++ /* Switch to standby mode */ ++ writel(RK3288_PGENB | RK3288_CSB, efuse->base + REG_EFUSE_CTRL); ++ udelay(1); ++ ++ clk_disable_unprepare(efuse->clk); ++ ++ return 0; ++} ++ + static int rockchip_rk3288_efuse_read(void *context, unsigned int offset, + void *val, size_t bytes) + { +@@ -222,7 +269,7 @@ static const struct of_device_id rockchip_efuse_match[] = { + }, + { + .compatible = "rockchip,rk3188-efuse", +- .data = (void *)&rockchip_rk3288_efuse_read, ++ .data = (void *)&rockchip_rk3188_efuse_read, + }, + { + .compatible = "rockchip,rk3228-efuse", + +From e95330563d2dfd9086ac3cadee0129b045c7a25d Mon Sep 17 00:00:00 2001 +From: Alex Bee +Date: Sun, 16 Aug 2020 17:43:08 +0200 +Subject: [PATCH] ARM: dts: rockchip: fix RK3188 efuse register width + +As with most Rockchip SoCs the RK3188s non-secure efuse contains 32 bytes of data. +This adapts the register width, so that we don't get repeated data when reading +out the values from it. +--- + arch/arm/boot/dts/rk3188.dtsi | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm/boot/dts/rk3188.dtsi b/arch/arm/boot/dts/rk3188.dtsi +index b6c1699345d0..9fab375231ec 100644 +--- a/arch/arm/boot/dts/rk3188.dtsi ++++ b/arch/arm/boot/dts/rk3188.dtsi +@@ -216,7 +216,7 @@ cru: clock-controller@20000000 { + + efuse: efuse@20010000 { + compatible = "rockchip,rk3188-efuse"; +- reg = <0x20010000 0x4000>; ++ reg = <0x20010000 0x20>; + #address-cells = <1>; + #size-cells = <1>; + clocks = <&cru PCLK_EFUSE>; + +From e12fc84e0782e332a2d309cc89f52119eee55de3 Mon Sep 17 00:00:00 2001 +From: Alex Bee +Date: Sun, 16 Aug 2020 18:51:38 +0200 +Subject: [PATCH] ARM: dts: rockchip add operating-points, power-domain for + RK322Xs GPU + +This adds the operating-points table and the power-domain and the respective +qos registers for RK322xs GPU. +While at this it also adds the GPU to be a cooling cell. +--- + arch/arm/boot/dts/rk322x.dtsi | 39 ++++++++++++++++++++++++++++++++++- + 1 file changed, 38 insertions(+), 1 deletion(-) + +diff --git a/arch/arm/boot/dts/rk322x.dtsi b/arch/arm/boot/dts/rk322x.dtsi +index 81dfdc8c864a..9e531d229ae1 100644 +--- a/arch/arm/boot/dts/rk322x.dtsi ++++ b/arch/arm/boot/dts/rk322x.dtsi +@@ -215,6 +215,12 @@ power: power-controller { + #address-cells = <1>; + #size-cells = <0>; + ++ pd_gpu@RK3228_PD_GPU { ++ reg = ; ++ clocks = <&cru ACLK_GPU>; ++ pm_qos = <&qos_gpu>; ++ }; ++ + pd_vpu@RK3228_PD_VPU { + reg = ; + clocks = <&cru ACLK_VPU>, <&cru HCLK_VPU>; +@@ -533,6 +539,11 @@ map1 { + <&cpu2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + }; ++ map2 { ++ trip = <&cpu_alert1>; ++ cooling-device = ++ <&gpu THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; ++ }; + }; + }; + }; +@@ -587,7 +598,28 @@ gpu: gpu@20000000 { + clocks = <&cru ACLK_GPU>, <&cru ACLK_GPU>; + clock-names = "bus", "core"; + resets = <&cru SRST_GPU_A>; +- status = "disabled"; ++ operating-points-v2 = <&gpu_opp_table>; ++ power-domains = <&power RK3228_PD_GPU>; ++ #cooling-cells = <2>; /* min followed by max */ ++ }; ++ ++ gpu_opp_table: opp-table2 { ++ compatible = "operating-points-v2"; ++ ++ opp-200000000 { ++ opp-hz = /bits/ 64 <200000000>; ++ opp-microvolt = <1050000>; ++ }; ++ ++ opp-300000000 { ++ opp-hz = /bits/ 64 <300000000>; ++ opp-microvolt = <1050000>; ++ }; ++ ++ opp-500000000 { ++ opp-hz = /bits/ 64 <500000000>; ++ opp-microvolt = <1150000>; ++ }; + }; + + vpu: video-codec@20020000 { +@@ -872,6 +904,11 @@ qos_vpu: qos@31040000 { + reg = <0x31040000 0x20>; + }; + ++ qos_gpu: qos@31050000 { ++ compatible = "syscon"; ++ reg = <0x31050000 0x20>; ++ }; ++ + qos_rkvdec_r: qos@31070000 { + compatible = "syscon"; + reg = <0x31070000 0x20>; + +From 19b4b92aa56381148255f8d962649869f734b5f9 Mon Sep 17 00:00:00 2001 +From: Alex Bee +Date: Sun, 16 Aug 2020 19:44:42 +0200 +Subject: [PATCH] ARM: dts: rockchip: add ethernet0 alias + +Add ethernet0 alias for gmac. This will, for example, be used +by u-boot to inject a "local-mac-address" in the devicetree. +--- + arch/arm/boot/dts/rk322x.dtsi | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/arch/arm/boot/dts/rk322x.dtsi b/arch/arm/boot/dts/rk322x.dtsi +index 9e531d229ae1..14eedffea4a3 100644 +--- a/arch/arm/boot/dts/rk322x.dtsi ++++ b/arch/arm/boot/dts/rk322x.dtsi +@@ -15,6 +15,7 @@ / { + interrupt-parent = <&gic>; + + aliases { ++ ethernet0 = &gmac; + serial0 = &uart0; + serial1 = &uart1; + serial2 = &uart2; + +From 7c1f6ab6b0c97b7aacaa39f842a9e8ef7bbea83e Mon Sep 17 00:00:00 2001 +From: Alex Bee +Date: Sun, 16 Aug 2020 20:00:01 +0200 +Subject: [PATCH] ARM: dts: rockchip: add hdmi simple-audio-card for RK322x + +Add "simple-audio-card" definition for hdmi-sound. While at +that also add the missing #sound-dai-cells for i2s, spdif and hdmi +nodes. +--- + arch/arm/boot/dts/rk322x.dtsi | 20 ++++++++++++++++++++ + 1 file changed, 20 insertions(+) + +diff --git a/arch/arm/boot/dts/rk322x.dtsi b/arch/arm/boot/dts/rk322x.dtsi +index 14eedffea4a3..7f15fc838c36 100644 +--- a/arch/arm/boot/dts/rk322x.dtsi ++++ b/arch/arm/boot/dts/rk322x.dtsi +@@ -124,6 +124,22 @@ arm-pmu { + interrupt-affinity = <&cpu0>, <&cpu1>, <&cpu2>, <&cpu3>; + }; + ++ hdmi_sound: hdmi-sound { ++ compatible = "simple-audio-card"; ++ simple-audio-card,name = "hdmi-sound"; ++ simple-audio-card,format = "i2s"; ++ simple-audio-card,mclk-fs = <256>; ++ status = "disabled"; ++ ++ simple-audio-card,cpu { ++ sound-dai = <&i2s0>; ++ }; ++ ++ simple-audio-card,codec { ++ sound-dai = <&hdmi>; ++ }; ++ }; ++ + psci { + compatible = "arm,psci-1.0", "arm,psci-0.2"; + method = "smc"; +@@ -161,6 +177,7 @@ i2s1: i2s1@100b0000 { + dma-names = "tx", "rx"; + pinctrl-names = "default"; + pinctrl-0 = <&i2s1_bus>; ++ #sound-dai-cells = <0>; + status = "disabled"; + }; + +@@ -172,6 +189,7 @@ i2s0: i2s0@100c0000 { + clocks = <&cru SCLK_I2S0>, <&cru HCLK_I2S0_8CH>; + dmas = <&pdma 11>, <&pdma 12>; + dma-names = "tx", "rx"; ++ #sound-dai-cells = <0>; + status = "disabled"; + }; + +@@ -185,6 +203,7 @@ spdif: spdif@100d0000 { + dma-names = "tx"; + pinctrl-names = "default"; + pinctrl-0 = <&spdif_tx>; ++ #sound-dai-cells = <0>; + status = "disabled"; + }; + +@@ -746,6 +765,7 @@ hdmi: hdmi@200a0000 { + phys = <&hdmi_phy>; + phy-names = "hdmi"; + rockchip,grf = <&grf>; ++ #sound-dai-cells = <0>; + status = "disabled"; + + ports { + +From 6fa1bf91b123f703a2fde726ad52af1539f365d0 Mon Sep 17 00:00:00 2001 +From: Alex Bee +Date: Sun, 16 Aug 2020 21:16:11 +0200 +Subject: [PATCH] ARM: dts: rockchip: add uart1-1 pins for RK322x + +Add uart uart1-1 pins. +While at this also correct the uart2 default pinctrl, which is uart21_xfer. +--- + arch/arm/boot/dts/rk322x.dtsi | 19 ++++++++++++++++++- + 1 file changed, 18 insertions(+), 1 deletion(-) + +diff --git a/arch/arm/boot/dts/rk322x.dtsi b/arch/arm/boot/dts/rk322x.dtsi +index 7f15fc838c36..693c6f18a889 100644 +--- a/arch/arm/boot/dts/rk322x.dtsi ++++ b/arch/arm/boot/dts/rk322x.dtsi +@@ -345,7 +345,7 @@ uart2: serial@11030000 { + clocks = <&cru SCLK_UART2>, <&cru PCLK_UART2>; + clock-names = "baudclk", "apb_pclk"; + pinctrl-names = "default"; +- pinctrl-0 = <&uart2_xfer>; ++ pinctrl-0 = <&uart21_xfer>; + reg-shift = <2>; + reg-io-width = <4>; + status = "disabled"; +@@ -1275,13 +1275,30 @@ uart1_xfer: uart1-xfer { + <1 RK_PB2 1 &pcfg_pull_none>; + }; + ++ uart11_xfer: uart11-xfer { ++ rockchip,pins = <3 RK_PB6 1 &pcfg_pull_up>, ++ <3 RK_PB5 1 &pcfg_pull_none>; ++ }; ++ + uart1_cts: uart1-cts { + rockchip,pins = <1 RK_PB0 1 &pcfg_pull_none>; + }; + ++ uart11_cts: uart11-cts { ++ rockchip,pins = <3 RK_PA7 1 &pcfg_pull_none>; ++ }; ++ + uart1_rts: uart1-rts { + rockchip,pins = <1 RK_PB3 1 &pcfg_pull_none>; + }; ++ ++ uart11_rts: uart11-rts { ++ rockchip,pins = <3 RK_PA6 1 &pcfg_pull_none>; ++ }; ++ ++ uart11_rts_gpio: uart11-rts-gpio { ++ rockchip,pins = <3 RK_PA6 RK_FUNC_GPIO &pcfg_pull_none>; ++ }; + }; + + uart2 { + +From 1c37c9a10362d2e049be1386bb1da7d4f488b1d8 Mon Sep 17 00:00:00 2001 +From: Alex Bee +Date: Sun, 16 Aug 2020 21:58:56 +0200 +Subject: [PATCH] ARM: dts: rockchip: align mmc* node properties with driver + +Add resets, max-frequency and bus-width properties where required to emmc +,sdmmc and sdio nodes. While at that also add the sdmmc_pwr pinctrl which +is required to get the sd-card controller to work, if it was not/wrong +initialized by the bootloader (i.e. u-boot) +--- + arch/arm/boot/dts/rk322x.dtsi | 17 ++++++++++++++--- + 1 file changed, 14 insertions(+), 3 deletions(-) + +diff --git a/arch/arm/boot/dts/rk322x.dtsi b/arch/arm/boot/dts/rk322x.dtsi +index 693c6f18a889..92e3eb1e7938 100644 +--- a/arch/arm/boot/dts/rk322x.dtsi ++++ b/arch/arm/boot/dts/rk322x.dtsi +@@ -787,9 +787,13 @@ sdmmc: mmc@30000000 { + clocks = <&cru HCLK_SDMMC>, <&cru SCLK_SDMMC>, + <&cru SCLK_SDMMC_DRV>, <&cru SCLK_SDMMC_SAMPLE>; + clock-names = "biu", "ciu", "ciu-drive", "ciu-sample"; ++ bus-width = <4>; + fifo-depth = <0x100>; ++ max-frequency = <150000000>; + pinctrl-names = "default"; +- pinctrl-0 = <&sdmmc_clk &sdmmc_cmd &sdmmc_bus4>; ++ pinctrl-0 = <&sdmmc_clk &sdmmc_cmd &sdmmc_bus4 &sdmmc_pwr>; ++ resets = <&cru SRST_SDMMC>; ++ reset-names = "reset"; + status = "disabled"; + }; + +@@ -799,10 +803,14 @@ sdio: mmc@30010000 { + interrupts = ; + clocks = <&cru HCLK_SDIO>, <&cru SCLK_SDIO>, + <&cru SCLK_SDIO_DRV>, <&cru SCLK_SDIO_SAMPLE>; ++ bus-width = <4>; + clock-names = "biu", "ciu", "ciu-drive", "ciu-sample"; + fifo-depth = <0x100>; ++ max-frequency = <150000000>; + pinctrl-names = "default"; + pinctrl-0 = <&sdio_clk &sdio_cmd &sdio_bus4>; ++ resets = <&cru SRST_SDIO>; ++ reset-names = "reset"; + status = "disabled"; + }; + +@@ -810,14 +818,13 @@ emmc: mmc@30020000 { + compatible = "rockchip,rk3228-dw-mshc", "rockchip,rk3288-dw-mshc"; + reg = <0x30020000 0x4000>; + interrupts = ; +- clock-frequency = <37500000>; +- max-frequency = <37500000>; + clocks = <&cru HCLK_EMMC>, <&cru SCLK_EMMC>, + <&cru SCLK_EMMC_DRV>, <&cru SCLK_EMMC_SAMPLE>; + clock-names = "biu", "ciu", "ciu-drive", "ciu-sample"; + bus-width = <8>; + rockchip,default-sample-phase = <158>; + fifo-depth = <0x100>; ++ max-frequency = <150000000>; + pinctrl-names = "default"; + pinctrl-0 = <&emmc_clk &emmc_cmd &emmc_bus8>; + resets = <&cru SRST_EMMC>; +@@ -1043,6 +1050,10 @@ sdmmc_bus4: sdmmc-bus4 { + <1 RK_PC4 1 &pcfg_pull_none_drv_12ma>, + <1 RK_PC5 1 &pcfg_pull_none_drv_12ma>; + }; ++ ++ sdmmc_pwr: sdmmc-pwr { ++ rockchip,pins = <1 RK_PB6 RK_FUNC_GPIO &pcfg_pull_none>; ++ }; + }; + + sdio { + +From 9a9db392c9d0fd23dd84c39f36290ab0bfbc2021 Mon Sep 17 00:00:00 2001 +From: Jeffy Chen +Date: Wed, 8 Jun 2016 14:05:42 +0800 +Subject: [PATCH] clk: rockchip: rk3036: add ACLK_VCODEC + +Change-Id: I36f6b23139345941656c127718cc4ff01c6d629f +Signed-off-by: Jeffy Chen +--- + drivers/clk/rockchip/clk-rk3036.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/clk/rockchip/clk-rk3036.c b/drivers/clk/rockchip/clk-rk3036.c +index 6a46f85ad837..3b285261ce39 100644 +--- a/drivers/clk/rockchip/clk-rk3036.c ++++ b/drivers/clk/rockchip/clk-rk3036.c +@@ -258,7 +258,7 @@ static struct rockchip_clk_branch rk3036_clk_branches[] __initdata = { + RK2928_CLKGATE_CON(1), 13, GFLAGS, + &rk3036_uart2_fracmux), + +- COMPOSITE(0, "aclk_vcodec", mux_pll_src_3plls_p, 0, ++ COMPOSITE(ACLK_VCODEC, "aclk_vcodec", mux_pll_src_3plls_p, 0, + RK2928_CLKSEL_CON(32), 14, 2, MFLAGS, 8, 5, DFLAGS, + RK2928_CLKGATE_CON(3), 11, GFLAGS), + FACTOR_GATE(HCLK_VCODEC, "hclk_vcodec", "aclk_vcodec", 0, 1, 4, + +From e1dd6aaa44b5ae46657f83bb066f50f5c9e0568a Mon Sep 17 00:00:00 2001 +From: Randy Li +Date: Fri, 20 Oct 2017 14:38:09 +0800 +Subject: [PATCH] clk: rockchip: rk3036: export the hevc core clock + +The clock hevc core will be used to drive the hevc decoder. + +Change-Id: Ic1298ce1edd07f86e5c243e3a2c9876481f4cba9 +Signed-off-by: Randy Li +--- + drivers/clk/rockchip/clk-rk3036.c | 2 +- + include/dt-bindings/clock/rk3036-cru.h | 1 + + 2 files changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/clk/rockchip/clk-rk3036.c b/drivers/clk/rockchip/clk-rk3036.c +index 3b285261ce39..a98ea978fc8a 100644 +--- a/drivers/clk/rockchip/clk-rk3036.c ++++ b/drivers/clk/rockchip/clk-rk3036.c +@@ -264,7 +264,7 @@ static struct rockchip_clk_branch rk3036_clk_branches[] __initdata = { + FACTOR_GATE(HCLK_VCODEC, "hclk_vcodec", "aclk_vcodec", 0, 1, 4, + RK2928_CLKGATE_CON(3), 12, GFLAGS), + +- COMPOSITE(0, "aclk_hvec", mux_pll_src_3plls_p, 0, ++ COMPOSITE(ACLK_HEVC, "aclk_hevc", mux_pll_src_3plls_p, 0, + RK2928_CLKSEL_CON(20), 0, 2, MFLAGS, 2, 5, DFLAGS, + RK2928_CLKGATE_CON(10), 6, GFLAGS), + +diff --git a/include/dt-bindings/clock/rk3036-cru.h b/include/dt-bindings/clock/rk3036-cru.h +index 35a5a01f9697..cd231f57278d 100644 +--- a/include/dt-bindings/clock/rk3036-cru.h ++++ b/include/dt-bindings/clock/rk3036-cru.h +@@ -55,6 +55,7 @@ + #define ACLK_VCODEC 208 + #define ACLK_CPU 209 + #define ACLK_PERI 210 ++#define ACLK_HEVC 211 + + /* pclk gates */ + #define PCLK_GPIO0 320 + +From e9752790e4c92f83924dc881cf1555977c512214 Mon Sep 17 00:00:00 2001 +From: Caesar Wang +Date: Mon, 13 Nov 2017 09:28:12 +0800 +Subject: [PATCH] clk: rockchip: export SCLK_I2S_PRE and SCLK_I2S_FRAC of i2s + on rk3036 + +Change-Id: I627c8c2582be2b27414e7b82e9d56dd560f68e64 +Signed-off-by: Caesar Wang +--- + drivers/clk/rockchip/clk-rk3036.c | 4 ++-- + include/dt-bindings/clock/rk3036-cru.h | 2 ++ + 2 files changed, 4 insertions(+), 2 deletions(-) + +diff --git a/drivers/clk/rockchip/clk-rk3036.c b/drivers/clk/rockchip/clk-rk3036.c +index a98ea978fc8a..c67ee61ef0cd 100644 +--- a/drivers/clk/rockchip/clk-rk3036.c ++++ b/drivers/clk/rockchip/clk-rk3036.c +@@ -157,7 +157,7 @@ static struct rockchip_clk_branch rk3036_uart2_fracmux __initdata = + RK2928_CLKSEL_CON(15), 8, 2, MFLAGS); + + static struct rockchip_clk_branch rk3036_i2s_fracmux __initdata = +- MUX(0, "i2s_pre", mux_i2s_pre_p, CLK_SET_RATE_PARENT, ++ MUX(SCLK_I2S_PRE, "i2s_pre", mux_i2s_pre_p, CLK_SET_RATE_PARENT, + RK2928_CLKSEL_CON(3), 8, 2, MFLAGS); + + static struct rockchip_clk_branch rk3036_spdif_fracmux __initdata = +@@ -306,7 +306,7 @@ static struct rockchip_clk_branch rk3036_clk_branches[] __initdata = { + COMPOSITE(0, "i2s_src", mux_pll_src_3plls_p, 0, + RK2928_CLKSEL_CON(3), 14, 2, MFLAGS, 0, 7, DFLAGS, + RK2928_CLKGATE_CON(0), 9, GFLAGS), +- COMPOSITE_FRACMUX(0, "i2s_frac", "i2s_src", CLK_SET_RATE_PARENT, ++ COMPOSITE_FRACMUX(SCLK_I2S_FRAC, "i2s_frac", "i2s_src", CLK_SET_RATE_PARENT, + RK2928_CLKSEL_CON(7), 0, + RK2928_CLKGATE_CON(0), 10, GFLAGS, + &rk3036_i2s_fracmux), +diff --git a/include/dt-bindings/clock/rk3036-cru.h b/include/dt-bindings/clock/rk3036-cru.h +index cd231f57278d..4c7ff6141a67 100644 +--- a/include/dt-bindings/clock/rk3036-cru.h ++++ b/include/dt-bindings/clock/rk3036-cru.h +@@ -43,6 +43,8 @@ + #define SCLK_PVTM_CORE 123 + #define SCLK_PVTM_GPU 124 + #define SCLK_PVTM_VIDEO 125 ++#define SCLK_I2S_FRAC 126 ++#define SCLK_I2S_PRE 127 + #define SCLK_MAC 151 + #define SCLK_MACREF 152 + #define SCLK_MACPLL 153 + +From 1cfffef46d411629c71da2dea69c41b261355d5b Mon Sep 17 00:00:00 2001 +From: Caesar Wang +Date: Fri, 17 Nov 2017 14:49:16 +0800 +Subject: [PATCH] clk: rockchip: protect the armclk for rk3036 + +Some clocks may get disabled as a side effect of another clock +being disabled, because have no consumers. Says the dclk_hdmi's parent may +change from apll to gpll, but the apll's son clocks are very less. + +Change-Id: I4fb4e5fdf83a8f73979b50dbcf4f3e4543896fcf +Signed-off-by: Caesar Wang +--- + drivers/clk/rockchip/clk-rk3036.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/drivers/clk/rockchip/clk-rk3036.c b/drivers/clk/rockchip/clk-rk3036.c +index c67ee61ef0cd..ac5c1cfb3f54 100644 +--- a/drivers/clk/rockchip/clk-rk3036.c ++++ b/drivers/clk/rockchip/clk-rk3036.c +@@ -424,6 +424,7 @@ static struct rockchip_clk_branch rk3036_clk_branches[] __initdata = { + }; + + static const char *const rk3036_critical_clocks[] __initconst = { ++ "armclk", + "aclk_cpu", + "aclk_peri", + "hclk_peri", +@@ -467,14 +468,14 @@ static void __init rk3036_clk_init(struct device_node *np) + RK3036_GRF_SOC_STATUS0); + rockchip_clk_register_branches(ctx, rk3036_clk_branches, + ARRAY_SIZE(rk3036_clk_branches)); +- rockchip_clk_protect_critical(rk3036_critical_clocks, +- ARRAY_SIZE(rk3036_critical_clocks)); +- + rockchip_clk_register_armclk(ctx, ARMCLK, "armclk", + mux_armclk_p, ARRAY_SIZE(mux_armclk_p), + &rk3036_cpuclk_data, rk3036_cpuclk_rates, + ARRAY_SIZE(rk3036_cpuclk_rates)); + ++ rockchip_clk_protect_critical(rk3036_critical_clocks, ++ ARRAY_SIZE(rk3036_critical_clocks)); ++ + rockchip_register_softrst(np, 9, reg_base + RK2928_SOFTRST_CON(0), + ROCKCHIP_SOFTRST_HIWORD_MASK); + + +From 84f5c9e7a40b0e30b087aea7a618b18e2bb87fd5 Mon Sep 17 00:00:00 2001 +From: Finley Xiao +Date: Mon, 13 Nov 2017 15:32:25 +0800 +Subject: [PATCH] clk: rockchip: rk3036: leave apll for core, mac and lcdc only + +In order not to affect other clocks, remove the apll from the +parent list of other clocks and only core, mac and lcdc can +select apll as parent. + +Change-Id: I58b995f8ccf69c6564f74b5823f618a186030d70 +Signed-off-by: Finley Xiao +--- + drivers/clk/rockchip/clk-rk3036.c | 38 ++++++++++++++++--------------- + 1 file changed, 20 insertions(+), 18 deletions(-) + +diff --git a/drivers/clk/rockchip/clk-rk3036.c b/drivers/clk/rockchip/clk-rk3036.c +index ac5c1cfb3f54..4ce2cf844123 100644 +--- a/drivers/clk/rockchip/clk-rk3036.c ++++ b/drivers/clk/rockchip/clk-rk3036.c +@@ -114,14 +114,16 @@ static const struct rockchip_cpuclk_reg_data rk3036_cpuclk_data = { + PNAME(mux_pll_p) = { "xin24m", "xin24m" }; + + PNAME(mux_armclk_p) = { "apll", "gpll_armclk" }; +-PNAME(mux_busclk_p) = { "apll", "dpll_cpu", "gpll_cpu" }; ++PNAME(mux_busclk_p) = { "dummy_apll", "dpll_cpu", "gpll_cpu" }; + PNAME(mux_ddrphy_p) = { "dpll_ddr", "gpll_ddr" }; +-PNAME(mux_pll_src_3plls_p) = { "apll", "dpll", "gpll" }; ++PNAME(mux_pll_src_apll_dpll_gpll_p) = { "apll", "dpll", "gpll" }; ++PNAME(mux_pll_src_dmyapll_dpll_gpll_p) = { "dummy_apll", "dpll", "gpll" }; ++ + PNAME(mux_timer_p) = { "xin24m", "pclk_peri_src" }; + +-PNAME(mux_pll_src_apll_dpll_gpll_usb480m_p) = { "apll", "dpll", "gpll", "usb480m" }; ++PNAME(mux_pll_src_dmyapll_dpll_gpll_usb480m_p) = { "dummy_apll", "dpll", "gpll", "usb480m" }; + +-PNAME(mux_mmc_src_p) = { "apll", "dpll", "gpll", "xin24m" }; ++PNAME(mux_mmc_src_p) = { "dummy_apll", "dpll", "gpll", "xin24m" }; + PNAME(mux_i2s_pre_p) = { "i2s_src", "i2s_frac", "ext_i2s", "xin12m" }; + PNAME(mux_i2s_clkout_p) = { "i2s_pre", "xin12m" }; + PNAME(mux_spdif_p) = { "spdif_src", "spdif_frac", "xin12m" }; +@@ -206,7 +208,7 @@ static struct rockchip_clk_branch rk3036_clk_branches[] __initdata = { + RK2928_CLKSEL_CON(1), 8, 2, DFLAGS | CLK_DIVIDER_READ_ONLY, + RK2928_CLKGATE_CON(0), 4, GFLAGS), + +- COMPOSITE(0, "aclk_peri_src", mux_pll_src_3plls_p, 0, ++ COMPOSITE(0, "aclk_peri_src", mux_pll_src_dmyapll_dpll_gpll_p, 0, + RK2928_CLKSEL_CON(10), 14, 2, MFLAGS, 0, 5, DFLAGS, + RK2928_CLKGATE_CON(2), 0, GFLAGS), + +@@ -234,7 +236,7 @@ static struct rockchip_clk_branch rk3036_clk_branches[] __initdata = { + RK2928_CLKSEL_CON(2), 7, 1, MFLAGS, + RK2928_CLKGATE_CON(2), 5, GFLAGS), + +- MUX(0, "uart_pll_clk", mux_pll_src_apll_dpll_gpll_usb480m_p, 0, ++ MUX(0, "uart_pll_clk", mux_pll_src_dmyapll_dpll_gpll_usb480m_p, 0, + RK2928_CLKSEL_CON(13), 10, 2, MFLAGS), + COMPOSITE_NOMUX(0, "uart0_src", "uart_pll_clk", 0, + RK2928_CLKSEL_CON(13), 0, 7, DFLAGS, +@@ -258,23 +260,23 @@ static struct rockchip_clk_branch rk3036_clk_branches[] __initdata = { + RK2928_CLKGATE_CON(1), 13, GFLAGS, + &rk3036_uart2_fracmux), + +- COMPOSITE(ACLK_VCODEC, "aclk_vcodec", mux_pll_src_3plls_p, 0, ++ COMPOSITE(ACLK_VCODEC, "aclk_vcodec", mux_pll_src_dmyapll_dpll_gpll_p, 0, + RK2928_CLKSEL_CON(32), 14, 2, MFLAGS, 8, 5, DFLAGS, + RK2928_CLKGATE_CON(3), 11, GFLAGS), + FACTOR_GATE(HCLK_VCODEC, "hclk_vcodec", "aclk_vcodec", 0, 1, 4, + RK2928_CLKGATE_CON(3), 12, GFLAGS), + +- COMPOSITE(ACLK_HEVC, "aclk_hevc", mux_pll_src_3plls_p, 0, ++ COMPOSITE(ACLK_HEVC, "aclk_hevc", mux_pll_src_dmyapll_dpll_gpll_p, 0, + RK2928_CLKSEL_CON(20), 0, 2, MFLAGS, 2, 5, DFLAGS, + RK2928_CLKGATE_CON(10), 6, GFLAGS), + +- COMPOSITE(0, "aclk_disp1_pre", mux_pll_src_3plls_p, 0, ++ COMPOSITE(0, "aclk_disp1_pre", mux_pll_src_dmyapll_dpll_gpll_p, 0, + RK2928_CLKSEL_CON(31), 14, 2, MFLAGS, 8, 5, DFLAGS, + RK2928_CLKGATE_CON(1), 4, GFLAGS), +- COMPOSITE(0, "hclk_disp_pre", mux_pll_src_3plls_p, 0, ++ COMPOSITE(0, "hclk_disp_pre", mux_pll_src_dmyapll_dpll_gpll_p, 0, + RK2928_CLKSEL_CON(30), 14, 2, MFLAGS, 8, 5, DFLAGS, + RK2928_CLKGATE_CON(0), 11, GFLAGS), +- COMPOSITE(SCLK_LCDC, "dclk_lcdc", mux_pll_src_3plls_p, 0, ++ COMPOSITE(SCLK_LCDC, "dclk_lcdc", mux_pll_src_apll_dpll_gpll_p, 0, + RK2928_CLKSEL_CON(28), 0, 2, MFLAGS, 8, 8, DFLAGS, + RK2928_CLKGATE_CON(3), 2, GFLAGS), + +@@ -303,7 +305,7 @@ static struct rockchip_clk_branch rk3036_clk_branches[] __initdata = { + MMC(SCLK_EMMC_DRV, "emmc_drv", "sclk_emmc", RK3036_EMMC_CON0, 1), + MMC(SCLK_EMMC_SAMPLE, "emmc_sample", "sclk_emmc", RK3036_EMMC_CON1, 0), + +- COMPOSITE(0, "i2s_src", mux_pll_src_3plls_p, 0, ++ COMPOSITE(0, "i2s_src", mux_pll_src_dmyapll_dpll_gpll_p, 0, + RK2928_CLKSEL_CON(3), 14, 2, MFLAGS, 0, 7, DFLAGS, + RK2928_CLKGATE_CON(0), 9, GFLAGS), + COMPOSITE_FRACMUX(SCLK_I2S_FRAC, "i2s_frac", "i2s_src", CLK_SET_RATE_PARENT, +@@ -316,7 +318,7 @@ static struct rockchip_clk_branch rk3036_clk_branches[] __initdata = { + GATE(SCLK_I2S, "sclk_i2s", "i2s_pre", CLK_SET_RATE_PARENT, + RK2928_CLKGATE_CON(0), 14, GFLAGS), + +- COMPOSITE(0, "spdif_src", mux_pll_src_3plls_p, 0, ++ COMPOSITE(0, "spdif_src", mux_pll_src_dmyapll_dpll_gpll_p, 0, + RK2928_CLKSEL_CON(5), 10, 2, MFLAGS, 0, 7, DFLAGS, + RK2928_CLKGATE_CON(2), 10, GFLAGS), + COMPOSITE_FRACMUX(0, "spdif_frac", "spdif_src", 0, +@@ -327,23 +329,23 @@ static struct rockchip_clk_branch rk3036_clk_branches[] __initdata = { + GATE(SCLK_OTGPHY0, "sclk_otgphy0", "xin12m", CLK_IGNORE_UNUSED, + RK2928_CLKGATE_CON(1), 5, GFLAGS), + +- COMPOSITE(SCLK_GPU, "sclk_gpu", mux_pll_src_3plls_p, 0, ++ COMPOSITE(SCLK_GPU, "sclk_gpu", mux_pll_src_dmyapll_dpll_gpll_p, 0, + RK2928_CLKSEL_CON(34), 8, 2, MFLAGS, 0, 5, DFLAGS, + RK2928_CLKGATE_CON(3), 13, GFLAGS), + +- COMPOSITE(SCLK_SPI, "sclk_spi", mux_pll_src_3plls_p, 0, ++ COMPOSITE(SCLK_SPI, "sclk_spi", mux_pll_src_dmyapll_dpll_gpll_p, 0, + RK2928_CLKSEL_CON(25), 8, 2, MFLAGS, 0, 7, DFLAGS, + RK2928_CLKGATE_CON(2), 9, GFLAGS), + +- COMPOSITE(SCLK_NANDC, "sclk_nandc", mux_pll_src_3plls_p, 0, ++ COMPOSITE(SCLK_NANDC, "sclk_nandc", mux_pll_src_dmyapll_dpll_gpll_p, 0, + RK2928_CLKSEL_CON(16), 8, 2, MFLAGS, 10, 5, DFLAGS, + RK2928_CLKGATE_CON(10), 4, GFLAGS), + +- COMPOSITE(SCLK_SFC, "sclk_sfc", mux_pll_src_apll_dpll_gpll_usb480m_p, 0, ++ COMPOSITE(SCLK_SFC, "sclk_sfc", mux_pll_src_dmyapll_dpll_gpll_usb480m_p, 0, + RK2928_CLKSEL_CON(16), 0, 2, MFLAGS, 2, 5, DFLAGS, + RK2928_CLKGATE_CON(10), 5, GFLAGS), + +- COMPOSITE_NOGATE(SCLK_MACPLL, "mac_pll_src", mux_pll_src_3plls_p, CLK_SET_RATE_NO_REPARENT, ++ COMPOSITE_NOGATE(SCLK_MACPLL, "mac_pll_src", mux_pll_src_apll_dpll_gpll_p, CLK_SET_RATE_NO_REPARENT, + RK2928_CLKSEL_CON(21), 0, 2, MFLAGS, 9, 5, DFLAGS), + MUX(SCLK_MACREF, "mac_clk_ref", mux_mac_p, CLK_SET_RATE_PARENT, + RK2928_CLKSEL_CON(21), 3, 1, MFLAGS), + +From 30337bfc416283d487d91e82397c81f1cae745a9 Mon Sep 17 00:00:00 2001 +From: Randy Li +Date: Fri, 20 Apr 2018 10:43:46 +0800 +Subject: [PATCH] clk: rockchip: rk3036: export the sfc clocks + +The serial Flash controller on the rk3036 would request +two clock nodes. + +Change-Id: Iaa50c4a25602a68241b0b9b2f186e4c7e55bc3da +Signed-off-by: Randy Li +--- + drivers/clk/rockchip/clk-rk3036.c | 2 +- + include/dt-bindings/clock/rk3036-cru.h | 1 + + 2 files changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/clk/rockchip/clk-rk3036.c b/drivers/clk/rockchip/clk-rk3036.c +index 4ce2cf844123..0d1556ac185a 100644 +--- a/drivers/clk/rockchip/clk-rk3036.c ++++ b/drivers/clk/rockchip/clk-rk3036.c +@@ -404,7 +404,7 @@ static struct rockchip_clk_branch rk3036_clk_branches[] __initdata = { + GATE(HCLK_OTG0, "hclk_otg0", "hclk_peri", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(5), 13, GFLAGS), + GATE(HCLK_OTG1, "hclk_otg1", "hclk_peri", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(7), 3, GFLAGS), + GATE(HCLK_I2S, "hclk_i2s", "hclk_peri", 0, RK2928_CLKGATE_CON(7), 2, GFLAGS), +- GATE(0, "hclk_sfc", "hclk_peri", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(3), 14, GFLAGS), ++ GATE(HCLK_SFC, "hclk_sfc", "hclk_peri", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(3), 14, GFLAGS), + GATE(HCLK_MAC, "hclk_mac", "hclk_peri", 0, RK2928_CLKGATE_CON(3), 5, GFLAGS), + + /* pclk_peri gates */ +diff --git a/include/dt-bindings/clock/rk3036-cru.h b/include/dt-bindings/clock/rk3036-cru.h +index 4c7ff6141a67..72ba1952071d 100644 +--- a/include/dt-bindings/clock/rk3036-cru.h ++++ b/include/dt-bindings/clock/rk3036-cru.h +@@ -84,6 +84,7 @@ + #define HCLK_OTG0 449 + #define HCLK_OTG1 450 + #define HCLK_NANDC 453 ++#define HCLK_SFC 454 + #define HCLK_SDMMC 456 + #define HCLK_SDIO 457 + #define HCLK_EMMC 459 + +From 62768587c0db32f4180bd4cebbd9f8d8ad865901 Mon Sep 17 00:00:00 2001 +From: Elaine Zhang +Date: Mon, 1 Jun 2020 15:36:35 +0800 +Subject: [PATCH] clk: rockchip: rk3036: fix up the sclk_sfc parent error + +Change-Id: I0903161f34de8f309392bec6926348ffe37ba2f6 +Signed-off-by: Elaine Zhang +--- + drivers/clk/rockchip/clk-rk3036.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/clk/rockchip/clk-rk3036.c b/drivers/clk/rockchip/clk-rk3036.c +index 0d1556ac185a..693bee4009db 100644 +--- a/drivers/clk/rockchip/clk-rk3036.c ++++ b/drivers/clk/rockchip/clk-rk3036.c +@@ -122,6 +122,7 @@ PNAME(mux_pll_src_dmyapll_dpll_gpll_p) = { "dummy_apll", "dpll", "gpll" }; + PNAME(mux_timer_p) = { "xin24m", "pclk_peri_src" }; + + PNAME(mux_pll_src_dmyapll_dpll_gpll_usb480m_p) = { "dummy_apll", "dpll", "gpll", "usb480m" }; ++PNAME(mux_pll_src_dmyapll_dpll_gpll_xin24_p) = { "dummy_apll", "dpll", "gpll", "xin24m" }; + + PNAME(mux_mmc_src_p) = { "dummy_apll", "dpll", "gpll", "xin24m" }; + PNAME(mux_i2s_pre_p) = { "i2s_src", "i2s_frac", "ext_i2s", "xin12m" }; +@@ -341,7 +342,7 @@ static struct rockchip_clk_branch rk3036_clk_branches[] __initdata = { + RK2928_CLKSEL_CON(16), 8, 2, MFLAGS, 10, 5, DFLAGS, + RK2928_CLKGATE_CON(10), 4, GFLAGS), + +- COMPOSITE(SCLK_SFC, "sclk_sfc", mux_pll_src_dmyapll_dpll_gpll_usb480m_p, 0, ++ COMPOSITE(SCLK_SFC, "sclk_sfc", mux_pll_src_dmyapll_dpll_gpll_xin24_p, 0, + RK2928_CLKSEL_CON(16), 0, 2, MFLAGS, 2, 5, DFLAGS, + RK2928_CLKGATE_CON(10), 5, GFLAGS), + + +From cef2d7b595360c89a57fcf38d1dcf41759ceac95 Mon Sep 17 00:00:00 2001 +From: Alex Bee +Date: Sun, 16 Aug 2020 22:41:29 +0200 +Subject: [PATCH] clk: rockchip: export PCLK_EFUSE for RK3036 + +Export PCLK_EFUSE for RK3036. +--- + drivers/clk/rockchip/clk-rk3036.c | 2 +- + include/dt-bindings/clock/rk3036-cru.h | 1 + + 2 files changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/clk/rockchip/clk-rk3036.c b/drivers/clk/rockchip/clk-rk3036.c +index 693bee4009db..06e92dd5ce25 100644 +--- a/drivers/clk/rockchip/clk-rk3036.c ++++ b/drivers/clk/rockchip/clk-rk3036.c +@@ -410,7 +410,7 @@ static struct rockchip_clk_branch rk3036_clk_branches[] __initdata = { + + /* pclk_peri gates */ + GATE(0, "pclk_peri_matrix", "pclk_peri", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(4), 1, GFLAGS), +- GATE(0, "pclk_efuse", "pclk_peri", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(5), 2, GFLAGS), ++ GATE(PCLK_EFUSE, "pclk_efuse", "pclk_peri", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(5), 2, GFLAGS), + GATE(PCLK_TIMER, "pclk_timer", "pclk_peri", 0, RK2928_CLKGATE_CON(7), 7, GFLAGS), + GATE(PCLK_PWM, "pclk_pwm", "pclk_peri", 0, RK2928_CLKGATE_CON(7), 10, GFLAGS), + GATE(PCLK_SPI, "pclk_spi", "pclk_peri", 0, RK2928_CLKGATE_CON(7), 12, GFLAGS), +diff --git a/include/dt-bindings/clock/rk3036-cru.h b/include/dt-bindings/clock/rk3036-cru.h +index 72ba1952071d..febab04521a2 100644 +--- a/include/dt-bindings/clock/rk3036-cru.h ++++ b/include/dt-bindings/clock/rk3036-cru.h +@@ -79,6 +79,7 @@ + #define PCLK_DDRUPCTL 364 + #define PCLK_WDT 368 + #define PCLK_ACODEC 369 ++#define PCLK_EFUSE 370 + + /* hclk gates */ + #define HCLK_OTG0 449 + +From bf25b1441ad681e8b56ae6ec069165dc4fb6b445 Mon Sep 17 00:00:00 2001 +From: Alex Bee +Date: Sun, 16 Aug 2020 22:43:41 +0200 +Subject: [PATCH] ARM: dts: rockchip: add RK3036 efuse node + +Add RK3036 efuse node to the devicetree and add the new compatible string +to bindings document. +--- + .../devicetree/bindings/nvmem/rockchip-efuse.yaml | 1 + + arch/arm/boot/dts/rk3036.dtsi | 7 +++++++ + 2 files changed, 8 insertions(+) + +diff --git a/Documentation/devicetree/bindings/nvmem/rockchip-efuse.yaml b/Documentation/devicetree/bindings/nvmem/rockchip-efuse.yaml +index 3ae00b0b23bc..c3fdabcb1e0a 100644 +--- a/Documentation/devicetree/bindings/nvmem/rockchip-efuse.yaml ++++ b/Documentation/devicetree/bindings/nvmem/rockchip-efuse.yaml +@@ -15,6 +15,7 @@ allOf: + properties: + compatible: + enum: ++ - rockchip,rk3036-efuse + - rockchip,rk3066a-efuse + - rockchip,rk3188-efuse + - rockchip,rk3228-efuse +diff --git a/arch/arm/boot/dts/rk3036.dtsi b/arch/arm/boot/dts/rk3036.dtsi +index 10f15cdb932c..6700a17a6446 100644 +--- a/arch/arm/boot/dts/rk3036.dtsi ++++ b/arch/arm/boot/dts/rk3036.dtsi +@@ -873,4 +873,11 @@ spi_cs1:spi-cs1 { + }; + }; + }; ++ ++ efuse: efuse@20090000 { ++ compatible = "rockchip,rk3036-efuse", "rockchip,rk3288-efuse"; ++ reg = <0x20090000 0x20>; ++ clocks = <&cru PCLK_EFUSE>; ++ clock-names = "pclk_efuse"; ++ }; + }; + +From 490be97e9fdc5e4ea8afd5b41d2a9f2942f82b02 Mon Sep 17 00:00:00 2001 +From: Alex Bee +Date: Sun, 16 Aug 2020 23:02:00 +0200 +Subject: [PATCH] ARM: dts: add opp-table for RK3188s GPU + +Add opp-table for RK3188s mali400 MP4 GPU +--- + arch/arm/boot/dts/rk3188.dtsi | 30 ++++++++++++++++++++++++++++++ + 1 file changed, 30 insertions(+) + +diff --git a/arch/arm/boot/dts/rk3188.dtsi b/arch/arm/boot/dts/rk3188.dtsi +index 9fab375231ec..894fe6259ef2 100644 +--- a/arch/arm/boot/dts/rk3188.dtsi ++++ b/arch/arm/boot/dts/rk3188.dtsi +@@ -112,6 +112,35 @@ smp-sram@0 { + }; + }; + ++ gpu_opp_table: opp-table2 { ++ compatible = "operating-points-v2"; ++ ++ opp-133000000 { ++ opp-hz = /bits/ 64 <133000000>; ++ opp-microvolt = <975000>; ++ }; ++ opp-200000000 { ++ opp-hz = /bits/ 64 <200000000>; ++ opp-microvolt = <1000000>; ++ }; ++ opp-266000000 { ++ opp-hz = /bits/ 64 <266000000>; ++ opp-microvolt = <1025000>; ++ }; ++ opp-300000000 { ++ opp-hz = /bits/ 64 <300000000>; ++ opp-microvolt = <1050000>; ++ }; ++ opp-400000000 { ++ opp-hz = /bits/ 64 <400000000>; ++ opp-microvolt = <1100000>; ++ }; ++ opp-600000000 { ++ opp-hz = /bits/ 64 <600000000>; ++ opp-microvolt = <1250000>; ++ }; ++ }; ++ + vpu: video-codec@10104000 { + compatible = "rockchip,rk3188-vpu"; + reg = <0x10104000 0x800>; +@@ -672,6 +701,7 @@ &gpu { + "ppmmu2", + "pp3", + "ppmmu3"; ++ operating-points-v2 = <&gpu_opp_table>; + power-domains = <&power RK3188_PD_GPU>; + }; + + +From 313b1d3730fc3a9076a783e9e296a13fdae599ce Mon Sep 17 00:00:00 2001 +From: Alex Bee +Date: Sun, 16 Aug 2020 23:12:25 +0200 +Subject: [PATCH] ARM: dts: rk322x: add crypto node + +In order to add support for RK322x's crypto HW, the node +has been added t its dts. + +Signed-off-by: Alex Bee +--- + arch/arm/boot/dts/rk322x.dtsi | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/arch/arm/boot/dts/rk322x.dtsi b/arch/arm/boot/dts/rk322x.dtsi +index 92e3eb1e7938..be46697e125e 100644 +--- a/arch/arm/boot/dts/rk322x.dtsi ++++ b/arch/arm/boot/dts/rk322x.dtsi +@@ -167,6 +167,17 @@ display_subsystem: display-subsystem { + ports = <&vop_out>; + }; + ++ crypto: cypto-controller@100a0000 { ++ compatible = "rockchip,rk3288-crypto"; ++ reg = <0x100a0000 0x4000>; ++ interrupts = ; ++ clocks = <&cru HCLK_M_CRYPTO>, <&cru HCLK_S_CRYPTO>, ++ <&cru SCLK_CRYPTO>, <&cru ACLK_DMAC>; ++ clock-names = "aclk", "hclk", "sclk", "apb_pclk"; ++ resets = <&cru SRST_CRYPTO>; ++ reset-names = "crypto-rst"; ++ }; ++ + i2s1: i2s1@100b0000 { + compatible = "rockchip,rk3228-i2s", "rockchip,rk3066-i2s"; + reg = <0x100b0000 0x4000>; diff --git a/patch/kernel/rk322x-dev/01-linux-9000-rockchip-linux-le-wip.patch b/patch/kernel/rk322x-dev/01-linux-9000-rockchip-linux-le-wip.patch new file mode 100644 index 000000000..dad10c696 --- /dev/null +++ b/patch/kernel/rk322x-dev/01-linux-9000-rockchip-linux-le-wip.patch @@ -0,0 +1,912 @@ +From 71fba6c19fa57e219657226d3d20528ebec86def Mon Sep 17 00:00:00 2001 +From: Alex Bee +Date: Sun, 16 Aug 2020 23:03:12 +0200 +Subject: [PATCH] WIP: ARM: dts: add RK322x box device trees + +--- + arch/arm/boot/dts/Makefile | 4 + + arch/arm/boot/dts/rk3228a-box-h96mini.dts | 115 +++++++++ + arch/arm/boot/dts/rk3228a-box.dts | 47 ++++ + arch/arm/boot/dts/rk3228a-box.dtsi | 12 + + arch/arm/boot/dts/rk3229-box-a95xr1.dts | 57 ++++ + arch/arm/boot/dts/rk3229-box.dts | 50 ++++ + arch/arm/boot/dts/rk3229-box.dtsi | 21 ++ + arch/arm/boot/dts/rk3229-cpu-opp.dtsi | 50 ++++ + arch/arm/boot/dts/rk322x-box-dcdc.dtsi | 164 ++++++++++++ + arch/arm/boot/dts/rk322x-box.dtsi | 301 ++++++++++++++++++++++ + 10 files changed, 821 insertions(+) + create mode 100644 arch/arm/boot/dts/rk3228a-box-h96mini.dts + create mode 100644 arch/arm/boot/dts/rk3228a-box.dts + create mode 100644 arch/arm/boot/dts/rk3228a-box.dtsi + create mode 100644 arch/arm/boot/dts/rk3229-box-a95xr1.dts + create mode 100644 arch/arm/boot/dts/rk3229-box.dts + create mode 100644 arch/arm/boot/dts/rk3229-box.dtsi + create mode 100644 arch/arm/boot/dts/rk3229-cpu-opp.dtsi + create mode 100644 arch/arm/boot/dts/rk322x-box-dcdc.dtsi + create mode 100644 arch/arm/boot/dts/rk322x-box.dtsi + +diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile +index e6a1cac0bfc7..1e633e4aa5a2 100644 +--- a/arch/arm/boot/dts/Makefile ++++ b/arch/arm/boot/dts/Makefile +@@ -961,7 +961,11 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += \ + rk3188-bqedison2qc.dtb \ + rk3188-px3-evb.dtb \ + rk3188-radxarock.dtb \ ++ rk3228a-box.dtb \ ++ rk3228a-box-h96mini.dtb \ + rk3228-evb.dtb \ ++ rk3229-box.dtb \ ++ rk3229-box-a95xr1.dtb \ + rk3229-evb.dtb \ + rk3229-xms6.dtb \ + rk3288-evb-act8846.dtb \ +diff --git a/arch/arm/boot/dts/rk3228a-box-h96mini.dts b/arch/arm/boot/dts/rk3228a-box-h96mini.dts +new file mode 100644 +index 000000000000..1041b6737d40 +--- /dev/null ++++ b/arch/arm/boot/dts/rk3228a-box-h96mini.dts +@@ -0,0 +1,115 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR MIT) ++ ++/dts-v1/; ++#include ++#include ++#include "rk3228a-box.dtsi" ++ ++/ { ++ compatible = "eledvb,h96mini", "rockchip,rk3228a-box", "rockchip,rk3229"; ++ model = "Rockchip RK3228A Box H96 mini"; ++ ++ leds { ++ compatible = "gpio-leds"; ++ ++ led_green { ++ gpios = <&gpio3 RK_PC5 GPIO_ACTIVE_HIGH>; ++ default-state = "on"; ++ }; ++ ++ led_red { ++ gpios = <&gpio0 RK_PB0 GPIO_ACTIVE_HIGH>; ++ default-state = "off"; ++ }; ++ }; ++ ++ openvfd { ++ compatible = "open,vfd"; ++ dev_name = "openvfd"; ++ openvfd_gpio_clk = <&gpio0 RK_PA0 GPIO_ACTIVE_HIGH>; ++ openvfd_gpio_dat = <&gpio0 RK_PA1 GPIO_ACTIVE_HIGH>; ++ openvfd_display_type = <0x06000100>; ++ openvfd_dot_bits = [00 01 03 02 04 05 06]; ++ }; ++ ++}; ++ ++&emmc { ++ mmc-hs200-1_8v; ++ status = "okay"; ++}; ++ ++&gmac { ++ tx_delay = <0x26>; ++ rx_delay = <0x11>; ++}; ++ ++&ir_receiver { ++ status = "okay"; ++}; ++ ++&pinctrl { ++ wifi { ++ wifi_host_wake_l: wifi-host-wake-l { ++ rockchip,pins = <0 RK_PD4 RK_FUNC_GPIO &pcfg_pull_none>; ++ }; ++ }; ++ ++ bt { ++ bt_host_wake_l: bt-host-wake-l { ++ rockchip,pins = <3 RK_PD2 RK_FUNC_GPIO &pcfg_pull_none>; ++ }; ++ ++ bt_reg_on_h: bt-reg-on-h { ++ rockchip,pins = <2 RK_PD5 RK_FUNC_GPIO &pcfg_pull_none>; ++ }; ++ ++ bt_wake_l: bt-wake-l { ++ rockchip,pins = <3 RK_PD3 RK_FUNC_GPIO &pcfg_pull_none>; ++ }; ++ }; ++}; ++ ++&power_key { ++ status = "okay"; ++}; ++ ++&sdio { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "okay"; ++ ++ brcmf: wifi@1 { ++ compatible = "brcm,bcm4329-fmac"; ++ reg = <1>; ++ interrupt-parent = <&gpio0>; ++ interrupts = ; ++ interrupt-names = "host-wake"; ++ brcm,drive-strength = <5>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&wifi_host_wake_l>; ++ }; ++}; ++ ++&sdmmc { ++ disable-wp; ++ status = "okay"; ++}; ++ ++&uart1 { ++ status = "okay"; ++ ++ bluetooth { ++ compatible = "brcm,bcm4330-bt"; ++ host-wakeup-gpios = <&gpio3 RK_PD2 GPIO_ACTIVE_HIGH>; ++ device-wakeup-gpios = <&gpio3 RK_PD3 GPIO_ACTIVE_HIGH>; ++ shutdown-gpios = <&gpio2 RK_PD5 GPIO_ACTIVE_HIGH>; ++ max-speed = <4000000>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&bt_reg_on_h &bt_host_wake_l &bt_wake_l>; ++ }; ++}; ++ ++&usb_otg { ++ dr_mode = "host"; ++}; +diff --git a/arch/arm/boot/dts/rk3228a-box.dts b/arch/arm/boot/dts/rk3228a-box.dts +new file mode 100644 +index 000000000000..e68ef44b95c9 +--- /dev/null ++++ b/arch/arm/boot/dts/rk3228a-box.dts +@@ -0,0 +1,47 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR MIT) ++ ++/dts-v1/; ++#include "rk3228a-box.dtsi" ++ ++/ { ++ model = "Rockchip RK3228A Box"; ++ ++ leds { ++ compatible = "gpio-leds"; ++ ++ led_blue { ++ gpios = <&gpio3 RK_PC5 GPIO_ACTIVE_HIGH>; ++ default-state = "on"; ++ }; ++ ++ led_red { ++ gpios = <&gpio1 RK_PA7 GPIO_ACTIVE_HIGH>; ++ default-state = "off"; ++ }; ++ }; ++ ++}; ++ ++&emmc { ++ status = "okay"; ++}; ++ ++&ir_receiver { ++ status = "okay"; ++}; ++ ++&sdio { ++ status = "okay"; ++}; ++ ++&sdmmc { ++ status = "okay"; ++}; ++ ++&uart1 { ++ status = "okay"; ++}; ++ ++&usb_otg { ++ dr_mode = "host"; ++}; +diff --git a/arch/arm/boot/dts/rk3228a-box.dtsi b/arch/arm/boot/dts/rk3228a-box.dtsi +new file mode 100644 +index 000000000000..056945c6c9a7 +--- /dev/null ++++ b/arch/arm/boot/dts/rk3228a-box.dtsi +@@ -0,0 +1,12 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR MIT) ++ ++/dts-v1/; ++ ++#include "rk322x-box-dcdc.dtsi" ++ ++/ { ++ ++ model = "Rockchip RK3228A Box"; ++ compatible = "rockchip,rk3228a-box", "rockchip,rk3229"; ++ ++}; +diff --git a/arch/arm/boot/dts/rk3229-box-a95xr1.dts b/arch/arm/boot/dts/rk3229-box-a95xr1.dts +new file mode 100644 +index 000000000000..b3695fb0b255 +--- /dev/null ++++ b/arch/arm/boot/dts/rk3229-box-a95xr1.dts +@@ -0,0 +1,57 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR MIT) ++ ++/dts-v1/; ++#include ++#include ++#include "rk3229-box.dtsi" ++ ++/ { ++ model = "Rockchip RK3229 Box A95X-R1"; ++ ++ leds { ++ compatible = "gpio-leds"; ++ ++ led_blue { ++ gpios = <&gpio3 RK_PC5 GPIO_ACTIVE_HIGH>; ++ default-state = "on"; ++ }; ++ ++ led_red { ++ gpios = <&gpio1 RK_PA7 GPIO_ACTIVE_HIGH>; ++ default-state = "off"; ++ linux,default-trigger = "rc-feedback"; ++ }; ++ }; ++ ++}; ++ ++&emmc { ++ mmc-hs200-1_8v; ++ status = "okay"; ++}; ++ ++&gmac { ++ tx_delay = <0x26>; ++ rx_delay = <0x11>; ++}; ++ ++&ir_receiver { ++ status = "okay"; ++}; ++ ++&power_key { ++ status = "okay"; ++}; ++ ++&sdio { ++ status = "okay"; ++}; ++ ++&sdmmc { ++ disable-wp; ++ status = "okay"; ++}; ++ ++&usb_otg { ++ dr_mode = "host"; ++}; +diff --git a/arch/arm/boot/dts/rk3229-box.dts b/arch/arm/boot/dts/rk3229-box.dts +new file mode 100644 +index 000000000000..b63e61cda257 +--- /dev/null ++++ b/arch/arm/boot/dts/rk3229-box.dts +@@ -0,0 +1,50 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR MIT) ++ ++/dts-v1/; ++#include "rk3229-box.dtsi" ++ ++/ { ++ model = "Rockchip RK3229 Box"; ++ ++ leds { ++ compatible = "gpio-leds"; ++ ++ led_green { ++ gpios = <&gpio3 RK_PC5 GPIO_ACTIVE_HIGH>; ++ default-state = "on"; ++ }; ++ ++ led_red { ++ gpios = <&gpio0 RK_PB0 GPIO_ACTIVE_HIGH>; ++ default-state = "off"; ++ }; ++ }; ++}; ++ ++&emmc { ++ status = "okay"; ++}; ++ ++&ir_receiver { ++ status = "okay"; ++}; ++ ++&power_key { ++ status = "okay"; ++}; ++ ++&sdio { ++ status = "okay"; ++}; ++ ++&sdmmc { ++ status = "okay"; ++}; ++ ++&uart1 { ++ status = "okay"; ++}; ++ ++&usb_otg { ++ dr_mode = "host"; ++}; +diff --git a/arch/arm/boot/dts/rk3229-box.dtsi b/arch/arm/boot/dts/rk3229-box.dtsi +new file mode 100644 +index 000000000000..84f98fc53ebf +--- /dev/null ++++ b/arch/arm/boot/dts/rk3229-box.dtsi +@@ -0,0 +1,21 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR MIT) ++ ++/dts-v1/; ++ ++#include "rk322x-box-dcdc.dtsi" ++#include "rk3229-cpu-opp.dtsi" ++ ++/ { ++ ++ model = "Rockchip RK3229 Box"; ++ compatible = "rockchip,rk3229-box", "rockchip,rk3229"; ++ ++}; ++ ++&cpu0_opp_table { ++ ++ opp-1464000000 { ++ status = "disabled"; ++ }; ++ ++}; +diff --git a/arch/arm/boot/dts/rk3229-cpu-opp.dtsi b/arch/arm/boot/dts/rk3229-cpu-opp.dtsi +new file mode 100644 +index 000000000000..c1c7613bab11 +--- /dev/null ++++ b/arch/arm/boot/dts/rk3229-cpu-opp.dtsi +@@ -0,0 +1,50 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR MIT) ++/* ++ * Copyright (c) 2017 Fuzhou Rockchip Electronics Co., Ltd ++ */ ++ ++/ { ++ compatible = "rockchip,rk3229"; ++ ++ /delete-node/ opp-table0; ++ ++ cpu0_opp_table: opp_table0 { ++ compatible = "operating-points-v2"; ++ opp-shared; ++ ++ opp-408000000 { ++ opp-hz = /bits/ 64 <408000000>; ++ opp-microvolt = <950000 950000 1400000>; ++ clock-latency-ns = <40000>; ++ opp-suspend; ++ }; ++ opp-600000000 { ++ opp-hz = /bits/ 64 <600000000>; ++ opp-microvolt = <975000 975000 1400000>; ++ }; ++ opp-816000000 { ++ opp-hz = /bits/ 64 <816000000>; ++ opp-microvolt = <1000000 1000000 1400000>; ++ }; ++ opp-1008000000 { ++ opp-hz = /bits/ 64 <1008000000>; ++ opp-microvolt = <1175000 1175000 1400000>; ++ }; ++ opp-1200000000 { ++ opp-hz = /bits/ 64 <1200000000>; ++ opp-microvolt = <1275000 1275000 1400000>; ++ }; ++ opp-1296000000 { ++ opp-hz = /bits/ 64 <1296000000>; ++ opp-microvolt = <1325000 1325000 1400000>; ++ }; ++ opp-1392000000 { ++ opp-hz = /bits/ 64 <1392000000>; ++ opp-microvolt = <1350000 1350000 1400000>; ++ }; ++ opp-1464000000 { ++ opp-hz = /bits/ 64 <1464000000>; ++ opp-microvolt = <1400000 1400000 1400000>; ++ }; ++ }; ++}; +diff --git a/arch/arm/boot/dts/rk322x-box-dcdc.dtsi b/arch/arm/boot/dts/rk322x-box-dcdc.dtsi +new file mode 100644 +index 000000000000..b2e47c5b4693 +--- /dev/null ++++ b/arch/arm/boot/dts/rk322x-box-dcdc.dtsi +@@ -0,0 +1,164 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR MIT) ++ ++/dts-v1/; ++ ++#include ++#include ++#include "rk322x-box.dtsi" ++ ++/ { ++ ++ vcc_host: vcc-host-regulator { ++ compatible = "regulator-fixed"; ++ enable-active-high; ++ gpio = <&gpio3 RK_PC4 GPIO_ACTIVE_HIGH>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&host_vbus_drv>; ++ regulator-name = "vcc_host"; ++ regulator-always-on; ++ regulator-boot-on; ++ vin-supply = <&vcc_sys>; ++ }; ++ ++ vccio_1v8: vccio-1v8-regulator { ++ compatible = "regulator-fixed"; ++ regulator-name = "vccio_1v8"; ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <1800000>; ++ regulator-always-on; ++ vin-supply = <&vcc_sys>; ++ }; ++ ++ vccio_3v3: vccio-3v3-regulator { ++ compatible = "regulator-fixed"; ++ regulator-name = "vccio_3v3"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-always-on; ++ vin-supply = <&vcc_sys>; ++ }; ++ ++ ++ vcc_otg: vcc-otg-regulator { ++ compatible = "regulator-fixed"; ++ enable-active-high; ++ gpio = <&gpio3 RK_PC6 GPIO_ACTIVE_HIGH>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&otg_vbus_drv>; ++ regulator-name = "vcc_otg_vbus"; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; ++ regulator-always-on; ++ regulator-boot-on; ++ vin-supply = <&vcc_sys>; ++ }; ++ ++ vcc_phy: vcc-phy-regulator { ++ compatible = "regulator-fixed"; ++ enable-active-high; ++ regulator-name = "vcc_phy"; ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <1800000>; ++ regulator-always-on; ++ regulator-boot-on; ++ vin-supply = <&vccio_1v8>; ++ }; ++ ++ vcc_sys: vcc-sys-regulator { ++ compatible = "regulator-fixed"; ++ regulator-name = "vcc_sys"; ++ regulator-always-on; ++ regulator-boot-on; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; ++ }; ++ ++ vdd_arm: vdd-arm-regulator { ++ compatible = "pwm-regulator"; ++ pwms = <&pwm1 0 5000 1>; ++ pwm-supply = <&vcc_sys>; ++ regulator-name = "vdd_arm"; ++ regulator-min-microvolt = <950000>; ++ regulator-max-microvolt = <1400000>; ++ regulator-ramp-delay = <12500>; ++ regulator-settling-time-up-us = <250>; ++ regulator-always-on; ++ regulator-boot-on; ++ }; ++ ++ vdd_log: vdd-log-regulator { ++ compatible = "pwm-regulator"; ++ pwms = <&pwm2 0 5000 1>; ++ pwm-supply = <&vcc_sys>; ++ regulator-name = "vdd_log"; ++ regulator-min-microvolt = <1000000>; ++ regulator-max-microvolt = <1300000>; ++ regulator-ramp-delay = <12500>; ++ regulator-settling-time-up-us = <250>; ++ regulator-always-on; ++ regulator-boot-on; ++ }; ++ ++}; ++ ++ ++&cpu0 { ++ cpu-supply = <&vdd_arm>; ++}; ++ ++&cpu1 { ++ cpu-supply = <&vdd_arm>; ++}; ++ ++&cpu2 { ++ cpu-supply = <&vdd_arm>; ++}; ++ ++&cpu3 { ++ cpu-supply = <&vdd_arm>; ++}; ++ ++&io_domains { ++ vccio1-supply = <&vccio_3v3>; ++ vccio2-supply = <&vccio_1v8>; ++ vccio4-supply = <&vccio_3v3>; ++ status = "okay"; ++}; ++ ++&gmac { ++ phy-supply = <&vcc_phy>; ++}; ++ ++&gpu { ++ mali-supply = <&vdd_log>; ++}; ++ ++&pwm1 { ++ pinctrl-0 = <&pwm1_pin_pull_down>; ++ status = "okay"; ++}; ++ ++&pwm2 { ++ pinctrl-0 = <&pwm2_pin_pull_up>; ++ status = "okay"; ++}; ++ ++&u2phy0 { ++ u2phy0_host: host-port { ++ phy-supply = <&vcc_host>; ++ }; ++ ++ u2phy0_otg: otg-port { ++ phy-supply = <&vcc_otg>; ++ }; ++}; ++ ++&u2phy1 { ++ u2phy1_host: host-port { ++ phy-supply = <&vcc_host>; ++ }; ++ ++ u2phy1_otg: otg-port { ++ phy-supply = <&vcc_otg>; ++ }; ++}; +diff --git a/arch/arm/boot/dts/rk322x-box.dtsi b/arch/arm/boot/dts/rk322x-box.dtsi +new file mode 100644 +index 000000000000..02c9b3540f38 +--- /dev/null ++++ b/arch/arm/boot/dts/rk322x-box.dtsi +@@ -0,0 +1,299 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR MIT) ++ ++/dts-v1/; ++ ++#include ++#include ++#include ++#include ++#include "rk322x.dtsi" ++ ++/ { ++ model = "Rockchip RK322x Box"; ++ compatible = "rockchip,rk3229"; ++ ++ chosen { ++ bootargs = "earlyprintk=uart8250,mmio32,0x11030000"; ++ }; ++ ++ gpio_keys { ++ compatible = "gpio-keys"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ autorepeat; ++ ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pwr_key>; ++ ++ power_key: power-key { ++ label = "GPIO Key Power"; ++ gpios = <&gpio3 RK_PD1 GPIO_ACTIVE_LOW>; ++ linux,code = ; ++ debounce-interval = <100>; ++ wakeup-source; ++ status = "disabled"; ++ }; ++ }; ++ ++ ir_receiver: ir-receiver { ++ compatible = "gpio-ir-receiver"; ++ gpios = <&gpio1 RK_PB3 GPIO_ACTIVE_LOW>; ++ pinctrl-0 = <&ir_int>; ++ pinctrl-names = "default"; ++ status = "disabled"; ++ }; ++ ++ memory@60000000 { ++ device_type = "memory"; ++ reg = <0x60000000 0x40000000>; ++ }; ++ ++ reserved-memory { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ranges; ++ ++ /* Not needed since u-boot 2020.07 ++ trust_reserved: trust@68400000 { ++ reg = <0x68400000 0xe00000>; ++ no-map; ++ };*/ ++ }; ++ ++ sdio_pwrseq: sdio-pwrseq { ++ compatible = "mmc-pwrseq-simple"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&wifi_enable_h>; ++ reset-gpios = <&gpio2 RK_PD2 GPIO_ACTIVE_LOW>; ++ }; ++ ++}; ++ ++&cpu_alert1 { ++ temperature = <105000>; ++}; ++ ++&cpu_crit { ++ temperature = <115000>; ++}; ++ ++&cpu_thermal { ++ cooling-maps { ++ /delete-node/ map0; ++ }; ++}; ++ ++&cpu0_opp_table { ++ ++ opp-408000000 { ++ opp-microvolt = <950000 950000 1275000>; ++ }; ++ ++ opp-600000000 { ++ opp-microvolt = <975000 975000 1275000>; ++ }; ++ ++ opp-816000000 { ++ opp-microvolt = <1000000 1000000 1275000>; ++ }; ++ ++ opp-1008000000 { ++ opp-microvolt = <1175000 1175000 1275000>; ++ }; ++ ++ opp-1200000000 { ++ opp-microvolt = <1275000 1275000 1275000>; ++ }; ++}; ++ ++&cru { ++ assigned-clocks = ++ <&cru PLL_GPLL>, <&cru ARMCLK>, ++ <&cru PLL_CPLL>, <&cru ACLK_PERI>, ++ <&cru HCLK_PERI>, <&cru PCLK_PERI>, ++ <&cru ACLK_CPU>, <&cru HCLK_CPU>, ++ <&cru PCLK_CPU>, <&cru ACLK_VOP>; ++ assigned-clock-rates = ++ <1200000000>, <816000000>, ++ <500000000>, <150000000>, ++ <150000000>, <75000000>, ++ <150000000>, <150000000>, ++ <75000000>, <400000000>; ++}; ++ ++&emmc { ++ cap-mmc-highspeed; ++ keep-power-in-suspend; ++ non-removable; ++}; ++ ++&gmac { ++ assigned-clocks = <&cru SCLK_MAC_SRC>; ++ assigned-clock-rates = <50000000>; ++ clock_in_out = "output"; ++ phy-handle = <&phy>; ++ phy-mode = "rmii"; ++ status = "okay"; ++ ++ mdio { ++ compatible = "snps,dwmac-mdio"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ phy: phy@0 { ++ compatible = "ethernet-phy-id1234.d400", ++ "ethernet-phy-ieee802.3-c22"; ++ reg = <0>; ++ clocks = <&cru SCLK_MAC_PHY>; ++ phy-is-integrated; ++ resets = <&cru SRST_MACPHY>; ++ }; ++ }; ++}; ++ ++&gpu { ++ assigned-clocks = <&cru ACLK_GPU>; ++ assigned-clock-rates = <300000000>; ++}; ++ ++&hdmi { ++ status = "okay"; ++}; ++ ++&hdmi_sound { ++ status = "okay"; ++}; ++ ++&hdmi_phy { ++ status = "okay"; ++}; ++ ++&i2s0 { ++ status = "okay"; ++}; ++ ++&pinctrl { ++ ++ ir { ++ ir_int: ir-int { ++ rockchip,pins = <1 RK_PB3 RK_FUNC_GPIO &pcfg_pull_none>; ++ }; ++ }; ++ ++ keys { ++ pwr_key: pwr-key { ++ rockchip,pins = <3 RK_PC7 RK_FUNC_GPIO &pcfg_pull_up>; ++ }; ++ }; ++ ++ pwm1 { ++ pwm1_pin_pull_down: pwm1-pin-pull-down { ++ rockchip,pins = <0 RK_PD6 2 &pcfg_pull_down>; ++ }; ++ }; ++ ++ pwm2 { ++ pwm2_pin_pull_up: pwm2-pin-pull-up { ++ rockchip,pins = <1 RK_PB4 2 &pcfg_pull_up>; ++ }; ++ }; ++ ++ sdio-pwrseq { ++ wifi_enable_h: wifi-enable-h { ++ rockchip,pins = <2 RK_PD2 RK_FUNC_GPIO &pcfg_pull_none>; ++ }; ++ }; ++ ++ usb { ++ host_vbus_drv: host-vbus-drv { ++ rockchip,pins = <3 RK_PC4 RK_FUNC_GPIO &pcfg_pull_none>; ++ }; ++ ++ otg_vbus_drv: otg-vbus-drv { ++ rockchip,pins = <3 RK_PC6 RK_FUNC_GPIO &pcfg_pull_none>; ++ }; ++ }; ++ ++}; ++ ++&sdio { ++ mmc-pwrseq = <&sdio_pwrseq>; ++ cap-sd-highspeed; ++ cap-sdio-irq; ++ keep-power-in-suspend; ++ non-removable; ++ no-sd; ++}; ++ ++&sdmmc { ++ cap-sd-highspeed; ++ keep-power-in-suspend; ++ no-sdio; ++}; ++ ++&tsadc { ++ rockchip,grf = <&grf>; ++ rockchip,hw-tshut-mode = <0>; ++ rockchip,hw-tshut-polarity = <1>; ++ rockchip,hw-tshut-temp = <120000>; ++ status = "okay"; ++}; ++ ++&u2phy0 { ++ status = "okay"; ++}; ++ ++&u2phy1 { ++ status = "okay"; ++}; ++ ++&uart1 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&uart11_xfer &uart11_rts &uart11_cts>; ++}; ++ ++&uart2 { ++ status = "okay"; ++}; ++ ++&usb_host0_ehci { ++ status = "okay"; ++}; ++ ++&usb_host0_ohci { ++ status = "okay"; ++}; ++ ++&usb_host1_ehci { ++ status = "okay"; ++}; ++ ++&usb_host1_ohci { ++ status = "okay"; ++}; ++ ++&usb_host2_ehci { ++ status = "okay"; ++}; ++ ++&usb_host2_ohci { ++ status = "okay"; ++}; ++ ++&usb_otg { ++ status = "okay"; ++}; ++ ++&vop { ++ assigned-clocks = <&cru DCLK_VOP>; ++ assigned-clock-parents = <&cru SCLK_HDMI_PHY>; ++ status = "okay"; ++}; ++ ++&vop_mmu { ++ status = "okay"; ++}; ++ ++&wdt { ++ status = "okay"; ++}; diff --git a/patch/kernel/rk322x-dev/02-linux-0004-dtsi-adjust-nand-pinctrls.patch b/patch/kernel/rk322x-dev/02-linux-0004-dtsi-adjust-nand-pinctrls.patch index db3e79e6c..a6ea7e3d4 100644 --- a/patch/kernel/rk322x-dev/02-linux-0004-dtsi-adjust-nand-pinctrls.patch +++ b/patch/kernel/rk322x-dev/02-linux-0004-dtsi-adjust-nand-pinctrls.patch @@ -1,91 +1,92 @@ diff --git a/arch/arm/boot/dts/rk322x.dtsi b/arch/arm/boot/dts/rk322x.dtsi -index b2fcf0e75..25051c03f 100644 +index be46697e1..b2a0246fb 100644 --- a/arch/arm/boot/dts/rk322x.dtsi +++ b/arch/arm/boot/dts/rk322x.dtsi -@@ -1149,51 +1149,71 @@ +@@ -843,6 +843,22 @@ + status = "disabled"; + }; - flash_cs0: flash-cs0 { - rockchip,pins = -- <2 RK_PA6 1 &pcfg_pull_none>; -+ <2 RK_PA6 1 &pcfg_pull_up>; - }; - - flash_cs1: flash-cs1 { - rockchip,pins = -- <0 RK_PC7 1 &pcfg_pull_none>; -+ <0 RK_PC7 1 &pcfg_pull_up>; -+ }; ++ nfc: nand-controller@ff4b0000 { ++ compatible = "rockchip,rk3228_nfc"; ++ reg = <0x30030000 0x4000>; ++ interrupts = ; ++ clocks = <&cru SCLK_NANDC>, <&cru HCLK_NANDC>; ++ clock-names = "nfc", "ahb"; ++ assigned-clocks = <&cru SCLK_NANDC>; ++ assigned-clock-rates = <150000000>; + -+ flash_cs2: flash-cs2 { -+ rockchip,pins = -+ <1 RK_PC6 1 &pcfg_pull_up>; -+ }; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&flash_cs0 &flash_rdy &flash_ale &flash_cle ++ &flash_wrn &flash_rdn &flash_bus8>; ++ status = "disabled"; + -+ flash_cs3: flash-cs3 { -+ rockchip,pins = -+ <1 RK_PC7 1 &pcfg_pull_up>; - }; - - flash_rdy: flash-rdy { - rockchip,pins = -- <2 RK_PA4 1 &pcfg_pull_none>; -+ <2 RK_PA4 1 &pcfg_pull_up>; - }; - - flash_ale: flash-ale { - rockchip,pins = -- <2 RK_PA0 1 &pcfg_pull_none>; -+ <2 RK_PA0 1 &pcfg_pull_down>; - }; - - flash_cle: flash-cle { - rockchip,pins = -- <2 RK_PA1 1 &pcfg_pull_none>; -+ <2 RK_PA1 1 &pcfg_pull_down>; - }; - - flash_wrn: flash-wrn { -- rockchip,pins = -- <2 RK_PA2 1 &pcfg_pull_none>; -+ rockchip,pins = -+ <2 RK_PA2 1 &pcfg_pull_up>; - }; - - flash_rdn: flash-rdn { - rockchip,pins = -- <2 RK_PA3 1 &pcfg_pull_none>; -+ <2 RK_PA3 1 &pcfg_pull_up>; - }; - - flash_bus8: flash-bus8 { -- rockchip,pins = <1 RK_PD0 1 &pcfg_pull_none>, -- <1 RK_PD1 1 &pcfg_pull_none>, -- <1 RK_PD2 1 &pcfg_pull_none>, -- <1 RK_PD3 1 &pcfg_pull_none>, -- <1 RK_PD4 1 &pcfg_pull_none>, -- <1 RK_PD5 1 &pcfg_pull_none>, -- <1 RK_PD6 1 &pcfg_pull_none>, -- <1 RK_PD7 1 &pcfg_pull_none>; -+ rockchip,pins = <1 RK_PD0 1 &pcfg_pull_up>, -+ <1 RK_PD1 1 &pcfg_pull_up>, -+ <1 RK_PD2 1 &pcfg_pull_up>, -+ <1 RK_PD3 1 &pcfg_pull_up>, -+ <1 RK_PD4 1 &pcfg_pull_up>, -+ <1 RK_PD5 1 &pcfg_pull_up>, -+ <1 RK_PD6 1 &pcfg_pull_up>, -+ <1 RK_PD7 1 &pcfg_pull_up>; - }; -+ -+ flash_dqs: flash-dqs { -+ rockchip,pins = <2 RK_PA7 1 &pcfg_pull_up>; -+ }; -+ -+ flash_wp: flash-wp { -+ rockchip,pins = <2 RK_PA5 1 &pcfg_pull_down>; -+ }; ++ }; + + usb_otg: usb@30040000 { + compatible = "rockchip,rk3228-usb", "rockchip,rk3066-usb", + "snps,dwc2"; +@@ -1105,6 +1121,65 @@ + }; }; ++ flash { ++ ++ flash_cs0: flash-cs0 { ++ rockchip,pins = <2 RK_PA6 1 &pcfg_pull_up>; ++ }; ++ ++ flash_cs1: flash-cs1 { ++ rockchip,pins = <0 RK_PC7 1 &pcfg_pull_up>; ++ }; ++ ++ flash_cs2: flash-cs2 { ++ rockchip,pins = <1 RK_PC6 1 &pcfg_pull_up>; ++ }; ++ ++ flash_cs3: flash-cs3 { ++ rockchip,pins = <1 RK_PC7 1 &pcfg_pull_up>; ++ }; ++ ++ flash_rdy: flash-rdy { ++ rockchip,pins = <2 RK_PA4 1 &pcfg_pull_up>; ++ }; ++ ++ flash_ale: flash-ale { ++ rockchip,pins = <2 RK_PA0 1 &pcfg_pull_down>; ++ }; ++ ++ flash_cle: flash-cle { ++ rockchip,pins = <2 RK_PA1 1 &pcfg_pull_down>; ++ }; ++ ++ flash_wrn: flash-wrn { ++ rockchip,pins = <2 RK_PA2 1 &pcfg_pull_up>; ++ }; ++ ++ flash_rdn: flash-rdn { ++ rockchip,pins = <2 RK_PA3 1 &pcfg_pull_up>; ++ }; ++ ++ flash_bus8: flash-bus8 { ++ rockchip,pins = <1 RK_PD0 1 &pcfg_pull_up>, ++ <1 RK_PD1 1 &pcfg_pull_up>, ++ <1 RK_PD2 1 &pcfg_pull_up>, ++ <1 RK_PD3 1 &pcfg_pull_up>, ++ <1 RK_PD4 1 &pcfg_pull_up>, ++ <1 RK_PD5 1 &pcfg_pull_up>, ++ <1 RK_PD6 1 &pcfg_pull_up>, ++ <1 RK_PD7 1 &pcfg_pull_up>; ++ }; ++ ++ flash_dqs: flash-dqs { ++ rockchip,pins = <2 RK_PA7 1 &pcfg_pull_up>; ++ }; ++ ++ flash_wp: flash-wp { ++ rockchip,pins = <2 RK_PA5 1 &pcfg_pull_down>; ++ }; ++ ++ }; + gmac { rgmii_pins: rgmii-pins { diff --git a/patch/kernel/rk322x-dev/02-linux-0005-drm-plane-overlay.patch b/patch/kernel/rk322x-dev/02-linux-0005-drm-plane-overlay.patch new file mode 100644 index 000000000..15319a894 --- /dev/null +++ b/patch/kernel/rk322x-dev/02-linux-0005-drm-plane-overlay.patch @@ -0,0 +1,66 @@ +diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c +index 73d24c6bbf05..d4ac6e161ef2 100644 +--- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c ++++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c +@@ -614,6 +614,44 @@ static const struct vop_common rk3288_common = { + .dsp_background = VOP_REG(RK3288_DSP_BG, 0xffffffff, 0), + }; + ++static const struct vop_win_phy rk3228_win0_data = { ++ .scl = &rk3288_win_full_scl, ++ .data_formats = formats_win_full, ++ .nformats = ARRAY_SIZE(formats_win_full), ++ .enable = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 0), ++ .format = VOP_REG(RK3288_WIN0_CTRL0, 0x7, 1), ++ .rb_swap = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 12), ++ .act_info = VOP_REG(RK3288_WIN0_ACT_INFO, 0x1fff1fff, 0), ++ .dsp_info = VOP_REG(RK3288_WIN0_DSP_INFO, 0x0fff0fff, 0), ++ .dsp_st = VOP_REG(RK3288_WIN0_DSP_ST, 0x1fff1fff, 0), ++ .yrgb_mst = VOP_REG(RK3288_WIN0_YRGB_MST, 0xffffffff, 0), ++ .uv_mst = VOP_REG(RK3288_WIN0_CBR_MST, 0xffffffff, 0), ++ .yrgb_vir = VOP_REG(RK3288_WIN0_VIR, 0x3fff, 0), ++ .uv_vir = VOP_REG(RK3288_WIN0_VIR, 0x3fff, 16), ++ .src_alpha_ctl = VOP_REG(RK3288_WIN0_SRC_ALPHA_CTRL, 0xff, 0), ++ .dst_alpha_ctl = VOP_REG(RK3288_WIN0_DST_ALPHA_CTRL, 0xff, 0), ++ .channel = VOP_REG(RK3288_WIN0_CTRL2, 0xff, 0), ++}; ++ ++static const struct vop_win_phy rk3228_win1_data = { ++ .scl = &rk3288_win_full_scl, ++ .data_formats = formats_win_lite, ++ .nformats = ARRAY_SIZE(formats_win_lite), ++ .enable = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 0), ++ .format = VOP_REG(RK3288_WIN0_CTRL0, 0x7, 1), ++ .rb_swap = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 12), ++ .act_info = VOP_REG(RK3288_WIN0_ACT_INFO, 0x1fff1fff, 0), ++ .dsp_info = VOP_REG(RK3288_WIN0_DSP_INFO, 0x0fff0fff, 0), ++ .dsp_st = VOP_REG(RK3288_WIN0_DSP_ST, 0x1fff1fff, 0), ++ .yrgb_mst = VOP_REG(RK3288_WIN0_YRGB_MST, 0xffffffff, 0), ++ .uv_mst = VOP_REG(RK3288_WIN0_CBR_MST, 0xffffffff, 0), ++ .yrgb_vir = VOP_REG(RK3288_WIN0_VIR, 0x3fff, 0), ++ .uv_vir = VOP_REG(RK3288_WIN0_VIR, 0x3fff, 16), ++ .src_alpha_ctl = VOP_REG(RK3288_WIN0_SRC_ALPHA_CTRL, 0xff, 0), ++ .dst_alpha_ctl = VOP_REG(RK3288_WIN0_DST_ALPHA_CTRL, 0xff, 0), ++ .channel = VOP_REG(RK3288_WIN0_CTRL2, 0xff, 0), ++}; ++ + /* + * Note: rk3288 has a dedicated 'cursor' window, however, that window requires + * special support to get alpha blending working. For now, just use overlay +@@ -864,10 +902,10 @@ static const struct vop_data rk3399_vop_lit = { + }; + + static const struct vop_win_data rk3228_vop_win_data[] = { +- { .base = 0x00, .phy = &rk3288_win01_data, ++ { .base = 0x00, .phy = &rk3228_win0_data, + .type = DRM_PLANE_TYPE_PRIMARY }, +- { .base = 0x40, .phy = &rk3288_win01_data, +- .type = DRM_PLANE_TYPE_CURSOR }, ++ { .base = 0x40, .phy = &rk3228_win1_data, ++ .type = DRM_PLANE_TYPE_OVERLAY }, + }; + + static const struct vop_data rk3228_vop = { +-- +2.17.1 + diff --git a/patch/kernel/rk322x-dev/board-rk322x-box.patch b/patch/kernel/rk322x-dev/board-rk322x-box.patch index afec537f1..2b92f90c3 100644 --- a/patch/kernel/rk322x-dev/board-rk322x-box.patch +++ b/patch/kernel/rk322x-dev/board-rk322x-box.patch @@ -3,7 +3,7 @@ new file mode 100644 index 000000000..24590f864 --- /dev/null +++ b/arch/arm/boot/dts/rk322x-box.dts -@@ -0,0 +1,239 @@ +@@ -0,0 +1,235 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) + +/dts-v1/; @@ -53,10 +53,6 @@ index 000000000..24590f864 + rockchip,default-sample-phase = <180>; +}; + -+&nfc { -+ status = "okay"; -+}; -+ +&gmac { + tx_delay = <0x26>; + rx_delay = <0x11>; diff --git a/patch/kernel/rk322x-dev/wifi-4003-fix-sha256_state-clashes.patch b/patch/kernel/rk322x-dev/wifi-4003-fix-sha256_state-clashes.patch new file mode 100644 index 000000000..0dce511a1 --- /dev/null +++ b/patch/kernel/rk322x-dev/wifi-4003-fix-sha256_state-clashes.patch @@ -0,0 +1,248 @@ +diff --git a/drivers/net/wireless/rtl8189es/include/rtw_security.h b/drivers/net/wireless/rtl8189es/include/rtw_security.h +index 5820a55..3e8e428 100644 +--- a/drivers/net/wireless/rtl8189es/include/rtw_security.h ++++ b/drivers/net/wireless/rtl8189es/include/rtw_security.h +@@ -238,7 +238,7 @@ struct security_priv + #endif /* DBG_SW_SEC_CNT */ + }; + +-struct sha256_state { ++struct rtl_sha256_state { + u64 length; + u32 state[8], curlen; + u8 buf[64]; +diff --git a/drivers/net/wireless/rtl8189es/core/rtw_security.c b/drivers/net/wireless/rtl8189es/core/rtw_security.c +index 8dac771..9b3a1f9 100644 +--- a/drivers/net/wireless/rtl8189es/core/rtw_security.c ++++ b/drivers/net/wireless/rtl8189es/core/rtw_security.c +@@ -2281,7 +2281,7 @@ BIP_exit: + + #ifndef PLATFORM_FREEBSD + /* compress 512-bits */ +-static int sha256_compress(struct sha256_state *md, unsigned char *buf) ++static int sha256_compress(struct rtl_sha256_state *md, unsigned char *buf) + { + u32 S[8], W[64], t0, t1; + u32 t; +@@ -2323,7 +2323,7 @@ static int sha256_compress(struct sha256_state *md, unsigned char *buf) + } + + /* Initialize the hash state */ +-static void sha256_init(struct sha256_state *md) ++static void sha256_init(struct rtl_sha256_state *md) + { + md->curlen = 0; + md->length = 0; +@@ -2344,7 +2344,7 @@ static void sha256_init(struct sha256_state *md) + @param inlen The length of the data (octets) + @return CRYPT_OK if successful + */ +-static int sha256_process(struct sha256_state *md, unsigned char *in, ++static int sha256_process(struct rtl_sha256_state *md, unsigned char *in, + unsigned long inlen) + { + unsigned long n; +@@ -2385,7 +2385,7 @@ static int sha256_process(struct sha256_state *md, unsigned char *in, + @param out [out] The destination of the hash (32 bytes) + @return CRYPT_OK if successful + */ +-static int sha256_done(struct sha256_state *md, unsigned char *out) ++static int sha256_done(struct rtl_sha256_state *md, unsigned char *out) + { + int i; + +@@ -2437,7 +2437,7 @@ static int sha256_done(struct sha256_state *md, unsigned char *out) + static int sha256_vector(size_t num_elem, u8 *addr[], size_t *len, + u8 *mac) + { +- struct sha256_state ctx; ++ struct rtl_sha256_state ctx; + size_t i; + + sha256_init(&ctx); +diff --git a/drivers/net/wireless/rtl8811cu/include/rtw_security.h b/drivers/net/wireless/rtl8811cu/include/rtw_security.h +index ac8432e..5f74fb7 100755 +--- a/drivers/net/wireless/rtl8811cu/include/rtw_security.h ++++ b/drivers/net/wireless/rtl8811cu/include/rtw_security.h +@@ -249,7 +249,7 @@ struct security_priv { + #define SEC_IS_BIP_KEY_INSTALLED(sec) _FALSE + #endif + +-struct sha256_state { ++struct rtl_sha256_state { + u64 length; + u32 state[8], curlen; + u8 buf[64]; +diff --git a/drivers/net/wireless/rtl8811cu/core/rtw_security.c b/drivers/net/wireless/rtl8811cu/core/rtw_security.c +index b537a26..f8c42f4 100755 +--- a/drivers/net/wireless/rtl8811cu/core/rtw_security.c ++++ b/drivers/net/wireless/rtl8811cu/core/rtw_security.c +@@ -2133,7 +2133,7 @@ BIP_exit: + #ifndef PLATFORM_FREEBSD + #if defined(CONFIG_TDLS) + /* compress 512-bits */ +-static int sha256_compress(struct sha256_state *md, unsigned char *buf) ++static int sha256_compress(struct rtl_sha256_state *md, unsigned char *buf) + { + u32 S[8], W[64], t0, t1; + u32 t; +@@ -2181,7 +2181,7 @@ static int sha256_compress(struct sha256_state *md, unsigned char *buf) + } + + /* Initialize the hash state */ +-static void sha256_init(struct sha256_state *md) ++static void sha256_init(struct rtl_sha256_state *md) + { + md->curlen = 0; + md->length = 0; +@@ -2202,7 +2202,7 @@ static void sha256_init(struct sha256_state *md) + @param inlen The length of the data (octets) + @return CRYPT_OK if successful + */ +-static int sha256_process(struct sha256_state *md, unsigned char *in, ++static int sha256_process(struct rtl_sha256_state *md, unsigned char *in, + unsigned long inlen) + { + unsigned long n; +@@ -2243,7 +2243,7 @@ static int sha256_process(struct sha256_state *md, unsigned char *in, + @param out [out] The destination of the hash (32 bytes) + @return CRYPT_OK if successful + */ +-static int sha256_done(struct sha256_state *md, unsigned char *out) ++static int sha256_done(struct rtl_sha256_state *md, unsigned char *out) + { + int i; + +@@ -2293,7 +2293,7 @@ static int sha256_done(struct sha256_state *md, unsigned char *out) + static int sha256_vector(size_t num_elem, u8 *addr[], size_t *len, + u8 *mac) + { +- struct sha256_state ctx; ++ struct rtl_sha256_state ctx; + size_t i; + + sha256_init(&ctx); +diff --git a/drivers/net/wireless/rtl8188eu/include/rtw_security.h b/drivers/net/wireless/rtl8188eu/include/rtw_security.h +index 0adc700..2a9cf9d 100644 +--- a/drivers/net/wireless/rtl8188eu/include/rtw_security.h ++++ b/drivers/net/wireless/rtl8188eu/include/rtw_security.h +@@ -249,7 +249,7 @@ struct security_priv { + #define SEC_IS_BIP_KEY_INSTALLED(sec) _FALSE + #endif + +-struct sha256_state { ++struct rtl_sha256_state { + u64 length; + u32 state[8], curlen; + u8 buf[64]; +diff --git a/drivers/net/wireless/rtl8188eu/core/rtw_security.c b/drivers/net/wireless/rtl8188eu/core/rtw_security.c +index 5807521..0b3eed2 100644 +--- a/drivers/net/wireless/rtl8188eu/core/rtw_security.c ++++ b/drivers/net/wireless/rtl8188eu/core/rtw_security.c +@@ -2133,7 +2133,7 @@ BIP_exit: + #ifndef PLATFORM_FREEBSD + #if defined(CONFIG_TDLS) + /* compress 512-bits */ +-static int sha256_compress(struct sha256_state *md, unsigned char *buf) ++static int sha256_compress(struct rtl_sha256_state *md, unsigned char *buf) + { + u32 S[8], W[64], t0, t1; + u32 t; +@@ -2181,7 +2181,7 @@ static int sha256_compress(struct sha256_state *md, unsigned char *buf) + } + + /* Initialize the hash state */ +-static void sha256_init(struct sha256_state *md) ++static void sha256_init(struct rtl_sha256_state *md) + { + md->curlen = 0; + md->length = 0; +@@ -2202,7 +2202,7 @@ static void sha256_init(struct sha256_state *md) + @param inlen The length of the data (octets) + @return CRYPT_OK if successful + */ +-static int sha256_process(struct sha256_state *md, unsigned char *in, ++static int sha256_process(struct rtl_sha256_state *md, unsigned char *in, + unsigned long inlen) + { + unsigned long n; +@@ -2243,7 +2243,7 @@ static int sha256_process(struct sha256_state *md, unsigned char *in, + @param out [out] The destination of the hash (32 bytes) + @return CRYPT_OK if successful + */ +-static int sha256_done(struct sha256_state *md, unsigned char *out) ++static int sha256_done(struct rtl_sha256_state *md, unsigned char *out) + { + int i; + +@@ -2293,7 +2293,7 @@ static int sha256_done(struct sha256_state *md, unsigned char *out) + static int sha256_vector(size_t num_elem, u8 *addr[], size_t *len, + u8 *mac) + { +- struct sha256_state ctx; ++ struct rtl_sha256_state ctx; + size_t i; + + sha256_init(&ctx); +diff --git a/drivers/net/wireless/rtl88x2bu/include/rtw_security.h b/drivers/net/wireless/rtl88x2bu/include/rtw_security.h +index ac8432e..5f74fb7 100644 +--- a/drivers/net/wireless/rtl88x2bu/include/rtw_security.h ++++ b/drivers/net/wireless/rtl88x2bu/include/rtw_security.h +@@ -249,7 +249,7 @@ struct security_priv { + #define SEC_IS_BIP_KEY_INSTALLED(sec) _FALSE + #endif + +-struct sha256_state { ++struct rtl_sha256_state { + u64 length; + u32 state[8], curlen; + u8 buf[64]; +diff --git a/drivers/net/wireless/rtl88x2bu/core/rtw_security.c b/drivers/net/wireless/rtl88x2bu/core/rtw_security.c +index b537a26..f8c42f4 100644 +--- a/drivers/net/wireless/rtl88x2bu/core/rtw_security.c ++++ b/drivers/net/wireless/rtl88x2bu/core/rtw_security.c +@@ -2133,7 +2133,7 @@ BIP_exit: + #ifndef PLATFORM_FREEBSD + #if defined(CONFIG_TDLS) + /* compress 512-bits */ +-static int sha256_compress(struct sha256_state *md, unsigned char *buf) ++static int sha256_compress(struct rtl_sha256_state *md, unsigned char *buf) + { + u32 S[8], W[64], t0, t1; + u32 t; +@@ -2181,7 +2181,7 @@ static int sha256_compress(struct sha256_state *md, unsigned char *buf) + } + + /* Initialize the hash state */ +-static void sha256_init(struct sha256_state *md) ++static void sha256_init(struct rtl_sha256_state *md) + { + md->curlen = 0; + md->length = 0; +@@ -2202,7 +2202,7 @@ static void sha256_init(struct sha256_state *md) + @param inlen The length of the data (octets) + @return CRYPT_OK if successful + */ +-static int sha256_process(struct sha256_state *md, unsigned char *in, ++static int sha256_process(struct rtl_sha256_state *md, unsigned char *in, + unsigned long inlen) + { + unsigned long n; +@@ -2243,7 +2243,7 @@ static int sha256_process(struct sha256_state *md, unsigned char *in, + @param out [out] The destination of the hash (32 bytes) + @return CRYPT_OK if successful + */ +-static int sha256_done(struct sha256_state *md, unsigned char *out) ++static int sha256_done(struct rtl_sha256_state *md, unsigned char *out) + { + int i; + +@@ -2293,7 +2293,7 @@ static int sha256_done(struct sha256_state *md, unsigned char *out) + static int sha256_vector(size_t num_elem, u8 *addr[], size_t *len, + u8 *mac) + { +- struct sha256_state ctx; ++ struct rtl_sha256_state ctx; + size_t i; + + sha256_init(&ctx); diff --git a/patch/kernel/rk322x-dev/wifi-4004-fix-cfg80211-for-5.8.patch b/patch/kernel/rk322x-dev/wifi-4004-fix-cfg80211-for-5.8.patch new file mode 100644 index 000000000..587d60460 --- /dev/null +++ b/patch/kernel/rk322x-dev/wifi-4004-fix-cfg80211-for-5.8.patch @@ -0,0 +1,236 @@ +diff --git a/drivers/net/wireless/rtl8189es/os_dep/linux/ioctl_cfg80211.c b/drivers/net/wireless/rtl8189es/os_dep/linux/ioctl_cfg80211.c +index d77cc17..32cc240 100644 +--- a/drivers/net/wireless/rtl8189es/os_dep/linux/ioctl_cfg80211.c ++++ b/drivers/net/wireless/rtl8189es/os_dep/linux/ioctl_cfg80211.c +@@ -5567,6 +5567,33 @@ exit: + return ret; + } + ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0)) ++ ++static void ++cfg80211_rtw_update_mgmt_frame_registrations(struct wiphy *wiphy, ++ struct wireless_dev *wdev, ++ struct mgmt_frame_regs *upd) ++{ ++ struct net_device *ndev = wdev_to_ndev(wdev); ++ struct rtw_wdev_priv *pwdev_priv; ++ _adapter *adapter; ++ ++ if (ndev == NULL) ++ return; ++ ++ adapter = (_adapter *)rtw_netdev_priv(ndev); ++ pwdev_priv = adapter_wdev_data(adapter); ++ ++#ifdef CONFIG_DEBUG_CFG80211 ++ RTW_INFO(FUNC_ADPT_FMT" stypes:%x\n", FUNC_ADPT_ARG(adapter), ++ upd->interface_stypes); ++#endif ++ ++ /* not implemented, see bellow */ ++} ++ ++#else ++ + static void cfg80211_rtw_mgmt_frame_register(struct wiphy *wiphy, + #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) + struct wireless_dev *wdev, +@@ -5611,6 +5638,8 @@ exit: + return; + } + ++#endif ++ + #if defined(CONFIG_TDLS) && (LINUX_VERSION_CODE >= KERNEL_VERSION(3,2,0)) + static int cfg80211_rtw_tdls_mgmt(struct wiphy *wiphy, + struct net_device *ndev, +@@ -6505,7 +6534,11 @@ static struct cfg80211_ops rtw_cfg80211_ops = { + + #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37)) || defined(COMPAT_KERNEL_RELEASE) + .mgmt_tx = cfg80211_rtw_mgmt_tx, ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0)) ++ .update_mgmt_frame_registrations = cfg80211_rtw_update_mgmt_frame_registrations, ++#else + .mgmt_frame_register = cfg80211_rtw_mgmt_frame_register, ++#endif + #elif (LINUX_VERSION_CODE>=KERNEL_VERSION(2,6,34) && LINUX_VERSION_CODE<=KERNEL_VERSION(2,6,35)) + .action = cfg80211_rtw_mgmt_tx, + #endif +diff --git a/drivers/net/wireless/rtl8811cu/os_dep/linux/ioctl_cfg80211.c b/drivers/net/wireless/rtl8811cu/os_dep/linux/ioctl_cfg80211.c +index c0df148..9bff924 100755 +--- a/drivers/net/wireless/rtl8811cu/os_dep/linux/ioctl_cfg80211.c ++++ b/drivers/net/wireless/rtl8811cu/os_dep/linux/ioctl_cfg80211.c +@@ -7143,6 +7143,33 @@ exit: + return ret; + } + ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0)) ++ ++static void ++cfg80211_rtw_update_mgmt_frame_registrations(struct wiphy *wiphy, ++ struct wireless_dev *wdev, ++ struct mgmt_frame_regs *upd) ++{ ++ struct net_device *ndev = wdev_to_ndev(wdev); ++ struct rtw_wdev_priv *pwdev_priv; ++ _adapter *adapter; ++ ++ if (ndev == NULL) ++ return; ++ ++ adapter = (_adapter *)rtw_netdev_priv(ndev); ++ pwdev_priv = adapter_wdev_data(adapter); ++ ++#ifdef CONFIG_DEBUG_CFG80211 ++ RTW_INFO(FUNC_ADPT_FMT" stypes:%x\n", FUNC_ADPT_ARG(adapter), ++ upd->interface_stypes); ++#endif ++ ++ /* not implemented, see bellow */ ++} ++ ++#else ++ + static void cfg80211_rtw_mgmt_frame_register(struct wiphy *wiphy, + #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) + struct wireless_dev *wdev, +@@ -7187,6 +7214,8 @@ exit: + return; + } + ++#endif ++ + #if defined(CONFIG_TDLS) && (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)) + static int cfg80211_rtw_tdls_mgmt(struct wiphy *wiphy, + struct net_device *ndev, +@@ -9457,7 +9486,11 @@ static struct cfg80211_ops rtw_cfg80211_ops = { + + #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)) || defined(COMPAT_KERNEL_RELEASE) + .mgmt_tx = cfg80211_rtw_mgmt_tx, ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0)) ++ .update_mgmt_frame_registrations = cfg80211_rtw_update_mgmt_frame_registrations, ++#else + .mgmt_frame_register = cfg80211_rtw_mgmt_frame_register, ++#endif + #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 34) && LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 35)) + .action = cfg80211_rtw_mgmt_tx, + #endif +diff --git a/drivers/net/wireless/rtl8188eu/os_dep/linux/ioctl_cfg80211.c b/drivers/net/wireless/rtl8188eu/os_dep/linux/ioctl_cfg80211.c +index 721723e..62fd530 100644 +--- a/drivers/net/wireless/rtl8188eu/os_dep/linux/ioctl_cfg80211.c ++++ b/drivers/net/wireless/rtl8188eu/os_dep/linux/ioctl_cfg80211.c +@@ -7470,6 +7470,33 @@ exit: + return ret; + } + ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0)) ++ ++static void ++cfg80211_rtw_update_mgmt_frame_registrations(struct wiphy *wiphy, ++ struct wireless_dev *wdev, ++ struct mgmt_frame_regs *upd) ++{ ++ struct net_device *ndev = wdev_to_ndev(wdev); ++ struct rtw_wdev_priv *pwdev_priv; ++ _adapter *adapter; ++ ++ if (ndev == NULL) ++ return; ++ ++ adapter = (_adapter *)rtw_netdev_priv(ndev); ++ pwdev_priv = adapter_wdev_data(adapter); ++ ++#ifdef CONFIG_DEBUG_CFG80211 ++ RTW_INFO(FUNC_ADPT_FMT" stypes:%x\n", FUNC_ADPT_ARG(adapter), ++ upd->interface_stypes); ++#endif ++ ++ /* not implemented, see bellow */ ++} ++ ++#else ++ + static void cfg80211_rtw_mgmt_frame_register(struct wiphy *wiphy, + #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) + struct wireless_dev *wdev, +@@ -7525,6 +7552,8 @@ exit: + return; + } + ++#endif ++ + #if defined(CONFIG_TDLS) && (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)) + static int cfg80211_rtw_tdls_mgmt(struct wiphy *wiphy, + struct net_device *ndev, +@@ -9903,7 +9932,11 @@ static struct cfg80211_ops rtw_cfg80211_ops = { + + #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)) || defined(COMPAT_KERNEL_RELEASE) + .mgmt_tx = cfg80211_rtw_mgmt_tx, ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0)) ++ .update_mgmt_frame_registrations = cfg80211_rtw_update_mgmt_frame_registrations, ++#else + .mgmt_frame_register = cfg80211_rtw_mgmt_frame_register, ++#endif + #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 34) && LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 35)) + .action = cfg80211_rtw_mgmt_tx, + #endif +diff --git a/drivers/net/wireless/rtl88x2bu/os_dep/linux/ioctl_cfg80211.c b/drivers/net/wireless/rtl88x2bu/os_dep/linux/ioctl_cfg80211.c +index 2fd4e28..b463e55 100755 +--- a/drivers/net/wireless/rtl88x2bu/os_dep/linux/ioctl_cfg80211.c ++++ b/drivers/net/wireless/rtl88x2bu/os_dep/linux/ioctl_cfg80211.c +@@ -7325,6 +7325,33 @@ exit: + return ret; + } + ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0)) ++ ++static void ++cfg80211_rtw_update_mgmt_frame_registrations(struct wiphy *wiphy, ++ struct wireless_dev *wdev, ++ struct mgmt_frame_regs *upd) ++{ ++ struct net_device *ndev = wdev_to_ndev(wdev); ++ struct rtw_wdev_priv *pwdev_priv; ++ _adapter *adapter; ++ ++ if (ndev == NULL) ++ return; ++ ++ adapter = (_adapter *)rtw_netdev_priv(ndev); ++ pwdev_priv = adapter_wdev_data(adapter); ++ ++#ifdef CONFIG_DEBUG_CFG80211 ++ RTW_INFO(FUNC_ADPT_FMT" stypes:%x\n", FUNC_ADPT_ARG(adapter), ++ upd->interface_stypes); ++#endif ++ ++ /* not implemented, see bellow */ ++} ++ ++#else ++ + static void cfg80211_rtw_mgmt_frame_register(struct wiphy *wiphy, + #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) + struct wireless_dev *wdev, +@@ -7369,6 +7396,8 @@ exit: + return; + } + ++#endif ++ + #if defined(CONFIG_TDLS) && (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)) + static int cfg80211_rtw_tdls_mgmt(struct wiphy *wiphy, + struct net_device *ndev, +@@ -9652,7 +9681,11 @@ static struct cfg80211_ops rtw_cfg80211_ops = { + + #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)) || defined(COMPAT_KERNEL_RELEASE) + .mgmt_tx = cfg80211_rtw_mgmt_tx, ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0)) ++ .update_mgmt_frame_registrations = cfg80211_rtw_update_mgmt_frame_registrations, ++#else + .mgmt_frame_register = cfg80211_rtw_mgmt_frame_register, ++#endif + #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 34) && LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 35)) + .action = cfg80211_rtw_mgmt_tx, + #endif diff --git a/patch/kernel/rk322x-legacy/01-linux-1002-rk322x-dts.patch b/patch/kernel/rk322x-legacy/01-linux-1002-rk322x-dts.patch index e546eadb8..81105648c 100644 --- a/patch/kernel/rk322x-legacy/01-linux-1002-rk322x-dts.patch +++ b/patch/kernel/rk322x-legacy/01-linux-1002-rk322x-dts.patch @@ -3,7 +3,7 @@ new file mode 100644 index 0000000..04330d3 --- /dev/null +++ b/arch/arm/boot/dts/rk322x-box.dtsi -@@ -0,0 +1,503 @@ +@@ -0,0 +1,504 @@ +/* + * Copyright (C) 2020 knaerzche + * @@ -36,14 +36,15 @@ index 0000000..04330d3 + #size-cells = <1>; + ranges; + -+ ramoops_mem: ramoops@62e00000 { ++ /*ramoops_mem: ramoops@62e00000 { + reg = <0x62e00000 0xf0000>; -+ }; ++ };*/ + ++ /* Not neeed for u-boot 2020.07 and up + trust_reserved: trust@68400000 { + reg = <0x68400000 0xe00000>; + no-map; -+ }; ++ };*/ + }; + + ramoops { diff --git a/patch/kernel/rk322x-legacy/03-001-wifi-esp8089-driver.patch b/patch/kernel/rk322x-legacy/03-001-wifi-esp8089-driver.patch index 7cca266fc..17fd43a3b 100644 --- a/patch/kernel/rk322x-legacy/03-001-wifi-esp8089-driver.patch +++ b/patch/kernel/rk322x-legacy/03-001-wifi-esp8089-driver.patch @@ -5324,8 +5324,8 @@ index 000000000..0f523fd20 + + /* ONLY station for now, support P2P soon... */ + hw->wiphy->interface_modes = -+ BIT(NL80211_IFTYPE_P2P_GO) | -+ BIT(NL80211_IFTYPE_P2P_CLIENT) | ++ //BIT(NL80211_IFTYPE_P2P_GO) | ++ //BIT(NL80211_IFTYPE_P2P_CLIENT) | + BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_AP); + + hw->wiphy->max_scan_ssids = 2; diff --git a/patch/kernel/rk322x-legacy/03-003-wifi-ssv6051-optimizations.patch b/patch/kernel/rk322x-legacy/03-003-wifi-ssv6051-optimizations.patch new file mode 100644 index 000000000..eafe28e9e --- /dev/null +++ b/patch/kernel/rk322x-legacy/03-003-wifi-ssv6051-optimizations.patch @@ -0,0 +1,36 @@ +diff --git a/drivers/net/wireless/rockchip_wlan/ssv6xxx/platform-config.mak b/drivers/net/wireless/rockchip_wlan/ssv6xxx/platform-config.mak +index 00d4792a0..373fc2bda 100644 +--- a/drivers/net/wireless/rockchip_wlan/ssv6xxx/platform-config.mak ++++ b/drivers/net/wireless/rockchip_wlan/ssv6xxx/platform-config.mak +@@ -9,7 +9,8 @@ ccflags-y += -Werror + + # Enable -g to help debug. Deassembly from .o to .S would help to track to + # the problomatic line from call stack dump. +-ccflags-y += -g ++#ccflags-y += -g ++ccflags += -Os + + ############################################################ + # If you change the settings, please change the file synchronization +@@ -71,7 +72,7 @@ ccflags-y += -DUSE_GENERIC_DECI_TBL + ccflags-y += -DUSE_LOCAL_CRYPTO + ccflags-y += -DUSE_LOCAL_WEP_CRYPTO + #ccflags-y += -DUSE_LOCAL_TKIP_CRYPTO +-ccflags-y += -DUSE_LOCAL_CCMP_CRYPTO ++#ccflags-y += -DUSE_LOCAL_CCMP_CRYPTO + ccflags-y += -DUSE_LOCAL_SMS4_CRYPTO + + ccflags-y += -DCONFIG_SSV_WAPI +diff --git a/drivers/net/wireless/rockchip_wlan/ssv6xxx/ssvdevice/ssvdevice.c b/drivers/net/wireless/rockchip_wlan/ssv6xxx/ssvdevice/ssvdevice.c +index 8718d8900..afce4ecef 100644 +--- a/drivers/net/wireless/rockchip_wlan/ssv6xxx/ssvdevice/ssvdevice.c ++++ b/drivers/net/wireless/rockchip_wlan/ssv6xxx/ssvdevice/ssvdevice.c +@@ -58,7 +58,7 @@ static char *ssv6xxx_cmd_buf; + char *ssv6xxx_result_buf; + extern struct ssv6xxx_cfg_cmd_table cfg_cmds[]; + extern struct ssv6xxx_cfg ssv_cfg; +-char DEFAULT_CFG_PATH[] = "/etc/firmware/ssv6051/ssv6051-wifi.cfg"; ++char DEFAULT_CFG_PATH[] = "/lib/firmware/ssv6051-wifi.cfg"; + static int ssv6xxx_dbg_open(struct inode *inode, struct file *filp) + { + filp->private_data = inode->i_private; diff --git a/patch/u-boot/u-boot-rk322x/u-boot-1000-rockchip.patch b/patch/u-boot/u-boot-rk322x/u-boot-1000-rockchip.patch index 4c2e4aa67..847ec67b9 100644 --- a/patch/u-boot/u-boot-rk322x/u-boot-1000-rockchip.patch +++ b/patch/u-boot/u-boot-rk322x/u-boot-1000-rockchip.patch @@ -268,31 +268,6 @@ index 866fc08215..b0d1b2f90a 100644 }; gic: interrupt-controller@ffc01000 { -diff --git a/arch/arm/dts/rk3328.dtsi b/arch/arm/dts/rk3328.dtsi -index 060c84e6c0..34c0b7de41 100644 ---- a/arch/arm/dts/rk3328.dtsi -+++ b/arch/arm/dts/rk3328.dtsi -@@ -337,6 +337,20 @@ - }; - }; - -+ efuse: efuse@ff260000 { -+ compatible = "rockchip,rk3328-efuse"; -+ reg = <0x0 0xff260000 0x0 0x80>; -+ #address-cells = <1>; -+ #size-cells = <1>; -+ clocks = <&cru SCLK_EFUSE>; -+ clock-names = "pclk_efuse"; -+ -+ /* Data cells */ -+ cpu_id: cpu-id@7 { -+ reg = <0x07 0x10>; -+ }; -+ }; -+ - saradc: saradc@ff280000 { - compatible = "rockchip,rk3328-saradc", "rockchip,saradc"; - reg = <0x0 0xff280000 0x0 0x100>; diff --git a/configs/evb-rk3328_defconfig b/configs/evb-rk3328_defconfig index 3db40a9a1a..edd1c41f09 100644 --- a/configs/evb-rk3328_defconfig @@ -314,19 +289,6 @@ index 3db40a9a1a..edd1c41f09 100644 CONFIG_MMC_DW=y CONFIG_MMC_DW_ROCKCHIP=y CONFIG_SF_DEFAULT_SPEED=20000000 -diff --git a/configs/evb-rk3399_defconfig b/configs/evb-rk3399_defconfig -index 8b8cdc5109..71c2daf8f5 100644 ---- a/configs/evb-rk3399_defconfig -+++ b/configs/evb-rk3399_defconfig -@@ -28,6 +28,8 @@ CONFIG_SYS_RELOC_GD_ENV_ADDR=y - CONFIG_NET_RANDOM_ETHADDR=y - CONFIG_ROCKCHIP_GPIO=y - CONFIG_SYS_I2C_ROCKCHIP=y -+CONFIG_MISC=y -+CONFIG_ROCKCHIP_EFUSE=y - CONFIG_MMC_DW=y - CONFIG_MMC_SDHCI=y - CONFIG_MMC_SDHCI_ROCKCHIP=y diff --git a/configs/miqi-rk3288_defconfig b/configs/miqi-rk3288_defconfig index cec8e42c5e..ac05d35392 100644 --- a/configs/miqi-rk3288_defconfig diff --git a/patch/u-boot/u-boot-rk322x/u-boot-1001-rockchip-rmii-integrated-phy.patch b/patch/u-boot/u-boot-rk322x/u-boot-1001-rockchip-rmii-integrated-phy.patch index b10a7950a..8777210de 100644 --- a/patch/u-boot/u-boot-rk322x/u-boot-1001-rockchip-rmii-integrated-phy.patch +++ b/patch/u-boot/u-boot-rk322x/u-boot-1001-rockchip-rmii-integrated-phy.patch @@ -63,27 +63,6 @@ index 4a8be5dabb..3c2861f271 100644 rockchip,grf = <&grf>; status = "disabled"; }; -diff --git a/arch/arm/dts/rk3328-evb.dts b/arch/arm/dts/rk3328-evb.dts -index a2ee838fcd..704712a05e 100644 ---- a/arch/arm/dts/rk3328-evb.dts -+++ b/arch/arm/dts/rk3328-evb.dts -@@ -100,6 +100,16 @@ - pinctrl-0 = <&rgmiim1_pins>; - tx_delay = <0x26>; - rx_delay = <0x11>; -+ status = "disabled"; -+}; -+ -+&gmac2phy { -+ phy-supply = <&vcc_phy>; -+ clock_in_out = "output"; -+ assigned-clocks = <&cru SCLK_MAC2PHY_SRC>; -+ assigned-clock-rate = <50000000>; -+ assigned-clocks = <&cru SCLK_MAC2PHY>; -+ assigned-clock-parents = <&cru SCLK_MAC2PHY_SRC>; - status = "okay"; - }; - diff --git a/arch/arm/dts/rk3328.dtsi b/arch/arm/dts/rk3328.dtsi index 060c84e6c0..c9419db07f 100644 --- a/arch/arm/dts/rk3328.dtsi @@ -388,11 +367,12 @@ index e152faf083..d3f6973043 100644 #include #include #include -@@ -23,6 +24,7 @@ +@@ -23,6 +24,8 @@ #include #include #include +#include ++#include #include #include "designware.h" diff --git a/patch/u-boot/u-boot-rk322x/u-boot-rk322x-with-spl.bin b/patch/u-boot/u-boot-rk322x/u-boot-rk322x-with-spl.bin new file mode 100644 index 000000000..e69de29bb