projects: add modifications for ROCKNIX

This commit is contained in:
ROCKNIX Team
2025-07-13 18:53:11 +01:00
parent 89da8137d4
commit 9f1fab30f6
2476 changed files with 485122 additions and 0 deletions
+78
View File
@@ -0,0 +1,78 @@
<dtb>
<H700 bootmethod="extlinux">
<file>sun50i-h700-anbernic-rg35xx-plus</file>
<file>sun50i-h700-anbernic-rg35xx-plus-rev6-panel</file>
<file>sun50i-h700-anbernic-rg35xx-pro</file>
<file>sun50i-h700-anbernic-rg35xx-h</file>
<file>sun50i-h700-anbernic-rg35xx-h-rev6-panel</file>
<file>sun50i-h700-anbernic-rg35xx-sp</file>
<file>sun50i-h700-anbernic-rg35xx-sp-v2-panel</file>
<file>sun50i-h700-anbernic-rg35xx-2024</file>
<file>sun50i-h700-anbernic-rg35xx-2024-rev6-panel</file>
<file>sun50i-h700-anbernic-rg40xx-h</file>
<file>sun50i-h700-anbernic-rg40xx-v</file>
<file>sun50i-h700-anbernic-rgcubexx</file>
<file>sun50i-h700-anbernic-rg28xx</file>
<file>sun50i-h700-anbernic-rg34xx</file>
<file>sun50i-h700-anbernic-rg34xx-sp</file>
</H700>
<RK3326>
<a bootmethod="bootini">
<file>rk3326-anbernic-rg351m</file>
<file>rk3326-anbernic-rg351v</file>
<file>rk3326-gameconsole-r33s</file>
<file>rk3326-gameconsole-r36s</file>
<file>rk3326-magicx-xu10</file>
<file>rk3326-odroid-go2</file>
<file>rk3326-odroid-go2-v11</file>
<file>rk3326-odroid-go3</file>
<file>rk3326-powkiddy-rgb10</file>
<file>rk3326-powkiddy-rgb20s</file>
</a>
<b bootmethod="bootini">
<file>rk3326-powkiddy-rgb10x</file>
<file>rk3326-magicx-xu10</file>
<file>rk3326-magicx-xu-mini-m</file>
<file>rk3326-gameconsole-r36max</file>
</b>
</RK3326>
<RK3399 bootmethod="extlinux">
<file>rk3399-anbernic-rg552</file>
</RK3399>
<RK3566>
<Generic bootmethod="extlinux_fdtdir">
<file>rk3566-anbernic-rg-arc-d</file>
<file>rk3566-anbernic-rg-arc-s</file>
<file>rk3566-anbernic-rg353p</file>
<file>rk3566-anbernic-rg353ps</file>
<file>rk3566-anbernic-rg353v</file>
<file>rk3566-anbernic-rg353vs</file>
<file>rk3566-anbernic-rg503</file>
<file>rk3566-powkiddy-rgb10max3</file>
<file>rk3566-powkiddy-rgb20-pro</file>
<file>rk3566-powkiddy-rgb20sx</file>
<file>rk3566-powkiddy-rgb30</file>
<file>rk3566-powkiddy-rk2023</file>
</Generic>
<Powkiddy_x55 bootmethod="extlinux">
<file>rk3566-powkiddy-x55</file>
<file>rk3566-powkiddy-x35s</file>
</Powkiddy_x55>
</RK3566>
<RK3588 bootmethod="extlinux">
<file>rk3588s-gameforce-ace</file>
<file>rk3588-orangepi-5-plus</file>
<file>rk3588-orangepi-5-max</file>
<file>rk3588-rock-5b</file>
<file>rk3588-rock-5b-plus</file>
<file>rk3588s-orangepi-5</file>
<file>rk3588s-orangepi-5-pro</file>
<file>rk3588s-retro-lite-cm5</file>
<file>rk3588s-retroled-cm5</file>
<file>rk3588s-rock-5a</file>
</RK3588>
<S922X bootmethod="extlinux_fdtdir">
<file>meson-g12b-odroid-go-ultra</file>
<file>meson-g12b-powkiddy-rgb10-max-3-pro</file>
</S922X>
</dtb>
+5
View File
@@ -0,0 +1,5 @@
# SPDX-License-Identifier: GPL-2.0
# Copyright (C) 2024-present ROCKNIX (https://github.com/ROCKNIX)
mkdir -p ${RELEASE_DIR}/3rdparty/bootloader
cp -a ${INSTALL}/usr/share/bootloader/* ${RELEASE_DIR}/3rdparty/bootloader
+60
View File
@@ -0,0 +1,60 @@
# SPDX-License-Identifier: GPL-2.0
# Copyright (C) 2024-present ROCKNIX (https://rocknix.org)
PKG_SOC="${DEVICE/RK/rk}"
# Make idbloader.img
case "${DEVICE}" in
RK3326)
# mkimage does not support packing second level bootloader on rk3326
${PKG_BUILD}/tools/mkimage -n px30 -T rksd -d "${PKG_DDR_BIN}" -C bzip2 idbloader.img
cat ${PKG_MINILOADER} >> idbloader.img
;;
RK3399|RK3566|RK3588)
[ "${PKG_SOC}" = "rk3566" ] && PKG_SOC="rk3568"
${PKG_BUILD}/tools/mkimage -n "${PKG_SOC}" -T rksd -d "${PKG_DDR_BIN}":"${PKG_MINILOADER}" -C bzip2 idbloader.img
;;
esac
# Pack uboot.img
case "${DEVICE}" in
RK3326|RK3399)
${PKG_RKBIN}/tools/loaderimage --pack --uboot u-boot-dtb.bin uboot.img 0x00200000
;;
esac
# Merge trust.img
case "${DEVICE}" in
RK3326)
cat >trust.ini <<EOF
[BL30_OPTION]
SEC=0
[BL31_OPTION]
SEC=1
PATH=${PKG_BL31}
ADDR=0x00010000
[BL32_OPTION]
SEC=0
[BL33_OPTION]
SEC=0
[OUTPUT]
PATH=trust.img
EOF
${PKG_RKBIN}/tools/trust_merger --verbose trust.ini
;;
RK3399)
${PKG_RKBIN}/tools/trust_merger --ignore-bl32 --prepath "${PKG_RKBIN}"/ "${PKG_ATF_INI}"
;;
esac
# Build a unified uboot.bin image
dd if=idbloader.img of=uboot.bin bs=512 seek=0 conv=fsync,notrunc
for BOOT_IMAGE in uboot.img u-boot.itb; do
if [ -f "$BOOT_IMAGE" ]; then
dd if=$BOOT_IMAGE of=uboot.bin bs=512 seek=16320 conv=fsync,notrunc
break
fi
done
if [ -f "trust.img" ]; then
dd if=trust.img of=uboot.bin bs=512 seek=24512 conv=fsync,notrunc
fi
@@ -0,0 +1,41 @@
# SPDX-License-Identifier: GPL-2.0
# Copyright (C) 2024-present ROCKNIX (https://github.com/ROCKNIX)
mkimage_uboot() {
if [ -f "${RELEASE_DIR}/3rdparty/bootloader/u-boot-sunxi-with-spl.bin" ]; then
echo "image: writing u-boot-sunxi-with-spl.bin to $(basename ${DISK})..."
dd if="${RELEASE_DIR}/3rdparty/bootloader/u-boot-sunxi-with-spl.bin" of="${DISK}" bs=1K seek=8 conv=fsync,notrunc >"${SAVE_ERROR}" 2>&1 || show_error
fi
}
mkimage_extlinux(){
echo "image: set exlinux.conf to FDT /dtb.img..."
mkdir -p "${IMG_TMP}/extlinux"
cat << EOF > "${IMG_TMP}/extlinux/extlinux.conf"
LABEL ${DISTRO}
LINUX /${KERNEL_NAME}
FDT /dtb.img
APPEND boot=LABEL=${DISTRO_BOOTLABEL} disk=LABEL=${DISTRO_DISKLABEL} ${EXTRA_CMDLINE}
EOF
echo "image: copying exlinux.conf..."
mcopy -s -o "${IMG_TMP}/extlinux" ::
}
mkimage_dtb() {
if [ -d ${RELEASE_DIR}/3rdparty/bootloader/device_trees ]; then
echo "image: copying device trees..."
mcopy -s ${RELEASE_DIR}/3rdparty/bootloader/device_trees ::
fi
if [ -d ${RELEASE_DIR}/3rdparty/bootloader/overlays ]; then
echo "image: copying device tree overlays..."
mcopy -s ${RELEASE_DIR}/3rdparty/bootloader/overlays ::
fi
}
DTBXML="${PROJECT_DIR}/${PROJECT}/bootloader/dtb.xml"
readarray -t DTB < <(xmlstarlet sel -t -v "//dtb/${DEVICE}/${SUBDEVICE}/file" ${DTBXML})
BOOTMETHOD=$(xmlstarlet sel -t -v "//dtb/${DEVICE}/${SUBDEVICE}/@bootmethod" ${DTBXML})
mkimage_dtb
mkimage_${BOOTMETHOD}
mkimage_uboot
+47
View File
@@ -0,0 +1,47 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
# Copyright (C) 2024-present ROCKNIX (https://github.com/ROCKNIX)
[ -z "$SYSTEM_ROOT" ] && SYSTEM_ROOT=""
[ -z "$BOOT_ROOT" ] && BOOT_ROOT="/flash"
[ -z "$BOOT_PART" ] && BOOT_PART=$(df "$BOOT_ROOT" | tail -1 | awk {' print $1 '})
# identify the boot device
if [ -z "$BOOT_DISK" ]; then
case $BOOT_PART in
/dev/mmcblk*)
BOOT_DISK=$(echo $BOOT_PART | sed -e "s,p[0-9]*,,g")
;;
esac
fi
# mount $BOOT_ROOT rw
mount -o remount,rw $BOOT_ROOT
echo "Updating device trees..."
cp -f $SYSTEM_ROOT/usr/share/bootloader/device_trees/* $BOOT_ROOT/device_trees
DT_ID=$(cat /proc/device-tree/rocknix-dt-id)
# TODO remove - workaround for RG34XXSP incorrect DT bug
[[ ${DT_ID} = "sun50i-h700-anbernic-rg35xx-plus" ]] &&
[[ $(cat /sys/class/graphics/fb0/virtual_size) = "720,480" ]] &&
DT_ID="sun50i-h700-anbernic-rg34xx-sp"
UPDATE_DTB_SOURCE="$BOOT_ROOT/device_trees/$DT_ID.dtb"
if [ -f "$UPDATE_DTB_SOURCE" ]; then
echo "Updating dtb.img from $(basename $UPDATE_DTB_SOURCE)..."
cp -f "$UPDATE_DTB_SOURCE" "$BOOT_ROOT/dtb.img"
fi
# update bootloader
if [ -f $SYSTEM_ROOT/usr/share/bootloader/u-boot-sunxi-with-spl.bin ]; then
echo "Updating u-boot on: $BOOT_DISK..."
dd if=$SYSTEM_ROOT/usr/share/bootloader/u-boot-sunxi-with-spl.bin of=$BOOT_DISK bs=1K seek=8 conv=fsync,notrunc &>/dev/null
fi
# mount $BOOT_ROOT ro
sync
mount -o remount,ro $BOOT_ROOT
echo "UPDATE" > /storage/.boot.hint
@@ -0,0 +1,16 @@
# RTW_88
rtw88/rtw8821c_fw.bin
# RTL_8821CS
rtl_bt/rtl8821cs_config.bin
rtl_bt/rtl8821cs_fw.bin
# Panels
panels/anbernic,rg28xx-panel.panel
panels/anbernic,rgcubexx-panel.panel
panels/anbernic,rg40xx-panel.panel
panels/anbernic,rg35xx-plus-rev6-panel.panel
panels/anbernic,rg35xx-plus-panel.panel
panels/anbernic,rg35xx-sp-v2-panel.panel
panels/anbernic,rg34xx-panel.panel
panels/anbernic,rg34xx-sp-panel.panel
File diff suppressed because it is too large Load Diff
+78
View File
@@ -0,0 +1,78 @@
################################################################################
# setup device defaults
################################################################################
# The TARGET_CPU variable controls which processor should be targeted for
# generated code.
case ${TARGET_ARCH} in
aarch64)
TARGET_KERNEL_ARCH="arm64"
TARGET_KERNEL_PATCH_ARCH="aarch64"
TARGET_CPU="cortex-a53"
TARGET_ARCH_FLAGS="+crc+fp+simd"
TARGET_FEATURES="64bit"
;;
arm)
TARGET_KERNEL_ARCH="arm64"
TARGET_KERNEL_PATCH_ARCH="aarch64"
TARGET_FLOAT="hard"
TARGET_CPU="cortex-a53"
TARGET_ARCH_FLAGS="+crc"
TARGET_FPU="crypto-neon-fp-armv8"
TARGET_FEATURES="32bit"
;;
esac
DEVICE_NAME="H700"
PARTITION_TABLE="msdos"
HW_CPU="Allwinner H700"
# Kernel target
KERNEL_TARGET="Image"
# Kernel extra targets to build
KERNEL_MAKE_EXTRACMD=" $(xmlstarlet sel -t -m "//dtb/${DEVICE}//file" -o "allwinner/" -v "." -o ".dtb " "${PROJECT_DIR}/${PROJECT}/bootloader/dtb.xml")"
# Kernel cmdline
EXTRA_CMDLINE="quiet console=ttyS0,115200 console=tty0 systemd.debug_shell=ttyS0"
# Bootloader to use (syslinux / u-boot)
BOOTLOADER="u-boot"
# U-Boot firmware package(s) to use
UBOOT_FIRMWARE+=" atf"
ATF_PLATFORM="sun50i_h616"
ATF_BL31_BINARY="bl31.bin"
# Mali GPU family
MALI_FAMILY="g31"
GRAPHIC_DRIVERS="panfrost"
# For maximum cross compatbility
PREFER_GLES="yes"
# Displayserver to use (wl / no)
DISPLAYSERVER="wl"
# Windowmanager to use (weston / swaywm-env / no)
WINDOWMANAGER="swaywm-env"
# Additional drivers to install:
# for a list of additional drivers see packages/linux-drivers
# Space separated list is supported,
# e.g. ADDITIONAL_DRIVERS="DRIVER1 DRIVER2"
ADDITIONAL_DRIVERS=""
# Additional Firmware to use ( )
# Space separated list is supported,
# e.g. FIRMWARE=""
FIRMWARE=""
# Additional packages to install
ADDITIONAL_PACKAGES=""
# Debug tty path
DEBUG_TTY="/dev/ttyS0"
# ROCKNIX Subdevices
SUBDEVICES=$(xmlstarlet sel -t -m "//dtb/${DEVICE}/*[@bootmethod]" -v "name()" -n "${PROJECT_DIR}/${PROJECT}/bootloader/dtb.xml")
@@ -0,0 +1,42 @@
# SPDX-License-Identifier: GPL-2.0
# Copyright (C) 2024-present ROCKNIX (https://github.com/ROCKNIX)
PKG_NAME="u-boot"
PKG_VERSION="v2025.07-rc3"
PKG_LICENSE="GPL"
PKG_SITE="https://www.denx.de/wiki/U-Boot"
PKG_URL="https://github.com/u-boot/u-boot/archive/${PKG_VERSION}.tar.gz"
PKG_DEPENDS_TARGET="toolchain Python3 swig:host pyelftools:host"
PKG_LONGDESC="Das U-Boot is a cross-platform bootloader for embedded systems."
PKG_TOOLCHAIN="manual"
PKG_NEED_UNPACK="${PROJECT_DIR}/${PROJECT}/bootloader ${PROJECT_DIR}/${PROJECT}/devices/${DEVICE}/bootloader"
PKG_NEED_UNPACK+=" ${PROJECT_DIR}/${PROJECT}/options ${PROJECT_DIR}/${PROJECT}/devices/${DEVICE}/options"
if [ -n "${UBOOT_FIRMWARE}" ]; then
PKG_DEPENDS_TARGET+=" ${UBOOT_FIRMWARE}"
PKG_DEPENDS_UNPACK+=" ${UBOOT_FIRMWARE}"
fi
configure_package() {
PKG_UBOOT_CONFIG="anbernic_rg35xx_h700_defconfig"
PKG_BL31="$(get_build_dir atf)/build/sun50i_h616/release/bl31.bin"
}
make_target() {
[ "${BUILD_WITH_DEBUG}" = "yes" ] && PKG_DEBUG=1 || PKG_DEBUG=0
setup_pkg_config_host
DEBUG=${PKG_DEBUG} CROSS_COMPILE="${TARGET_KERNEL_PREFIX}" LDFLAGS="" ARCH=arm make mrproper
DEBUG=${PKG_DEBUG} CROSS_COMPILE="${TARGET_KERNEL_PREFIX}" LDFLAGS="" ARCH=arm make ${PKG_UBOOT_CONFIG}
DEBUG=${PKG_DEBUG} CROSS_COMPILE="${TARGET_KERNEL_PREFIX}" LDFLAGS="" ARCH=arm _python_sysroot="${TOOLCHAIN}" _python_prefix=/ _python_exec_prefix=/ make BL31="${PKG_BL31}" HOSTCC="${HOST_CC}" HOSTCFLAGS="-I${TOOLCHAIN}/include" HOSTLDFLAGS="${HOST_LDFLAGS}" CONFIG_MKIMAGE_DTC_PATH="scripts/dtc/dtc"
}
makeinstall_target() {
mkdir -p $INSTALL/usr/share/bootloader
# Always install the update script
find_file_path bootloader/update.sh && cp -av ${FOUND_PATH} ${INSTALL}/usr/share/bootloader
cp -av u-boot-sunxi-with-spl.bin $INSTALL/usr/share/bootloader
}
@@ -0,0 +1,14 @@
574987574987--- u-boot.orig/configs/anbernic_rg35xx_h700_defconfig 2024-10-29 17:03:21.768276666 +0100
+++ u-boot/configs/anbernic_rg35xx_h700_defconfig 2024-10-29 17:17:21.719469834 +0100
@@ -25,3 +25,10 @@ CONFIG_REGULATOR_AXP=y
CONFIG_AXP717_POWER=y
CONFIG_AXP_DCDC2_VOLT=940
CONFIG_AXP_DCDC3_VOLT=1100
+CONFIG_EFI_LOADER=n
+CONFIG_BOOTDELAY=0
+CONFIG_LED_STATUS=y
+CONFIG_LED_STATUS_GPIO=y
+CONFIG_LED_STATUS0=y
+CONFIG_LED_STATUS_BIT=267
+CONFIG_LED_STATUS_STATE=2
\ No newline at end of file
@@ -0,0 +1,49 @@
From git@z Thu Jan 1 00:00:00 1970
Subject: [PATCH v3 4/5] arm64: dts: allwinner: h700: Add hp-det-gpios for
Anbernic RG35XX
From: Chris Morgan <macromorgan@hotmail.com>
Date: Sat, 15 Feb 2025 11:02:26 +1300
Message-Id: <20250214220247.10810-5-ryan@testtoast.com>
MIME-Version: 1.0
Content-Type: text/plain; charset="utf-8"
Content-Transfer-Encoding: 7bit
Add support for headphone insertion detection via GPIO for the
RG35XX series, and add the corresponding routing to the codec node.
Signed-off-by: Chris Morgan <macromorgan@hotmail.com>
Signed-off-by: Ryan Walklin <ryan@testtoast.com>
Tested-by: Philippe Simons <simons.philippe@gmail.com>
--
Changelog v1..v2:
- Remove vendor prefix from GPIO description.
- Whitespace fix
Changelog v2..v3:
- Add Tested-by tag
---
.../boot/dts/allwinner/sun50i-h700-anbernic-rg35xx-2024.dts | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h700-anbernic-rg35xx-2024.dts b/arch/arm64/boot/dts/allwinner/sun50i-h700-anbernic-rg35xx-2024.dts
index a231abf1684ad..b482fdf1fdba8 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-h700-anbernic-rg35xx-2024.dts
+++ b/arch/arm64/boot/dts/allwinner/sun50i-h700-anbernic-rg35xx-2024.dts
@@ -178,8 +178,11 @@ reg_vcc5v: regulator-vcc5v { /* USB-C power input */
};
&codec {
- allwinner,audio-routing = "Line Out", "LINEOUT";
+ /* Both speakers and headphone jack connected to 74HC4052D analog mux*/
+ allwinner,audio-routing = "Speaker", "LINEOUT",
+ "Headphone", "LINEOUT";
allwinner,pa-gpios = <&pio 8 5 GPIO_ACTIVE_HIGH>; // PI5
+ hp-det-gpios = <&pio 8 3 GPIO_ACTIVE_HIGH>; // PI3
status = "okay";
};
--
2.48.1
@@ -0,0 +1,260 @@
From git@z Thu Jan 1 00:00:00 1970
Subject: [PATCH v2 1/3] drm/panfrost: Add PM runtime flag
From: Philippe Simons <simons.philippe@gmail.com>
Date: Thu, 03 Apr 2025 07:52:08 +0200
Message-Id: <20250403055210.54486-2-simons.philippe@gmail.com>
MIME-Version: 1.0
Content-Type: text/plain; charset="utf-8"
Content-Transfer-Encoding: 7bit
When the GPU is the only device attached to a single power domain,
core genpd disable and enable it when gpu enter and leave runtime suspend.
Some power-domain requires a sequence before disabled,
and the reverse when enabled.
Add GPU_PM_RT flag, and implement in
panfrost_device_runtime_suspend/resume.
Reviewed-by: Steven Price <steven.price@arm.com>
Signed-off-by: Philippe Simons <simons.philippe@gmail.com>
---
drivers/gpu/drm/panfrost/panfrost_device.c | 33 ++++++++++++++++++++++
drivers/gpu/drm/panfrost/panfrost_device.h | 3 ++
2 files changed, 36 insertions(+)
diff --git a/drivers/gpu/drm/panfrost/panfrost_device.c b/drivers/gpu/drm/panfrost/panfrost_device.c
index a45e4addcc19..93d48e97ce10 100644
--- a/drivers/gpu/drm/panfrost/panfrost_device.c
+++ b/drivers/gpu/drm/panfrost/panfrost_device.c
@@ -406,11 +406,36 @@ void panfrost_device_reset(struct panfrost_device *pfdev)
static int panfrost_device_runtime_resume(struct device *dev)
{
struct panfrost_device *pfdev = dev_get_drvdata(dev);
+ int ret;
+
+ if (pfdev->comp->pm_features & BIT(GPU_PM_RT)) {
+ ret = reset_control_deassert(pfdev->rstc);
+ if (ret)
+ return ret;
+
+ ret = clk_enable(pfdev->clock);
+ if (ret)
+ goto err_clk;
+
+ if (pfdev->bus_clock) {
+ ret = clk_enable(pfdev->bus_clock);
+ if (ret)
+ goto err_bus_clk;
+ }
+ }
panfrost_device_reset(pfdev);
panfrost_devfreq_resume(pfdev);
return 0;
+
+err_bus_clk:
+ if (pfdev->comp->pm_features & BIT(GPU_PM_RT))
+ clk_disable(pfdev->clock);
+err_clk:
+ if (pfdev->comp->pm_features & BIT(GPU_PM_RT))
+ reset_control_assert(pfdev->rstc);
+ return ret;
}
static int panfrost_device_runtime_suspend(struct device *dev)
@@ -426,6 +451,14 @@ static int panfrost_device_runtime_suspend(struct device *dev)
panfrost_gpu_suspend_irq(pfdev);
panfrost_gpu_power_off(pfdev);
+ if (pfdev->comp->pm_features & BIT(GPU_PM_RT)) {
+ if (pfdev->bus_clock)
+ clk_disable(pfdev->bus_clock);
+
+ clk_disable(pfdev->clock);
+ reset_control_assert(pfdev->rstc);
+ }
+
return 0;
}
diff --git a/drivers/gpu/drm/panfrost/panfrost_device.h b/drivers/gpu/drm/panfrost/panfrost_device.h
index cffcb0ac7c11..861555ceea65 100644
--- a/drivers/gpu/drm/panfrost/panfrost_device.h
+++ b/drivers/gpu/drm/panfrost/panfrost_device.h
@@ -36,10 +36,13 @@ enum panfrost_drv_comp_bits {
* enum panfrost_gpu_pm - Supported kernel power management features
* @GPU_PM_CLK_DIS: Allow disabling clocks during system suspend
* @GPU_PM_VREG_OFF: Allow turning off regulators during system suspend
+ * @GPU_PM_RT: Allow disabling clocks and asserting the reset control during
+ * system runtime suspend
*/
enum panfrost_gpu_pm {
GPU_PM_CLK_DIS,
GPU_PM_VREG_OFF,
+ GPU_PM_RT
};
struct panfrost_features {
--
2.49.0
From git@z Thu Jan 1 00:00:00 1970
Subject: [PATCH v2 2/3] drm/panfrost: add h616 compatible string
From: Philippe Simons <simons.philippe@gmail.com>
Date: Thu, 03 Apr 2025 07:52:09 +0200
Message-Id: <20250403055210.54486-3-simons.philippe@gmail.com>
MIME-Version: 1.0
Content-Type: text/plain; charset="utf-8"
Content-Transfer-Encoding: 7bit
Tie the Allwinner compatible string to the GPU_PM_RT feature bits that will
toggle the clocks and the reset line whenever the power domain is changing
state.
Signed-off-by: Philippe Simons <simons.philippe@gmail.com>
---
drivers/gpu/drm/panfrost/panfrost_drv.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/drivers/gpu/drm/panfrost/panfrost_drv.c b/drivers/gpu/drm/panfrost/panfrost_drv.c
index 0f3935556ac7..9470c04c5487 100644
--- a/drivers/gpu/drm/panfrost/panfrost_drv.c
+++ b/drivers/gpu/drm/panfrost/panfrost_drv.c
@@ -776,6 +776,13 @@ static const struct panfrost_compatible default_data = {
.pm_domain_names = NULL,
};
+static const struct panfrost_compatible allwinner_h616_data = {
+ .num_supplies = ARRAY_SIZE(default_supplies) - 1,
+ .supply_names = default_supplies,
+ .num_pm_domains = 1,
+ .pm_features = BIT(GPU_PM_RT),
+};
+
static const struct panfrost_compatible amlogic_data = {
.num_supplies = ARRAY_SIZE(default_supplies) - 1,
.supply_names = default_supplies,
@@ -859,6 +866,7 @@ static const struct of_device_id dt_match[] = {
{ .compatible = "mediatek,mt8186-mali", .data = &mediatek_mt8186_data },
{ .compatible = "mediatek,mt8188-mali", .data = &mediatek_mt8188_data },
{ .compatible = "mediatek,mt8192-mali", .data = &mediatek_mt8192_data },
+ { .compatible = "allwinner,sun50i-h616-mali", .data = &allwinner_h616_data },
{}
};
MODULE_DEVICE_TABLE(of, dt_match);
--
2.49.0
From git@z Thu Jan 1 00:00:00 1970
Subject: [PATCH v2 3/3] drm/panfrost: reorder pd/clk/rst sequence
From: Philippe Simons <simons.philippe@gmail.com>
Date: Thu, 03 Apr 2025 07:52:10 +0200
Message-Id: <20250403055210.54486-4-simons.philippe@gmail.com>
MIME-Version: 1.0
Content-Type: text/plain; charset="utf-8"
Content-Transfer-Encoding: 7bit
According to Mali manuals, the powerup sequence should be
enable pd, asserting the reset then enabling the clock and
the reverse for powerdown.
Tested-by: John Williams <porschemad911@gmail.com>
Signed-off-by: Philippe Simons <simons.philippe@gmail.com>
---
drivers/gpu/drm/panfrost/panfrost_device.c | 38 +++++++++++-----------
1 file changed, 19 insertions(+), 19 deletions(-)
diff --git a/drivers/gpu/drm/panfrost/panfrost_device.c b/drivers/gpu/drm/panfrost/panfrost_device.c
index 93d48e97ce10..5d35076b2e6d 100644
--- a/drivers/gpu/drm/panfrost/panfrost_device.c
+++ b/drivers/gpu/drm/panfrost/panfrost_device.c
@@ -209,10 +209,20 @@ int panfrost_device_init(struct panfrost_device *pfdev)
spin_lock_init(&pfdev->cycle_counter.lock);
+ err = panfrost_pm_domain_init(pfdev);
+ if (err)
+ return err;
+
+ err = panfrost_reset_init(pfdev);
+ if (err) {
+ dev_err(pfdev->dev, "reset init failed %d\n", err);
+ goto out_pm_domain;
+ }
+
err = panfrost_clk_init(pfdev);
if (err) {
dev_err(pfdev->dev, "clk init failed %d\n", err);
- return err;
+ goto out_reset;
}
err = panfrost_devfreq_init(pfdev);
@@ -229,25 +239,15 @@ int panfrost_device_init(struct panfrost_device *pfdev)
goto out_devfreq;
}
- err = panfrost_reset_init(pfdev);
- if (err) {
- dev_err(pfdev->dev, "reset init failed %d\n", err);
- goto out_regulator;
- }
-
- err = panfrost_pm_domain_init(pfdev);
- if (err)
- goto out_reset;
-
pfdev->iomem = devm_platform_ioremap_resource(pfdev->pdev, 0);
if (IS_ERR(pfdev->iomem)) {
err = PTR_ERR(pfdev->iomem);
- goto out_pm_domain;
+ goto out_regulator;
}
err = panfrost_gpu_init(pfdev);
if (err)
- goto out_pm_domain;
+ goto out_regulator;
err = panfrost_mmu_init(pfdev);
if (err)
@@ -268,16 +268,16 @@ int panfrost_device_init(struct panfrost_device *pfdev)
panfrost_mmu_fini(pfdev);
out_gpu:
panfrost_gpu_fini(pfdev);
-out_pm_domain:
- panfrost_pm_domain_fini(pfdev);
-out_reset:
- panfrost_reset_fini(pfdev);
out_regulator:
panfrost_regulator_fini(pfdev);
out_devfreq:
panfrost_devfreq_fini(pfdev);
out_clk:
panfrost_clk_fini(pfdev);
+out_reset:
+ panfrost_reset_fini(pfdev);
+out_pm_domain:
+ panfrost_pm_domain_fini(pfdev);
return err;
}
@@ -287,11 +287,11 @@ 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_devfreq_fini(pfdev);
panfrost_regulator_fini(pfdev);
panfrost_clk_fini(pfdev);
+ panfrost_reset_fini(pfdev);
+ panfrost_pm_domain_fini(pfdev);
}
#define PANFROST_EXCEPTION(id) \
--
2.49.0
@@ -0,0 +1,71 @@
From c2907f97fc1e40f41093f96e252b826d2e0e702b Mon Sep 17 00:00:00 2001
From: Philippe Simons <simons.philippe@gmail.com>
Date: Tue, 22 Apr 2025 12:39:49 +0200
Subject: [PATCH] rg35xx add gpu opp table
---
.../sun50i-h700-anbernic-rg35xx-2024.dts | 34 +++++++++++++++++--
1 file changed, 32 insertions(+), 2 deletions(-)
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h700-anbernic-rg35xx-2024.dts b/arch/arm64/boot/dts/allwinner/sun50i-h700-anbernic-rg35xx-2024.dts
index f76391d8027d..1433345567ae 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-h700-anbernic-rg35xx-2024.dts
+++ b/arch/arm64/boot/dts/allwinner/sun50i-h700-anbernic-rg35xx-2024.dts
@@ -224,6 +224,35 @@ panel_in_rgb: endpoint {
};
};
};
+
+ gpu_opp_table: opp-table-1 {
+ compatible = "operating-points-v2";
+
+ opp-420000000 {
+ opp-hz = /bits/ 64 <420000000>;
+ opp-microvolt = <900000>;
+ };
+ opp-456000000 {
+ opp-hz = /bits/ 64 <456000000>;
+ opp-microvolt = <900000>;
+ };
+ opp-504000000 {
+ opp-hz = /bits/ 64 <504000000>;
+ opp-microvolt = <900000>;
+ };
+ opp-552000000 {
+ opp-hz = /bits/ 64 <552000000>;
+ opp-microvolt = <900000>;
+ };
+ opp-600000000 {
+ opp-hz = /bits/ 64 <600000000>;
+ opp-microvolt = <900000>;
+ };
+ opp-648000000 {
+ opp-hz = /bits/ 64 <648000000>;
+ opp-microvolt = <960000>;
+ };
+ };
};
&codec {
@@ -249,6 +278,7 @@ &ehci0 {
&gpu {
mali-supply = <&reg_dcdc2>;
+ operating-points-v2 = <&gpu_opp_table>;
status = "okay";
};
@@ -311,8 +341,8 @@ reg_dcdc1: dcdc1 {
reg_dcdc2: dcdc2 {
regulator-always-on;
- regulator-min-microvolt = <940000>;
- regulator-max-microvolt = <940000>;
+ regulator-min-microvolt = <900000>;
+ regulator-max-microvolt = <960000>;
regulator-name = "vdd-gpu-sys";
};
--
2.49.0
@@ -0,0 +1,495 @@
From 83753f7dd56bbb36af578f0152d66cbe46272109 Mon Sep 17 00:00:00 2001
From: Philippe Simons <simons.philippe@gmail.com>
Date: Thu, 23 Jan 2025 23:39:15 +0100
Subject: [PATCH 7/9] sun20i: add pwm driver
---
arch/arm64/configs/defconfig | 1 +
drivers/pwm/Kconfig | 10 +
drivers/pwm/Makefile | 1 +
drivers/pwm/pwm-sun20i.c | 428 +++++++++++++++++++++++++++++++++++
4 files changed, 440 insertions(+)
create mode 100644 drivers/pwm/pwm-sun20i.c
diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig
index c62831e61..7d631556b 100644
--- a/arch/arm64/configs/defconfig
+++ b/arch/arm64/configs/defconfig
@@ -1517,6 +1517,7 @@ CONFIG_PWM_RZ_MTU3=m
CONFIG_PWM_SAMSUNG=y
CONFIG_PWM_SL28CPLD=m
CONFIG_PWM_SUN4I=m
+CONFIG_PWM_SUN20I=m
CONFIG_PWM_TEGRA=m
CONFIG_PWM_TIECAP=m
CONFIG_PWM_TIEHRPWM=m
diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
index 0915c1e7d..a4a7eb286 100644
--- a/drivers/pwm/Kconfig
+++ b/drivers/pwm/Kconfig
@@ -652,6 +652,16 @@ config PWM_SUN4I
To compile this driver as a module, choose M here: the module
will be called pwm-sun4i.
+config PWM_SUN20I
+ tristate "Allwinner D1/H616 PWM support"
+ depends on ARCH_SUNXI || COMPILE_TEST
+ depends on HAS_IOMEM && COMMON_CLK
+ help
+ Generic PWM framework driver for Newer Allwinner SoCs.
+
+ To compile this driver as a module, choose M here: the module
+ will be called pwm-sun20i.
+
config PWM_SUNPLUS
tristate "Sunplus PWM support"
depends on ARCH_SUNPLUS || COMPILE_TEST
diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
index 9081e0c0e..85ad1fe0d 100644
--- a/drivers/pwm/Makefile
+++ b/drivers/pwm/Makefile
@@ -60,6 +60,7 @@ obj-$(CONFIG_PWM_STM32) += pwm-stm32.o
obj-$(CONFIG_PWM_STM32_LP) += pwm-stm32-lp.o
obj-$(CONFIG_PWM_STMPE) += pwm-stmpe.o
obj-$(CONFIG_PWM_SUN4I) += pwm-sun4i.o
+obj-$(CONFIG_PWM_SUN20I) += pwm-sun20i.o
obj-$(CONFIG_PWM_SUNPLUS) += pwm-sunplus.o
obj-$(CONFIG_PWM_TEGRA) += pwm-tegra.o
obj-$(CONFIG_PWM_TIECAP) += pwm-tiecap.o
diff --git a/drivers/pwm/pwm-sun20i.c b/drivers/pwm/pwm-sun20i.c
new file mode 100644
index 000000000..7262a99ab
--- /dev/null
+++ b/drivers/pwm/pwm-sun20i.c
@@ -0,0 +1,428 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Driver for Allwinner's new PWM Controller (such as D1 / H616 / T5 series)
+ *
+ * Copyright (C) 2024 Hironori KIKUCHI <kikuchan98@gmail.com>
+ *
+ */
+
+#include <linux/bitops.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/gcd.h>
+#include <linux/io.h>
+#include <linux/jiffies.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pwm.h>
+#include <linux/reset.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/time.h>
+
+// SoC specific offsets
+#define SUN20I_REG_OFFSET_PER_SUN20I (0x0080)
+#define SUN20I_REG_OFFSET_PCR_SUN20I (0x0100 + 0x0000)
+#define SUN20I_REG_OFFSET_PPR_SUN20I (0x0100 + 0x0004)
+#define SUN20I_REG_OFFSET_PER_SUN50I (0x0040)
+#define SUN20I_REG_OFFSET_PCR_SUN50I (0x0060 + 0x0000)
+#define SUN20I_REG_OFFSET_PPR_SUN50I (0x0060 + 0x0004)
+
+// Register offsets
+#define SUN20I_REG_OFFSET_PCCR(chip, ch) (0x0020 + 0x04 * ((ch) >> 1))
+#define SUN20I_REG_OFFSET_PCGR(chip, ch) (0x0040)
+#define SUN20I_REG_OFFSET_PER(chip, ch) ((chip)->data->reg_per)
+#define SUN20I_REG_OFFSET_PCR(chip, ch) ((chip)->data->reg_pcr + 0x20 * (ch))
+#define SUN20I_REG_OFFSET_PPR(chip, ch) ((chip)->data->reg_ppr + 0x20 * (ch))
+
+// PCCR: PWMxx Clock Configuration Register
+#define SUN20I_REG_PCCR_CLK_SRC_MASK GENMASK(8, 7)
+#define SUN20I_REG_PCCR_CLK_DIV_M_MASK GENMASK(3, 0)
+#define SUN20I_REG_PCCR_CLK_BYPASS(ch) BIT(5 + ((ch) & 1))
+#define SUN20I_REG_PCCR_CLK_GATING(ch) BIT(4)
+
+// PCGR: PWM Clock Gating Register
+#define SUN20I_REG_PCGR_CLK_BYPASS(ch) BIT(16 + (ch))
+#define SUN20I_REG_PCGR_CLK_GATING(ch) BIT(ch)
+
+// PER: PWM Enable Regsiter
+#define SUN20I_REG_PER_ENABLE(ch) BIT(ch)
+
+// PCR: PWM Control Register
+#define SUN20I_REG_PCR_ACT_STA BIT(8)
+#define SUN20I_REG_PCR_PRESCAL_K_MASK GENMASK(7, 0)
+
+// PPR: PWM Period Register
+#define SUN20I_REG_PPR_ENTIRE_CYCLE_MASK GENMASK(31, 16)
+#define SUN20I_REG_PPR_ACT_CYCLE_MASK GENMASK(15, 0)
+
+// Constants
+#define SUN20I_PWM_CHANNELS_MAX (16)
+#define SUN20I_PWM_CLOCK_SRC_HOSC (0)
+#define SUN20I_PWM_CLOCK_SRC_APB (1)
+#define SUN20I_PWM_DIV_M_SHIFT_MAX (8)
+#define SUN20I_PWM_PRESCALE_K_MAX (256)
+#define SUN20I_PWM_ENT_CYCLE_MAX (0xffffULL)
+
+// Configuration
+#define SUN20I_PWM_DIV_M_SHIFT_DEFAULT (0)
+#define SUN20I_PWM_CLOCK_SRC_DEFAULT SUN20I_PWM_CLOCK_SRC_HOSC
+
+struct sun20i_pwm_data {
+ unsigned long reg_per;
+ unsigned long reg_pcr;
+ unsigned long reg_ppr;
+ bool has_pcgr;
+};
+
+struct sun20i_pwm_chip {
+ struct clk *clk_bus;
+ struct clk *clk_hosc;
+ struct clk *clk_apb;
+ struct reset_control *rst;
+ void __iomem *base;
+ spinlock_t ctrl_lock;
+ const struct sun20i_pwm_data *data;
+
+ unsigned int clk_src[(SUN20I_PWM_CHANNELS_MAX + 1) / 2];
+ unsigned int div_m_shift[(SUN20I_PWM_CHANNELS_MAX + 1) / 2];
+};
+
+static inline struct sun20i_pwm_chip *to_sun20i_pwm_chip(struct pwm_chip *chip)
+{
+ return pwmchip_get_drvdata(chip);
+}
+
+static inline u32 sun20i_pwm_readl(struct sun20i_pwm_chip *sun20i_chip, unsigned long offset)
+{
+ return readl(sun20i_chip->base + offset);
+}
+
+static inline void sun20i_pwm_writel(struct sun20i_pwm_chip *sun20i_chip, u32 val, unsigned long offset)
+{
+ writel(val, sun20i_chip->base + offset);
+}
+
+static inline bool sun20i_pwm_is_channel_enabled(struct sun20i_pwm_chip *sun20i_chip, int hwpwm)
+{
+ u32 val;
+ val = sun20i_pwm_readl(sun20i_chip, SUN20I_REG_OFFSET_PER(sun20i_chip, hwpwm));
+ return val & SUN20I_REG_PER_ENABLE(hwpwm) ? true : false;
+}
+
+static inline void sun20i_pwm_enable_channel(struct sun20i_pwm_chip *sun20i_chip, struct pwm_device *pwm, bool enable)
+{
+ u32 val;
+
+ // PWM Clock Configuration Register
+ u32 pccr = sun20i_pwm_readl(sun20i_chip, SUN20I_REG_OFFSET_PCCR(sun20i_chip, pwm->hwpwm));
+ if (enable) {
+ unsigned int idx = pwm->hwpwm / 2;
+ // Set clock source
+ pccr &= ~SUN20I_REG_PCCR_CLK_SRC_MASK;
+ pccr |= FIELD_PREP(SUN20I_REG_PCCR_CLK_SRC_MASK, sun20i_chip->clk_src[idx]);
+
+ // Set DIV_M shift
+ pccr &= ~SUN20I_REG_PCCR_CLK_DIV_M_MASK;
+ pccr |= FIELD_PREP(SUN20I_REG_PCCR_CLK_DIV_M_MASK, sun20i_chip->div_m_shift[idx]);
+ }
+
+ if (sun20i_chip->data->has_pcgr) {
+ // PWM Clock Gating Register
+ val = sun20i_pwm_readl(sun20i_chip, SUN20I_REG_OFFSET_PCGR(sun20i_chip, pwm->hwpwm));
+ if (enable) {
+ val &= ~SUN20I_REG_PCGR_CLK_BYPASS(pwm->hwpwm);
+ val |= SUN20I_REG_PCGR_CLK_GATING(pwm->hwpwm);
+ } else {
+ val &= ~SUN20I_REG_PCGR_CLK_GATING(pwm->hwpwm);
+ }
+ sun20i_pwm_writel(sun20i_chip, val, SUN20I_REG_OFFSET_PCGR(sun20i_chip, pwm->hwpwm));
+ } else {
+ // CLK_BYPASS and CLK_GATING are in PCCR otherwise
+ if (enable) {
+ pccr &= ~SUN20I_REG_PCCR_CLK_BYPASS(pwm->hwpwm);
+ pccr |= SUN20I_REG_PCCR_CLK_GATING(pwm->hwpwm);
+ } else if (!sun20i_pwm_is_channel_enabled(sun20i_chip, pwm->hwpwm ^ 1)) {
+ // drop the flag if and only if the counterpart is disabled
+ pccr &= ~SUN20I_REG_PCCR_CLK_GATING(pwm->hwpwm);
+ }
+ }
+
+ sun20i_pwm_writel(sun20i_chip, pccr, SUN20I_REG_OFFSET_PCCR(sun20i_chip, pwm->hwpwm));
+
+ // PWM Enabling
+ val = sun20i_pwm_readl(sun20i_chip, SUN20I_REG_OFFSET_PER(sun20i_chip, pwm->hwpwm));
+ if (enable)
+ val |= SUN20I_REG_PER_ENABLE(pwm->hwpwm);
+ else
+ val &= ~SUN20I_REG_PER_ENABLE(pwm->hwpwm);
+
+ sun20i_pwm_writel(sun20i_chip, val, SUN20I_REG_OFFSET_PER(sun20i_chip, pwm->hwpwm));
+}
+
+static inline u64 sun20i_pwm_get_clock_rate(struct sun20i_pwm_chip *sun20i_chip, unsigned int clksrc)
+{
+ switch (clksrc) {
+ case SUN20I_PWM_CLOCK_SRC_HOSC:
+ return clk_get_rate(sun20i_chip->clk_hosc);
+
+ case SUN20I_PWM_CLOCK_SRC_APB:
+ return clk_get_rate(sun20i_chip->clk_apb);
+
+ default:
+ return 0;
+ }
+}
+
+static int sun20i_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, struct pwm_state *state)
+{
+ struct sun20i_pwm_chip *sun20i_chip = to_sun20i_pwm_chip(chip);
+ u64 clk_rate;
+
+ u32 pccr = sun20i_pwm_readl(sun20i_chip, SUN20I_REG_OFFSET_PCCR(sun20i_chip, pwm->hwpwm));
+ u32 pcr = sun20i_pwm_readl(sun20i_chip, SUN20I_REG_OFFSET_PCR(sun20i_chip, pwm->hwpwm));
+ u32 ppr = sun20i_pwm_readl(sun20i_chip, SUN20I_REG_OFFSET_PPR(sun20i_chip, pwm->hwpwm));
+
+ clk_rate = sun20i_pwm_get_clock_rate(sun20i_chip, FIELD_GET(SUN20I_REG_PCCR_CLK_SRC_MASK, pccr));
+ if (!clk_rate) {
+ dev_err(pwmchip_parent(chip), "Invalid CLK_SRC is detected\n");
+ return -EINVAL;
+ }
+
+ unsigned int prescale_k = FIELD_GET(SUN20I_REG_PCR_PRESCAL_K_MASK, pcr) + 1;
+ u32 ent_cycle = FIELD_GET(SUN20I_REG_PPR_ENTIRE_CYCLE_MASK, ppr) + 1;
+ u32 act_cycle = min(ent_cycle, FIELD_GET(SUN20I_REG_PPR_ACT_CYCLE_MASK, ppr));
+
+ unsigned int div_m_shift = FIELD_GET(SUN20I_REG_PCCR_CLK_DIV_M_MASK, pccr);
+ if (div_m_shift > SUN20I_PWM_DIV_M_SHIFT_MAX) {
+ dev_err(pwmchip_parent(chip), "Invalid DIV_M is detected\n");
+ return -EINVAL;
+ }
+ unsigned int div_m = 1 << div_m_shift;
+
+ // set to the state
+ state->enabled = sun20i_pwm_is_channel_enabled(sun20i_chip, pwm->hwpwm);
+ state->polarity = (pcr & SUN20I_REG_PCR_ACT_STA) ? PWM_POLARITY_NORMAL : PWM_POLARITY_INVERSED;
+ state->period = DIV_ROUND_CLOSEST_ULL(ent_cycle * prescale_k * div_m * NSEC_PER_SEC, clk_rate);
+ state->duty_cycle = DIV_ROUND_CLOSEST_ULL(act_cycle * prescale_k * div_m * NSEC_PER_SEC, clk_rate);
+
+ return 0;
+}
+
+static inline unsigned long sun20i_pwm_find_prescale_k(unsigned long long ent_cycle, unsigned long long act_cycle)
+{
+ if (ent_cycle == 0 || ent_cycle > SUN20I_PWM_ENT_CYCLE_MAX * SUN20I_PWM_PRESCALE_K_MAX || ent_cycle < act_cycle)
+ return 0;
+
+ return clamp(DIV_ROUND_UP_ULL(ent_cycle, SUN20I_PWM_ENT_CYCLE_MAX), 1, SUN20I_PWM_PRESCALE_K_MAX);
+}
+
+static int sun20i_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, const struct pwm_state *state)
+{
+ struct sun20i_pwm_chip *sun20i_chip = to_sun20i_pwm_chip(chip);
+ u64 clk_rate;
+ u32 ctrl;
+
+ spin_lock(&sun20i_chip->ctrl_lock);
+
+ // Period and Duty cycle
+ if (state->duty_cycle != pwm->state.duty_cycle || state->period != pwm->state.period) {
+ unsigned int idx = pwm->hwpwm / 2;
+ clk_rate = sun20i_pwm_get_clock_rate(sun20i_chip, sun20i_chip->clk_src[idx]);
+ unsigned long div_m = 1U << sun20i_chip->div_m_shift[idx];
+ unsigned long long ent_cycle = DIV_ROUND_CLOSEST(state->period * clk_rate, NSEC_PER_SEC * div_m);
+ unsigned long long act_cycle = min(DIV_ROUND_CLOSEST(state->duty_cycle * clk_rate, NSEC_PER_SEC * div_m), ent_cycle);
+
+ unsigned long prescale_k = sun20i_pwm_find_prescale_k(ent_cycle, act_cycle);
+ if (!prescale_k)
+ goto err;
+
+ ent_cycle = clamp(DIV_ROUND_CLOSEST_ULL(ent_cycle, prescale_k), 1, SUN20I_PWM_ENT_CYCLE_MAX);
+ act_cycle = clamp(DIV_ROUND_CLOSEST_ULL(act_cycle, prescale_k), 0, ent_cycle);
+
+ // Set prescale_k
+ ctrl = sun20i_pwm_readl(sun20i_chip, SUN20I_REG_OFFSET_PCR(sun20i_chip, pwm->hwpwm));
+ ctrl &= ~SUN20I_REG_PCR_PRESCAL_K_MASK;
+ ctrl |= FIELD_PREP(SUN20I_REG_PCR_PRESCAL_K_MASK, prescale_k - 1);
+ sun20i_pwm_writel(sun20i_chip, ctrl, SUN20I_REG_OFFSET_PCR(sun20i_chip, pwm->hwpwm));
+
+ // Set period and duty cycle
+ ctrl = (((ent_cycle - 1) & 0xFFFF) << 16) | (act_cycle & 0xFFFF);
+ sun20i_pwm_writel(sun20i_chip, ctrl, SUN20I_REG_OFFSET_PPR(sun20i_chip, pwm->hwpwm));
+ }
+
+ // Polarity
+ if (state->polarity != pwm->state.polarity) {
+ ctrl = sun20i_pwm_readl(sun20i_chip, SUN20I_REG_OFFSET_PCR(sun20i_chip, pwm->hwpwm));
+ if (state->polarity == PWM_POLARITY_NORMAL) {
+ ctrl |= SUN20I_REG_PCR_ACT_STA;
+ } else {
+ ctrl &= ~SUN20I_REG_PCR_ACT_STA;
+ }
+ sun20i_pwm_writel(sun20i_chip, ctrl, SUN20I_REG_OFFSET_PCR(sun20i_chip, pwm->hwpwm));
+ }
+
+ // Enable
+ if (state->enabled != pwm->state.enabled)
+ sun20i_pwm_enable_channel(sun20i_chip, pwm, state->enabled);
+
+ spin_unlock(&sun20i_chip->ctrl_lock);
+ return 0;
+
+err:
+ spin_unlock(&sun20i_chip->ctrl_lock);
+ return -EINVAL;
+}
+
+static const struct pwm_ops sun20i_pwm_ops = {
+ .apply = sun20i_pwm_apply,
+ .get_state = sun20i_pwm_get_state,
+};
+
+static const struct sun20i_pwm_data sun20i_d1_pwm_data = {
+ .reg_per = SUN20I_REG_OFFSET_PER_SUN20I,
+ .reg_pcr = SUN20I_REG_OFFSET_PCR_SUN20I,
+ .reg_ppr = SUN20I_REG_OFFSET_PPR_SUN20I,
+ .has_pcgr = true,
+};
+
+static const struct sun20i_pwm_data sun50i_h616_pwm_data = {
+ .reg_per = SUN20I_REG_OFFSET_PER_SUN50I,
+ .reg_pcr = SUN20I_REG_OFFSET_PCR_SUN50I,
+ .reg_ppr = SUN20I_REG_OFFSET_PPR_SUN50I,
+ .has_pcgr = false,
+};
+
+static const struct of_device_id sun20i_pwm_dt_ids[] = {
+ {
+ .compatible = "allwinner,sun20i-d1-pwm",
+ .data = &sun20i_d1_pwm_data,
+ },
+ {
+ .compatible = "allwinner,sun50i-h616-pwm",
+ .data = &sun50i_h616_pwm_data,
+ },
+ {
+ /* sentinel */
+ },
+};
+MODULE_DEVICE_TABLE(of, sun20i_pwm_dt_ids);
+
+static int sun20i_pwm_probe(struct platform_device *pdev)
+{
+ struct pwm_chip *chip;
+ const struct sun20i_pwm_data *data;
+ struct sun20i_pwm_chip *sun20i_chip;
+ u32 npwm;
+ int ret;
+
+ struct device_node *node = pdev->dev.of_node;
+
+ data = of_device_get_match_data(&pdev->dev);
+ if (!data)
+ return -ENODEV;
+
+ ret = of_property_read_u32(node, "allwinner,pwm-channels", &npwm);
+ if (ret)
+ return dev_err_probe(&pdev->dev, -EINVAL, "No PWM channels are configured\n");
+
+ if (npwm > SUN20I_PWM_CHANNELS_MAX)
+ return dev_err_probe(&pdev->dev, -EINVAL, "Too many PWM channels are configured\n");
+
+ chip = devm_pwmchip_alloc(&pdev->dev, npwm, sizeof(*sun20i_chip));
+ if (IS_ERR(chip))
+ return PTR_ERR(chip);
+ sun20i_chip = to_sun20i_pwm_chip(chip);
+
+ sun20i_chip->data = data;
+
+ for (int i = 0; i < (npwm + 1) / 2; i++) {
+ sun20i_chip->clk_src[i] = SUN20I_PWM_CLOCK_SRC_DEFAULT;
+ sun20i_chip->div_m_shift[i] = SUN20I_PWM_DIV_M_SHIFT_DEFAULT;
+
+ const char *source;
+ ret = of_property_read_string_index(node, "allwinner,pwm-paired-channel-clock-sources", i, &source);
+ if (!ret) {
+ if (!strcasecmp(source, "hosc"))
+ sun20i_chip->clk_src[i] = SUN20I_PWM_CLOCK_SRC_HOSC;
+ else if (!strcasecmp(source, "apb"))
+ sun20i_chip->clk_src[i] = SUN20I_PWM_CLOCK_SRC_APB;
+ else
+ return dev_err_probe(&pdev->dev, -EINVAL, "Unknown clock source: %s\n", source);
+ }
+
+ u32 value;
+ ret = of_property_read_u32_index(node, "allwinner,pwm-paired-channel-clock-prescales", i, &value);
+ if (!ret) {
+ if (value <= SUN20I_PWM_DIV_M_SHIFT_MAX)
+ sun20i_chip->div_m_shift[i] = value;
+ else
+ return dev_err_probe(&pdev->dev, -EINVAL, "Invalid prescale value: %u\n", value);
+ }
+ }
+
+ sun20i_chip->base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(sun20i_chip->base))
+ return PTR_ERR(sun20i_chip->base);
+
+ sun20i_chip->clk_bus = devm_clk_get_enabled(&pdev->dev, "bus");
+ if (IS_ERR(sun20i_chip->clk_bus))
+ return dev_err_probe(&pdev->dev, PTR_ERR(sun20i_chip->clk_bus), "Failed to get `bus` clock\n");
+
+ sun20i_chip->clk_hosc = devm_clk_get_enabled(&pdev->dev, "hosc");
+ if (IS_ERR(sun20i_chip->clk_hosc))
+ return dev_err_probe(&pdev->dev, PTR_ERR(sun20i_chip->clk_hosc), "Failed to get `hosc` clock\n");
+
+ sun20i_chip->clk_apb = devm_clk_get_enabled(&pdev->dev, "apb");
+ if (IS_ERR(sun20i_chip->clk_apb))
+ return dev_err_probe(&pdev->dev, PTR_ERR(sun20i_chip->clk_apb), "Failed to get `apb` clock\n");
+
+ sun20i_chip->rst = devm_reset_control_get_exclusive(&pdev->dev, NULL);
+ if (IS_ERR(sun20i_chip->rst))
+ return dev_err_probe(&pdev->dev, PTR_ERR(sun20i_chip->rst), "Failed to get bus reset\n");
+
+ ret = reset_control_deassert(sun20i_chip->rst);
+ if (ret)
+ return dev_err_probe(&pdev->dev, ret, "Failed to deassert reset control\n");
+
+ chip->ops = &sun20i_pwm_ops;
+
+ spin_lock_init(&sun20i_chip->ctrl_lock);
+
+ ret = pwmchip_add(chip);
+ if (ret < 0) {
+ reset_control_assert(sun20i_chip->rst);
+ return dev_err_probe(&pdev->dev, ret, "Failed to add PWM chip\n");
+ }
+
+ platform_set_drvdata(pdev, chip);
+
+ return 0;
+}
+
+static void sun20i_pwm_remove(struct platform_device *pdev)
+{
+ struct pwm_chip *chip = platform_get_drvdata(pdev);
+ struct sun20i_pwm_chip *sun20i_chip = to_sun20i_pwm_chip(chip);
+
+ pwmchip_remove(chip);
+
+ reset_control_assert(sun20i_chip->rst);
+}
+
+static struct platform_driver sun20i_pwm_driver = {
+ .driver = {
+ .name = "sun20i-pwm",
+ .of_match_table = sun20i_pwm_dt_ids,
+ },
+ .probe = sun20i_pwm_probe,
+ .remove = sun20i_pwm_remove,
+};
+module_platform_driver(sun20i_pwm_driver);
+
+MODULE_ALIAS("platform:sun20i-pwm");
+MODULE_AUTHOR("Hironori KIKUCHI <kikuchan98@gmail.com>");
+MODULE_DESCRIPTION("Allwinner sun20i PWM driver");
+MODULE_LICENSE("GPL v2");
--
2.47.1
@@ -0,0 +1,37 @@
From 193e59a21f1a828e1860cd6fdfcb3fbf041a3f19 Mon Sep 17 00:00:00 2001
From: Philippe Simons <simons.philippe@gmail.com>
Date: Thu, 23 Jan 2025 23:39:47 +0100
Subject: [PATCH 8/9] h616: add pwm node
---
arch/arm64/boot/dts/allwinner/sun50i-h616.dtsi | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h616.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-h616.dtsi
index c335e81a5..7417a214a 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-h616.dtsi
+++ b/arch/arm64/boot/dts/allwinner/sun50i-h616.dtsi
@@ -257,6 +257,20 @@ ccu: clock@3001000 {
#reset-cells = <1>;
};
+ pwm: pwm@300a000 {
+ compatible = "allwinner,sun50i-h616-pwm";
+ reg = <0x0300a000 0x400>;
+ clocks = <&ccu CLK_BUS_PWM>,
+ <&osc24M>,
+ <&ccu CLK_APB1>;
+ clock-names = "bus", "hosc", "apb";
+ resets = <&ccu RST_BUS_PWM>;
+ #pwm-cells = <0x3>;
+ status = "disabled";
+
+ allwinner,pwm-channels = <6>;
+ };
+
dma: dma-controller@3002000 {
compatible = "allwinner,sun50i-h616-dma",
"allwinner,sun50i-a100-dma";
--
2.47.1
@@ -0,0 +1,52 @@
From e82b0cfa996e55f6e5f70815ac04cda0b58bf9c4 Mon Sep 17 00:00:00 2001
From: Philippe Simons <simons.philippe@gmail.com>
Date: Thu, 23 Jan 2025 23:41:16 +0100
Subject: [PATCH 9/9] rg35xx: enable pwm backlight
---
.../sun50i-h700-anbernic-rg35xx-2024.dts | 18 +++++++++++++++---
1 file changed, 15 insertions(+), 3 deletions(-)
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h700-anbernic-rg35xx-2024.dts b/arch/arm64/boot/dts/allwinner/sun50i-h700-anbernic-rg35xx-2024.dts
index 5d2b13aa7..3397cad0c 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-h700-anbernic-rg35xx-2024.dts
+++ b/arch/arm64/boot/dts/allwinner/sun50i-h700-anbernic-rg35xx-2024.dts
@@ -22,9 +22,10 @@ aliases {
};
backlight: backlight {
- compatible = "gpio-backlight";
- gpios = <&pio 3 28 GPIO_ACTIVE_HIGH>; // PD28
- default-on;
+ compatible = "pwm-backlight";
+ pwms = <&pwm 0 50000 0>;
+ pinctrl-0 = <&lcd_backlight_pin>;
+ pinctrl-names = "default";
};
battery: battery {
@@ -304,6 +305,11 @@ &pio {
vcc-pg-supply = <&reg_aldo4>;
vcc-ph-supply = <&reg_cldo3>;
vcc-pi-supply = <&reg_cldo3>;
+
+ lcd_backlight_pin: pwm0-pin {
+ pins = "PD28";
+ function = "pwm0";
+ };
};
&r_i2c {
@@ -458,3 +464,9 @@ &usbotg {
&usbphy {
status = "okay";
};
+
+&pwm {
+ allwinner,pwm-paired-channel-clock-sources = "hosc", "hosc", "hosc";
+ allwinner,pwm-paired-channel-clock-prescales = <0>, <0>, <0>;
+ status = "okay";
+};
--
2.47.1
@@ -0,0 +1,41 @@
From 8e7f804d1f1aedf946b229b3f59501ddee840149 Mon Sep 17 00:00:00 2001
From: Philippe Simons <simons.philippe@gmail.com>
Date: Sat, 19 Apr 2025 18:36:09 +0200
Subject: [PATCH] Revert "usb: musb: Fix hardware lockup on first Rx endpoint
request"
This reverts commit 3fc137386c4620305bbc2a216868c53f9245670a.
---
drivers/usb/musb/musb_gadget.c | 13 +++----------
1 file changed, 3 insertions(+), 10 deletions(-)
diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c
index 6869c58367f2..661c6a16f4f7 100644
--- a/drivers/usb/musb/musb_gadget.c
+++ b/drivers/usb/musb/musb_gadget.c
@@ -1162,19 +1162,12 @@ void musb_free_request(struct usb_ep *ep, struct usb_request *req)
*/
void musb_ep_restart(struct musb *musb, struct musb_request *req)
{
- u16 csr;
- void __iomem *epio = req->ep->hw_ep->regs;
-
trace_musb_req_start(req);
musb_ep_select(musb->mregs, req->epnum);
- if (req->tx) {
+ if (req->tx)
txstate(musb, req);
- } else {
- csr = musb_readw(epio, MUSB_RXCSR);
- csr |= MUSB_RXCSR_FLUSHFIFO | MUSB_RXCSR_P_WZC_BITS;
- musb_writew(epio, MUSB_RXCSR, csr);
- musb_writew(epio, MUSB_RXCSR, csr);
- }
+ else
+ rxstate(musb, req);
}
static int musb_ep_restart_resume_work(struct musb *musb, void *data)
--
2.49.0

Some files were not shown because too many files have changed in this diff Show More