From 618bd22dd44a69fdf7fbcf92e7bd6ecacca16959 Mon Sep 17 00:00:00 2001 From: Diogo Ivo Date: Thu, 12 Oct 2023 11:00:19 +0100 Subject: [PATCH] linux-iot2050: Update to v6.1.54-cip6[-rt3] Signed-off-by: Diogo Ivo --- conf/distro/iot2050-debian.conf | 4 +- .../linux/files/iot2050_defconfig_base | 67 +- ...-ti-iot2050-Add-layout-of-OSPI-flash.patch | 75 + ...ti-Add-binding-for-Siemens-IOT2050-M.patch | 31 + ...-iot2050-Add-support-for-M.2-variant.patch | 169 ++ ...remoteproc-Add-PRU-consumer-bindings.patch | 93 + ...ru-Add-enum-for-PRU-Core-Identifiers.patch | 97 + ...dd-APIs-to-get-and-put-the-PRU-cores.patch | 253 +++ ...ake-sysfs-entries-read-only-for-PRU-.patch | 47 + ...ru-Add-pru_rproc_set_ctable-function.patch | 200 ++ ...onfigure-firmware-based-on-client-se.patch | 94 + ...emoteproc-pru-Add-Interrupt-property.patch | 78 + ...1-soc-ti-pruss-Add-pruss_get-put-API.patch | 157 ++ ...-pruss_-request-release-_mem_region-.patch | 187 ++ ...-pruss_cfg_read-update-pruss_cfg_get.patch | 252 +++ ...-helper-functions-to-set-GPI-mode-MI.patch | 215 ++ ...dd-support-for-configuring-GPMUX-bas.patch | 81 + ...eth-Add-Firmware-Interface-for-ICSSG.patch | 260 +++ ...rueth-Add-mii-helper-apis-and-macros.patch | 510 +++++ ...eth-Add-Firmware-config-and-classifi.patch | 1085 +++++++++ ...eth-Add-icssg-queues-APIs-and-macros.patch | 90 + ...0-dt-bindings-net-Add-ICSSG-Ethernet.patch | 211 ++ ...ssg-prueth-Add-ICSSG-ethernet-driver.patch | 1958 +++++++++++++++++ ...-net-ti-icssg-prueth-Add-ICSSG-Stats.patch | 332 +++ ...eth-Add-Standard-network-staticstics.patch | 98 + ...eth-Add-ethtool-ops-for-ICSSG-Ethern.patch | 259 +++ ...-prueth-Add-Power-management-support.patch | 93 + .../0026-dt-bindings-net-Add-ICSS-IEP.patch | 72 + ...ndings-net-Add-IEP-property-in-ICSSG.patch | 49 + .../0028-net-ti-icss-iep-Add-IEP-driver.patch | 1046 +++++++++ ...eth-add-packet-timestamping-and-ptp-.patch | 797 +++++++ ...eth-am65x-SR2.0-add-10M-full-duplex-.patch | 194 ++ ...Add-documentation-for-Half-duplex-su.patch | 46 + ...eth-Add-support-for-half-duplex-oper.patch | 131 ++ ...udma-Add-system-suspend-resume-suppo.patch | 119 + ...k3-udma-Fix-BCDMA-for-case-w-o-BCHAN.patch | 32 + ...c-remove-non-fatal-probe-deferral-lo.patch | 35 + ...udma-remove-non-fatal-probe-deferral.patch | 32 + ...Use-dev_err_probe-for-mmc_of_parse-r.patch | 33 + ...54-Add-support-for-PM-suspend-resume.patch | 233 ++ ...hdog-ti-rti-wdt-Add-support-for-WDIO.patch | 77 + ..._wdt-Add-support-for-WDIOF_CARDRESET.patch | 106 + ...-ti-Add-reserved-memory-for-watchdog.patch | 46 + ...-ti-k3-am65-main-Add-ICSSG-IEP-nodes.patch | 81 + ...uss-intc-Fix-enabling-of-intc-events.patch | 131 ++ ...s-intc-Fix-listed-IRQ-type-in-proc-i.patch | 57 + ...s-intc-Fix-processing-of-IEP-interru.patch | 103 + ...am65-main-Add-PRU-system-events-for-.patch | 159 ++ ...udma-glue-do-not-create-glue-dma-dev.patch | 126 ++ ...-supplicant-based-device-enumeration.patch | 131 ++ ...-efivarfs-expose-used-and-total-size.patch | 183 ++ ...s-drop-kobject-from-efivars_register.patch | 150 ++ ...efivar-generic-ops-register-function.patch | 59 + ...fi-Add-EFI_ACCESS_DENIED-status-code.patch | 31 + ...fi-Add-tee-based-EFI-variable-driver.patch | 940 ++++++++ ...3-am65-main-fix-DSS-irq-trigger-type.patch | 39 + ...Disable-data-error-interrupts-while-.patch | 58 + ...ost-sdhci_am654-fix-start-loop-index.patch | 33 + ...-sdhci_am654-update-OTAP-and-ITAP-de.patch | 46 + ...vert-to-using-hierarchy-domain-for-l.patch | 322 +++ ...-PCI-legacy-interrupt-support-for-AM.patch | 148 ++ ...-workaround-for-Errata-i2037-AM65x-S.patch | 114 + ...am65-main-Add-properties-to-support-.patch | 65 + ...Update-ti_sci_msg_req_reboot-to-incl.patch | 57 + ...-iot2050-Add-node-for-generic-spidev.patch | 38 + ...2050-Add-icssg-prueth-nodes-for-PG1-.patch | 185 ++ ...2050-Definitions-for-runtime-pinmuxi.patch | 777 +++++++ ...2050-Refactor-the-m.2-and-minipcie-p.patch | 93 + ...icate-the-green-light-is-off-when-pa.patch | 30 + ...K-setting-the-RJ45-port-led-behavior.patch | 42 + ...xtend-led-panic-indicator-on-and-off.patch | 129 ++ recipes-kernel/linux/linux-iot2050-6.1.inc | 29 + .../linux/linux-iot2050-rt_6.1.54-cip6-rt3.bb | 12 + .../linux/linux-iot2050_6.1.54-cip6.bb | 10 + 74 files changed, 14371 insertions(+), 51 deletions(-) create mode 100644 recipes-kernel/linux/files/patches-6.1/0001-arm64-dts-ti-iot2050-Add-layout-of-OSPI-flash.patch create mode 100644 recipes-kernel/linux/files/patches-6.1/0002-dt-bindings-arm-ti-Add-binding-for-Siemens-IOT2050-M.patch create mode 100644 recipes-kernel/linux/files/patches-6.1/0003-arm64-dts-ti-iot2050-Add-support-for-M.2-variant.patch create mode 100644 recipes-kernel/linux/files/patches-6.1/0004-dt-bindings-remoteproc-Add-PRU-consumer-bindings.patch create mode 100644 recipes-kernel/linux/files/patches-6.1/0005-remoteproc-pru-Add-enum-for-PRU-Core-Identifiers.patch create mode 100644 recipes-kernel/linux/files/patches-6.1/0006-remoteproc-pru-Add-APIs-to-get-and-put-the-PRU-cores.patch create mode 100644 recipes-kernel/linux/files/patches-6.1/0007-remoteproc-pru-Make-sysfs-entries-read-only-for-PRU-.patch create mode 100644 recipes-kernel/linux/files/patches-6.1/0008-remoteproc-pru-Add-pru_rproc_set_ctable-function.patch create mode 100644 recipes-kernel/linux/files/patches-6.1/0009-remoteproc-pru-Configure-firmware-based-on-client-se.patch create mode 100644 recipes-kernel/linux/files/patches-6.1/0010-dt-bindings-remoteproc-pru-Add-Interrupt-property.patch create mode 100644 recipes-kernel/linux/files/patches-6.1/0011-soc-ti-pruss-Add-pruss_get-put-API.patch create mode 100644 recipes-kernel/linux/files/patches-6.1/0012-soc-ti-pruss-Add-pruss_-request-release-_mem_region-.patch create mode 100644 recipes-kernel/linux/files/patches-6.1/0013-soc-ti-pruss-Add-pruss_cfg_read-update-pruss_cfg_get.patch create mode 100644 recipes-kernel/linux/files/patches-6.1/0014-soc-ti-pruss-Add-helper-functions-to-set-GPI-mode-MI.patch create mode 100644 recipes-kernel/linux/files/patches-6.1/0015-remoteproc-pru-add-support-for-configuring-GPMUX-bas.patch create mode 100644 recipes-kernel/linux/files/patches-6.1/0016-net-ti-icssg-prueth-Add-Firmware-Interface-for-ICSSG.patch create mode 100644 recipes-kernel/linux/files/patches-6.1/0017-net-ti-icssg-prueth-Add-mii-helper-apis-and-macros.patch create mode 100644 recipes-kernel/linux/files/patches-6.1/0018-net-ti-icssg-prueth-Add-Firmware-config-and-classifi.patch create mode 100644 recipes-kernel/linux/files/patches-6.1/0019-net-ti-icssg-prueth-Add-icssg-queues-APIs-and-macros.patch create mode 100644 recipes-kernel/linux/files/patches-6.1/0020-dt-bindings-net-Add-ICSSG-Ethernet.patch create mode 100644 recipes-kernel/linux/files/patches-6.1/0021-net-ti-icssg-prueth-Add-ICSSG-ethernet-driver.patch create mode 100644 recipes-kernel/linux/files/patches-6.1/0022-net-ti-icssg-prueth-Add-ICSSG-Stats.patch create mode 100644 recipes-kernel/linux/files/patches-6.1/0023-net-ti-icssg-prueth-Add-Standard-network-staticstics.patch create mode 100644 recipes-kernel/linux/files/patches-6.1/0024-net-ti-icssg-prueth-Add-ethtool-ops-for-ICSSG-Ethern.patch create mode 100644 recipes-kernel/linux/files/patches-6.1/0025-net-ti-icssg-prueth-Add-Power-management-support.patch create mode 100644 recipes-kernel/linux/files/patches-6.1/0026-dt-bindings-net-Add-ICSS-IEP.patch create mode 100644 recipes-kernel/linux/files/patches-6.1/0027-dt-bindings-net-Add-IEP-property-in-ICSSG.patch create mode 100644 recipes-kernel/linux/files/patches-6.1/0028-net-ti-icss-iep-Add-IEP-driver.patch create mode 100644 recipes-kernel/linux/files/patches-6.1/0029-net-ti-icssg-prueth-add-packet-timestamping-and-ptp-.patch create mode 100644 recipes-kernel/linux/files/patches-6.1/0030-net-ti-icssg-prueth-am65x-SR2.0-add-10M-full-duplex-.patch create mode 100644 recipes-kernel/linux/files/patches-6.1/0031-dt-bindings-net-Add-documentation-for-Half-duplex-su.patch create mode 100644 recipes-kernel/linux/files/patches-6.1/0032-net-ti-icssg-prueth-Add-support-for-half-duplex-oper.patch create mode 100644 recipes-kernel/linux/files/patches-6.1/0033-dmaengine-ti-k3-udma-Add-system-suspend-resume-suppo.patch create mode 100644 recipes-kernel/linux/files/patches-6.1/0034-dmaengine-ti-k3-udma-Fix-BCDMA-for-case-w-o-BCHAN.patch create mode 100644 recipes-kernel/linux/files/patches-6.1/0035-soc-ti-k3-ringacc-remove-non-fatal-probe-deferral-lo.patch create mode 100644 recipes-kernel/linux/files/patches-6.1/0036-dmaengine-ti-k3-udma-remove-non-fatal-probe-deferral.patch create mode 100644 recipes-kernel/linux/files/patches-6.1/0037-mmc-sdhci_am654-Use-dev_err_probe-for-mmc_of_parse-r.patch create mode 100644 recipes-kernel/linux/files/patches-6.1/0038-mmc-sdhci_am654-Add-support-for-PM-suspend-resume.patch create mode 100644 recipes-kernel/linux/files/patches-6.1/0039-dt-bindings-watchdog-ti-rti-wdt-Add-support-for-WDIO.patch create mode 100644 recipes-kernel/linux/files/patches-6.1/0040-watchdog-rit_wdt-Add-support-for-WDIOF_CARDRESET.patch create mode 100644 recipes-kernel/linux/files/patches-6.1/0041-arm64-dts-ti-Add-reserved-memory-for-watchdog.patch create mode 100644 recipes-kernel/linux/files/patches-6.1/0042-arm64-dts-ti-k3-am65-main-Add-ICSSG-IEP-nodes.patch create mode 100644 recipes-kernel/linux/files/patches-6.1/0043-irqchip-irq-pruss-intc-Fix-enabling-of-intc-events.patch create mode 100644 recipes-kernel/linux/files/patches-6.1/0044-irqchip-irq-pruss-intc-Fix-listed-IRQ-type-in-proc-i.patch create mode 100644 recipes-kernel/linux/files/patches-6.1/0045-irqchip-irq-pruss-intc-Fix-processing-of-IEP-interru.patch create mode 100644 recipes-kernel/linux/files/patches-6.1/0046-arm64-dts-ti-k3-am65-main-Add-PRU-system-events-for-.patch create mode 100644 recipes-kernel/linux/files/patches-6.1/0047-dmaengine-ti-k3-udma-glue-do-not-create-glue-dma-dev.patch create mode 100644 recipes-kernel/linux/files/patches-6.1/0048-tee-optee-Fix-supplicant-based-device-enumeration.patch create mode 100644 recipes-kernel/linux/files/patches-6.1/0049-efivarfs-expose-used-and-total-size.patch create mode 100644 recipes-kernel/linux/files/patches-6.1/0050-efi-efivars-drop-kobject-from-efivars_register.patch create mode 100644 recipes-kernel/linux/files/patches-6.1/0051-efi-expose-efivar-generic-ops-register-function.patch create mode 100644 recipes-kernel/linux/files/patches-6.1/0052-efi-Add-EFI_ACCESS_DENIED-status-code.patch create mode 100644 recipes-kernel/linux/files/patches-6.1/0053-efi-Add-tee-based-EFI-variable-driver.patch create mode 100644 recipes-kernel/linux/files/patches-6.1/0054-arm64-dts-ti-k3-am65-main-fix-DSS-irq-trigger-type.patch create mode 100644 recipes-kernel/linux/files/patches-6.1/0055-mmc-sdhci_am654-Disable-data-error-interrupts-while-.patch create mode 100644 recipes-kernel/linux/files/patches-6.1/0056-drivers-mmc-host-sdhci_am654-fix-start-loop-index.patch create mode 100644 recipes-kernel/linux/files/patches-6.1/0057-drivers-mmc-host-sdhci_am654-update-OTAP-and-ITAP-de.patch create mode 100644 recipes-kernel/linux/files/patches-6.1/0058-PCI-keystone-Convert-to-using-hierarchy-domain-for-l.patch create mode 100644 recipes-kernel/linux/files/patches-6.1/0059-PCI-keystone-Add-PCI-legacy-interrupt-support-for-AM.patch create mode 100644 recipes-kernel/linux/files/patches-6.1/0060-PCI-keystone-Add-workaround-for-Errata-i2037-AM65x-S.patch create mode 100644 recipes-kernel/linux/files/patches-6.1/0061-arm64-dts-ti-k3-am65-main-Add-properties-to-support-.patch create mode 100644 recipes-kernel/linux/files/patches-6.1/0062-firmware-ti_sci-Update-ti_sci_msg_req_reboot-to-incl.patch create mode 100644 recipes-kernel/linux/files/patches-6.1/0063-WIP-arm64-dts-ti-iot2050-Add-node-for-generic-spidev.patch create mode 100644 recipes-kernel/linux/files/patches-6.1/0064-arm64-dts-ti-iot2050-Add-icssg-prueth-nodes-for-PG1-.patch create mode 100644 recipes-kernel/linux/files/patches-6.1/0065-arm64-dts-ti-iot2050-Definitions-for-runtime-pinmuxi.patch create mode 100644 recipes-kernel/linux/files/patches-6.1/0066-arm64-dts-ti-iot2050-Refactor-the-m.2-and-minipcie-p.patch create mode 100644 recipes-kernel/linux/files/patches-6.1/0067-arm64-dts-ti-Indicate-the-green-light-is-off-when-pa.patch create mode 100644 recipes-kernel/linux/files/patches-6.1/0068-HACK-setting-the-RJ45-port-led-behavior.patch create mode 100644 recipes-kernel/linux/files/patches-6.1/0069-WIP-feat-extend-led-panic-indicator-on-and-off.patch create mode 100644 recipes-kernel/linux/linux-iot2050-6.1.inc create mode 100644 recipes-kernel/linux/linux-iot2050-rt_6.1.54-cip6-rt3.bb create mode 100644 recipes-kernel/linux/linux-iot2050_6.1.54-cip6.bb diff --git a/conf/distro/iot2050-debian.conf b/conf/distro/iot2050-debian.conf index 78eb5ec32..584fe88ae 100644 --- a/conf/distro/iot2050-debian.conf +++ b/conf/distro/iot2050-debian.conf @@ -16,8 +16,8 @@ DISTRO_NAME = "IOT2050 Debian System" HOSTNAME ??= "iot2050-debian" -PREFERRED_VERSION_linux-iot2050 ?= "5.10.%" -PREFERRED_VERSION_linux-iot2050-rt ?= "5.10.%" +PREFERRED_VERSION_linux-iot2050 ?= "6.1.%" +PREFERRED_VERSION_linux-iot2050-rt ?= "6.1.%" KERNEL_NAME ?= "cip" diff --git a/recipes-kernel/linux/files/iot2050_defconfig_base b/recipes-kernel/linux/files/iot2050_defconfig_base index bedcb34b9..0437e5a3c 100644 --- a/recipes-kernel/linux/files/iot2050_defconfig_base +++ b/recipes-kernel/linux/files/iot2050_defconfig_base @@ -2,6 +2,7 @@ CONFIG_SYSVIPC=y CONFIG_POSIX_MQUEUE=y CONFIG_NO_HZ_IDLE=y CONFIG_HIGH_RES_TIMERS=y +CONFIG_BPF_JIT=y CONFIG_PREEMPT=y CONFIG_IRQ_TIME_ACCOUNTING=y CONFIG_BSD_PROCESS_ACCT=y @@ -30,8 +31,6 @@ CONFIG_BLK_DEV_INITRD=y CONFIG_KALLSYMS_ALL=y CONFIG_EMBEDDED=y CONFIG_PERF_EVENTS=y -# CONFIG_SLUB_DEBUG is not set -# CONFIG_COMPAT_BRK is not set CONFIG_ARCH_K3=y # CONFIG_CAVIUM_ERRATUM_22375 is not set # CONFIG_CAVIUM_ERRATUM_23154 is not set @@ -64,6 +63,7 @@ CONFIG_MODULE_FORCE_UNLOAD=y CONFIG_MODVERSIONS=y CONFIG_MODULE_SRCVERSION_ALL=y # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +# CONFIG_COMPAT_BRK is not set CONFIG_KSM=y CONFIG_MEMORY_FAILURE=y CONFIG_TRANSPARENT_HUGEPAGE=y @@ -175,7 +175,6 @@ CONFIG_NET_SCH_CODEL=m CONFIG_NET_SCH_FQ_CODEL=m CONFIG_NET_SCH_INGRESS=m CONFIG_NET_CLS_BASIC=m -CONFIG_NET_CLS_TCINDEX=m CONFIG_NET_CLS_ROUTE4=m CONFIG_NET_CLS_FW=m CONFIG_NET_CLS_U32=m @@ -202,11 +201,7 @@ CONFIG_NET_ACT_SIMP=m CONFIG_NET_ACT_SKBEDIT=m CONFIG_NET_ACT_CSUM=m CONFIG_NET_SWITCHDEV=y -CONFIG_BPF_JIT=y CONFIG_CAN=m -CONFIG_CAN_C_CAN=m -CONFIG_CAN_C_CAN_PLATFORM=m -CONFIG_CAN_M_CAN=m CONFIG_BT=m CONFIG_BT_HIDP=m # CONFIG_BT_LE is not set @@ -224,6 +219,7 @@ CONFIG_NET_9P=y CONFIG_NET_9P_VIRTIO=y CONFIG_PCI=y CONFIG_PCI_IOV=y +# CONFIG_VGA_ARB is not set CONFIG_HOTPLUG_PCI=y CONFIG_PCI_HOST_GENERIC=y CONFIG_PCI_HOST_THUNDER_PEM=y @@ -235,7 +231,6 @@ CONFIG_PCI_ENDPOINT_CONFIGFS=y CONFIG_PCI_EPF_TEST=y CONFIG_DEVTMPFS=y CONFIG_DEVTMPFS_MOUNT=y -CONFIG_SIMPLE_PM_BUS=y CONFIG_MTD=y CONFIG_MTD_TESTS=m CONFIG_MTD_CMDLINE_PARTS=y @@ -259,11 +254,6 @@ CONFIG_SCSI=y CONFIG_BLK_DEV_SD=y CONFIG_SCSI_SAS_ATA=y CONFIG_SCSI_HISI_SAS=m -CONFIG_SCSI_UFSHCD=y -CONFIG_SCSI_UFSHCD_PLATFORM=y -CONFIG_SCSI_UFS_CDNS_PLATFORM=y -CONFIG_SCSI_UFS_TI_J721E=y -CONFIG_SCSI_UFS_BSG=y CONFIG_ATA=m CONFIG_SATA_AHCI=m CONFIG_SATA_AHCI_PLATFORM=m @@ -271,7 +261,6 @@ CONFIG_AHCI_CEVA=m CONFIG_AHCI_XGENE=m CONFIG_AHCI_QORIQ=m CONFIG_SATA_SIL24=m -CONFIG_PATA_PLATFORM=m CONFIG_PATA_OF_PLATFORM=m CONFIG_NETDEVICES=y CONFIG_DUMMY=m @@ -291,7 +280,6 @@ CONFIG_VIRTIO_NET=y # CONFIG_NET_VENDOR_ARC is not set # CONFIG_NET_VENDOR_ATHEROS is not set CONFIG_TIGON3=m -# CONFIG_NET_VENDOR_BROCADE is not set CONFIG_MACB=y # CONFIG_NET_VENDOR_CAVIUM is not set # CONFIG_NET_VENDOR_CHELSIO is not set @@ -315,6 +303,7 @@ CONFIG_SKY2=y # CONFIG_NET_VENDOR_NVIDIA is not set # CONFIG_NET_VENDOR_OKI is not set # CONFIG_NET_VENDOR_QLOGIC is not set +# CONFIG_NET_VENDOR_BROCADE is not set # CONFIG_NET_VENDOR_QUALCOMM is not set # CONFIG_NET_VENDOR_RDC is not set # CONFIG_NET_VENDOR_REALTEK is not set @@ -330,7 +319,8 @@ CONFIG_SMSC911X=y # CONFIG_NET_VENDOR_SUN is not set # CONFIG_NET_VENDOR_SYNOPSYS is not set # CONFIG_NET_VENDOR_TEHUTI is not set -CONFIG_TI_ICSSG_PRUETH=m +CONFIG_TI_DAVINCI_MDIO=y +CONFIG_TI_ICSSG_PRUETH=y # CONFIG_NET_VENDOR_VIA is not set # CONFIG_NET_VENDOR_WIZNET is not set CONFIG_MARVELL_PHY=y @@ -341,6 +331,9 @@ CONFIG_REALTEK_PHY=m CONFIG_ROCKCHIP_PHY=y CONFIG_DP83848_PHY=y CONFIG_DP83867_PHY=y +CONFIG_CAN_C_CAN=m +CONFIG_CAN_C_CAN_PLATFORM=m +CONFIG_CAN_M_CAN=m CONFIG_MDIO_BUS_MUX_MMIOREG=y CONFIG_USB_PEGASUS=m CONFIG_USB_RTL8150=m @@ -400,8 +393,8 @@ CONFIG_SPI_OMAP24XX=y CONFIG_SPI_PL022=y CONFIG_SPMI=y CONFIG_PINCTRL=y -CONFIG_PINCTRL_SINGLE=y CONFIG_PINCTRL_MAX77620=y +CONFIG_PINCTRL_SINGLE=y CONFIG_GPIOLIB=y CONFIG_GPIO_SYSFS=y CONFIG_GPIO_DAVINCI=y @@ -444,7 +437,6 @@ CONFIG_REGULATOR_GPIO=y CONFIG_REGULATOR_HI6421V530=y CONFIG_REGULATOR_MAX77620=y CONFIG_REGULATOR_PALMAS=y -CONFIG_REGULATOR_PWM=y CONFIG_REGULATOR_QCOM_SPMI=y CONFIG_REGULATOR_RK808=y CONFIG_REGULATOR_S2MPS11=y @@ -457,30 +449,18 @@ CONFIG_MEDIA_SUPPORT=y CONFIG_MEDIA_USB_SUPPORT=y CONFIG_USB_VIDEO_CLASS=m CONFIG_V4L_PLATFORM_DRIVERS=y -CONFIG_VIDEO_TI_CAL=m CONFIG_V4L_MEM2MEM_DRIVERS=y +CONFIG_VIDEO_TI_CAL=m CONFIG_VIDEO_OV2659=m CONFIG_VIDEO_OV5640=m -# CONFIG_VGA_ARB is not set CONFIG_DRM=y CONFIG_DRM_I2C_NXP_TDA998X=y -CONFIG_DRM_PANEL_SIMPLE=y -CONFIG_DRM_PANEL_OSD_OSD101T2587_53TS=y CONFIG_DRM_SII902X=y CONFIG_DRM_TOSHIBA_TC358767=y CONFIG_DRM_TOSHIBA_TC358768=y CONFIG_DRM_TI_TFP410=y CONFIG_DRM_TIDSS=y CONFIG_DRM_LEGACY=y -CONFIG_FB_SSD1307=y -CONFIG_BACKLIGHT_PWM=y -CONFIG_BACKLIGHT_LP855X=m -CONFIG_BACKLIGHT_GPIO=y -CONFIG_BACKLIGHT_LED=y -CONFIG_FRAMEBUFFER_CONSOLE=y -CONFIG_LOGO=y -# CONFIG_LOGO_LINUX_MONO is not set -# CONFIG_LOGO_LINUX_VGA16 is not set CONFIG_SOUND=y CONFIG_SND=y # CONFIG_SND_SPI is not set @@ -490,11 +470,9 @@ CONFIG_SND_SOC_DAVINCI_MCASP=y CONFIG_SND_SOC_AK4613=m CONFIG_SND_SOC_PCM3168A_I2C=m CONFIG_SND_SOC_TLV320AIC31XX=m -CONFIG_SND_SOC_TLV320AIC3X=m CONFIG_SND_SIMPLE_CARD=m CONFIG_SND_AUDIO_GRAPH_CARD=m CONFIG_HID_MULTITOUCH=m -CONFIG_I2C_HID=m CONFIG_USB_ULPI_BUS=y CONFIG_USB=m CONFIG_USB_ANNOUNCE_NEW_DEVICES=y @@ -506,9 +484,6 @@ CONFIG_USB_OHCI_HCD=m CONFIG_USB_OHCI_HCD_PLATFORM=m CONFIG_USB_ACM=m CONFIG_USB_STORAGE=m -CONFIG_USB_CDNS3=m -CONFIG_USB_CDNS3_GADGET=y -CONFIG_USB_CDNS3_HOST=y CONFIG_USB_MUSB_HDRC=m CONFIG_USB_DWC3=m CONFIG_USB_ISP1760=m @@ -573,10 +548,14 @@ CONFIG_MMC_SPI=y CONFIG_MMC_SDHCI_XENON=y CONFIG_MMC_SDHCI_OMAP=y CONFIG_MMC_SDHCI_AM654=y +CONFIG_SCSI_UFSHCD=y +CONFIG_SCSI_UFS_BSG=y +CONFIG_SCSI_UFSHCD_PLATFORM=y +CONFIG_SCSI_UFS_CDNS_PLATFORM=y +CONFIG_SCSI_UFS_TI_J721E=y CONFIG_NEW_LEDS=y CONFIG_LEDS_CLASS=y CONFIG_LEDS_GPIO=y -CONFIG_LEDS_PWM=y CONFIG_LEDS_TLC591XX=y CONFIG_LEDS_SYSCON=y CONFIG_LEDS_TRIGGER_DISK=y @@ -604,13 +583,9 @@ CONFIG_VIRTIO_PCI=y CONFIG_VIRTIO_BALLOON=y CONFIG_VIRTIO_MMIO=y CONFIG_STAGING=y -CONFIG_ION=y -CONFIG_ION_SYSTEM_HEAP=y CONFIG_COMMON_CLK_RK808=y CONFIG_COMMON_CLK_CS2000_CP=y CONFIG_COMMON_CLK_S2MPS11=y -CONFIG_CLK_QORIQ=y -CONFIG_COMMON_CLK_PWM=y CONFIG_TI_SCI_CLK=y CONFIG_HWSPINLOCK=y CONFIG_HWSPINLOCK_OMAP=y @@ -622,18 +597,13 @@ CONFIG_TI_K3_DSP_REMOTEPROC=m CONFIG_TI_K3_R5_REMOTEPROC=m CONFIG_RPMSG_QCOM_GLINK_RPM=y CONFIG_RPMSG_VIRTIO=m -CONFIG_ARCH_K3_AM6_SOC=y -CONFIG_ARCH_K3_J721E_SOC=y CONFIG_TI_SCI_PM_DOMAINS=y -CONFIG_TI_PRUSS=m +CONFIG_TI_PRUSS=y CONFIG_EXTCON_PALMAS=m CONFIG_EXTCON_USB_GPIO=m CONFIG_MEMORY=y CONFIG_IIO=y CONFIG_TI_AM335X_ADC=m -CONFIG_PWM_TIECAP=y -CONFIG_PWM_TIEHRPWM=y -CONFIG_TI_PRUSS_INTC=m CONFIG_RESET_CONTROLLER=y CONFIG_RESET_TI_SCI=y CONFIG_RESET_TI_SYSCON=y @@ -643,7 +613,6 @@ CONFIG_PHY_QCOM_USB_HS=y CONFIG_PHY_AM654_SERDES=y CONFIG_PHY_J721E_WIZ=y CONFIG_OMAP_USB2=m -CONFIG_ANDROID=y CONFIG_TEE=y CONFIG_OPTEE=y CONFIG_EXT2_FS=y @@ -684,10 +653,10 @@ CONFIG_CMA_SIZE_MBYTES=24 CONFIG_PRINTK_TIME=y CONFIG_MAGIC_SYSRQ=y CONFIG_DEBUG_FS=y +# CONFIG_SLUB_DEBUG is not set CONFIG_SCHEDSTATS=y # CONFIG_DEBUG_PREEMPT is not set # CONFIG_FTRACE is not set CONFIG_SAMPLES=y CONFIG_SAMPLE_RPMSG_CLIENT=m CONFIG_MEMTEST=y -CONFIG_TI_DAVINCI_MDIO=y diff --git a/recipes-kernel/linux/files/patches-6.1/0001-arm64-dts-ti-iot2050-Add-layout-of-OSPI-flash.patch b/recipes-kernel/linux/files/patches-6.1/0001-arm64-dts-ti-iot2050-Add-layout-of-OSPI-flash.patch new file mode 100644 index 000000000..f594c8f47 --- /dev/null +++ b/recipes-kernel/linux/files/patches-6.1/0001-arm64-dts-ti-iot2050-Add-layout-of-OSPI-flash.patch @@ -0,0 +1,75 @@ +From fda33bec60e688419a47c0584f426a3ab7bb8d54 Mon Sep 17 00:00:00 2001 +From: Jan Kiszka +Date: Thu, 19 Jan 2023 07:40:40 +0100 +Subject: [PATCH 01/69] arm64: dts: ti: iot2050: Add layout of OSPI flash + +Describe the layout of the OSPI flash as the latest firmware uses it. +Specifically the location of the U-Boot envs is important for userspace +in order to access it. + +Signed-off-by: Jan Kiszka +[Commit 12f0158f3e98 upstream] +--- + .../boot/dts/ti/k3-am65-iot2050-common.dtsi | 46 +++++++++++++++++++ + 1 file changed, 46 insertions(+) + +diff --git a/arch/arm64/boot/dts/ti/k3-am65-iot2050-common.dtsi b/arch/arm64/boot/dts/ti/k3-am65-iot2050-common.dtsi +index 32b797237581..180bfb2a9ddf 100644 +--- a/arch/arm64/boot/dts/ti/k3-am65-iot2050-common.dtsi ++++ b/arch/arm64/boot/dts/ti/k3-am65-iot2050-common.dtsi +@@ -603,6 +603,52 @@ flash@0 { + cdns,tchsh-ns = <60>; + cdns,tslch-ns = <60>; + cdns,read-delay = <2>; ++ ++ partitions { ++ compatible = "fixed-partitions"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ++ seboot@0 { ++ label = "seboot"; ++ reg = <0x0 0x180000>; /* 1.5M */ ++ }; ++ ++ tispl@180000 { ++ label = "tispl"; ++ reg = <0x180000 0x200000>; /* 2M */ ++ }; ++ ++ u-boot@380000 { ++ label = "u-boot"; ++ reg = <0x380000 0x300000>; /* 3M */ ++ }; ++ ++ env@680000 { ++ label = "env"; ++ reg = <0x680000 0x20000>; /* 128K */ ++ }; ++ ++ env-backup@6a0000 { ++ label = "env.backup"; ++ reg = <0x6a0000 0x20000>; /* 128K */ ++ }; ++ ++ otpcmd@6c0000 { ++ label = "otpcmd"; ++ reg = <0x6c0000 0x10000>; /* 64K */ ++ }; ++ ++ unused@6d0000 { ++ label = "unused"; ++ reg = <0x6d0000 0x7b0000>; /* 7872K */ ++ }; ++ ++ seboot-backup@e80000 { ++ label = "seboot.backup"; ++ reg = <0xe80000 0x180000>; /* 1.5M */ ++ }; ++ }; + }; + }; + +-- +2.42.0 + diff --git a/recipes-kernel/linux/files/patches-6.1/0002-dt-bindings-arm-ti-Add-binding-for-Siemens-IOT2050-M.patch b/recipes-kernel/linux/files/patches-6.1/0002-dt-bindings-arm-ti-Add-binding-for-Siemens-IOT2050-M.patch new file mode 100644 index 000000000..f793591f3 --- /dev/null +++ b/recipes-kernel/linux/files/patches-6.1/0002-dt-bindings-arm-ti-Add-binding-for-Siemens-IOT2050-M.patch @@ -0,0 +1,31 @@ +From 8d579a3d6d2a0f9482d01787a3144aabde802a1d Mon Sep 17 00:00:00 2001 +From: Jan Kiszka +Date: Thu, 19 Jan 2023 07:40:41 +0100 +Subject: [PATCH 02/69] dt-bindings: arm: ti: Add binding for Siemens IOT2050 + M.2 variant + +This new variant is derived from the Advanced PG2 board, replacing the +MiniPCI slot with B and E-keyed M.2 slots. + +Signed-off-by: Jan Kiszka +Acked-by: Krzysztof Kozlowski +[Commit 31170b8c028f upstream] +--- + Documentation/devicetree/bindings/arm/ti/k3.yaml | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/Documentation/devicetree/bindings/arm/ti/k3.yaml b/Documentation/devicetree/bindings/arm/ti/k3.yaml +index 28b8232e1c5b..d16231bdee6e 100644 +--- a/Documentation/devicetree/bindings/arm/ti/k3.yaml ++++ b/Documentation/devicetree/bindings/arm/ti/k3.yaml +@@ -42,6 +42,7 @@ properties: + items: + - enum: + - siemens,iot2050-advanced ++ - siemens,iot2050-advanced-m2 + - siemens,iot2050-advanced-pg2 + - siemens,iot2050-basic + - siemens,iot2050-basic-pg2 +-- +2.42.0 + diff --git a/recipes-kernel/linux/files/patches-6.1/0003-arm64-dts-ti-iot2050-Add-support-for-M.2-variant.patch b/recipes-kernel/linux/files/patches-6.1/0003-arm64-dts-ti-iot2050-Add-support-for-M.2-variant.patch new file mode 100644 index 000000000..f2fc89b05 --- /dev/null +++ b/recipes-kernel/linux/files/patches-6.1/0003-arm64-dts-ti-iot2050-Add-support-for-M.2-variant.patch @@ -0,0 +1,169 @@ +From e637dbedf70d3a6fb2dc5f3b5fd4a43d244bc7b3 Mon Sep 17 00:00:00 2001 +From: chao zeng +Date: Thu, 19 Jan 2023 07:40:42 +0100 +Subject: [PATCH 03/69] arm64: dts: ti: iot2050: Add support for M.2 variant + +The M.2 variant comes with 2 slots, one B-keyed and another one E-keyed. +They are configured by the firmware during startup. Also the device tree +will be adjusted according to the detect or manually configured +interface mode by the firmware. The kernel only carries a single +configuration as base device tree. It has to be built with a symbols +node so that the firmware can apply overlays for the connector modes. + +Signed-off-by: chao zeng +[Jan: refactored to a single DT] +Signed-off-by: Jan Kiszka +Reviewed-by: Siddharth Vadapalli +[Commit 175357d1deed upstream] +--- + arch/arm64/boot/dts/ti/Makefile | 3 + + .../dts/ti/k3-am6548-iot2050-advanced-m2.dts | 121 ++++++++++++++++++ + 2 files changed, 124 insertions(+) + create mode 100644 arch/arm64/boot/dts/ti/k3-am6548-iot2050-advanced-m2.dts + +diff --git a/arch/arm64/boot/dts/ti/Makefile b/arch/arm64/boot/dts/ti/Makefile +index 4555a5be2257..efdd3bb1e263 100644 +--- a/arch/arm64/boot/dts/ti/Makefile ++++ b/arch/arm64/boot/dts/ti/Makefile +@@ -10,8 +10,11 @@ dtb-$(CONFIG_ARCH_K3) += k3-am654-base-board.dtb + dtb-$(CONFIG_ARCH_K3) += k3-am6528-iot2050-basic.dtb + dtb-$(CONFIG_ARCH_K3) += k3-am6528-iot2050-basic-pg2.dtb + dtb-$(CONFIG_ARCH_K3) += k3-am6548-iot2050-advanced.dtb ++dtb-$(CONFIG_ARCH_K3) += k3-am6548-iot2050-advanced-m2.dtb + dtb-$(CONFIG_ARCH_K3) += k3-am6548-iot2050-advanced-pg2.dtb + ++DTC_FLAGS_k3-am6548-iot2050-advanced-m2 += -@ ++ + dtb-$(CONFIG_ARCH_K3) += k3-j721e-common-proc-board.dtb + dtb-$(CONFIG_ARCH_K3) += k3-j721e-sk.dtb + +diff --git a/arch/arm64/boot/dts/ti/k3-am6548-iot2050-advanced-m2.dts b/arch/arm64/boot/dts/ti/k3-am6548-iot2050-advanced-m2.dts +new file mode 100644 +index 000000000000..9400e35882a6 +--- /dev/null ++++ b/arch/arm64/boot/dts/ti/k3-am6548-iot2050-advanced-m2.dts +@@ -0,0 +1,121 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (c) Siemens AG, 2018-2023 ++ * ++ * Authors: ++ * Chao Zeng ++ * Jan Kiszka ++ * ++ * AM6548-based (quad-core) IOT2050 M.2 variant (based on Advanced Product ++ * Generation 2), 2 GB RAM, 16 GB eMMC, USB-serial converter on connector X30 ++ * ++ * Product homepage: ++ * https://new.siemens.com/global/en/products/automation/pc-based/iot-gateways/simatic-iot2050.html ++ */ ++ ++#include "k3-am6548-iot2050-advanced-common.dtsi" ++#include "k3-am65-iot2050-common-pg2.dtsi" ++ ++/ { ++ compatible = "siemens,iot2050-advanced-m2", "ti,am654"; ++ model = "SIMATIC IOT2050 Advanced M2"; ++}; ++ ++&mcu_r5fss0 { ++ /* lock-step mode not supported on this board */ ++ ti,cluster-mode = <0>; ++}; ++ ++&main_pmx0 { ++ main_m2_enable_pins_default: main-m2-enable-pins-default { ++ pinctrl-single,pins = < ++ AM65X_IOPAD(0x01c4, PIN_INPUT_PULLUP, 7) /* (AH13) GPIO1_17 */ ++ >; ++ }; ++ ++ main_bkey_pcie_reset: main-bkey-pcie-reset { ++ pinctrl-single,pins = < ++ AM65X_IOPAD(0x01bc, PIN_OUTPUT_PULLUP, 7) /* (AG13) GPIO1_15 */ ++ >; ++ }; ++ ++ main_pmx0_m2_config_pins_default: main-pmx0-m2-config-pins-default { ++ pinctrl-single,pins = < ++ AM65X_IOPAD(0x01c8, PIN_INPUT_PULLUP, 7) /* (AE13) GPIO1_18 */ ++ AM65X_IOPAD(0x01cc, PIN_INPUT_PULLUP, 7) /* (AD13) GPIO1_19 */ ++ >; ++ }; ++ ++ main_m2_pcie_mux_control: main-m2-pcie-mux-control { ++ pinctrl-single,pins = < ++ AM65X_IOPAD(0x0148, PIN_INPUT_PULLUP, 7) /* (AG22) GPIO0_82 */ ++ AM65X_IOPAD(0x0160, PIN_INPUT_PULLUP, 7) /* (AE20) GPIO0_88 */ ++ AM65X_IOPAD(0x0164, PIN_INPUT_PULLUP, 7) /* (AF19) GPIO0_89 */ ++ >; ++ }; ++}; ++ ++&main_pmx1 { ++ main_pmx1_m2_config_pins_default: main-pmx1-m2-config-pins-default { ++ pinctrl-single,pins = < ++ AM65X_IOPAD(0x0018, PIN_INPUT_PULLUP, 7) /* (B22) GPIO1_88 */ ++ AM65X_IOPAD(0x001c, PIN_INPUT_PULLUP, 7) /* (C23) GPIO1_89 */ ++ >; ++ }; ++}; ++ ++&main_gpio0 { ++ pinctrl-names = "default"; ++ pinctrl-0 = < ++ &main_m2_pcie_mux_control ++ &arduino_io_d4_to_d9_pins_default ++ >; ++}; ++ ++&main_gpio1 { ++ pinctrl-names = "default"; ++ pinctrl-0 = < ++ &main_m2_enable_pins_default ++ &main_pmx0_m2_config_pins_default ++ &main_pmx1_m2_config_pins_default ++ &cp2102n_reset_pin_default ++ >; ++}; ++ ++/* ++ * Base configuration for B-key slot with PCIe x2, E-key with USB 2.0 only. ++ * Firmware switches to other modes via device tree overlays. ++ */ ++ ++&serdes0 { ++ assigned-clocks = <&k3_clks 153 4>, <&serdes0 AM654_SERDES_CMU_REFCLK>; ++ assigned-clock-parents = <&k3_clks 153 8>, <&k3_clks 153 4>; ++}; ++ ++&pcie0_rc { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&main_bkey_pcie_reset>; ++ ++ num-lanes = <2>; ++ phys = <&serdes0 PHY_TYPE_PCIE 1>, <&serdes1 PHY_TYPE_PCIE 1>; ++ phy-names = "pcie-phy0","pcie-phy1"; ++ reset-gpios = <&main_gpio1 15 GPIO_ACTIVE_HIGH>; ++ status = "okay"; ++}; ++ ++&pcie1_rc { ++ status = "disabled"; ++}; ++ ++&dwc3_0 { ++ assigned-clock-parents = <&k3_clks 151 4>, /* set REF_CLK to 20MHz i.e. PER0_PLL/48 */ ++ <&k3_clks 151 9>; /* set PIPE3_TXB_CLK to CLK_12M_RC/256 (for HS only) */ ++ /delete-property/ phys; ++ /delete-property/ phy-names; ++}; ++ ++&usb0 { ++ maximum-speed = "high-speed"; ++ /delete-property/ snps,dis-u1-entry-quirk; ++ /delete-property/ snps,dis-u2-entry-quirk; ++}; +-- +2.42.0 + diff --git a/recipes-kernel/linux/files/patches-6.1/0004-dt-bindings-remoteproc-Add-PRU-consumer-bindings.patch b/recipes-kernel/linux/files/patches-6.1/0004-dt-bindings-remoteproc-Add-PRU-consumer-bindings.patch new file mode 100644 index 000000000..c437878fa --- /dev/null +++ b/recipes-kernel/linux/files/patches-6.1/0004-dt-bindings-remoteproc-Add-PRU-consumer-bindings.patch @@ -0,0 +1,93 @@ +From 5f92864dc0c57de9b871da1e78c8c719a4762fbb Mon Sep 17 00:00:00 2001 +From: Suman Anna +Date: Fri, 6 Jan 2023 17:40:41 +0530 +Subject: [PATCH 04/69] dt-bindings: remoteproc: Add PRU consumer bindings + +Add DT schema binding for PRU consumers. The binding includes +all the common properties that can be used by different PRU consumer +or application nodes and supported by the PRU remoteproc driver. +These are used to configure the PRU hardware for specific user +applications. + +The application nodes themselves should define their own bindings. + +Signed-off-by: Tero Kristo +Signed-off-by: Suman Anna +Signed-off-by: Grzegorz Jaszczyk +Signed-off-by: MD Danish Anwar +Reviewed-by: Rob Herring +[Commit d6e21ef31e7f upstream] +--- + .../bindings/remoteproc/ti,pru-consumer.yaml | 60 +++++++++++++++++++ + 1 file changed, 60 insertions(+) + create mode 100644 Documentation/devicetree/bindings/remoteproc/ti,pru-consumer.yaml + +diff --git a/Documentation/devicetree/bindings/remoteproc/ti,pru-consumer.yaml b/Documentation/devicetree/bindings/remoteproc/ti,pru-consumer.yaml +new file mode 100644 +index 000000000000..c6d86964b72a +--- /dev/null ++++ b/Documentation/devicetree/bindings/remoteproc/ti,pru-consumer.yaml +@@ -0,0 +1,60 @@ ++# SPDX-License-Identifier: (GPL-2.0-only or BSD-2-Clause) ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/remoteproc/ti,pru-consumer.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: Common TI PRU Consumer Binding ++ ++maintainers: ++ - Suman Anna ++ ++description: | ++ A PRU application/consumer/user node typically uses one or more PRU device ++ nodes to implement a PRU application/functionality. Each application/client ++ node would need a reference to at least a PRU node, and optionally define ++ some properties needed for hardware/firmware configuration. The below ++ properties are a list of common properties supported by the PRU remoteproc ++ infrastructure. ++ ++ The application nodes shall define their own bindings like regular platform ++ devices, so below are in addition to each node's bindings. ++ ++properties: ++ ti,prus: ++ $ref: /schemas/types.yaml#/definitions/phandle-array ++ description: phandles to the PRU, RTU or Tx_PRU nodes used ++ minItems: 1 ++ maxItems: 6 ++ items: ++ maxItems: 1 ++ ++ firmware-name: ++ $ref: /schemas/types.yaml#/definitions/string-array ++ minItems: 1 ++ maxItems: 6 ++ description: | ++ firmwares for the PRU cores, the default firmware for the core from ++ the PRU node will be used if not provided. The firmware names should ++ correspond to the PRU cores listed in the 'ti,prus' property ++ ++ ti,pruss-gp-mux-sel: ++ $ref: /schemas/types.yaml#/definitions/uint32-array ++ minItems: 1 ++ maxItems: 6 ++ items: ++ enum: [0, 1, 2, 3, 4] ++ description: | ++ array of values for the GP_MUX_SEL under PRUSS_GPCFG register for a PRU. ++ This selects the internal muxing scheme for the PRU instance. Values ++ should correspond to the PRU cores listed in the 'ti,prus' property. The ++ GP_MUX_SEL setting is a per-slice setting (one setting for PRU0, RTU0, ++ and Tx_PRU0 on K3 SoCs). Use the same value for all cores within the ++ same slice in the associative array. If the array size is smaller than ++ the size of 'ti,prus' property, the default out-of-reset value (0) for the ++ PRU core is used. ++ ++required: ++ - ti,prus ++ ++additionalProperties: true +-- +2.42.0 + diff --git a/recipes-kernel/linux/files/patches-6.1/0005-remoteproc-pru-Add-enum-for-PRU-Core-Identifiers.patch b/recipes-kernel/linux/files/patches-6.1/0005-remoteproc-pru-Add-enum-for-PRU-Core-Identifiers.patch new file mode 100644 index 000000000..ffd22320c --- /dev/null +++ b/recipes-kernel/linux/files/patches-6.1/0005-remoteproc-pru-Add-enum-for-PRU-Core-Identifiers.patch @@ -0,0 +1,97 @@ +From e28d3a3921d113b45e469adc3041ac579c6a29fa Mon Sep 17 00:00:00 2001 +From: MD Danish Anwar +Date: Fri, 6 Jan 2023 17:40:42 +0530 +Subject: [PATCH 05/69] remoteproc: pru: Add enum for PRU Core Identifiers. + +Introducing enum pruss_pru_id for PRU Core Identifiers. +PRUSS_PRU0 indicates PRU Core 0. +PRUSS_PRU1 indicates PRU Core 1. +PRUSS_NUM_PRUS indicates the total number of PRU Cores. + +Signed-off-by: MD Danish Anwar +Reviewed-by: Roger Quadros +[Commit 9b9ad70f2867 upstream] +--- + drivers/remoteproc/pru_rproc.c | 7 ++++--- + include/linux/remoteproc/pruss.h | 31 +++++++++++++++++++++++++++++++ + 2 files changed, 35 insertions(+), 3 deletions(-) + create mode 100644 include/linux/remoteproc/pruss.h + +diff --git a/drivers/remoteproc/pru_rproc.c b/drivers/remoteproc/pru_rproc.c +index 128bf9912f2c..f8b196a2b72a 100644 +--- a/drivers/remoteproc/pru_rproc.c ++++ b/drivers/remoteproc/pru_rproc.c +@@ -16,6 +16,7 @@ + #include + #include + #include ++#include + #include + #include + +@@ -438,7 +439,7 @@ static void *pru_d_da_to_va(struct pru_rproc *pru, u32 da, size_t len) + dram0 = pruss->mem_regions[PRUSS_MEM_DRAM0]; + dram1 = pruss->mem_regions[PRUSS_MEM_DRAM1]; + /* PRU1 has its local RAM addresses reversed */ +- if (pru->id == 1) ++ if (pru->id == PRUSS_PRU1) + swap(dram0, dram1); + shrd_ram = pruss->mem_regions[PRUSS_MEM_SHRD_RAM2]; + +@@ -747,14 +748,14 @@ static int pru_rproc_set_id(struct pru_rproc *pru) + case RTU0_IRAM_ADDR_MASK: + fallthrough; + case PRU0_IRAM_ADDR_MASK: +- pru->id = 0; ++ pru->id = PRUSS_PRU0; + break; + case TX_PRU1_IRAM_ADDR_MASK: + fallthrough; + case RTU1_IRAM_ADDR_MASK: + fallthrough; + case PRU1_IRAM_ADDR_MASK: +- pru->id = 1; ++ pru->id = PRUSS_PRU1; + break; + default: + ret = -EINVAL; +diff --git a/include/linux/remoteproc/pruss.h b/include/linux/remoteproc/pruss.h +new file mode 100644 +index 000000000000..e94a81e97a4c +--- /dev/null ++++ b/include/linux/remoteproc/pruss.h +@@ -0,0 +1,31 @@ ++/* SPDX-License-Identifier: GPL-2.0-only */ ++/** ++ * PRU-ICSS Subsystem user interfaces ++ * ++ * Copyright (C) 2015-2022 Texas Instruments Incorporated - http://www.ti.com ++ * Suman Anna ++ */ ++ ++#ifndef __LINUX_PRUSS_H ++#define __LINUX_PRUSS_H ++ ++#include ++#include ++ ++#define PRU_RPROC_DRVNAME "pru-rproc" ++ ++/** ++ * enum pruss_pru_id - PRU core identifiers ++ * @PRUSS_PRU0: PRU Core 0. ++ * @PRUSS_PRU1: PRU Core 1. ++ * @PRUSS_NUM_PRUS: Total number of PRU Cores available. ++ * ++ */ ++ ++enum pruss_pru_id { ++ PRUSS_PRU0 = 0, ++ PRUSS_PRU1, ++ PRUSS_NUM_PRUS, ++}; ++ ++#endif /* __LINUX_PRUSS_H */ +-- +2.42.0 + diff --git a/recipes-kernel/linux/files/patches-6.1/0006-remoteproc-pru-Add-APIs-to-get-and-put-the-PRU-cores.patch b/recipes-kernel/linux/files/patches-6.1/0006-remoteproc-pru-Add-APIs-to-get-and-put-the-PRU-cores.patch new file mode 100644 index 000000000..5fae9c9fa --- /dev/null +++ b/recipes-kernel/linux/files/patches-6.1/0006-remoteproc-pru-Add-APIs-to-get-and-put-the-PRU-cores.patch @@ -0,0 +1,253 @@ +From 1bdbae1629825e6788d085c08806276512b20274 Mon Sep 17 00:00:00 2001 +From: MD Danish Anwar +Date: Fri, 6 Jan 2023 17:40:43 +0530 +Subject: [PATCH 06/69] remoteproc: pru: Add APIs to get and put the PRU cores + +Add two new APIs, pru_rproc_get() and pru_rproc_put(), to the PRU +driver to allow client drivers to acquire and release the remoteproc +device associated with a PRU core. The PRU cores are treated as +resources with only one client owning it at a time. + +The pru_rproc_get() function returns the rproc handle corresponding +to a PRU core identified by the device tree "ti,prus" property under +the client node. The pru_rproc_put() is the complementary function +to pru_rproc_get(). + +Signed-off-by: Suman Anna +Signed-off-by: Tero Kristo +Signed-off-by: Grzegorz Jaszczyk +Signed-off-by: MD Danish Anwar +Reviewed-by: Roger Quadros +[Commit 919e8942548a upstream] +--- + drivers/remoteproc/pru_rproc.c | 128 ++++++++++++++++++++++++++++++- + include/linux/remoteproc/pruss.h | 30 ++++++++ + 2 files changed, 156 insertions(+), 2 deletions(-) + +diff --git a/drivers/remoteproc/pru_rproc.c b/drivers/remoteproc/pru_rproc.c +index f8b196a2b72a..1036bfd446b6 100644 +--- a/drivers/remoteproc/pru_rproc.c ++++ b/drivers/remoteproc/pru_rproc.c +@@ -2,12 +2,14 @@ + /* + * PRU-ICSS remoteproc driver for various TI SoCs + * +- * Copyright (C) 2014-2020 Texas Instruments Incorporated - https://www.ti.com/ ++ * Copyright (C) 2014-2022 Texas Instruments Incorporated - https://www.ti.com/ + * + * Author(s): + * Suman Anna + * Andrew F. Davis + * Grzegorz Jaszczyk for Texas Instruments ++ * Puranjay Mohan ++ * Md Danish Anwar + */ + + #include +@@ -112,6 +114,8 @@ struct pru_private_data { + * @rproc: remoteproc pointer for this PRU core + * @data: PRU core specific data + * @mem_regions: data for each of the PRU memory regions ++ * @client_np: client device node ++ * @lock: mutex to protect client usage + * @fw_name: name of firmware image used during loading + * @mapped_irq: virtual interrupt numbers of created fw specific mapping + * @pru_interrupt_map: pointer to interrupt mapping description (firmware) +@@ -127,6 +131,8 @@ struct pru_rproc { + struct rproc *rproc; + const struct pru_private_data *data; + struct pruss_mem_region mem_regions[PRU_IOMEM_MAX]; ++ struct device_node *client_np; ++ struct mutex lock; + const char *fw_name; + unsigned int *mapped_irq; + struct pru_irq_rsc *pru_interrupt_map; +@@ -147,6 +153,120 @@ void pru_control_write_reg(struct pru_rproc *pru, unsigned int reg, u32 val) + writel_relaxed(val, pru->mem_regions[PRU_IOMEM_CTRL].va + reg); + } + ++static struct rproc *__pru_rproc_get(struct device_node *np, int index) ++{ ++ struct rproc *rproc; ++ phandle rproc_phandle; ++ int ret; ++ ++ ret = of_property_read_u32_index(np, "ti,prus", index, &rproc_phandle); ++ if (ret) ++ return ERR_PTR(ret); ++ ++ rproc = rproc_get_by_phandle(rproc_phandle); ++ if (!rproc) { ++ ret = -EPROBE_DEFER; ++ return ERR_PTR(ret); ++ } ++ ++ /* make sure it is PRU rproc */ ++ if (!is_pru_rproc(rproc->dev.parent)) { ++ rproc_put(rproc); ++ return ERR_PTR(-ENODEV); ++ } ++ ++ return rproc; ++} ++ ++/** ++ * pru_rproc_get() - get the PRU rproc instance from a device node ++ * @np: the user/client device node ++ * @index: index to use for the ti,prus property ++ * @pru_id: optional pointer to return the PRU remoteproc processor id ++ * ++ * This function looks through a client device node's "ti,prus" property at ++ * index @index and returns the rproc handle for a valid PRU remote processor if ++ * found. The function allows only one user to own the PRU rproc resource at a ++ * time. Caller must call pru_rproc_put() when done with using the rproc, not ++ * required if the function returns a failure. ++ * ++ * When optional @pru_id pointer is passed the PRU remoteproc processor id is ++ * returned. ++ * ++ * Return: rproc handle on success, and an ERR_PTR on failure using one ++ * of the following error values ++ * -ENODEV if device is not found ++ * -EBUSY if PRU is already acquired by anyone ++ * -EPROBE_DEFER is PRU device is not probed yet ++ */ ++struct rproc *pru_rproc_get(struct device_node *np, int index, ++ enum pruss_pru_id *pru_id) ++{ ++ struct rproc *rproc; ++ struct pru_rproc *pru; ++ struct device *dev; ++ int ret; ++ ++ rproc = __pru_rproc_get(np, index); ++ if (IS_ERR(rproc)) ++ return rproc; ++ ++ pru = rproc->priv; ++ dev = &rproc->dev; ++ ++ mutex_lock(&pru->lock); ++ ++ if (pru->client_np) { ++ mutex_unlock(&pru->lock); ++ ret = -EBUSY; ++ goto err_no_rproc_handle; ++ } ++ ++ pru->client_np = np; ++ ++ mutex_unlock(&pru->lock); ++ ++ if (pru_id) ++ *pru_id = pru->id; ++ ++ return rproc; ++ ++err_no_rproc_handle: ++ rproc_put(rproc); ++ return ERR_PTR(ret); ++} ++EXPORT_SYMBOL_GPL(pru_rproc_get); ++ ++/** ++ * pru_rproc_put() - release the PRU rproc resource ++ * @rproc: the rproc resource to release ++ * ++ * Releases the PRU rproc resource and makes it available to other ++ * users. ++ */ ++void pru_rproc_put(struct rproc *rproc) ++{ ++ struct pru_rproc *pru; ++ ++ if (IS_ERR_OR_NULL(rproc) || !is_pru_rproc(rproc->dev.parent)) ++ return; ++ ++ pru = rproc->priv; ++ ++ mutex_lock(&pru->lock); ++ ++ if (!pru->client_np) { ++ mutex_unlock(&pru->lock); ++ return; ++ } ++ ++ pru->client_np = NULL; ++ mutex_unlock(&pru->lock); ++ ++ rproc_put(rproc); ++} ++EXPORT_SYMBOL_GPL(pru_rproc_put); ++ + static inline u32 pru_debug_read_reg(struct pru_rproc *pru, unsigned int reg) + { + return readl_relaxed(pru->mem_regions[PRU_IOMEM_DEBUG].va + reg); +@@ -817,6 +937,8 @@ static int pru_rproc_probe(struct platform_device *pdev) + pru->pruss = platform_get_drvdata(ppdev); + pru->rproc = rproc; + pru->fw_name = fw_name; ++ pru->client_np = NULL; ++ mutex_init(&pru->lock); + + for (i = 0; i < ARRAY_SIZE(mem_names); i++) { + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, +@@ -905,7 +1027,7 @@ MODULE_DEVICE_TABLE(of, pru_rproc_match); + + static struct platform_driver pru_rproc_driver = { + .driver = { +- .name = "pru-rproc", ++ .name = PRU_RPROC_DRVNAME, + .of_match_table = pru_rproc_match, + .suppress_bind_attrs = true, + }, +@@ -917,5 +1039,7 @@ module_platform_driver(pru_rproc_driver); + MODULE_AUTHOR("Suman Anna "); + MODULE_AUTHOR("Andrew F. Davis "); + MODULE_AUTHOR("Grzegorz Jaszczyk "); ++MODULE_AUTHOR("Puranjay Mohan "); ++MODULE_AUTHOR("Md Danish Anwar "); + MODULE_DESCRIPTION("PRU-ICSS Remote Processor Driver"); + MODULE_LICENSE("GPL v2"); +diff --git a/include/linux/remoteproc/pruss.h b/include/linux/remoteproc/pruss.h +index e94a81e97a4c..efe89c586b4b 100644 +--- a/include/linux/remoteproc/pruss.h ++++ b/include/linux/remoteproc/pruss.h +@@ -28,4 +28,34 @@ enum pruss_pru_id { + PRUSS_NUM_PRUS, + }; + ++struct device_node; ++ ++#if IS_ENABLED(CONFIG_PRU_REMOTEPROC) ++ ++struct rproc *pru_rproc_get(struct device_node *np, int index, ++ enum pruss_pru_id *pru_id); ++void pru_rproc_put(struct rproc *rproc); ++ ++#else ++ ++static inline struct rproc * ++pru_rproc_get(struct device_node *np, int index, enum pruss_pru_id *pru_id) ++{ ++ return ERR_PTR(-EOPNOTSUPP); ++} ++ ++static inline void pru_rproc_put(struct rproc *rproc) { } ++ ++#endif /* CONFIG_PRU_REMOTEPROC */ ++ ++static inline bool is_pru_rproc(struct device *dev) ++{ ++ const char *drv_name = dev_driver_string(dev); ++ ++ if (strncmp(drv_name, PRU_RPROC_DRVNAME, sizeof(PRU_RPROC_DRVNAME))) ++ return false; ++ ++ return true; ++} ++ + #endif /* __LINUX_PRUSS_H */ +-- +2.42.0 + diff --git a/recipes-kernel/linux/files/patches-6.1/0007-remoteproc-pru-Make-sysfs-entries-read-only-for-PRU-.patch b/recipes-kernel/linux/files/patches-6.1/0007-remoteproc-pru-Make-sysfs-entries-read-only-for-PRU-.patch new file mode 100644 index 000000000..07fbaed5e --- /dev/null +++ b/recipes-kernel/linux/files/patches-6.1/0007-remoteproc-pru-Make-sysfs-entries-read-only-for-PRU-.patch @@ -0,0 +1,47 @@ +From 2b35372b9becddae498e588130c9867dac1c5967 Mon Sep 17 00:00:00 2001 +From: Suman Anna +Date: Fri, 6 Jan 2023 17:40:44 +0530 +Subject: [PATCH 07/69] remoteproc: pru: Make sysfs entries read-only for PRU + client driven boots + +The PRU remoteproc driver is not configured for 'auto-boot' by default, +and allows to be booted either by in-kernel PRU client drivers or by +userspace using the generic remoteproc sysfs interfaces. The sysfs +interfaces should not be permitted to change the remoteproc firmwares +or states when a PRU is being managed by an in-kernel client driver. +Use the newly introduced remoteproc generic 'sysfs_read_only' flag to +provide these restrictions by setting and clearing it appropriately +during the PRU acquire and release steps. + +Signed-off-by: Suman Anna +Signed-off-by: Grzegorz Jaszczyk +Signed-off-by: MD Danish Anwar +Reviewed-by: Roger Quadros +[Commit 2da812ffcd11 upstream] +--- + drivers/remoteproc/pru_rproc.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/remoteproc/pru_rproc.c b/drivers/remoteproc/pru_rproc.c +index 1036bfd446b6..c16242e2d435 100644 +--- a/drivers/remoteproc/pru_rproc.c ++++ b/drivers/remoteproc/pru_rproc.c +@@ -223,6 +223,7 @@ struct rproc *pru_rproc_get(struct device_node *np, int index, + } + + pru->client_np = np; ++ rproc->sysfs_read_only = true; + + mutex_unlock(&pru->lock); + +@@ -261,6 +262,7 @@ void pru_rproc_put(struct rproc *rproc) + } + + pru->client_np = NULL; ++ rproc->sysfs_read_only = false; + mutex_unlock(&pru->lock); + + rproc_put(rproc); +-- +2.42.0 + diff --git a/recipes-kernel/linux/files/patches-6.1/0008-remoteproc-pru-Add-pru_rproc_set_ctable-function.patch b/recipes-kernel/linux/files/patches-6.1/0008-remoteproc-pru-Add-pru_rproc_set_ctable-function.patch new file mode 100644 index 000000000..ec37c76ae --- /dev/null +++ b/recipes-kernel/linux/files/patches-6.1/0008-remoteproc-pru-Add-pru_rproc_set_ctable-function.patch @@ -0,0 +1,200 @@ +From d0845c2b7260f7e3704b10fb71329f830a5db8f8 Mon Sep 17 00:00:00 2001 +From: Roger Quadros +Date: Fri, 6 Jan 2023 17:40:45 +0530 +Subject: [PATCH 08/69] remoteproc: pru: Add pru_rproc_set_ctable() function + +Some firmwares expect the OS drivers to configure the CTABLE +entries publishing dynamically allocated memory regions. For +example, the PRU Ethernet firmwares use the C28 and C30 entries +for retrieving the Shared RAM and System SRAM (OCMC) areas +allocated by the PRU Ethernet client driver. + +Provide a way for users to do that through a new API, +pru_rproc_set_ctable(). The API returns 0 on success and +a negative value on error. + +NOTE: +The programmable CTABLE entries are typically re-programmed by +the PRU firmwares when dealing with a certain block of memory +during block processing. This API provides an interface to the +PRU client drivers to publish a dynamically allocated memory +block with the PRU firmware using a CTABLE entry instead of a +negotiated address in shared memory. Additional synchronization +may be needed between the PRU client drivers and firmwares if +different addresses needs to be published at run-time reusing +the same CTABLE entry. + +CTABLE for stands for "constant table". +Each CTable entry just holds the upper address bits so PRU can +reference to external memory with larger address bits. + +For use case please see +prueth_sw_emac_config() in "drivers/net/ethernet/ti/prueth_switch.c" + + /* Set in constant table C28 of PRUn to ICSS Shared memory */ + pru_rproc_set_ctable(prueth->pru0, PRU_C28, sharedramaddr); + pru_rproc_set_ctable(prueth->pru1, PRU_C28, sharedramaddr); + + /* Set in constant table C30 of PRUn to OCMC memory */ + pru_rproc_set_ctable(prueth->pru0, PRU_C30, ocmcaddr); + pru_rproc_set_ctable(prueth->pru1, PRU_C30, ocmcaddr); + +Signed-off-by: "Andrew F. Davis" +Signed-off-by: Suman Anna +Signed-off-by: Roger Quadros +Signed-off-by: Grzegorz Jaszczyk +Signed-off-by: MD Danish Anwar +[Commit 102853400321 upstream] +--- + drivers/remoteproc/pru_rproc.c | 59 ++++++++++++++++++++++++++++++++ + include/linux/remoteproc/pruss.h | 22 ++++++++++++ + 2 files changed, 81 insertions(+) + +diff --git a/drivers/remoteproc/pru_rproc.c b/drivers/remoteproc/pru_rproc.c +index c16242e2d435..f6ea445d2fa2 100644 +--- a/drivers/remoteproc/pru_rproc.c ++++ b/drivers/remoteproc/pru_rproc.c +@@ -120,6 +120,7 @@ struct pru_private_data { + * @mapped_irq: virtual interrupt numbers of created fw specific mapping + * @pru_interrupt_map: pointer to interrupt mapping description (firmware) + * @pru_interrupt_map_sz: pru_interrupt_map size ++ * @rmw_lock: lock for read, modify, write operations on registers + * @dbg_single_step: debug state variable to set PRU into single step mode + * @dbg_continuous: debug state variable to restore PRU execution mode + * @evt_count: number of mapped events +@@ -137,6 +138,7 @@ struct pru_rproc { + unsigned int *mapped_irq; + struct pru_irq_rsc *pru_interrupt_map; + size_t pru_interrupt_map_sz; ++ spinlock_t rmw_lock; + u32 dbg_single_step; + u32 dbg_continuous; + u8 evt_count; +@@ -153,6 +155,23 @@ void pru_control_write_reg(struct pru_rproc *pru, unsigned int reg, u32 val) + writel_relaxed(val, pru->mem_regions[PRU_IOMEM_CTRL].va + reg); + } + ++static inline ++void pru_control_set_reg(struct pru_rproc *pru, unsigned int reg, ++ u32 mask, u32 set) ++{ ++ u32 val; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&pru->rmw_lock, flags); ++ ++ val = pru_control_read_reg(pru, reg); ++ val &= ~mask; ++ val |= (set & mask); ++ pru_control_write_reg(pru, reg, val); ++ ++ spin_unlock_irqrestore(&pru->rmw_lock, flags); ++} ++ + static struct rproc *__pru_rproc_get(struct device_node *np, int index) + { + struct rproc *rproc; +@@ -269,6 +288,45 @@ void pru_rproc_put(struct rproc *rproc) + } + EXPORT_SYMBOL_GPL(pru_rproc_put); + ++/** ++ * pru_rproc_set_ctable() - set the constant table index for the PRU ++ * @rproc: the rproc instance of the PRU ++ * @c: constant table index to set ++ * @addr: physical address to set it to ++ * ++ * Return: 0 on success, or errno in error case. ++ */ ++int pru_rproc_set_ctable(struct rproc *rproc, enum pru_ctable_idx c, u32 addr) ++{ ++ struct pru_rproc *pru = rproc->priv; ++ unsigned int reg; ++ u32 mask, set; ++ u16 idx; ++ u16 idx_mask; ++ ++ if (IS_ERR_OR_NULL(rproc)) ++ return -EINVAL; ++ ++ if (!rproc->dev.parent || !is_pru_rproc(rproc->dev.parent)) ++ return -ENODEV; ++ ++ /* pointer is 16 bit and index is 8-bit so mask out the rest */ ++ idx_mask = (c >= PRU_C28) ? 0xFFFF : 0xFF; ++ ++ /* ctable uses bit 8 and upwards only */ ++ idx = (addr >> 8) & idx_mask; ++ ++ /* configurable ctable (i.e. C24) starts at PRU_CTRL_CTBIR0 */ ++ reg = PRU_CTRL_CTBIR0 + 4 * (c >> 1); ++ mask = idx_mask << (16 * (c & 1)); ++ set = idx << (16 * (c & 1)); ++ ++ pru_control_set_reg(pru, reg, mask, set); ++ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(pru_rproc_set_ctable); ++ + static inline u32 pru_debug_read_reg(struct pru_rproc *pru, unsigned int reg) + { + return readl_relaxed(pru->mem_regions[PRU_IOMEM_DEBUG].va + reg); +@@ -940,6 +998,7 @@ static int pru_rproc_probe(struct platform_device *pdev) + pru->rproc = rproc; + pru->fw_name = fw_name; + pru->client_np = NULL; ++ spin_lock_init(&pru->rmw_lock); + mutex_init(&pru->lock); + + for (i = 0; i < ARRAY_SIZE(mem_names); i++) { +diff --git a/include/linux/remoteproc/pruss.h b/include/linux/remoteproc/pruss.h +index efe89c586b4b..5c20da98a4b8 100644 +--- a/include/linux/remoteproc/pruss.h ++++ b/include/linux/remoteproc/pruss.h +@@ -28,13 +28,29 @@ enum pruss_pru_id { + PRUSS_NUM_PRUS, + }; + ++/* ++ * enum pru_ctable_idx - Configurable Constant table index identifiers ++ */ ++enum pru_ctable_idx { ++ PRU_C24 = 0, ++ PRU_C25, ++ PRU_C26, ++ PRU_C27, ++ PRU_C28, ++ PRU_C29, ++ PRU_C30, ++ PRU_C31, ++}; ++ + struct device_node; ++struct rproc; + + #if IS_ENABLED(CONFIG_PRU_REMOTEPROC) + + struct rproc *pru_rproc_get(struct device_node *np, int index, + enum pruss_pru_id *pru_id); + void pru_rproc_put(struct rproc *rproc); ++int pru_rproc_set_ctable(struct rproc *rproc, enum pru_ctable_idx c, u32 addr); + + #else + +@@ -46,6 +62,12 @@ pru_rproc_get(struct device_node *np, int index, enum pruss_pru_id *pru_id) + + static inline void pru_rproc_put(struct rproc *rproc) { } + ++static inline int pru_rproc_set_ctable(struct rproc *rproc, ++ enum pru_ctable_idx c, u32 addr) ++{ ++ return -EOPNOTSUPP; ++} ++ + #endif /* CONFIG_PRU_REMOTEPROC */ + + static inline bool is_pru_rproc(struct device *dev) +-- +2.42.0 + diff --git a/recipes-kernel/linux/files/patches-6.1/0009-remoteproc-pru-Configure-firmware-based-on-client-se.patch b/recipes-kernel/linux/files/patches-6.1/0009-remoteproc-pru-Configure-firmware-based-on-client-se.patch new file mode 100644 index 000000000..10c3c7670 --- /dev/null +++ b/recipes-kernel/linux/files/patches-6.1/0009-remoteproc-pru-Configure-firmware-based-on-client-se.patch @@ -0,0 +1,94 @@ +From 33215587de847333f9ae93e35d5bd39d1198ce14 Mon Sep 17 00:00:00 2001 +From: Tero Kristo +Date: Fri, 6 Jan 2023 17:40:46 +0530 +Subject: [PATCH 09/69] remoteproc: pru: Configure firmware based on client + setup + +Client device node property firmware-name is now used to configure +firmware for the PRU instances. The default firmware is also +restored once releasing the PRU resource. + +Signed-off-by: Suman Anna +Signed-off-by: Tero Kristo +Signed-off-by: Grzegorz Jaszczyk +Signed-off-by: MD Danish Anwar +Reviewed-by: Roger Quadros +[Commit 133f30d3a8e1 upstream] +--- + drivers/remoteproc/pru_rproc.c | 34 ++++++++++++++++++++++++++++++++++ + 1 file changed, 34 insertions(+) + +diff --git a/drivers/remoteproc/pru_rproc.c b/drivers/remoteproc/pru_rproc.c +index f6ea445d2fa2..b76db7fa693d 100644 +--- a/drivers/remoteproc/pru_rproc.c ++++ b/drivers/remoteproc/pru_rproc.c +@@ -172,6 +172,23 @@ void pru_control_set_reg(struct pru_rproc *pru, unsigned int reg, + spin_unlock_irqrestore(&pru->rmw_lock, flags); + } + ++/** ++ * pru_rproc_set_firmware() - set firmware for a PRU core ++ * @rproc: the rproc instance of the PRU ++ * @fw_name: the new firmware name, or NULL if default is desired ++ * ++ * Return: 0 on success, or errno in error case. ++ */ ++static int pru_rproc_set_firmware(struct rproc *rproc, const char *fw_name) ++{ ++ struct pru_rproc *pru = rproc->priv; ++ ++ if (!fw_name) ++ fw_name = pru->fw_name; ++ ++ return rproc_set_firmware(rproc, fw_name); ++} ++ + static struct rproc *__pru_rproc_get(struct device_node *np, int index) + { + struct rproc *rproc; +@@ -224,6 +241,7 @@ struct rproc *pru_rproc_get(struct device_node *np, int index, + struct rproc *rproc; + struct pru_rproc *pru; + struct device *dev; ++ const char *fw_name; + int ret; + + rproc = __pru_rproc_get(np, index); +@@ -249,11 +267,25 @@ struct rproc *pru_rproc_get(struct device_node *np, int index, + if (pru_id) + *pru_id = pru->id; + ++ ret = of_property_read_string_index(np, "firmware-name", index, ++ &fw_name); ++ if (!ret) { ++ ret = pru_rproc_set_firmware(rproc, fw_name); ++ if (ret) { ++ dev_err(dev, "failed to set firmware: %d\n", ret); ++ goto err; ++ } ++ } ++ + return rproc; + + err_no_rproc_handle: + rproc_put(rproc); + return ERR_PTR(ret); ++ ++err: ++ pru_rproc_put(rproc); ++ return ERR_PTR(ret); + } + EXPORT_SYMBOL_GPL(pru_rproc_get); + +@@ -273,6 +305,8 @@ void pru_rproc_put(struct rproc *rproc) + + pru = rproc->priv; + ++ pru_rproc_set_firmware(rproc, NULL); ++ + mutex_lock(&pru->lock); + + if (!pru->client_np) { +-- +2.42.0 + diff --git a/recipes-kernel/linux/files/patches-6.1/0010-dt-bindings-remoteproc-pru-Add-Interrupt-property.patch b/recipes-kernel/linux/files/patches-6.1/0010-dt-bindings-remoteproc-pru-Add-Interrupt-property.patch new file mode 100644 index 000000000..79e8851ab --- /dev/null +++ b/recipes-kernel/linux/files/patches-6.1/0010-dt-bindings-remoteproc-pru-Add-Interrupt-property.patch @@ -0,0 +1,78 @@ +From d6ad705112f76b32bb4e1dc57992f0995f97aed3 Mon Sep 17 00:00:00 2001 +From: MD Danish Anwar +Date: Mon, 14 Aug 2023 15:21:41 +0530 +Subject: [PATCH 10/69] dt-bindings: remoteproc: pru: Add Interrupt property + +Add interrupts and interrupt-names protperties for PRU and RTU cores. + +Signed-off-by: MD Danish Anwar +Reviewed-by: Conor Dooley +--- + .../bindings/remoteproc/ti,pru-rproc.yaml | 23 +++++++++++++++++++ + 1 file changed, 23 insertions(+) + +diff --git a/Documentation/devicetree/bindings/remoteproc/ti,pru-rproc.yaml b/Documentation/devicetree/bindings/remoteproc/ti,pru-rproc.yaml +index cd55d80137f7..fc81ba2ad2da 100644 +--- a/Documentation/devicetree/bindings/remoteproc/ti,pru-rproc.yaml ++++ b/Documentation/devicetree/bindings/remoteproc/ti,pru-rproc.yaml +@@ -66,6 +66,17 @@ properties: + Should contain the name of the default firmware image + file located on the firmware search path. + ++ interrupts: ++ maxItems: 1 ++ description: ++ Interrupt specifiers enable the virtio/rpmsg communication between MPU ++ and the PRU/RTU cores. For the values of the interrupt cells please refer ++ to interrupt-controller/ti,pruss-intc.yaml schema. ++ ++ interrupt-names: ++ items: ++ - const: vring ++ + if: + properties: + compatible: +@@ -171,6 +182,9 @@ examples: + <0x22400 0x100>; + reg-names = "iram", "control", "debug"; + firmware-name = "am65x-pru0_0-fw"; ++ interrupt-parent = <&icssg0_intc>; ++ interrupts = <16 2 2>; ++ interrupt-names = "vring"; + }; + + rtu0_0: rtu@4000 { +@@ -180,6 +194,9 @@ examples: + <0x23400 0x100>; + reg-names = "iram", "control", "debug"; + firmware-name = "am65x-rtu0_0-fw"; ++ interrupt-parent = <&icssg0_intc>; ++ interrupts = <20 4 4>; ++ interrupt-names = "vring"; + }; + + tx_pru0_0: txpru@a000 { +@@ -198,6 +215,9 @@ examples: + <0x24400 0x100>; + reg-names = "iram", "control", "debug"; + firmware-name = "am65x-pru0_1-fw"; ++ interrupt-parent = <&icssg0_intc>; ++ interrupts = <18 3 3>; ++ interrupt-names = "vring"; + }; + + rtu0_1: rtu@6000 { +@@ -207,6 +227,9 @@ examples: + <0x23c00 0x100>; + reg-names = "iram", "control", "debug"; + firmware-name = "am65x-rtu0_1-fw"; ++ interrupt-parent = <&icssg0_intc>; ++ interrupts = <22 5 5>; ++ interrupt-names = "vring"; + }; + + tx_pru0_1: txpru@c000 { +-- +2.42.0 + diff --git a/recipes-kernel/linux/files/patches-6.1/0011-soc-ti-pruss-Add-pruss_get-put-API.patch b/recipes-kernel/linux/files/patches-6.1/0011-soc-ti-pruss-Add-pruss_get-put-API.patch new file mode 100644 index 000000000..f148dac43 --- /dev/null +++ b/recipes-kernel/linux/files/patches-6.1/0011-soc-ti-pruss-Add-pruss_get-put-API.patch @@ -0,0 +1,157 @@ +From 2773cb730f05a28e89b24e56be34fe939dad937a Mon Sep 17 00:00:00 2001 +From: Tero Kristo +Date: Fri, 14 Apr 2023 10:25:39 +0530 +Subject: [PATCH 11/69] soc: ti: pruss: Add pruss_get()/put() API + +Add two new get and put API, pruss_get() and pruss_put() to the +PRUSS platform driver to allow client drivers to request a handle +to a PRUSS device. This handle will be used by client drivers to +request various operations of the PRUSS platform driver through +additional API that will be added in the following patches. + +The pruss_get() function returns the pruss handle corresponding +to a PRUSS device referenced by a PRU remoteproc instance. The +pruss_put() is the complimentary function to pruss_get(). + +Co-developed-by: Suman Anna +Signed-off-by: Suman Anna +Signed-off-by: Tero Kristo +Co-developed-by: Grzegorz Jaszczyk +Signed-off-by: Grzegorz Jaszczyk +Signed-off-by: Puranjay Mohan +Reviewed-by: Roger Quadros +Reviewed-by: Tony Lindgren +Reviewed-by: Simon Horman +Acked-by: Mathieu Poirier +Signed-off-by: MD Danish Anwar +[Commit 67d1b0a1030f upstream] +--- + drivers/soc/ti/pruss.c | 62 ++++++++++++++++++++++++++++++++++++ + include/linux/pruss_driver.h | 18 +++++++++++ + 2 files changed, 80 insertions(+) + +diff --git a/drivers/soc/ti/pruss.c b/drivers/soc/ti/pruss.c +index 6882c86b3ce5..3fac92df8790 100644 +--- a/drivers/soc/ti/pruss.c ++++ b/drivers/soc/ti/pruss.c +@@ -6,6 +6,7 @@ + * Author(s): + * Suman Anna + * Andrew F. Davis ++ * Tero Kristo + */ + + #include +@@ -18,6 +19,7 @@ + #include + #include + #include ++#include + #include + + /** +@@ -30,6 +32,66 @@ struct pruss_private_data { + bool has_core_mux_clock; + }; + ++/** ++ * pruss_get() - get the pruss for a given PRU remoteproc ++ * @rproc: remoteproc handle of a PRU instance ++ * ++ * Finds the parent pruss device for a PRU given the @rproc handle of the ++ * PRU remote processor. This function increments the pruss device's refcount, ++ * so always use pruss_put() to decrement it back once pruss isn't needed ++ * anymore. ++ * ++ * This API doesn't check if @rproc is valid or not. It is expected the caller ++ * will have done a pru_rproc_get() on @rproc, before calling this API to make ++ * sure that @rproc is valid. ++ * ++ * Return: pruss handle on success, and an ERR_PTR on failure using one ++ * of the following error values ++ * -EINVAL if invalid parameter ++ * -ENODEV if PRU device or PRUSS device is not found ++ */ ++struct pruss *pruss_get(struct rproc *rproc) ++{ ++ struct pruss *pruss; ++ struct device *dev; ++ struct platform_device *ppdev; ++ ++ if (IS_ERR_OR_NULL(rproc)) ++ return ERR_PTR(-EINVAL); ++ ++ dev = &rproc->dev; ++ ++ /* make sure it is PRU rproc */ ++ if (!dev->parent || !is_pru_rproc(dev->parent)) ++ return ERR_PTR(-ENODEV); ++ ++ ppdev = to_platform_device(dev->parent->parent); ++ pruss = platform_get_drvdata(ppdev); ++ if (!pruss) ++ return ERR_PTR(-ENODEV); ++ ++ get_device(pruss->dev); ++ ++ return pruss; ++} ++EXPORT_SYMBOL_GPL(pruss_get); ++ ++/** ++ * pruss_put() - decrement pruss device's usecount ++ * @pruss: pruss handle ++ * ++ * Complimentary function for pruss_get(). Needs to be called ++ * after the PRUSS is used, and only if the pruss_get() succeeds. ++ */ ++void pruss_put(struct pruss *pruss) ++{ ++ if (IS_ERR_OR_NULL(pruss)) ++ return; ++ ++ put_device(pruss->dev); ++} ++EXPORT_SYMBOL_GPL(pruss_put); ++ + static void pruss_of_free_clk_provider(void *data) + { + struct device_node *clk_mux_np = data; +diff --git a/include/linux/pruss_driver.h b/include/linux/pruss_driver.h +index ecfded30ed05..cb40c2b31045 100644 +--- a/include/linux/pruss_driver.h ++++ b/include/linux/pruss_driver.h +@@ -9,7 +9,9 @@ + #ifndef _PRUSS_DRIVER_H_ + #define _PRUSS_DRIVER_H_ + ++#include + #include ++#include + + /* + * enum pruss_mem - PRUSS memory range identifiers +@@ -51,4 +53,20 @@ struct pruss { + struct clk *iep_clk_mux; + }; + ++#if IS_ENABLED(CONFIG_TI_PRUSS) ++ ++struct pruss *pruss_get(struct rproc *rproc); ++void pruss_put(struct pruss *pruss); ++ ++#else ++ ++static inline struct pruss *pruss_get(struct rproc *rproc) ++{ ++ return ERR_PTR(-EOPNOTSUPP); ++} ++ ++static inline void pruss_put(struct pruss *pruss) { } ++ ++#endif /* CONFIG_TI_PRUSS */ ++ + #endif /* _PRUSS_DRIVER_H_ */ +-- +2.42.0 + diff --git a/recipes-kernel/linux/files/patches-6.1/0012-soc-ti-pruss-Add-pruss_-request-release-_mem_region-.patch b/recipes-kernel/linux/files/patches-6.1/0012-soc-ti-pruss-Add-pruss_-request-release-_mem_region-.patch new file mode 100644 index 000000000..fb40858bb --- /dev/null +++ b/recipes-kernel/linux/files/patches-6.1/0012-soc-ti-pruss-Add-pruss_-request-release-_mem_region-.patch @@ -0,0 +1,187 @@ +From d298c0de3f4ba7440d4b3fbe3c6fa3275b393ede Mon Sep 17 00:00:00 2001 +From: "Andrew F. Davis" +Date: Fri, 14 Apr 2023 10:25:40 +0530 +Subject: [PATCH 12/69] soc: ti: pruss: Add + pruss_{request,release}_mem_region() API + +Add two new API - pruss_request_mem_region() & pruss_release_mem_region(), +to the PRUSS platform driver to allow client drivers to acquire and release +the common memory resources present within a PRU-ICSS subsystem. This +allows the client drivers to directly manipulate the respective memories, +as per their design contract with the associated firmware. + +Co-developed-by: Suman Anna +Signed-off-by: Suman Anna +Signed-off-by: "Andrew F. Davis" +Co-developed-by: Grzegorz Jaszczyk +Signed-off-by: Grzegorz Jaszczyk +Reviewed-by: Roger Quadros +Acked-by: Mathieu Poirier +Reviewed-by: Tony Lindgren +Reviewed-by: Simon Horman +Signed-off-by: MD Danish Anwar +[Commit b789ca1e3380 upstream] +--- + drivers/soc/ti/pruss.c | 77 ++++++++++++++++++++++++++++++++++++ + include/linux/pruss_driver.h | 22 +++++++++++ + 2 files changed, 99 insertions(+) + +diff --git a/drivers/soc/ti/pruss.c b/drivers/soc/ti/pruss.c +index 3fac92df8790..8ada3758b31a 100644 +--- a/drivers/soc/ti/pruss.c ++++ b/drivers/soc/ti/pruss.c +@@ -92,6 +92,82 @@ void pruss_put(struct pruss *pruss) + } + EXPORT_SYMBOL_GPL(pruss_put); + ++/** ++ * pruss_request_mem_region() - request a memory resource ++ * @pruss: the pruss instance ++ * @mem_id: the memory resource id ++ * @region: pointer to memory region structure to be filled in ++ * ++ * This function allows a client driver to request a memory resource, ++ * and if successful, will let the client driver own the particular ++ * memory region until released using the pruss_release_mem_region() ++ * API. ++ * ++ * Return: 0 if requested memory region is available (in such case pointer to ++ * memory region is returned via @region), an error otherwise ++ */ ++int pruss_request_mem_region(struct pruss *pruss, enum pruss_mem mem_id, ++ struct pruss_mem_region *region) ++{ ++ if (!pruss || !region || mem_id >= PRUSS_MEM_MAX) ++ return -EINVAL; ++ ++ mutex_lock(&pruss->lock); ++ ++ if (pruss->mem_in_use[mem_id]) { ++ mutex_unlock(&pruss->lock); ++ return -EBUSY; ++ } ++ ++ *region = pruss->mem_regions[mem_id]; ++ pruss->mem_in_use[mem_id] = region; ++ ++ mutex_unlock(&pruss->lock); ++ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(pruss_request_mem_region); ++ ++/** ++ * pruss_release_mem_region() - release a memory resource ++ * @pruss: the pruss instance ++ * @region: the memory region to release ++ * ++ * This function is the complimentary function to ++ * pruss_request_mem_region(), and allows the client drivers to ++ * release back a memory resource. ++ * ++ * Return: 0 on success, an error code otherwise ++ */ ++int pruss_release_mem_region(struct pruss *pruss, ++ struct pruss_mem_region *region) ++{ ++ int id; ++ ++ if (!pruss || !region) ++ return -EINVAL; ++ ++ mutex_lock(&pruss->lock); ++ ++ /* find out the memory region being released */ ++ for (id = 0; id < PRUSS_MEM_MAX; id++) { ++ if (pruss->mem_in_use[id] == region) ++ break; ++ } ++ ++ if (id == PRUSS_MEM_MAX) { ++ mutex_unlock(&pruss->lock); ++ return -EINVAL; ++ } ++ ++ pruss->mem_in_use[id] = NULL; ++ ++ mutex_unlock(&pruss->lock); ++ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(pruss_release_mem_region); ++ + static void pruss_of_free_clk_provider(void *data) + { + struct device_node *clk_mux_np = data; +@@ -294,6 +370,7 @@ static int pruss_probe(struct platform_device *pdev) + return -ENOMEM; + + pruss->dev = dev; ++ mutex_init(&pruss->lock); + + child = of_get_child_by_name(np, "memories"); + if (!child) { +diff --git a/include/linux/pruss_driver.h b/include/linux/pruss_driver.h +index cb40c2b31045..c8f2e53b911b 100644 +--- a/include/linux/pruss_driver.h ++++ b/include/linux/pruss_driver.h +@@ -9,6 +9,7 @@ + #ifndef _PRUSS_DRIVER_H_ + #define _PRUSS_DRIVER_H_ + ++#include + #include + #include + #include +@@ -41,6 +42,8 @@ struct pruss_mem_region { + * @cfg_base: base iomap for CFG region + * @cfg_regmap: regmap for config region + * @mem_regions: data for each of the PRUSS memory regions ++ * @mem_in_use: to indicate if memory resource is in use ++ * @lock: mutex to serialize access to resources + * @core_clk_mux: clk handle for PRUSS CORE_CLK_MUX + * @iep_clk_mux: clk handle for PRUSS IEP_CLK_MUX + */ +@@ -49,6 +52,8 @@ struct pruss { + void __iomem *cfg_base; + struct regmap *cfg_regmap; + struct pruss_mem_region mem_regions[PRUSS_MEM_MAX]; ++ struct pruss_mem_region *mem_in_use[PRUSS_MEM_MAX]; ++ struct mutex lock; /* PRU resource lock */ + struct clk *core_clk_mux; + struct clk *iep_clk_mux; + }; +@@ -57,6 +62,10 @@ struct pruss { + + struct pruss *pruss_get(struct rproc *rproc); + void pruss_put(struct pruss *pruss); ++int pruss_request_mem_region(struct pruss *pruss, enum pruss_mem mem_id, ++ struct pruss_mem_region *region); ++int pruss_release_mem_region(struct pruss *pruss, ++ struct pruss_mem_region *region); + + #else + +@@ -67,6 +76,19 @@ static inline struct pruss *pruss_get(struct rproc *rproc) + + static inline void pruss_put(struct pruss *pruss) { } + ++static inline int pruss_request_mem_region(struct pruss *pruss, ++ enum pruss_mem mem_id, ++ struct pruss_mem_region *region) ++{ ++ return -EOPNOTSUPP; ++} ++ ++static inline int pruss_release_mem_region(struct pruss *pruss, ++ struct pruss_mem_region *region) ++{ ++ return -EOPNOTSUPP; ++} ++ + #endif /* CONFIG_TI_PRUSS */ + + #endif /* _PRUSS_DRIVER_H_ */ +-- +2.42.0 + diff --git a/recipes-kernel/linux/files/patches-6.1/0013-soc-ti-pruss-Add-pruss_cfg_read-update-pruss_cfg_get.patch b/recipes-kernel/linux/files/patches-6.1/0013-soc-ti-pruss-Add-pruss_cfg_read-update-pruss_cfg_get.patch new file mode 100644 index 000000000..f952f8a2a --- /dev/null +++ b/recipes-kernel/linux/files/patches-6.1/0013-soc-ti-pruss-Add-pruss_cfg_read-update-pruss_cfg_get.patch @@ -0,0 +1,252 @@ +From caf605480dbca628d9dad74f6e9033c93420d607 Mon Sep 17 00:00:00 2001 +From: Suman Anna +Date: Fri, 14 Apr 2023 10:25:41 +0530 +Subject: [PATCH 13/69] soc: ti: pruss: Add pruss_cfg_read()/update(), + pruss_cfg_get_gpmux()/set_gpmux() APIs + +Add two new generic API pruss_cfg_read() and pruss_cfg_update() to +the PRUSS platform driver to read and program respectively a register +within the PRUSS CFG sub-module represented by a syscon driver. These +APIs are internal to PRUSS driver. + +Add two new helper functions pruss_cfg_get_gpmux() & pruss_cfg_set_gpmux() +to get and set the GP MUX mode for programming the PRUSS internal wrapper +mux functionality as needed by usecases. + +Various useful registers and macros for certain register bit-fields and +their values have also been added. + +Signed-off-by: Suman Anna +Co-developed-by: Grzegorz Jaszczyk +Signed-off-by: Grzegorz Jaszczyk +Signed-off-by: Puranjay Mohan +Reviewed-by: Roger Quadros +Reviewed-by: Tony Lindgren +Reviewed-by: Simon Horman +Acked-by: Mathieu Poirier +Signed-off-by: MD Danish Anwar +[Commit 51b5760e56ef upstream] +--- + drivers/soc/ti/pruss.c | 45 ++++++++++++++++++ + drivers/soc/ti/pruss.h | 88 ++++++++++++++++++++++++++++++++++++ + include/linux/pruss_driver.h | 32 +++++++++++++ + 3 files changed, 165 insertions(+) + create mode 100644 drivers/soc/ti/pruss.h + +diff --git a/drivers/soc/ti/pruss.c b/drivers/soc/ti/pruss.c +index 8ada3758b31a..4ad6ccb039c8 100644 +--- a/drivers/soc/ti/pruss.c ++++ b/drivers/soc/ti/pruss.c +@@ -21,6 +21,7 @@ + #include + #include + #include ++#include "pruss.h" + + /** + * struct pruss_private_data - PRUSS driver private data +@@ -168,6 +169,50 @@ int pruss_release_mem_region(struct pruss *pruss, + } + EXPORT_SYMBOL_GPL(pruss_release_mem_region); + ++/** ++ * pruss_cfg_get_gpmux() - get the current GPMUX value for a PRU device ++ * @pruss: pruss instance ++ * @pru_id: PRU identifier (0-1) ++ * @mux: pointer to store the current mux value into ++ * ++ * Return: 0 on success, or an error code otherwise ++ */ ++int pruss_cfg_get_gpmux(struct pruss *pruss, enum pruss_pru_id pru_id, u8 *mux) ++{ ++ int ret; ++ u32 val; ++ ++ if (pru_id >= PRUSS_NUM_PRUS || !mux) ++ return -EINVAL; ++ ++ ret = pruss_cfg_read(pruss, PRUSS_CFG_GPCFG(pru_id), &val); ++ if (!ret) ++ *mux = (u8)((val & PRUSS_GPCFG_PRU_MUX_SEL_MASK) >> ++ PRUSS_GPCFG_PRU_MUX_SEL_SHIFT); ++ return ret; ++} ++EXPORT_SYMBOL_GPL(pruss_cfg_get_gpmux); ++ ++/** ++ * pruss_cfg_set_gpmux() - set the GPMUX value for a PRU device ++ * @pruss: pruss instance ++ * @pru_id: PRU identifier (0-1) ++ * @mux: new mux value for PRU ++ * ++ * Return: 0 on success, or an error code otherwise ++ */ ++int pruss_cfg_set_gpmux(struct pruss *pruss, enum pruss_pru_id pru_id, u8 mux) ++{ ++ if (mux >= PRUSS_GP_MUX_SEL_MAX || ++ pru_id >= PRUSS_NUM_PRUS) ++ return -EINVAL; ++ ++ return pruss_cfg_update(pruss, PRUSS_CFG_GPCFG(pru_id), ++ PRUSS_GPCFG_PRU_MUX_SEL_MASK, ++ (u32)mux << PRUSS_GPCFG_PRU_MUX_SEL_SHIFT); ++} ++EXPORT_SYMBOL_GPL(pruss_cfg_set_gpmux); ++ + static void pruss_of_free_clk_provider(void *data) + { + struct device_node *clk_mux_np = data; +diff --git a/drivers/soc/ti/pruss.h b/drivers/soc/ti/pruss.h +new file mode 100644 +index 000000000000..6c55987e0e55 +--- /dev/null ++++ b/drivers/soc/ti/pruss.h +@@ -0,0 +1,88 @@ ++/* SPDX-License-Identifier: GPL-2.0-only */ ++/* ++ * PRU-ICSS Subsystem user interfaces ++ * ++ * Copyright (C) 2015-2023 Texas Instruments Incorporated - http://www.ti.com ++ * MD Danish Anwar ++ */ ++ ++#ifndef _SOC_TI_PRUSS_H_ ++#define _SOC_TI_PRUSS_H_ ++ ++#include ++#include ++ ++/* ++ * PRU_ICSS_CFG registers ++ * SYSCFG, ISRP, ISP, IESP, IECP, SCRP applicable on AMxxxx devices only ++ */ ++#define PRUSS_CFG_REVID 0x00 ++#define PRUSS_CFG_SYSCFG 0x04 ++#define PRUSS_CFG_GPCFG(x) (0x08 + (x) * 4) ++#define PRUSS_CFG_CGR 0x10 ++#define PRUSS_CFG_ISRP 0x14 ++#define PRUSS_CFG_ISP 0x18 ++#define PRUSS_CFG_IESP 0x1C ++#define PRUSS_CFG_IECP 0x20 ++#define PRUSS_CFG_SCRP 0x24 ++#define PRUSS_CFG_PMAO 0x28 ++#define PRUSS_CFG_MII_RT 0x2C ++#define PRUSS_CFG_IEPCLK 0x30 ++#define PRUSS_CFG_SPP 0x34 ++#define PRUSS_CFG_PIN_MX 0x40 ++ ++/* PRUSS_GPCFG register bits */ ++#define PRUSS_GPCFG_PRU_GPI_MODE_MASK GENMASK(1, 0) ++#define PRUSS_GPCFG_PRU_GPI_MODE_SHIFT 0 ++ ++#define PRUSS_GPCFG_PRU_MUX_SEL_SHIFT 26 ++#define PRUSS_GPCFG_PRU_MUX_SEL_MASK GENMASK(29, 26) ++ ++/* PRUSS_MII_RT register bits */ ++#define PRUSS_MII_RT_EVENT_EN BIT(0) ++ ++/* PRUSS_SPP register bits */ ++#define PRUSS_SPP_XFER_SHIFT_EN BIT(1) ++#define PRUSS_SPP_PRU1_PAD_HP_EN BIT(0) ++#define PRUSS_SPP_RTU_XFR_SHIFT_EN BIT(3) ++ ++/** ++ * pruss_cfg_read() - read a PRUSS CFG sub-module register ++ * @pruss: the pruss instance handle ++ * @reg: register offset within the CFG sub-module ++ * @val: pointer to return the value in ++ * ++ * Reads a given register within the PRUSS CFG sub-module and ++ * returns it through the passed-in @val pointer ++ * ++ * Return: 0 on success, or an error code otherwise ++ */ ++static int pruss_cfg_read(struct pruss *pruss, unsigned int reg, unsigned int *val) ++{ ++ if (IS_ERR_OR_NULL(pruss)) ++ return -EINVAL; ++ ++ return regmap_read(pruss->cfg_regmap, reg, val); ++} ++ ++/** ++ * pruss_cfg_update() - configure a PRUSS CFG sub-module register ++ * @pruss: the pruss instance handle ++ * @reg: register offset within the CFG sub-module ++ * @mask: bit mask to use for programming the @val ++ * @val: value to write ++ * ++ * Programs a given register within the PRUSS CFG sub-module ++ * ++ * Return: 0 on success, or an error code otherwise ++ */ ++static int pruss_cfg_update(struct pruss *pruss, unsigned int reg, ++ unsigned int mask, unsigned int val) ++{ ++ if (IS_ERR_OR_NULL(pruss)) ++ return -EINVAL; ++ ++ return regmap_update_bits(pruss->cfg_regmap, reg, mask, val); ++} ++ ++#endif /* _SOC_TI_PRUSS_H_ */ +diff --git a/include/linux/pruss_driver.h b/include/linux/pruss_driver.h +index c8f2e53b911b..5bb8897724a9 100644 +--- a/include/linux/pruss_driver.h ++++ b/include/linux/pruss_driver.h +@@ -14,6 +14,24 @@ + #include + #include + ++/* ++ * enum pruss_gp_mux_sel - PRUSS GPI/O Mux modes for the ++ * PRUSS_GPCFG0/1 registers ++ * ++ * NOTE: The below defines are the most common values, but there ++ * are some exceptions like on 66AK2G, where the RESERVED and MII2 ++ * values are interchanged. Also, this bit-field does not exist on ++ * AM335x SoCs ++ */ ++enum pruss_gp_mux_sel { ++ PRUSS_GP_MUX_SEL_GP, ++ PRUSS_GP_MUX_SEL_ENDAT, ++ PRUSS_GP_MUX_SEL_RESERVED, ++ PRUSS_GP_MUX_SEL_SD, ++ PRUSS_GP_MUX_SEL_MII2, ++ PRUSS_GP_MUX_SEL_MAX, ++}; ++ + /* + * enum pruss_mem - PRUSS memory range identifiers + */ +@@ -66,6 +84,8 @@ int pruss_request_mem_region(struct pruss *pruss, enum pruss_mem mem_id, + struct pruss_mem_region *region); + int pruss_release_mem_region(struct pruss *pruss, + struct pruss_mem_region *region); ++int pruss_cfg_get_gpmux(struct pruss *pruss, enum pruss_pru_id pru_id, u8 *mux); ++int pruss_cfg_set_gpmux(struct pruss *pruss, enum pruss_pru_id pru_id, u8 mux); + + #else + +@@ -89,6 +109,18 @@ static inline int pruss_release_mem_region(struct pruss *pruss, + return -EOPNOTSUPP; + } + ++static inline int pruss_cfg_get_gpmux(struct pruss *pruss, ++ enum pruss_pru_id pru_id, u8 *mux) ++{ ++ return ERR_PTR(-EOPNOTSUPP); ++} ++ ++static inline int pruss_cfg_set_gpmux(struct pruss *pruss, ++ enum pruss_pru_id pru_id, u8 mux) ++{ ++ return ERR_PTR(-EOPNOTSUPP); ++} ++ + #endif /* CONFIG_TI_PRUSS */ + + #endif /* _PRUSS_DRIVER_H_ */ +-- +2.42.0 + diff --git a/recipes-kernel/linux/files/patches-6.1/0014-soc-ti-pruss-Add-helper-functions-to-set-GPI-mode-MI.patch b/recipes-kernel/linux/files/patches-6.1/0014-soc-ti-pruss-Add-helper-functions-to-set-GPI-mode-MI.patch new file mode 100644 index 000000000..7444f1b80 --- /dev/null +++ b/recipes-kernel/linux/files/patches-6.1/0014-soc-ti-pruss-Add-helper-functions-to-set-GPI-mode-MI.patch @@ -0,0 +1,215 @@ +From 2456e5083476f968649271c58a2d2b657ee0e77a Mon Sep 17 00:00:00 2001 +From: Suman Anna +Date: Fri, 14 Apr 2023 10:25:42 +0530 +Subject: [PATCH 14/69] soc: ti: pruss: Add helper functions to set GPI mode, + MII_RT_event and XFR + +The PRUSS CFG module is represented as a syscon node and is currently +managed by the PRUSS platform driver. Add easy accessor functions to set +GPI mode, MII_RT event enable/disable and XFR (XIN XOUT) enable/disable +to enable the PRUSS Ethernet usecase. These functions reuse the generic +pruss_cfg_update() API function. + +Signed-off-by: Suman Anna +Co-developed-by: Grzegorz Jaszczyk +Signed-off-by: Grzegorz Jaszczyk +Signed-off-by: Puranjay Mohan +Reviewed-by: Roger Quadros +Reviewed-by: Tony Lindgren +Reviewed-by: Simon Horman +Reviewed-by: Mathieu Poirier +Signed-off-by: MD Danish Anwar +[Commit 0211cc1e4fbb upstream] +--- + drivers/remoteproc/pru_rproc.c | 15 ------- + drivers/soc/ti/pruss.c | 71 ++++++++++++++++++++++++++++++++++ + include/linux/pruss_driver.h | 51 ++++++++++++++++++++++++ + 3 files changed, 122 insertions(+), 15 deletions(-) + +diff --git a/drivers/remoteproc/pru_rproc.c b/drivers/remoteproc/pru_rproc.c +index b76db7fa693d..40fc8a7bf14b 100644 +--- a/drivers/remoteproc/pru_rproc.c ++++ b/drivers/remoteproc/pru_rproc.c +@@ -81,21 +81,6 @@ enum pru_iomem { + PRU_IOMEM_MAX, + }; + +-/** +- * enum pru_type - PRU core type identifier +- * +- * @PRU_TYPE_PRU: Programmable Real-time Unit +- * @PRU_TYPE_RTU: Auxiliary Programmable Real-Time Unit +- * @PRU_TYPE_TX_PRU: Transmit Programmable Real-Time Unit +- * @PRU_TYPE_MAX: just keep this one at the end +- */ +-enum pru_type { +- PRU_TYPE_PRU = 0, +- PRU_TYPE_RTU, +- PRU_TYPE_TX_PRU, +- PRU_TYPE_MAX, +-}; +- + /** + * struct pru_private_data - device data for a PRU core + * @type: type of the PRU core (PRU, RTU, Tx_PRU) +diff --git a/drivers/soc/ti/pruss.c b/drivers/soc/ti/pruss.c +index 4ad6ccb039c8..f002fd9e79c6 100644 +--- a/drivers/soc/ti/pruss.c ++++ b/drivers/soc/ti/pruss.c +@@ -213,6 +213,77 @@ int pruss_cfg_set_gpmux(struct pruss *pruss, enum pruss_pru_id pru_id, u8 mux) + } + EXPORT_SYMBOL_GPL(pruss_cfg_set_gpmux); + ++/** ++ * pruss_cfg_gpimode() - set the GPI mode of the PRU ++ * @pruss: the pruss instance handle ++ * @pru_id: id of the PRU core within the PRUSS ++ * @mode: GPI mode to set ++ * ++ * Sets the GPI mode for a given PRU by programming the ++ * corresponding PRUSS_CFG_GPCFGx register ++ * ++ * Return: 0 on success, or an error code otherwise ++ */ ++int pruss_cfg_gpimode(struct pruss *pruss, enum pruss_pru_id pru_id, ++ enum pruss_gpi_mode mode) ++{ ++ if (pru_id >= PRUSS_NUM_PRUS || mode >= PRUSS_GPI_MODE_MAX) ++ return -EINVAL; ++ ++ return pruss_cfg_update(pruss, PRUSS_CFG_GPCFG(pru_id), ++ PRUSS_GPCFG_PRU_GPI_MODE_MASK, ++ mode << PRUSS_GPCFG_PRU_GPI_MODE_SHIFT); ++} ++EXPORT_SYMBOL_GPL(pruss_cfg_gpimode); ++ ++/** ++ * pruss_cfg_miirt_enable() - Enable/disable MII RT Events ++ * @pruss: the pruss instance ++ * @enable: enable/disable ++ * ++ * Enable/disable the MII RT Events for the PRUSS. ++ * ++ * Return: 0 on success, or an error code otherwise ++ */ ++int pruss_cfg_miirt_enable(struct pruss *pruss, bool enable) ++{ ++ u32 set = enable ? PRUSS_MII_RT_EVENT_EN : 0; ++ ++ return pruss_cfg_update(pruss, PRUSS_CFG_MII_RT, ++ PRUSS_MII_RT_EVENT_EN, set); ++} ++EXPORT_SYMBOL_GPL(pruss_cfg_miirt_enable); ++ ++/** ++ * pruss_cfg_xfr_enable() - Enable/disable XIN XOUT shift functionality ++ * @pruss: the pruss instance ++ * @pru_type: PRU core type identifier ++ * @enable: enable/disable ++ * ++ * Return: 0 on success, or an error code otherwise ++ */ ++int pruss_cfg_xfr_enable(struct pruss *pruss, enum pru_type pru_type, ++ bool enable) ++{ ++ u32 mask, set; ++ ++ switch (pru_type) { ++ case PRU_TYPE_PRU: ++ mask = PRUSS_SPP_XFER_SHIFT_EN; ++ break; ++ case PRU_TYPE_RTU: ++ mask = PRUSS_SPP_RTU_XFR_SHIFT_EN; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ set = enable ? mask : 0; ++ ++ return pruss_cfg_update(pruss, PRUSS_CFG_SPP, mask, set); ++} ++EXPORT_SYMBOL_GPL(pruss_cfg_xfr_enable); ++ + static void pruss_of_free_clk_provider(void *data) + { + struct device_node *clk_mux_np = data; +diff --git a/include/linux/pruss_driver.h b/include/linux/pruss_driver.h +index 5bb8897724a9..c9a31c567e85 100644 +--- a/include/linux/pruss_driver.h ++++ b/include/linux/pruss_driver.h +@@ -32,6 +32,33 @@ enum pruss_gp_mux_sel { + PRUSS_GP_MUX_SEL_MAX, + }; + ++/* ++ * enum pruss_gpi_mode - PRUSS GPI configuration modes, used ++ * to program the PRUSS_GPCFG0/1 registers ++ */ ++enum pruss_gpi_mode { ++ PRUSS_GPI_MODE_DIRECT, ++ PRUSS_GPI_MODE_PARALLEL, ++ PRUSS_GPI_MODE_28BIT_SHIFT, ++ PRUSS_GPI_MODE_MII, ++ PRUSS_GPI_MODE_MAX, ++}; ++ ++/** ++ * enum pru_type - PRU core type identifier ++ * ++ * @PRU_TYPE_PRU: Programmable Real-time Unit ++ * @PRU_TYPE_RTU: Auxiliary Programmable Real-Time Unit ++ * @PRU_TYPE_TX_PRU: Transmit Programmable Real-Time Unit ++ * @PRU_TYPE_MAX: just keep this one at the end ++ */ ++enum pru_type { ++ PRU_TYPE_PRU, ++ PRU_TYPE_RTU, ++ PRU_TYPE_TX_PRU, ++ PRU_TYPE_MAX, ++}; ++ + /* + * enum pruss_mem - PRUSS memory range identifiers + */ +@@ -86,6 +113,11 @@ int pruss_release_mem_region(struct pruss *pruss, + struct pruss_mem_region *region); + int pruss_cfg_get_gpmux(struct pruss *pruss, enum pruss_pru_id pru_id, u8 *mux); + int pruss_cfg_set_gpmux(struct pruss *pruss, enum pruss_pru_id pru_id, u8 mux); ++int pruss_cfg_gpimode(struct pruss *pruss, enum pruss_pru_id pru_id, ++ enum pruss_gpi_mode mode); ++int pruss_cfg_miirt_enable(struct pruss *pruss, bool enable); ++int pruss_cfg_xfr_enable(struct pruss *pruss, enum pru_type pru_type, ++ bool enable); + + #else + +@@ -121,6 +153,25 @@ static inline int pruss_cfg_set_gpmux(struct pruss *pruss, + return ERR_PTR(-EOPNOTSUPP); + } + ++static inline int pruss_cfg_gpimode(struct pruss *pruss, ++ enum pruss_pru_id pru_id, ++ enum pruss_gpi_mode mode) ++{ ++ return ERR_PTR(-EOPNOTSUPP); ++} ++ ++static inline int pruss_cfg_miirt_enable(struct pruss *pruss, bool enable) ++{ ++ return ERR_PTR(-EOPNOTSUPP); ++} ++ ++static inline int pruss_cfg_xfr_enable(struct pruss *pruss, ++ enum pru_type pru_type, ++ bool enable); ++{ ++ return ERR_PTR(-EOPNOTSUPP); ++} ++ + #endif /* CONFIG_TI_PRUSS */ + + #endif /* _PRUSS_DRIVER_H_ */ +-- +2.42.0 + diff --git a/recipes-kernel/linux/files/patches-6.1/0015-remoteproc-pru-add-support-for-configuring-GPMUX-bas.patch b/recipes-kernel/linux/files/patches-6.1/0015-remoteproc-pru-add-support-for-configuring-GPMUX-bas.patch new file mode 100644 index 000000000..65bb7a794 --- /dev/null +++ b/recipes-kernel/linux/files/patches-6.1/0015-remoteproc-pru-add-support-for-configuring-GPMUX-bas.patch @@ -0,0 +1,81 @@ +From 33d23e5a06eeb523ef763dd4bb43053e12cd438c Mon Sep 17 00:00:00 2001 +From: Tero Kristo +Date: Wed, 2 Aug 2023 12:19:25 +0530 +Subject: [PATCH 15/69] remoteproc: pru: add support for configuring GPMUX + based on client setup + +The GPMUX config value for a PRU device can now be configured by client +by specifying it in the device node ti,pruss-gp-mux-sel. + +Signed-off-by: Tero Kristo +Signed-off-by: Suman Anna +Signed-off-by: MD Danish Anwar +[Commit 18cf4fcd7bdc upstream] +--- + drivers/remoteproc/pru_rproc.c | 22 ++++++++++++++++++++++ + 1 file changed, 22 insertions(+) + +diff --git a/drivers/remoteproc/pru_rproc.c b/drivers/remoteproc/pru_rproc.c +index 40fc8a7bf14b..a312a8bfdb86 100644 +--- a/drivers/remoteproc/pru_rproc.c ++++ b/drivers/remoteproc/pru_rproc.c +@@ -109,6 +109,7 @@ struct pru_private_data { + * @dbg_single_step: debug state variable to set PRU into single step mode + * @dbg_continuous: debug state variable to restore PRU execution mode + * @evt_count: number of mapped events ++ * @gpmux_save: saved value for gpmux config + */ + struct pru_rproc { + int id; +@@ -127,6 +128,7 @@ struct pru_rproc { + u32 dbg_single_step; + u32 dbg_continuous; + u8 evt_count; ++ u8 gpmux_save; + }; + + static inline u32 pru_control_read_reg(struct pru_rproc *pru, unsigned int reg) +@@ -228,6 +230,7 @@ struct rproc *pru_rproc_get(struct device_node *np, int index, + struct device *dev; + const char *fw_name; + int ret; ++ u32 mux; + + rproc = __pru_rproc_get(np, index); + if (IS_ERR(rproc)) +@@ -252,6 +255,23 @@ struct rproc *pru_rproc_get(struct device_node *np, int index, + if (pru_id) + *pru_id = pru->id; + ++ ret = pruss_cfg_get_gpmux(pru->pruss, pru->id, &pru->gpmux_save); ++ if (ret) { ++ dev_err(dev, "failed to get cfg gpmux: %d\n", ret); ++ goto err; ++ } ++ ++ /* An error here is acceptable for backward compatibility */ ++ ret = of_property_read_u32_index(np, "ti,pruss-gp-mux-sel", index, ++ &mux); ++ if (!ret) { ++ ret = pruss_cfg_set_gpmux(pru->pruss, pru->id, mux); ++ if (ret) { ++ dev_err(dev, "failed to set cfg gpmux: %d\n", ret); ++ goto err; ++ } ++ } ++ + ret = of_property_read_string_index(np, "firmware-name", index, + &fw_name); + if (!ret) { +@@ -290,6 +310,8 @@ void pru_rproc_put(struct rproc *rproc) + + pru = rproc->priv; + ++ pruss_cfg_set_gpmux(pru->pruss, pru->id, pru->gpmux_save); ++ + pru_rproc_set_firmware(rproc, NULL); + + mutex_lock(&pru->lock); +-- +2.42.0 + diff --git a/recipes-kernel/linux/files/patches-6.1/0016-net-ti-icssg-prueth-Add-Firmware-Interface-for-ICSSG.patch b/recipes-kernel/linux/files/patches-6.1/0016-net-ti-icssg-prueth-Add-Firmware-Interface-for-ICSSG.patch new file mode 100644 index 000000000..b588ec55d --- /dev/null +++ b/recipes-kernel/linux/files/patches-6.1/0016-net-ti-icssg-prueth-Add-Firmware-Interface-for-ICSSG.patch @@ -0,0 +1,260 @@ +From 4fa62bfffd4c3dd7074ae31c3d5dfab8c87655b1 Mon Sep 17 00:00:00 2001 +From: MD Danish Anwar +Date: Tue, 1 Aug 2023 14:44:19 +0530 +Subject: [PATCH 16/69] net: ti: icssg-prueth: Add Firmware Interface for ICSSG + Ethernet driver. + +Add firmware interface related headers and macros for ICSSG Ethernet +driver. These macros will be later used by the ICSSG ethernet driver. + +Reviewed-by: Andrew Lunn +Signed-off-by: MD Danish Anwar +[Commit 61f4d2044aeb upstream] +--- + .../net/ethernet/ti/icssg/icssg_switch_map.h | 234 ++++++++++++++++++ + 1 file changed, 234 insertions(+) + create mode 100644 drivers/net/ethernet/ti/icssg/icssg_switch_map.h + +diff --git a/drivers/net/ethernet/ti/icssg/icssg_switch_map.h b/drivers/net/ethernet/ti/icssg/icssg_switch_map.h +new file mode 100644 +index 000000000000..424a7e945ea8 +--- /dev/null ++++ b/drivers/net/ethernet/ti/icssg/icssg_switch_map.h +@@ -0,0 +1,234 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* Texas Instruments ICSSG Ethernet driver ++ * ++ * Copyright (C) 2022 Texas Instruments Incorporated - https://www.ti.com/ ++ * ++ */ ++ ++#ifndef __NET_TI_ICSSG_SWITCH_MAP_H ++#define __NET_TI_ICSSG_SWITCH_MAP_H ++ ++/************************* Ethernet Switch Constants *********************/ ++ ++/* if bucket size is changed in firmware then this too should be changed ++ * because it directly impacts FDB ageing calculation ++ */ ++#define NUMBER_OF_FDB_BUCKET_ENTRIES (4) ++ ++/* This is fixed in ICSSG */ ++#define SIZE_OF_FDB (2048) ++ ++#define FW_LINK_SPEED_1G (0x00) ++#define FW_LINK_SPEED_100M (0x01) ++#define FW_LINK_SPEED_10M (0x02) ++#define FW_LINK_SPEED_HD (0x80) ++ ++/* Time after which FDB entries are checked for aged out values. ++ * Values are in nanoseconds ++ */ ++#define FDB_AGEING_TIMEOUT_OFFSET 0x0014 ++ ++/* Default VLAN tag for Host Port */ ++#define HOST_PORT_DF_VLAN_OFFSET 0x001C ++ ++/* Same as HOST_PORT_DF_VLAN_OFFSET */ ++#define EMAC_ICSSG_SWITCH_PORT0_DEFAULT_VLAN_OFFSET HOST_PORT_DF_VLAN_OFFSET ++ ++/* Default VLAN tag for P1 Port */ ++#define P1_PORT_DF_VLAN_OFFSET 0x0020 ++ ++/* Same as P1_PORT_DF_VLAN_OFFSET */ ++#define EMAC_ICSSG_SWITCH_PORT1_DEFAULT_VLAN_OFFSET P1_PORT_DF_VLAN_OFFSET ++ ++/* default VLAN tag for P2 Port */ ++#define P2_PORT_DF_VLAN_OFFSET 0x0024 ++ ++/* Same as P2_PORT_DF_VLAN_OFFSET */ ++#define EMAC_ICSSG_SWITCH_PORT2_DEFAULT_VLAN_OFFSET P2_PORT_DF_VLAN_OFFSET ++ ++/* VLAN-FID Table offset. 4096 VIDs. 2B per VID = 8KB = 0x2000 */ ++#define VLAN_STATIC_REG_TABLE_OFFSET 0x0100 ++ ++/* VLAN-FID Table offset for EMAC */ ++#define EMAC_ICSSG_SWITCH_DEFAULT_VLAN_TABLE_OFFSET VLAN_STATIC_REG_TABLE_OFFSET ++ ++/* Packet descriptor Q reserved memory */ ++#define PORT_DESC0_HI 0x2104 ++ ++/* Packet descriptor Q reserved memory */ ++#define PORT_DESC0_LO 0x2F6C ++ ++/* Packet descriptor Q reserved memory */ ++#define PORT_DESC1_HI 0x3DD4 ++ ++/* Packet descriptor Q reserved memory */ ++#define PORT_DESC1_LO 0x4C3C ++ ++/* Packet descriptor Q reserved memory */ ++#define HOST_DESC0_HI 0x5AA4 ++ ++/* Packet descriptor Q reserved memory */ ++#define HOST_DESC0_LO 0x5F0C ++ ++/* Packet descriptor Q reserved memory */ ++#define HOST_DESC1_HI 0x6374 ++ ++/* Packet descriptor Q reserved memory */ ++#define HOST_DESC1_LO 0x67DC ++ ++/* Special packet descriptor Q reserved memory */ ++#define HOST_SPPD0 0x7AAC ++ ++/* Special acket descriptor Q reserved memory */ ++#define HOST_SPPD1 0x7EAC ++ ++/* IEP count cycle counter*/ ++#define TIMESYNC_FW_WC_CYCLECOUNT_OFFSET 0x83EC ++ ++/* IEP count hi roll over count */ ++#define TIMESYNC_FW_WC_HI_ROLLOVER_COUNT_OFFSET 0x83F4 ++ ++/* IEP count hi sw counter */ ++#define TIMESYNC_FW_WC_COUNT_HI_SW_OFFSET_OFFSET 0x83F8 ++ ++/* Set clock descriptor */ ++#define TIMESYNC_FW_WC_SETCLOCK_DESC_OFFSET 0x83FC ++ ++/* IEP count syncout reduction factor */ ++#define TIMESYNC_FW_WC_SYNCOUT_REDUCTION_FACTOR_OFFSET 0x843C ++ ++/* IEP count syncout reduction counter */ ++#define TIMESYNC_FW_WC_SYNCOUT_REDUCTION_COUNT_OFFSET 0x8440 ++ ++/* IEP count syncout start time cycle counter */ ++#define TIMESYNC_FW_WC_SYNCOUT_START_TIME_CYCLECOUNT_OFFSET 0x8444 ++ ++/* Control variable to generate SYNC1 */ ++#define TIMESYNC_FW_WC_ISOM_PIN_SIGNAL_EN_OFFSET 0x844C ++ ++/* SystemTime Sync0 periodicity */ ++#define TIMESYNC_FW_ST_SYNCOUT_PERIOD_OFFSET 0x8450 ++ ++/* pktTxDelay for P1 = link speed dependent p1 mac delay + p1 phy delay */ ++#define TIMESYNC_FW_WC_PKTTXDELAY_P1_OFFSET 0x8454 ++ ++/* pktTxDelay for P2 = link speed dependent p2 mac delay + p2 phy delay */ ++#define TIMESYNC_FW_WC_PKTTXDELAY_P2_OFFSET 0x8458 ++ ++/* Set clock operation done signal for next task */ ++#define TIMESYNC_FW_SIG_PNFW_OFFSET 0x845C ++ ++/* Set clock operation done signal for next task */ ++#define TIMESYNC_FW_SIG_TIMESYNCFW_OFFSET 0x8460 ++ ++/* New list is copied at this time */ ++#define TAS_CONFIG_CHANGE_TIME 0x000C ++ ++/* config change error counter */ ++#define TAS_CONFIG_CHANGE_ERROR_COUNTER 0x0014 ++ ++/* TAS List update pending flag */ ++#define TAS_CONFIG_PENDING 0x0018 ++ ++/* TAS list update trigger flag */ ++#define TAS_CONFIG_CHANGE 0x0019 ++ ++/* List length for new TAS schedule */ ++#define TAS_ADMIN_LIST_LENGTH 0x001A ++ ++/* Currently active TAS list index */ ++#define TAS_ACTIVE_LIST_INDEX 0x001B ++ ++/* Cycle time for the new TAS schedule */ ++#define TAS_ADMIN_CYCLE_TIME 0x001C ++ ++/* Cycle counts remaining till the TAS list update */ ++#define TAS_CONFIG_CHANGE_CYCLE_COUNT 0x0020 ++ ++/* Base Flow ID for sending Packets to Host for Slice0 */ ++#define PSI_L_REGULAR_FLOW_ID_BASE_OFFSET 0x0024 ++ ++/* Same as PSI_L_REGULAR_FLOW_ID_BASE_OFFSET */ ++#define EMAC_ICSSG_SWITCH_PSI_L_REGULAR_FLOW_ID_BASE_OFFSET PSI_L_REGULAR_FLOW_ID_BASE_OFFSET ++ ++/* Base Flow ID for sending mgmt and Tx TS to Host for Slice0 */ ++#define PSI_L_MGMT_FLOW_ID_OFFSET 0x0026 ++ ++/* Same as PSI_L_MGMT_FLOW_ID_OFFSET */ ++#define EMAC_ICSSG_SWITCH_PSI_L_MGMT_FLOW_ID_BASE_OFFSET PSI_L_MGMT_FLOW_ID_OFFSET ++ ++/* Queue number for Special Packets written here */ ++#define SPL_PKT_DEFAULT_PRIORITY 0x0028 ++ ++/* Express Preemptible Queue Mask */ ++#define EXPRESS_PRE_EMPTIVE_Q_MASK 0x0029 ++ ++/* Port1/Port2 Default Queue number for untagged Packets, only 1B is used */ ++#define QUEUE_NUM_UNTAGGED 0x002A ++ ++/* Stores the table used for priority regeneration. 1B per PCP/Queue */ ++#define PORT_Q_PRIORITY_REGEN_OFFSET 0x002C ++ ++/* For marking Packet as priority/express (this feature is disabled) or ++ * cut-through/S&F. ++ */ ++#define EXPRESS_PRE_EMPTIVE_Q_MAP 0x0034 ++ ++/* Stores the table used for priority mapping. 1B per PCP/Queue */ ++#define PORT_Q_PRIORITY_MAPPING_OFFSET 0x003C ++ ++/* Used to notify the FW of the current link speed */ ++#define PORT_LINK_SPEED_OFFSET 0x00A8 ++ ++/* TAS gate mask for windows list0 */ ++#define TAS_GATE_MASK_LIST0 0x0100 ++ ++/* TAS gate mask for windows list1 */ ++#define TAS_GATE_MASK_LIST1 0x0350 ++ ++/* Memory to Enable/Disable Preemption on TX side */ ++#define PRE_EMPTION_ENABLE_TX 0x05A0 ++ ++/* Active State of Preemption on TX side */ ++#define PRE_EMPTION_ACTIVE_TX 0x05A1 ++ ++/* Memory to Enable/Disable Verify State Machine Preemption */ ++#define PRE_EMPTION_ENABLE_VERIFY 0x05A2 ++ ++/* Verify Status of State Machine */ ++#define PRE_EMPTION_VERIFY_STATUS 0x05A3 ++ ++/* Non Final Fragment Size supported by Link Partner */ ++#define PRE_EMPTION_ADD_FRAG_SIZE_REMOTE 0x05A4 ++ ++/* Non Final Fragment Size supported by Firmware */ ++#define PRE_EMPTION_ADD_FRAG_SIZE_LOCAL 0x05A6 ++ ++/* Time in ms the State machine waits for respond Packet */ ++#define PRE_EMPTION_VERIFY_TIME 0x05A8 ++ ++/* Memory used for R30 related management commands */ ++#define MGR_R30_CMD_OFFSET 0x05AC ++ ++/* HW Buffer Pool0 base address */ ++#define BUFFER_POOL_0_ADDR_OFFSET 0x05BC ++ ++/* 16B for Host Egress MSMC Q (Pre-emptible) context */ ++#define HOST_RX_Q_PRE_CONTEXT_OFFSET 0x0684 ++ ++/* Buffer for 8 FDB entries to be added by 'Add Multiple FDB entries IOCTL' */ ++#define FDB_CMD_BUFFER 0x0894 ++ ++/* TAS queue max sdu length list */ ++#define TAS_QUEUE_MAX_SDU_LIST 0x08FA ++ ++/* Used by FW to generate random number with the SEED value */ ++#define HD_RAND_SEED_OFFSET 0x0934 ++ ++/* 16B for Host Egress MSMC Q (Express) context */ ++#define HOST_RX_Q_EXP_CONTEXT_OFFSET 0x0940 ++ ++/* Start of 32 bits PA_STAT counters */ ++#define PA_STAT_32b_START_OFFSET 0x0080 ++ ++#endif /* __NET_TI_ICSSG_SWITCH_MAP_H */ +-- +2.42.0 + diff --git a/recipes-kernel/linux/files/patches-6.1/0017-net-ti-icssg-prueth-Add-mii-helper-apis-and-macros.patch b/recipes-kernel/linux/files/patches-6.1/0017-net-ti-icssg-prueth-Add-mii-helper-apis-and-macros.patch new file mode 100644 index 000000000..43ab1f9a8 --- /dev/null +++ b/recipes-kernel/linux/files/patches-6.1/0017-net-ti-icssg-prueth-Add-mii-helper-apis-and-macros.patch @@ -0,0 +1,510 @@ +From 5be81a0cf781ab5778c760300ffc77cca54ac4b1 Mon Sep 17 00:00:00 2001 +From: MD Danish Anwar +Date: Tue, 1 Aug 2023 14:44:20 +0530 +Subject: [PATCH 17/69] net: ti: icssg-prueth: Add mii helper apis and macros + +Add MII helper APIs and MACROs. These APIs and MACROs will be later used +by ICSSG Ethernet driver. Also introduce icssg_prueth.h which has +definition of prueth related structures. + +Reviewed-by: Andrew Lunn +Signed-off-by: MD Danish Anwar +[Commit b6ba7752149d upstream] +--- + drivers/net/ethernet/ti/icssg/icssg_mii_cfg.c | 120 +++++++++++ + drivers/net/ethernet/ti/icssg/icssg_mii_rt.h | 151 ++++++++++++++ + drivers/net/ethernet/ti/icssg/icssg_prueth.h | 197 ++++++++++++++++++ + 3 files changed, 468 insertions(+) + create mode 100644 drivers/net/ethernet/ti/icssg/icssg_mii_cfg.c + create mode 100644 drivers/net/ethernet/ti/icssg/icssg_mii_rt.h + create mode 100644 drivers/net/ethernet/ti/icssg/icssg_prueth.h + +diff --git a/drivers/net/ethernet/ti/icssg/icssg_mii_cfg.c b/drivers/net/ethernet/ti/icssg/icssg_mii_cfg.c +new file mode 100644 +index 000000000000..92718ae40d7e +--- /dev/null ++++ b/drivers/net/ethernet/ti/icssg/icssg_mii_cfg.c +@@ -0,0 +1,120 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* Texas Instruments ICSSG Ethernet Driver ++ * ++ * Copyright (C) 2018-2022 Texas Instruments Incorporated - https://www.ti.com/ ++ * ++ */ ++ ++#include ++#include ++#include ++ ++#include "icssg_mii_rt.h" ++#include "icssg_prueth.h" ++ ++void icssg_mii_update_ipg(struct regmap *mii_rt, int mii, u32 ipg) ++{ ++ u32 val; ++ ++ if (mii == ICSS_MII0) { ++ regmap_write(mii_rt, PRUSS_MII_RT_TX_IPG0, ipg); ++ } else { ++ regmap_read(mii_rt, PRUSS_MII_RT_TX_IPG0, &val); ++ regmap_write(mii_rt, PRUSS_MII_RT_TX_IPG1, ipg); ++ regmap_write(mii_rt, PRUSS_MII_RT_TX_IPG0, val); ++ } ++} ++ ++void icssg_mii_update_mtu(struct regmap *mii_rt, int mii, int mtu) ++{ ++ mtu += (ETH_HLEN + ETH_FCS_LEN); ++ if (mii == ICSS_MII0) { ++ regmap_update_bits(mii_rt, ++ PRUSS_MII_RT_RX_FRMS0, ++ PRUSS_MII_RT_RX_FRMS_MAX_FRM_MASK, ++ (mtu - 1) << PRUSS_MII_RT_RX_FRMS_MAX_FRM_SHIFT); ++ } else { ++ regmap_update_bits(mii_rt, ++ PRUSS_MII_RT_RX_FRMS1, ++ PRUSS_MII_RT_RX_FRMS_MAX_FRM_MASK, ++ (mtu - 1) << PRUSS_MII_RT_RX_FRMS_MAX_FRM_SHIFT); ++ } ++} ++ ++void icssg_update_rgmii_cfg(struct regmap *miig_rt, struct prueth_emac *emac) ++{ ++ u32 gig_en_mask, gig_val = 0, full_duplex_mask, full_duplex_val = 0; ++ int slice = prueth_emac_slice(emac); ++ u32 inband_en_mask, inband_val = 0; ++ ++ gig_en_mask = (slice == ICSS_MII0) ? RGMII_CFG_GIG_EN_MII0 : ++ RGMII_CFG_GIG_EN_MII1; ++ if (emac->speed == SPEED_1000) ++ gig_val = gig_en_mask; ++ regmap_update_bits(miig_rt, RGMII_CFG_OFFSET, gig_en_mask, gig_val); ++ ++ inband_en_mask = (slice == ICSS_MII0) ? RGMII_CFG_INBAND_EN_MII0 : ++ RGMII_CFG_INBAND_EN_MII1; ++ if (emac->speed == SPEED_10 && phy_interface_mode_is_rgmii(emac->phy_if)) ++ inband_val = inband_en_mask; ++ regmap_update_bits(miig_rt, RGMII_CFG_OFFSET, inband_en_mask, inband_val); ++ ++ full_duplex_mask = (slice == ICSS_MII0) ? RGMII_CFG_FULL_DUPLEX_MII0 : ++ RGMII_CFG_FULL_DUPLEX_MII1; ++ if (emac->duplex == DUPLEX_FULL) ++ full_duplex_val = full_duplex_mask; ++ regmap_update_bits(miig_rt, RGMII_CFG_OFFSET, full_duplex_mask, ++ full_duplex_val); ++} ++ ++void icssg_miig_set_interface_mode(struct regmap *miig_rt, int mii, phy_interface_t phy_if) ++{ ++ u32 val, mask, shift; ++ ++ mask = mii == ICSS_MII0 ? ICSSG_CFG_MII0_MODE : ICSSG_CFG_MII1_MODE; ++ shift = mii == ICSS_MII0 ? ICSSG_CFG_MII0_MODE_SHIFT : ICSSG_CFG_MII1_MODE_SHIFT; ++ ++ val = MII_MODE_RGMII; ++ if (phy_if == PHY_INTERFACE_MODE_MII) ++ val = MII_MODE_MII; ++ ++ val <<= shift; ++ regmap_update_bits(miig_rt, ICSSG_CFG_OFFSET, mask, val); ++ regmap_read(miig_rt, ICSSG_CFG_OFFSET, &val); ++} ++ ++u32 icssg_rgmii_cfg_get_bitfield(struct regmap *miig_rt, u32 mask, u32 shift) ++{ ++ u32 val; ++ ++ regmap_read(miig_rt, RGMII_CFG_OFFSET, &val); ++ val &= mask; ++ val >>= shift; ++ ++ return val; ++} ++ ++u32 icssg_rgmii_get_speed(struct regmap *miig_rt, int mii) ++{ ++ u32 shift = RGMII_CFG_SPEED_MII0_SHIFT, mask = RGMII_CFG_SPEED_MII0; ++ ++ if (mii == ICSS_MII1) { ++ shift = RGMII_CFG_SPEED_MII1_SHIFT; ++ mask = RGMII_CFG_SPEED_MII1; ++ } ++ ++ return icssg_rgmii_cfg_get_bitfield(miig_rt, mask, shift); ++} ++ ++u32 icssg_rgmii_get_fullduplex(struct regmap *miig_rt, int mii) ++{ ++ u32 shift = RGMII_CFG_FULLDUPLEX_MII0_SHIFT; ++ u32 mask = RGMII_CFG_FULLDUPLEX_MII0; ++ ++ if (mii == ICSS_MII1) { ++ shift = RGMII_CFG_FULLDUPLEX_MII1_SHIFT; ++ mask = RGMII_CFG_FULLDUPLEX_MII1; ++ } ++ ++ return icssg_rgmii_cfg_get_bitfield(miig_rt, mask, shift); ++} +diff --git a/drivers/net/ethernet/ti/icssg/icssg_mii_rt.h b/drivers/net/ethernet/ti/icssg/icssg_mii_rt.h +new file mode 100644 +index 000000000000..55a59bf5299c +--- /dev/null ++++ b/drivers/net/ethernet/ti/icssg/icssg_mii_rt.h +@@ -0,0 +1,151 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++ ++/* PRU-ICSS MII_RT register definitions ++ * ++ * Copyright (C) 2015-2022 Texas Instruments Incorporated - https://www.ti.com ++ */ ++ ++#ifndef __NET_PRUSS_MII_RT_H__ ++#define __NET_PRUSS_MII_RT_H__ ++ ++#include ++#include ++ ++/* PRUSS_MII_RT Registers */ ++#define PRUSS_MII_RT_RXCFG0 0x0 ++#define PRUSS_MII_RT_RXCFG1 0x4 ++#define PRUSS_MII_RT_TXCFG0 0x10 ++#define PRUSS_MII_RT_TXCFG1 0x14 ++#define PRUSS_MII_RT_TX_CRC0 0x20 ++#define PRUSS_MII_RT_TX_CRC1 0x24 ++#define PRUSS_MII_RT_TX_IPG0 0x30 ++#define PRUSS_MII_RT_TX_IPG1 0x34 ++#define PRUSS_MII_RT_PRS0 0x38 ++#define PRUSS_MII_RT_PRS1 0x3c ++#define PRUSS_MII_RT_RX_FRMS0 0x40 ++#define PRUSS_MII_RT_RX_FRMS1 0x44 ++#define PRUSS_MII_RT_RX_PCNT0 0x48 ++#define PRUSS_MII_RT_RX_PCNT1 0x4c ++#define PRUSS_MII_RT_RX_ERR0 0x50 ++#define PRUSS_MII_RT_RX_ERR1 0x54 ++ ++/* PRUSS_MII_RT_RXCFG0/1 bits */ ++#define PRUSS_MII_RT_RXCFG_RX_ENABLE BIT(0) ++#define PRUSS_MII_RT_RXCFG_RX_DATA_RDY_MODE_DIS BIT(1) ++#define PRUSS_MII_RT_RXCFG_RX_CUT_PREAMBLE BIT(2) ++#define PRUSS_MII_RT_RXCFG_RX_MUX_SEL BIT(3) ++#define PRUSS_MII_RT_RXCFG_RX_L2_EN BIT(4) ++#define PRUSS_MII_RT_RXCFG_RX_BYTE_SWAP BIT(5) ++#define PRUSS_MII_RT_RXCFG_RX_AUTO_FWD_PRE BIT(6) ++#define PRUSS_MII_RT_RXCFG_RX_L2_EOF_SCLR_DIS BIT(9) ++ ++/* PRUSS_MII_RT_TXCFG0/1 bits */ ++#define PRUSS_MII_RT_TXCFG_TX_ENABLE BIT(0) ++#define PRUSS_MII_RT_TXCFG_TX_AUTO_PREAMBLE BIT(1) ++#define PRUSS_MII_RT_TXCFG_TX_EN_MODE BIT(2) ++#define PRUSS_MII_RT_TXCFG_TX_BYTE_SWAP BIT(3) ++#define PRUSS_MII_RT_TXCFG_TX_MUX_SEL BIT(8) ++#define PRUSS_MII_RT_TXCFG_PRE_TX_AUTO_SEQUENCE BIT(9) ++#define PRUSS_MII_RT_TXCFG_PRE_TX_AUTO_ESC_ERR BIT(10) ++#define PRUSS_MII_RT_TXCFG_TX_32_MODE_EN BIT(11) ++#define PRUSS_MII_RT_TXCFG_TX_IPG_WIRE_CLK_EN BIT(12) /* SR2.0 onwards */ ++ ++#define PRUSS_MII_RT_TXCFG_TX_START_DELAY_SHIFT 16 ++#define PRUSS_MII_RT_TXCFG_TX_START_DELAY_MASK GENMASK(25, 16) ++ ++#define PRUSS_MII_RT_TXCFG_TX_CLK_DELAY_SHIFT 28 ++#define PRUSS_MII_RT_TXCFG_TX_CLK_DELAY_MASK GENMASK(30, 28) ++ ++/* PRUSS_MII_RT_TX_IPG0/1 bits */ ++#define PRUSS_MII_RT_TX_IPG_IPG_SHIFT 0 ++#define PRUSS_MII_RT_TX_IPG_IPG_MASK GENMASK(9, 0) ++ ++/* PRUSS_MII_RT_PRS0/1 bits */ ++#define PRUSS_MII_RT_PRS_COL BIT(0) ++#define PRUSS_MII_RT_PRS_CRS BIT(1) ++ ++/* PRUSS_MII_RT_RX_FRMS0/1 bits */ ++#define PRUSS_MII_RT_RX_FRMS_MIN_FRM_SHIFT 0 ++#define PRUSS_MII_RT_RX_FRMS_MIN_FRM_MASK GENMASK(15, 0) ++ ++#define PRUSS_MII_RT_RX_FRMS_MAX_FRM_SHIFT 16 ++#define PRUSS_MII_RT_RX_FRMS_MAX_FRM_MASK GENMASK(31, 16) ++ ++/* Min/Max in MII_RT_RX_FRMS */ ++/* For EMAC and Switch */ ++#define PRUSS_MII_RT_RX_FRMS_MAX (VLAN_ETH_FRAME_LEN + ETH_FCS_LEN) ++#define PRUSS_MII_RT_RX_FRMS_MIN_FRM (64) ++ ++/* for HSR and PRP */ ++#define PRUSS_MII_RT_RX_FRMS_MAX_FRM_LRE (PRUSS_MII_RT_RX_FRMS_MAX + \ ++ ICSS_LRE_TAG_RCT_SIZE) ++/* PRUSS_MII_RT_RX_PCNT0/1 bits */ ++#define PRUSS_MII_RT_RX_PCNT_MIN_PCNT_SHIFT 0 ++#define PRUSS_MII_RT_RX_PCNT_MIN_PCNT_MASK GENMASK(3, 0) ++ ++#define PRUSS_MII_RT_RX_PCNT_MAX_PCNT_SHIFT 4 ++#define PRUSS_MII_RT_RX_PCNT_MAX_PCNT_MASK GENMASK(7, 4) ++ ++/* PRUSS_MII_RT_RX_ERR0/1 bits */ ++#define PRUSS_MII_RT_RX_ERR_MIN_PCNT_ERR BIT(0) ++#define PRUSS_MII_RT_RX_ERR_MAX_PCNT_ERR BIT(1) ++#define PRUSS_MII_RT_RX_ERR_MIN_FRM_ERR BIT(2) ++#define PRUSS_MII_RT_RX_ERR_MAX_FRM_ERR BIT(3) ++ ++#define ICSSG_CFG_OFFSET 0 ++#define RGMII_CFG_OFFSET 4 ++ ++/* Constant to choose between MII0 and MII1 */ ++#define ICSS_MII0 0 ++#define ICSS_MII1 1 ++ ++/* ICSSG_CFG Register bits */ ++#define ICSSG_CFG_SGMII_MODE BIT(16) ++#define ICSSG_CFG_TX_PRU_EN BIT(11) ++#define ICSSG_CFG_RX_SFD_TX_SOF_EN BIT(10) ++#define ICSSG_CFG_RTU_PRU_PSI_SHARE_EN BIT(9) ++#define ICSSG_CFG_IEP1_TX_EN BIT(8) ++#define ICSSG_CFG_MII1_MODE GENMASK(6, 5) ++#define ICSSG_CFG_MII1_MODE_SHIFT 5 ++#define ICSSG_CFG_MII0_MODE GENMASK(4, 3) ++#define ICSSG_CFG_MII0_MODE_SHIFT 3 ++#define ICSSG_CFG_RX_L2_G_EN BIT(2) ++#define ICSSG_CFG_TX_L2_EN BIT(1) ++#define ICSSG_CFG_TX_L1_EN BIT(0) ++ ++enum mii_mode { ++ MII_MODE_MII = 0, ++ MII_MODE_RGMII ++}; ++ ++/* RGMII CFG Register bits */ ++#define RGMII_CFG_INBAND_EN_MII0 BIT(16) ++#define RGMII_CFG_GIG_EN_MII0 BIT(17) ++#define RGMII_CFG_INBAND_EN_MII1 BIT(20) ++#define RGMII_CFG_GIG_EN_MII1 BIT(21) ++#define RGMII_CFG_FULL_DUPLEX_MII0 BIT(18) ++#define RGMII_CFG_FULL_DUPLEX_MII1 BIT(22) ++#define RGMII_CFG_SPEED_MII0 GENMASK(2, 1) ++#define RGMII_CFG_SPEED_MII1 GENMASK(6, 5) ++#define RGMII_CFG_SPEED_MII0_SHIFT 1 ++#define RGMII_CFG_SPEED_MII1_SHIFT 5 ++#define RGMII_CFG_FULLDUPLEX_MII0 BIT(3) ++#define RGMII_CFG_FULLDUPLEX_MII1 BIT(7) ++#define RGMII_CFG_FULLDUPLEX_MII0_SHIFT 3 ++#define RGMII_CFG_FULLDUPLEX_MII1_SHIFT 7 ++#define RGMII_CFG_SPEED_10M 0 ++#define RGMII_CFG_SPEED_100M 1 ++#define RGMII_CFG_SPEED_1G 2 ++ ++struct regmap; ++struct prueth_emac; ++ ++void icssg_mii_update_ipg(struct regmap *mii_rt, int mii, u32 ipg); ++void icssg_mii_update_mtu(struct regmap *mii_rt, int mii, int mtu); ++void icssg_update_rgmii_cfg(struct regmap *miig_rt, struct prueth_emac *emac); ++u32 icssg_rgmii_cfg_get_bitfield(struct regmap *miig_rt, u32 mask, u32 shift); ++u32 icssg_rgmii_get_speed(struct regmap *miig_rt, int mii); ++u32 icssg_rgmii_get_fullduplex(struct regmap *miig_rt, int mii); ++void icssg_miig_set_interface_mode(struct regmap *miig_rt, int mii, phy_interface_t phy_if); ++ ++#endif /* __NET_PRUSS_MII_RT_H__ */ +diff --git a/drivers/net/ethernet/ti/icssg/icssg_prueth.h b/drivers/net/ethernet/ti/icssg/icssg_prueth.h +new file mode 100644 +index 000000000000..8512f19a9b4d +--- /dev/null ++++ b/drivers/net/ethernet/ti/icssg/icssg_prueth.h +@@ -0,0 +1,197 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* Texas Instruments ICSSG Ethernet driver ++ * ++ * Copyright (C) 2018-2022 Texas Instruments Incorporated - https://www.ti.com/ ++ * ++ */ ++ ++#ifndef __NET_TI_ICSSG_PRUETH_H ++#define __NET_TI_ICSSG_PRUETH_H ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#include ++ ++#include "icssg_switch_map.h" ++ ++#define ICSS_SLICE0 0 ++#define ICSS_SLICE1 1 ++ ++#define ICSSG_MAX_RFLOWS 8 /* per slice */ ++ ++/* In switch mode there are 3 real ports i.e. 3 mac addrs. ++ * however Linux sees only the host side port. The other 2 ports ++ * are the switch ports. ++ * In emac mode there are 2 real ports i.e. 2 mac addrs. ++ * Linux sees both the ports. ++ */ ++enum prueth_port { ++ PRUETH_PORT_HOST = 0, /* host side port */ ++ PRUETH_PORT_MII0, /* physical port RG/SG MII 0 */ ++ PRUETH_PORT_MII1, /* physical port RG/SG MII 1 */ ++ PRUETH_PORT_INVALID, /* Invalid prueth port */ ++}; ++ ++enum prueth_mac { ++ PRUETH_MAC0 = 0, ++ PRUETH_MAC1, ++ PRUETH_NUM_MACS, ++ PRUETH_MAC_INVALID, ++}; ++ ++struct prueth_tx_chn { ++ struct device *dma_dev; ++ struct napi_struct napi_tx; ++ struct k3_cppi_desc_pool *desc_pool; ++ struct k3_udma_glue_tx_channel *tx_chn; ++ struct prueth_emac *emac; ++ u32 id; ++ u32 descs_num; ++ unsigned int irq; ++ char name[32]; ++}; ++ ++struct prueth_rx_chn { ++ struct device *dev; ++ struct device *dma_dev; ++ struct k3_cppi_desc_pool *desc_pool; ++ struct k3_udma_glue_rx_channel *rx_chn; ++ u32 descs_num; ++ unsigned int irq[ICSSG_MAX_RFLOWS]; /* separate irq per flow */ ++ char name[32]; ++}; ++ ++/* There are 4 Tx DMA channels, but the highest priority is CH3 (thread 3) ++ * and lower three are lower priority channels or threads. ++ */ ++#define PRUETH_MAX_TX_QUEUES 4 ++ ++/* data for each emac port */ ++struct prueth_emac { ++ bool fw_running; ++ struct prueth *prueth; ++ struct net_device *ndev; ++ u8 mac_addr[6]; ++ struct napi_struct napi_rx; ++ u32 msg_enable; ++ ++ int link; ++ int speed; ++ int duplex; ++ ++ const char *phy_id; ++ struct device_node *phy_node; ++ phy_interface_t phy_if; ++ enum prueth_port port_id; ++ ++ /* DMA related */ ++ struct prueth_tx_chn tx_chns[PRUETH_MAX_TX_QUEUES]; ++ struct completion tdown_complete; ++ atomic_t tdown_cnt; ++ struct prueth_rx_chn rx_chns; ++ int rx_flow_id_base; ++ int tx_ch_num; ++ ++ spinlock_t lock; /* serialize access */ ++ ++ unsigned long state; ++ struct completion cmd_complete; ++ /* Mutex to serialize access to firmware command interface */ ++ struct mutex cmd_lock; ++ struct work_struct rx_mode_work; ++ struct workqueue_struct *cmd_wq; ++ ++ struct pruss_mem_region dram; ++}; ++ ++/** ++ * struct prueth_pdata - PRUeth platform data ++ * @fdqring_mode: Free desc queue mode ++ * @quirk_10m_link_issue: 10M link detect errata ++ */ ++struct prueth_pdata { ++ enum k3_ring_mode fdqring_mode; ++ u32 quirk_10m_link_issue:1; ++}; ++ ++/** ++ * struct prueth - PRUeth structure ++ * @dev: device ++ * @pruss: pruss handle ++ * @pru: rproc instances of PRUs ++ * @rtu: rproc instances of RTUs ++ * @txpru: rproc instances of TX_PRUs ++ * @shram: PRUSS shared RAM region ++ * @sram_pool: MSMC RAM pool for buffers ++ * @msmcram: MSMC RAM region ++ * @eth_node: DT node for the port ++ * @emac: private EMAC data structure ++ * @registered_netdevs: list of registered netdevs ++ * @miig_rt: regmap to mii_g_rt block ++ * @mii_rt: regmap to mii_rt block ++ * @pru_id: ID for each of the PRUs ++ * @pdev: pointer to ICSSG platform device ++ * @pdata: pointer to platform data for ICSSG driver ++ * @icssg_hwcmdseq: seq counter or HWQ messages ++ * @emacs_initialized: num of EMACs/ext ports that are up/running ++ */ ++struct prueth { ++ struct device *dev; ++ struct pruss *pruss; ++ struct rproc *pru[PRUSS_NUM_PRUS]; ++ struct rproc *rtu[PRUSS_NUM_PRUS]; ++ struct rproc *txpru[PRUSS_NUM_PRUS]; ++ struct pruss_mem_region shram; ++ struct gen_pool *sram_pool; ++ struct pruss_mem_region msmcram; ++ ++ struct device_node *eth_node[PRUETH_NUM_MACS]; ++ struct prueth_emac *emac[PRUETH_NUM_MACS]; ++ struct net_device *registered_netdevs[PRUETH_NUM_MACS]; ++ struct regmap *miig_rt; ++ struct regmap *mii_rt; ++ ++ enum pruss_pru_id pru_id[PRUSS_NUM_PRUS]; ++ struct platform_device *pdev; ++ struct prueth_pdata pdata; ++ u8 icssg_hwcmdseq; ++ ++ int emacs_initialized; ++}; ++ ++/* get PRUSS SLICE number from prueth_emac */ ++static inline int prueth_emac_slice(struct prueth_emac *emac) ++{ ++ switch (emac->port_id) { ++ case PRUETH_PORT_MII0: ++ return ICSS_SLICE0; ++ case PRUETH_PORT_MII1: ++ return ICSS_SLICE1; ++ default: ++ return -EINVAL; ++ } ++} ++ ++#endif /* __NET_TI_ICSSG_PRUETH_H */ +-- +2.42.0 + diff --git a/recipes-kernel/linux/files/patches-6.1/0018-net-ti-icssg-prueth-Add-Firmware-config-and-classifi.patch b/recipes-kernel/linux/files/patches-6.1/0018-net-ti-icssg-prueth-Add-Firmware-config-and-classifi.patch new file mode 100644 index 000000000..04fb0579e --- /dev/null +++ b/recipes-kernel/linux/files/patches-6.1/0018-net-ti-icssg-prueth-Add-Firmware-config-and-classifi.patch @@ -0,0 +1,1085 @@ +From e11b65e8eb0a16c1e59924ee4f6710800239ca4d Mon Sep 17 00:00:00 2001 +From: MD Danish Anwar +Date: Tue, 1 Aug 2023 14:44:21 +0530 +Subject: [PATCH 18/69] net: ti: icssg-prueth: Add Firmware config and + classification APIs. + +Add icssg_config.h / .c and icssg_classifier.c files. These are firmware +configuration and classification related files. These will be used by +ICSSG ethernet driver. + +Reviewed-by: Andrew Lunn +Signed-off-by: MD Danish Anwar +[Commit e9b4ece7d74b upstream] +--- + .../net/ethernet/ti/icssg/icssg_classifier.c | 367 ++++++++++++++ + drivers/net/ethernet/ti/icssg/icssg_config.c | 450 ++++++++++++++++++ + drivers/net/ethernet/ti/icssg/icssg_config.h | 200 ++++++++ + drivers/net/ethernet/ti/icssg/icssg_prueth.h | 15 + + 4 files changed, 1032 insertions(+) + create mode 100644 drivers/net/ethernet/ti/icssg/icssg_classifier.c + create mode 100644 drivers/net/ethernet/ti/icssg/icssg_config.c + create mode 100644 drivers/net/ethernet/ti/icssg/icssg_config.h + +diff --git a/drivers/net/ethernet/ti/icssg/icssg_classifier.c b/drivers/net/ethernet/ti/icssg/icssg_classifier.c +new file mode 100644 +index 000000000000..6df53ab17fbc +--- /dev/null ++++ b/drivers/net/ethernet/ti/icssg/icssg_classifier.c +@@ -0,0 +1,367 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* Texas Instruments ICSSG Ethernet Driver ++ * ++ * Copyright (C) 2018-2022 Texas Instruments Incorporated - https://www.ti.com/ ++ * ++ */ ++ ++#include ++#include ++#include ++ ++#include "icssg_prueth.h" ++ ++#define ICSSG_NUM_CLASSIFIERS 16 ++#define ICSSG_NUM_FT1_SLOTS 8 ++#define ICSSG_NUM_FT3_SLOTS 16 ++ ++#define ICSSG_NUM_CLASSIFIERS_IN_USE 5 ++ ++/* Filter 1 - FT1 */ ++#define FT1_NUM_SLOTS 8 ++#define FT1_SLOT_SIZE 0x10 /* bytes */ ++ ++/* offsets from FT1 slot base i.e. slot 1 start */ ++#define FT1_DA0 0x0 ++#define FT1_DA1 0x4 ++#define FT1_DA0_MASK 0x8 ++#define FT1_DA1_MASK 0xc ++ ++#define FT1_N_REG(slize, n, reg) \ ++ (offs[slice].ft1_slot_base + FT1_SLOT_SIZE * (n) + (reg)) ++ ++#define FT1_LEN_MASK GENMASK(19, 16) ++#define FT1_LEN_SHIFT 16 ++#define FT1_LEN(len) (((len) << FT1_LEN_SHIFT) & FT1_LEN_MASK) ++#define FT1_START_MASK GENMASK(14, 0) ++#define FT1_START(start) ((start) & FT1_START_MASK) ++#define FT1_MATCH_SLOT(n) (GENMASK(23, 16) & (BIT(n) << 16)) ++ ++/* FT1 config type */ ++enum ft1_cfg_type { ++ FT1_CFG_TYPE_DISABLED = 0, ++ FT1_CFG_TYPE_EQ, ++ FT1_CFG_TYPE_GT, ++ FT1_CFG_TYPE_LT, ++}; ++ ++#define FT1_CFG_SHIFT(n) (2 * (n)) ++#define FT1_CFG_MASK(n) (0x3 << FT1_CFG_SHIFT((n))) ++ ++/* Filter 3 - FT3 */ ++#define FT3_NUM_SLOTS 16 ++#define FT3_SLOT_SIZE 0x20 /* bytes */ ++ ++/* offsets from FT3 slot n's base */ ++#define FT3_START 0 ++#define FT3_START_AUTO 0x4 ++#define FT3_START_OFFSET 0x8 ++#define FT3_JUMP_OFFSET 0xc ++#define FT3_LEN 0x10 ++#define FT3_CFG 0x14 ++#define FT3_T 0x18 ++#define FT3_T_MASK 0x1c ++ ++#define FT3_N_REG(slize, n, reg) \ ++ (offs[slice].ft3_slot_base + FT3_SLOT_SIZE * (n) + (reg)) ++ ++/* offsets from rx_class n's base */ ++#define RX_CLASS_AND_EN 0 ++#define RX_CLASS_OR_EN 0x4 ++#define RX_CLASS_NUM_SLOTS 16 ++#define RX_CLASS_EN_SIZE 0x8 /* bytes */ ++ ++#define RX_CLASS_N_REG(slice, n, reg) \ ++ (offs[slice].rx_class_base + RX_CLASS_EN_SIZE * (n) + (reg)) ++ ++/* RX Class Gates */ ++#define RX_CLASS_GATES_SIZE 0x4 /* bytes */ ++ ++#define RX_CLASS_GATES_N_REG(slice, n) \ ++ (offs[slice].rx_class_gates_base + RX_CLASS_GATES_SIZE * (n)) ++ ++#define RX_CLASS_GATES_ALLOW_MASK BIT(6) ++#define RX_CLASS_GATES_RAW_MASK BIT(5) ++#define RX_CLASS_GATES_PHASE_MASK BIT(4) ++ ++/* RX Class traffic data matching bits */ ++#define RX_CLASS_FT_UC BIT(31) ++#define RX_CLASS_FT_MC BIT(30) ++#define RX_CLASS_FT_BC BIT(29) ++#define RX_CLASS_FT_FW BIT(28) ++#define RX_CLASS_FT_RCV BIT(27) ++#define RX_CLASS_FT_VLAN BIT(26) ++#define RX_CLASS_FT_DA_P BIT(25) ++#define RX_CLASS_FT_DA_I BIT(24) ++#define RX_CLASS_FT_FT1_MATCH_MASK GENMASK(23, 16) ++#define RX_CLASS_FT_FT1_MATCH_SHIFT 16 ++#define RX_CLASS_FT_FT3_MATCH_MASK GENMASK(15, 0) ++#define RX_CLASS_FT_FT3_MATCH_SHIFT 0 ++ ++#define RX_CLASS_FT_FT1_MATCH(slot) \ ++ ((BIT(slot) << RX_CLASS_FT_FT1_MATCH_SHIFT) & \ ++ RX_CLASS_FT_FT1_MATCH_MASK) ++ ++/* RX class type */ ++enum rx_class_sel_type { ++ RX_CLASS_SEL_TYPE_OR = 0, ++ RX_CLASS_SEL_TYPE_AND = 1, ++ RX_CLASS_SEL_TYPE_OR_AND_AND = 2, ++ RX_CLASS_SEL_TYPE_OR_OR_AND = 3, ++}; ++ ++#define FT1_CFG_SHIFT(n) (2 * (n)) ++#define FT1_CFG_MASK(n) (0x3 << FT1_CFG_SHIFT((n))) ++ ++#define RX_CLASS_SEL_SHIFT(n) (2 * (n)) ++#define RX_CLASS_SEL_MASK(n) (0x3 << RX_CLASS_SEL_SHIFT((n))) ++ ++#define ICSSG_CFG_OFFSET 0 ++#define MAC_INTERFACE_0 0x18 ++#define MAC_INTERFACE_1 0x1c ++ ++#define ICSSG_CFG_RX_L2_G_EN BIT(2) ++ ++/* These are register offsets per PRU */ ++struct miig_rt_offsets { ++ u32 mac0; ++ u32 mac1; ++ u32 ft1_start_len; ++ u32 ft1_cfg; ++ u32 ft1_slot_base; ++ u32 ft3_slot_base; ++ u32 ft3_p_base; ++ u32 ft_rx_ptr; ++ u32 rx_class_base; ++ u32 rx_class_cfg1; ++ u32 rx_class_cfg2; ++ u32 rx_class_gates_base; ++ u32 rx_green; ++ u32 rx_rate_cfg_base; ++ u32 rx_rate_src_sel0; ++ u32 rx_rate_src_sel1; ++ u32 tx_rate_cfg_base; ++ u32 stat_base; ++ u32 tx_hsr_tag; ++ u32 tx_hsr_seq; ++ u32 tx_vlan_type; ++ u32 tx_vlan_ins; ++}; ++ ++/* These are the offset values for miig_rt_offsets registers */ ++static const struct miig_rt_offsets offs[] = { ++ /* PRU0 */ ++ { ++ 0x8, ++ 0xc, ++ 0x80, ++ 0x84, ++ 0x88, ++ 0x108, ++ 0x308, ++ 0x408, ++ 0x40c, ++ 0x48c, ++ 0x490, ++ 0x494, ++ 0x4d4, ++ 0x4e4, ++ 0x504, ++ 0x508, ++ 0x50c, ++ 0x54c, ++ 0x63c, ++ 0x640, ++ 0x644, ++ 0x648, ++ }, ++ /* PRU1 */ ++ { ++ 0x10, ++ 0x14, ++ 0x64c, ++ 0x650, ++ 0x654, ++ 0x6d4, ++ 0x8d4, ++ 0x9d4, ++ 0x9d8, ++ 0xa58, ++ 0xa5c, ++ 0xa60, ++ 0xaa0, ++ 0xab0, ++ 0xad0, ++ 0xad4, ++ 0xad8, ++ 0xb18, ++ 0xc08, ++ 0xc0c, ++ 0xc10, ++ 0xc14, ++ }, ++}; ++ ++static void rx_class_ft1_set_start_len(struct regmap *miig_rt, int slice, ++ u16 start, u8 len) ++{ ++ u32 offset, val; ++ ++ offset = offs[slice].ft1_start_len; ++ val = FT1_LEN(len) | FT1_START(start); ++ regmap_write(miig_rt, offset, val); ++} ++ ++static void rx_class_ft1_set_da(struct regmap *miig_rt, int slice, ++ int n, const u8 *addr) ++{ ++ u32 offset; ++ ++ offset = FT1_N_REG(slice, n, FT1_DA0); ++ regmap_write(miig_rt, offset, (u32)(addr[0] | addr[1] << 8 | ++ addr[2] << 16 | addr[3] << 24)); ++ offset = FT1_N_REG(slice, n, FT1_DA1); ++ regmap_write(miig_rt, offset, (u32)(addr[4] | addr[5] << 8)); ++} ++ ++static void rx_class_ft1_set_da_mask(struct regmap *miig_rt, int slice, ++ int n, const u8 *addr) ++{ ++ u32 offset; ++ ++ offset = FT1_N_REG(slice, n, FT1_DA0_MASK); ++ regmap_write(miig_rt, offset, (u32)(addr[0] | addr[1] << 8 | ++ addr[2] << 16 | addr[3] << 24)); ++ offset = FT1_N_REG(slice, n, FT1_DA1_MASK); ++ regmap_write(miig_rt, offset, (u32)(addr[4] | addr[5] << 8)); ++} ++ ++static void rx_class_ft1_cfg_set_type(struct regmap *miig_rt, int slice, int n, ++ enum ft1_cfg_type type) ++{ ++ u32 offset; ++ ++ offset = offs[slice].ft1_cfg; ++ regmap_update_bits(miig_rt, offset, FT1_CFG_MASK(n), ++ type << FT1_CFG_SHIFT(n)); ++} ++ ++static void rx_class_sel_set_type(struct regmap *miig_rt, int slice, int n, ++ enum rx_class_sel_type type) ++{ ++ u32 offset; ++ ++ offset = offs[slice].rx_class_cfg1; ++ regmap_update_bits(miig_rt, offset, RX_CLASS_SEL_MASK(n), ++ type << RX_CLASS_SEL_SHIFT(n)); ++} ++ ++static void rx_class_set_and(struct regmap *miig_rt, int slice, int n, ++ u32 data) ++{ ++ u32 offset; ++ ++ offset = RX_CLASS_N_REG(slice, n, RX_CLASS_AND_EN); ++ regmap_write(miig_rt, offset, data); ++} ++ ++static void rx_class_set_or(struct regmap *miig_rt, int slice, int n, ++ u32 data) ++{ ++ u32 offset; ++ ++ offset = RX_CLASS_N_REG(slice, n, RX_CLASS_OR_EN); ++ regmap_write(miig_rt, offset, data); ++} ++ ++void icssg_class_set_host_mac_addr(struct regmap *miig_rt, const u8 *mac) ++{ ++ regmap_write(miig_rt, MAC_INTERFACE_0, (u32)(mac[0] | mac[1] << 8 | ++ mac[2] << 16 | mac[3] << 24)); ++ regmap_write(miig_rt, MAC_INTERFACE_1, (u32)(mac[4] | mac[5] << 8)); ++} ++ ++void icssg_class_set_mac_addr(struct regmap *miig_rt, int slice, u8 *mac) ++{ ++ regmap_write(miig_rt, offs[slice].mac0, (u32)(mac[0] | mac[1] << 8 | ++ mac[2] << 16 | mac[3] << 24)); ++ regmap_write(miig_rt, offs[slice].mac1, (u32)(mac[4] | mac[5] << 8)); ++} ++ ++/* disable all RX traffic */ ++void icssg_class_disable(struct regmap *miig_rt, int slice) ++{ ++ u32 data, offset; ++ int n; ++ ++ /* Enable RX_L2_G */ ++ regmap_update_bits(miig_rt, ICSSG_CFG_OFFSET, ICSSG_CFG_RX_L2_G_EN, ++ ICSSG_CFG_RX_L2_G_EN); ++ ++ for (n = 0; n < ICSSG_NUM_CLASSIFIERS; n++) { ++ /* AND_EN = 0 */ ++ rx_class_set_and(miig_rt, slice, n, 0); ++ /* OR_EN = 0 */ ++ rx_class_set_or(miig_rt, slice, n, 0); ++ ++ /* set CFG1 to OR */ ++ rx_class_sel_set_type(miig_rt, slice, n, RX_CLASS_SEL_TYPE_OR); ++ ++ /* configure gate */ ++ offset = RX_CLASS_GATES_N_REG(slice, n); ++ regmap_read(miig_rt, offset, &data); ++ /* clear class_raw so we go through filters */ ++ data &= ~RX_CLASS_GATES_RAW_MASK; ++ /* set allow and phase mask */ ++ data |= RX_CLASS_GATES_ALLOW_MASK | RX_CLASS_GATES_PHASE_MASK; ++ regmap_write(miig_rt, offset, data); ++ } ++ ++ /* FT1 Disabled */ ++ for (n = 0; n < ICSSG_NUM_FT1_SLOTS; n++) { ++ const u8 addr[] = { 0, 0, 0, 0, 0, 0, }; ++ ++ rx_class_ft1_cfg_set_type(miig_rt, slice, n, ++ FT1_CFG_TYPE_DISABLED); ++ rx_class_ft1_set_da(miig_rt, slice, n, addr); ++ rx_class_ft1_set_da_mask(miig_rt, slice, n, addr); ++ } ++ ++ /* clear CFG2 */ ++ regmap_write(miig_rt, offs[slice].rx_class_cfg2, 0); ++} ++ ++void icssg_class_default(struct regmap *miig_rt, int slice, bool allmulti) ++{ ++ u32 data; ++ ++ /* defaults */ ++ icssg_class_disable(miig_rt, slice); ++ ++ /* Setup Classifier */ ++ /* match on Broadcast or MAC_PRU address */ ++ data = RX_CLASS_FT_BC | RX_CLASS_FT_DA_P; ++ ++ /* multicast */ ++ if (allmulti) ++ data |= RX_CLASS_FT_MC; ++ ++ rx_class_set_or(miig_rt, slice, 0, data); ++ ++ /* set CFG1 for OR_OR_AND for classifier */ ++ rx_class_sel_set_type(miig_rt, slice, 0, RX_CLASS_SEL_TYPE_OR_OR_AND); ++ ++ /* clear CFG2 */ ++ regmap_write(miig_rt, offs[slice].rx_class_cfg2, 0); ++} ++ ++/* required for SAV check */ ++void icssg_ft1_set_mac_addr(struct regmap *miig_rt, int slice, u8 *mac_addr) ++{ ++ const u8 mask_addr[] = { 0, 0, 0, 0, 0, 0, }; ++ ++ rx_class_ft1_set_start_len(miig_rt, slice, 0, 6); ++ rx_class_ft1_set_da(miig_rt, slice, 0, mac_addr); ++ rx_class_ft1_set_da_mask(miig_rt, slice, 0, mask_addr); ++ rx_class_ft1_cfg_set_type(miig_rt, slice, 0, FT1_CFG_TYPE_EQ); ++} +diff --git a/drivers/net/ethernet/ti/icssg/icssg_config.c b/drivers/net/ethernet/ti/icssg/icssg_config.c +new file mode 100644 +index 000000000000..ab648d3efe85 +--- /dev/null ++++ b/drivers/net/ethernet/ti/icssg/icssg_config.c +@@ -0,0 +1,450 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ICSSG Ethernet driver ++ * ++ * Copyright (C) 2022 Texas Instruments Incorporated - https://www.ti.com ++ */ ++ ++#include ++#include ++#include ++#include "icssg_config.h" ++#include "icssg_prueth.h" ++#include "icssg_switch_map.h" ++#include "icssg_mii_rt.h" ++ ++/* TX IPG Values to be set for 100M link speed. These values are ++ * in ocp_clk cycles. So need change if ocp_clk is changed for a specific ++ * h/w design. ++ */ ++ ++/* IPG is in core_clk cycles */ ++#define MII_RT_TX_IPG_100M 0x17 ++#define MII_RT_TX_IPG_1G 0xb ++ ++#define ICSSG_QUEUES_MAX 64 ++#define ICSSG_QUEUE_OFFSET 0xd00 ++#define ICSSG_QUEUE_PEEK_OFFSET 0xe00 ++#define ICSSG_QUEUE_CNT_OFFSET 0xe40 ++#define ICSSG_QUEUE_RESET_OFFSET 0xf40 ++ ++#define ICSSG_NUM_TX_QUEUES 8 ++ ++#define RECYCLE_Q_SLICE0 16 ++#define RECYCLE_Q_SLICE1 17 ++ ++#define ICSSG_NUM_OTHER_QUEUES 5 /* port, host and special queues */ ++ ++#define PORT_HI_Q_SLICE0 32 ++#define PORT_LO_Q_SLICE0 33 ++#define HOST_HI_Q_SLICE0 34 ++#define HOST_LO_Q_SLICE0 35 ++#define HOST_SPL_Q_SLICE0 40 /* Special Queue */ ++ ++#define PORT_HI_Q_SLICE1 36 ++#define PORT_LO_Q_SLICE1 37 ++#define HOST_HI_Q_SLICE1 38 ++#define HOST_LO_Q_SLICE1 39 ++#define HOST_SPL_Q_SLICE1 41 /* Special Queue */ ++ ++#define MII_RXCFG_DEFAULT (PRUSS_MII_RT_RXCFG_RX_ENABLE | \ ++ PRUSS_MII_RT_RXCFG_RX_DATA_RDY_MODE_DIS | \ ++ PRUSS_MII_RT_RXCFG_RX_L2_EN | \ ++ PRUSS_MII_RT_RXCFG_RX_L2_EOF_SCLR_DIS) ++ ++#define MII_TXCFG_DEFAULT (PRUSS_MII_RT_TXCFG_TX_ENABLE | \ ++ PRUSS_MII_RT_TXCFG_TX_AUTO_PREAMBLE | \ ++ PRUSS_MII_RT_TXCFG_TX_32_MODE_EN | \ ++ PRUSS_MII_RT_TXCFG_TX_IPG_WIRE_CLK_EN) ++ ++#define ICSSG_CFG_DEFAULT (ICSSG_CFG_TX_L1_EN | \ ++ ICSSG_CFG_TX_L2_EN | ICSSG_CFG_RX_L2_G_EN | \ ++ ICSSG_CFG_TX_PRU_EN | \ ++ ICSSG_CFG_SGMII_MODE) ++ ++#define FDB_GEN_CFG1 0x60 ++#define SMEM_VLAN_OFFSET 8 ++#define SMEM_VLAN_OFFSET_MASK GENMASK(25, 8) ++ ++#define FDB_GEN_CFG2 0x64 ++#define FDB_VLAN_EN BIT(6) ++#define FDB_HOST_EN BIT(2) ++#define FDB_PRU1_EN BIT(1) ++#define FDB_PRU0_EN BIT(0) ++#define FDB_EN_ALL (FDB_PRU0_EN | FDB_PRU1_EN | \ ++ FDB_HOST_EN | FDB_VLAN_EN) ++ ++/** ++ * struct map - ICSSG Queue Map ++ * @queue: Queue number ++ * @pd_addr_start: Packet descriptor queue reserved memory ++ * @flags: Flags ++ * @special: Indicates whether this queue is a special queue or not ++ */ ++struct map { ++ int queue; ++ u32 pd_addr_start; ++ u32 flags; ++ bool special; ++}; ++ ++/* Hardware queue map for ICSSG */ ++static const struct map hwq_map[2][ICSSG_NUM_OTHER_QUEUES] = { ++ { ++ { PORT_HI_Q_SLICE0, PORT_DESC0_HI, 0x200000, 0 }, ++ { PORT_LO_Q_SLICE0, PORT_DESC0_LO, 0, 0 }, ++ { HOST_HI_Q_SLICE0, HOST_DESC0_HI, 0x200000, 0 }, ++ { HOST_LO_Q_SLICE0, HOST_DESC0_LO, 0, 0 }, ++ { HOST_SPL_Q_SLICE0, HOST_SPPD0, 0x400000, 1 }, ++ }, ++ { ++ { PORT_HI_Q_SLICE1, PORT_DESC1_HI, 0xa00000, 0 }, ++ { PORT_LO_Q_SLICE1, PORT_DESC1_LO, 0x800000, 0 }, ++ { HOST_HI_Q_SLICE1, HOST_DESC1_HI, 0xa00000, 0 }, ++ { HOST_LO_Q_SLICE1, HOST_DESC1_LO, 0x800000, 0 }, ++ { HOST_SPL_Q_SLICE1, HOST_SPPD1, 0xc00000, 1 }, ++ }, ++}; ++ ++static void icssg_config_mii_init(struct prueth_emac *emac) ++{ ++ u32 rxcfg, txcfg, rxcfg_reg, txcfg_reg, pcnt_reg; ++ struct prueth *prueth = emac->prueth; ++ int slice = prueth_emac_slice(emac); ++ struct regmap *mii_rt; ++ ++ mii_rt = prueth->mii_rt; ++ ++ rxcfg_reg = (slice == ICSS_MII0) ? PRUSS_MII_RT_RXCFG0 : ++ PRUSS_MII_RT_RXCFG1; ++ txcfg_reg = (slice == ICSS_MII0) ? PRUSS_MII_RT_TXCFG0 : ++ PRUSS_MII_RT_TXCFG1; ++ pcnt_reg = (slice == ICSS_MII0) ? PRUSS_MII_RT_RX_PCNT0 : ++ PRUSS_MII_RT_RX_PCNT1; ++ ++ rxcfg = MII_RXCFG_DEFAULT; ++ txcfg = MII_TXCFG_DEFAULT; ++ ++ if (slice == ICSS_MII1) ++ rxcfg |= PRUSS_MII_RT_RXCFG_RX_MUX_SEL; ++ ++ /* In MII mode TX lines swapped inside ICSSG, so TX_MUX_SEL cfg need ++ * to be swapped also comparing to RGMII mode. ++ */ ++ if (emac->phy_if == PHY_INTERFACE_MODE_MII && slice == ICSS_MII0) ++ txcfg |= PRUSS_MII_RT_TXCFG_TX_MUX_SEL; ++ else if (emac->phy_if != PHY_INTERFACE_MODE_MII && slice == ICSS_MII1) ++ txcfg |= PRUSS_MII_RT_TXCFG_TX_MUX_SEL; ++ ++ regmap_write(mii_rt, rxcfg_reg, rxcfg); ++ regmap_write(mii_rt, txcfg_reg, txcfg); ++ regmap_write(mii_rt, pcnt_reg, 0x1); ++} ++ ++static void icssg_miig_queues_init(struct prueth *prueth, int slice) ++{ ++ struct regmap *miig_rt = prueth->miig_rt; ++ void __iomem *smem = prueth->shram.va; ++ u8 pd[ICSSG_SPECIAL_PD_SIZE]; ++ int queue = 0, i, j; ++ u32 *pdword; ++ ++ /* reset hwqueues */ ++ if (slice) ++ queue = ICSSG_NUM_TX_QUEUES; ++ ++ for (i = 0; i < ICSSG_NUM_TX_QUEUES; i++) { ++ regmap_write(miig_rt, ICSSG_QUEUE_RESET_OFFSET, queue); ++ queue++; ++ } ++ ++ queue = slice ? RECYCLE_Q_SLICE1 : RECYCLE_Q_SLICE0; ++ regmap_write(miig_rt, ICSSG_QUEUE_RESET_OFFSET, queue); ++ ++ for (i = 0; i < ICSSG_NUM_OTHER_QUEUES; i++) { ++ regmap_write(miig_rt, ICSSG_QUEUE_RESET_OFFSET, ++ hwq_map[slice][i].queue); ++ } ++ ++ /* initialize packet descriptors in SMEM */ ++ /* push pakcet descriptors to hwqueues */ ++ ++ pdword = (u32 *)pd; ++ for (j = 0; j < ICSSG_NUM_OTHER_QUEUES; j++) { ++ const struct map *mp; ++ int pd_size, num_pds; ++ u32 pdaddr; ++ ++ mp = &hwq_map[slice][j]; ++ if (mp->special) { ++ pd_size = ICSSG_SPECIAL_PD_SIZE; ++ num_pds = ICSSG_NUM_SPECIAL_PDS; ++ } else { ++ pd_size = ICSSG_NORMAL_PD_SIZE; ++ num_pds = ICSSG_NUM_NORMAL_PDS; ++ } ++ ++ for (i = 0; i < num_pds; i++) { ++ memset(pd, 0, pd_size); ++ ++ pdword[0] &= ICSSG_FLAG_MASK; ++ pdword[0] |= mp->flags; ++ pdaddr = mp->pd_addr_start + i * pd_size; ++ ++ memcpy_toio(smem + pdaddr, pd, pd_size); ++ queue = mp->queue; ++ regmap_write(miig_rt, ICSSG_QUEUE_OFFSET + 4 * queue, ++ pdaddr); ++ } ++ } ++} ++ ++void icssg_config_ipg(struct prueth_emac *emac) ++{ ++ struct prueth *prueth = emac->prueth; ++ int slice = prueth_emac_slice(emac); ++ ++ switch (emac->speed) { ++ case SPEED_1000: ++ icssg_mii_update_ipg(prueth->mii_rt, slice, MII_RT_TX_IPG_1G); ++ break; ++ case SPEED_100: ++ icssg_mii_update_ipg(prueth->mii_rt, slice, MII_RT_TX_IPG_100M); ++ break; ++ default: ++ /* Other links speeds not supported */ ++ netdev_err(emac->ndev, "Unsupported link speed\n"); ++ return; ++ } ++} ++ ++static void emac_r30_cmd_init(struct prueth_emac *emac) ++{ ++ struct icssg_r30_cmd __iomem *p; ++ int i; ++ ++ p = emac->dram.va + MGR_R30_CMD_OFFSET; ++ ++ for (i = 0; i < 4; i++) ++ writel(EMAC_NONE, &p->cmd[i]); ++} ++ ++static int emac_r30_is_done(struct prueth_emac *emac) ++{ ++ const struct icssg_r30_cmd __iomem *p; ++ u32 cmd; ++ int i; ++ ++ p = emac->dram.va + MGR_R30_CMD_OFFSET; ++ ++ for (i = 0; i < 4; i++) { ++ cmd = readl(&p->cmd[i]); ++ if (cmd != EMAC_NONE) ++ return 0; ++ } ++ ++ return 1; ++} ++ ++static int prueth_emac_buffer_setup(struct prueth_emac *emac) ++{ ++ struct icssg_buffer_pool_cfg __iomem *bpool_cfg; ++ struct icssg_rxq_ctx __iomem *rxq_ctx; ++ struct prueth *prueth = emac->prueth; ++ int slice = prueth_emac_slice(emac); ++ u32 addr; ++ int i; ++ ++ /* Layout to have 64KB aligned buffer pool ++ * |BPOOL0|BPOOL1|RX_CTX0|RX_CTX1| ++ */ ++ ++ addr = lower_32_bits(prueth->msmcram.pa); ++ if (slice) ++ addr += PRUETH_NUM_BUF_POOLS * PRUETH_EMAC_BUF_POOL_SIZE; ++ ++ if (addr % SZ_64K) { ++ dev_warn(prueth->dev, "buffer pool needs to be 64KB aligned\n"); ++ return -EINVAL; ++ } ++ ++ bpool_cfg = emac->dram.va + BUFFER_POOL_0_ADDR_OFFSET; ++ /* workaround for f/w bug. bpool 0 needs to be initilalized */ ++ writel(addr, &bpool_cfg[0].addr); ++ writel(0, &bpool_cfg[0].len); ++ ++ for (i = PRUETH_EMAC_BUF_POOL_START; ++ i < PRUETH_EMAC_BUF_POOL_START + PRUETH_NUM_BUF_POOLS; ++ i++) { ++ writel(addr, &bpool_cfg[i].addr); ++ writel(PRUETH_EMAC_BUF_POOL_SIZE, &bpool_cfg[i].len); ++ addr += PRUETH_EMAC_BUF_POOL_SIZE; ++ } ++ ++ if (!slice) ++ addr += PRUETH_NUM_BUF_POOLS * PRUETH_EMAC_BUF_POOL_SIZE; ++ else ++ addr += PRUETH_EMAC_RX_CTX_BUF_SIZE * 2; ++ ++ /* Pre-emptible RX buffer queue */ ++ rxq_ctx = emac->dram.va + HOST_RX_Q_PRE_CONTEXT_OFFSET; ++ for (i = 0; i < 3; i++) ++ writel(addr, &rxq_ctx->start[i]); ++ ++ addr += PRUETH_EMAC_RX_CTX_BUF_SIZE; ++ writel(addr, &rxq_ctx->end); ++ ++ /* Express RX buffer queue */ ++ rxq_ctx = emac->dram.va + HOST_RX_Q_EXP_CONTEXT_OFFSET; ++ for (i = 0; i < 3; i++) ++ writel(addr, &rxq_ctx->start[i]); ++ ++ addr += PRUETH_EMAC_RX_CTX_BUF_SIZE; ++ writel(addr, &rxq_ctx->end); ++ ++ return 0; ++} ++ ++static void icssg_init_emac_mode(struct prueth *prueth) ++{ ++ /* When the device is configured as a bridge and it is being brought ++ * back to the emac mode, the host mac address has to be set as 0. ++ */ ++ u8 mac[ETH_ALEN] = { 0 }; ++ ++ if (prueth->emacs_initialized) ++ return; ++ ++ regmap_update_bits(prueth->miig_rt, FDB_GEN_CFG1, ++ SMEM_VLAN_OFFSET_MASK, 0); ++ regmap_write(prueth->miig_rt, FDB_GEN_CFG2, 0); ++ /* Clear host MAC address */ ++ icssg_class_set_host_mac_addr(prueth->miig_rt, mac); ++} ++ ++int icssg_config(struct prueth *prueth, struct prueth_emac *emac, int slice) ++{ ++ void __iomem *config = emac->dram.va + ICSSG_CONFIG_OFFSET; ++ struct icssg_flow_cfg __iomem *flow_cfg; ++ int ret; ++ ++ icssg_init_emac_mode(prueth); ++ ++ memset_io(config, 0, TAS_GATE_MASK_LIST0); ++ icssg_miig_queues_init(prueth, slice); ++ ++ emac->speed = SPEED_1000; ++ emac->duplex = DUPLEX_FULL; ++ if (!phy_interface_mode_is_rgmii(emac->phy_if)) { ++ emac->speed = SPEED_100; ++ emac->duplex = DUPLEX_FULL; ++ } ++ regmap_update_bits(prueth->miig_rt, ICSSG_CFG_OFFSET, ++ ICSSG_CFG_DEFAULT, ICSSG_CFG_DEFAULT); ++ icssg_miig_set_interface_mode(prueth->miig_rt, slice, emac->phy_if); ++ icssg_config_mii_init(emac); ++ icssg_config_ipg(emac); ++ icssg_update_rgmii_cfg(prueth->miig_rt, emac); ++ ++ /* set GPI mode */ ++ pruss_cfg_gpimode(prueth->pruss, prueth->pru_id[slice], ++ PRUSS_GPI_MODE_MII); ++ ++ /* enable XFR shift for PRU and RTU */ ++ pruss_cfg_xfr_enable(prueth->pruss, PRU_TYPE_PRU, true); ++ pruss_cfg_xfr_enable(prueth->pruss, PRU_TYPE_RTU, true); ++ ++ /* set C28 to 0x100 */ ++ pru_rproc_set_ctable(prueth->pru[slice], PRU_C28, 0x100 << 8); ++ pru_rproc_set_ctable(prueth->rtu[slice], PRU_C28, 0x100 << 8); ++ pru_rproc_set_ctable(prueth->txpru[slice], PRU_C28, 0x100 << 8); ++ ++ flow_cfg = config + PSI_L_REGULAR_FLOW_ID_BASE_OFFSET; ++ writew(emac->rx_flow_id_base, &flow_cfg->rx_base_flow); ++ writew(0, &flow_cfg->mgm_base_flow); ++ writeb(0, config + SPL_PKT_DEFAULT_PRIORITY); ++ writeb(0, config + QUEUE_NUM_UNTAGGED); ++ ++ ret = prueth_emac_buffer_setup(emac); ++ if (ret) ++ return ret; ++ ++ emac_r30_cmd_init(emac); ++ ++ return 0; ++} ++ ++/* Bitmask for ICSSG r30 commands */ ++static const struct icssg_r30_cmd emac_r32_bitmask[] = { ++ {{0xffff0004, 0xffff0100, 0xffff0100, EMAC_NONE}}, /* EMAC_PORT_DISABLE */ ++ {{0xfffb0040, 0xfeff0200, 0xfeff0200, EMAC_NONE}}, /* EMAC_PORT_BLOCK */ ++ {{0xffbb0000, 0xfcff0000, 0xdcff0000, EMAC_NONE}}, /* EMAC_PORT_FORWARD */ ++ {{0xffbb0000, 0xfcff0000, 0xfcff2000, EMAC_NONE}}, /* EMAC_PORT_FORWARD_WO_LEARNING */ ++ {{0xffff0001, EMAC_NONE, EMAC_NONE, EMAC_NONE}}, /* ACCEPT ALL */ ++ {{0xfffe0002, EMAC_NONE, EMAC_NONE, EMAC_NONE}}, /* ACCEPT TAGGED */ ++ {{0xfffc0000, EMAC_NONE, EMAC_NONE, EMAC_NONE}}, /* ACCEPT UNTAGGED and PRIO */ ++ {{EMAC_NONE, 0xffff0020, EMAC_NONE, EMAC_NONE}}, /* TAS Trigger List change */ ++ {{EMAC_NONE, 0xdfff1000, EMAC_NONE, EMAC_NONE}}, /* TAS set state ENABLE*/ ++ {{EMAC_NONE, 0xefff2000, EMAC_NONE, EMAC_NONE}}, /* TAS set state RESET*/ ++ {{EMAC_NONE, 0xcfff0000, EMAC_NONE, EMAC_NONE}}, /* TAS set state DISABLE*/ ++ {{EMAC_NONE, EMAC_NONE, 0xffff0400, EMAC_NONE}}, /* UC flooding ENABLE*/ ++ {{EMAC_NONE, EMAC_NONE, 0xfbff0000, EMAC_NONE}}, /* UC flooding DISABLE*/ ++ {{EMAC_NONE, EMAC_NONE, 0xffff0800, EMAC_NONE}}, /* MC flooding ENABLE*/ ++ {{EMAC_NONE, EMAC_NONE, 0xf7ff0000, EMAC_NONE}}, /* MC flooding DISABLE*/ ++ {{EMAC_NONE, 0xffff4000, EMAC_NONE, EMAC_NONE}}, /* Preemption on Tx ENABLE*/ ++ {{EMAC_NONE, 0xbfff0000, EMAC_NONE, EMAC_NONE}}, /* Preemption on Tx DISABLE*/ ++ {{0xffff0010, EMAC_NONE, 0xffff0010, EMAC_NONE}}, /* VLAN AWARE*/ ++ {{0xffef0000, EMAC_NONE, 0xffef0000, EMAC_NONE}} /* VLAN UNWARE*/ ++}; ++ ++int emac_set_port_state(struct prueth_emac *emac, ++ enum icssg_port_state_cmd cmd) ++{ ++ struct icssg_r30_cmd __iomem *p; ++ int ret = -ETIMEDOUT; ++ int done = 0; ++ int i; ++ ++ p = emac->dram.va + MGR_R30_CMD_OFFSET; ++ ++ if (cmd >= ICSSG_EMAC_PORT_MAX_COMMANDS) { ++ netdev_err(emac->ndev, "invalid port command\n"); ++ return -EINVAL; ++ } ++ ++ /* only one command at a time allowed to firmware */ ++ mutex_lock(&emac->cmd_lock); ++ ++ for (i = 0; i < 4; i++) ++ writel(emac_r32_bitmask[cmd].cmd[i], &p->cmd[i]); ++ ++ /* wait for done */ ++ ret = read_poll_timeout(emac_r30_is_done, done, done == 1, ++ 1000, 10000, false, emac); ++ ++ if (ret == -ETIMEDOUT) ++ netdev_err(emac->ndev, "timeout waiting for command done\n"); ++ ++ mutex_unlock(&emac->cmd_lock); ++ ++ return ret; ++} ++ ++void icssg_config_set_speed(struct prueth_emac *emac) ++{ ++ u8 fw_speed; ++ ++ switch (emac->speed) { ++ case SPEED_1000: ++ fw_speed = FW_LINK_SPEED_1G; ++ break; ++ case SPEED_100: ++ fw_speed = FW_LINK_SPEED_100M; ++ break; ++ default: ++ /* Other links speeds not supported */ ++ netdev_err(emac->ndev, "Unsupported link speed\n"); ++ return; ++ } ++ ++ writeb(fw_speed, emac->dram.va + PORT_LINK_SPEED_OFFSET); ++} +diff --git a/drivers/net/ethernet/ti/icssg/icssg_config.h b/drivers/net/ethernet/ti/icssg/icssg_config.h +new file mode 100644 +index 000000000000..43eb0922172a +--- /dev/null ++++ b/drivers/net/ethernet/ti/icssg/icssg_config.h +@@ -0,0 +1,200 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* Texas Instruments ICSSG Ethernet driver ++ * ++ * Copyright (C) 2022 Texas Instruments Incorporated - https://www.ti.com/ ++ * ++ */ ++ ++#ifndef __NET_TI_ICSSG_CONFIG_H ++#define __NET_TI_ICSSG_CONFIG_H ++ ++struct icssg_buffer_pool_cfg { ++ __le32 addr; ++ __le32 len; ++} __packed; ++ ++struct icssg_flow_cfg { ++ __le16 rx_base_flow; ++ __le16 mgm_base_flow; ++} __packed; ++ ++#define PRUETH_PKT_TYPE_CMD 0x10 ++#define PRUETH_NAV_PS_DATA_SIZE 16 /* Protocol specific data size */ ++#define PRUETH_NAV_SW_DATA_SIZE 16 /* SW related data size */ ++#define PRUETH_MAX_TX_DESC 512 ++#define PRUETH_MAX_RX_DESC 512 ++#define PRUETH_MAX_RX_FLOWS 1 /* excluding default flow */ ++#define PRUETH_RX_FLOW_DATA 0 ++ ++#define PRUETH_EMAC_BUF_POOL_SIZE SZ_8K ++#define PRUETH_EMAC_POOLS_PER_SLICE 24 ++#define PRUETH_EMAC_BUF_POOL_START 8 ++#define PRUETH_NUM_BUF_POOLS 8 ++#define PRUETH_EMAC_RX_CTX_BUF_SIZE SZ_16K /* per slice */ ++#define MSMC_RAM_SIZE \ ++ (2 * (PRUETH_EMAC_BUF_POOL_SIZE * PRUETH_NUM_BUF_POOLS + \ ++ PRUETH_EMAC_RX_CTX_BUF_SIZE * 2)) ++ ++struct icssg_rxq_ctx { ++ __le32 start[3]; ++ __le32 end; ++} __packed; ++ ++/* Load time Fiwmware Configuration */ ++ ++#define ICSSG_FW_MGMT_CMD_HEADER 0x81 ++#define ICSSG_FW_MGMT_FDB_CMD_TYPE 0x03 ++#define ICSSG_FW_MGMT_CMD_TYPE 0x04 ++#define ICSSG_FW_MGMT_PKT 0x80000000 ++ ++struct icssg_r30_cmd { ++ u32 cmd[4]; ++} __packed; ++ ++enum icssg_port_state_cmd { ++ ICSSG_EMAC_PORT_DISABLE = 0, ++ ICSSG_EMAC_PORT_BLOCK, ++ ICSSG_EMAC_PORT_FORWARD, ++ ICSSG_EMAC_PORT_FORWARD_WO_LEARNING, ++ ICSSG_EMAC_PORT_ACCEPT_ALL, ++ ICSSG_EMAC_PORT_ACCEPT_TAGGED, ++ ICSSG_EMAC_PORT_ACCEPT_UNTAGGED_N_PRIO, ++ ICSSG_EMAC_PORT_TAS_TRIGGER, ++ ICSSG_EMAC_PORT_TAS_ENABLE, ++ ICSSG_EMAC_PORT_TAS_RESET, ++ ICSSG_EMAC_PORT_TAS_DISABLE, ++ ICSSG_EMAC_PORT_UC_FLOODING_ENABLE, ++ ICSSG_EMAC_PORT_UC_FLOODING_DISABLE, ++ ICSSG_EMAC_PORT_MC_FLOODING_ENABLE, ++ ICSSG_EMAC_PORT_MC_FLOODING_DISABLE, ++ ICSSG_EMAC_PORT_PREMPT_TX_ENABLE, ++ ICSSG_EMAC_PORT_PREMPT_TX_DISABLE, ++ ICSSG_EMAC_PORT_VLAN_AWARE_ENABLE, ++ ICSSG_EMAC_PORT_VLAN_AWARE_DISABLE, ++ ICSSG_EMAC_PORT_MAX_COMMANDS ++}; ++ ++#define EMAC_NONE 0xffff0000 ++#define EMAC_PRU0_P_DI 0xffff0004 ++#define EMAC_PRU1_P_DI 0xffff0040 ++#define EMAC_TX_P_DI 0xffff0100 ++ ++#define EMAC_PRU0_P_EN 0xfffb0000 ++#define EMAC_PRU1_P_EN 0xffbf0000 ++#define EMAC_TX_P_EN 0xfeff0000 ++ ++#define EMAC_P_BLOCK 0xffff0040 ++#define EMAC_TX_P_BLOCK 0xffff0200 ++#define EMAC_P_UNBLOCK 0xffbf0000 ++#define EMAC_TX_P_UNBLOCK 0xfdff0000 ++#define EMAC_LEAN_EN 0xfff70000 ++#define EMAC_LEAN_DI 0xffff0008 ++ ++#define EMAC_ACCEPT_ALL 0xffff0001 ++#define EMAC_ACCEPT_TAG 0xfffe0002 ++#define EMAC_ACCEPT_PRIOR 0xfffc0000 ++ ++/* Config area lies in DRAM */ ++#define ICSSG_CONFIG_OFFSET 0x0 ++ ++/* Config area lies in shared RAM */ ++#define ICSSG_CONFIG_OFFSET_SLICE0 0 ++#define ICSSG_CONFIG_OFFSET_SLICE1 0x8000 ++ ++#define ICSSG_NUM_NORMAL_PDS 64 ++#define ICSSG_NUM_SPECIAL_PDS 16 ++ ++#define ICSSG_NORMAL_PD_SIZE 8 ++#define ICSSG_SPECIAL_PD_SIZE 20 ++ ++#define ICSSG_FLAG_MASK 0xff00ffff ++ ++struct icssg_setclock_desc { ++ u8 request; ++ u8 restore; ++ u8 acknowledgment; ++ u8 cmp_status; ++ u32 margin; ++ u32 cyclecounter0_set; ++ u32 cyclecounter1_set; ++ u32 iepcount_set; ++ u32 rsvd1; ++ u32 rsvd2; ++ u32 CMP0_current; ++ u32 iepcount_current; ++ u32 difference; ++ u32 cyclecounter0_new; ++ u32 cyclecounter1_new; ++ u32 CMP0_new; ++} __packed; ++ ++#define ICSSG_CMD_POP_SLICE0 56 ++#define ICSSG_CMD_POP_SLICE1 60 ++ ++#define ICSSG_CMD_PUSH_SLICE0 57 ++#define ICSSG_CMD_PUSH_SLICE1 61 ++ ++#define ICSSG_RSP_POP_SLICE0 58 ++#define ICSSG_RSP_POP_SLICE1 62 ++ ++#define ICSSG_RSP_PUSH_SLICE0 56 ++#define ICSSG_RSP_PUSH_SLICE1 60 ++ ++#define ICSSG_TS_POP_SLICE0 59 ++#define ICSSG_TS_POP_SLICE1 63 ++ ++#define ICSSG_TS_PUSH_SLICE0 40 ++#define ICSSG_TS_PUSH_SLICE1 41 ++ ++/* FDB FID_C2 flag definitions */ ++/* Indicates host port membership.*/ ++#define ICSSG_FDB_ENTRY_P0_MEMBERSHIP BIT(0) ++/* Indicates that MAC ID is connected to physical port 1 */ ++#define ICSSG_FDB_ENTRY_P1_MEMBERSHIP BIT(1) ++/* Indicates that MAC ID is connected to physical port 2 */ ++#define ICSSG_FDB_ENTRY_P2_MEMBERSHIP BIT(2) ++/* Ageable bit is set for learned entries and cleared for static entries */ ++#define ICSSG_FDB_ENTRY_AGEABLE BIT(3) ++/* If set for DA then packet is determined to be a special packet */ ++#define ICSSG_FDB_ENTRY_BLOCK BIT(4) ++/* If set for DA then the SA from the packet is not learned */ ++#define ICSSG_FDB_ENTRY_SECURE BIT(5) ++/* If set, it means packet has been seen recently with source address + FID ++ * matching MAC address/FID of entry ++ */ ++#define ICSSG_FDB_ENTRY_TOUCHED BIT(6) ++/* Set if entry is valid */ ++#define ICSSG_FDB_ENTRY_VALID BIT(7) ++ ++/** ++ * struct prueth_vlan_tbl - VLAN table entries struct in ICSSG SMEM ++ * @fid_c1: membership and forwarding rules flag to this table. See ++ * above to defines for bit definitions ++ * @fid: FDB index for this VID (there is 1-1 mapping b/w VID and FID) ++ */ ++struct prueth_vlan_tbl { ++ u8 fid_c1; ++ u8 fid; ++} __packed; ++ ++/** ++ * struct prueth_fdb_slot - Result of FDB slot lookup ++ * @mac: MAC address ++ * @fid: fid to be associated with MAC ++ * @fid_c2: FID_C2 entry for this MAC ++ */ ++struct prueth_fdb_slot { ++ u8 mac[ETH_ALEN]; ++ u8 fid; ++ u8 fid_c2; ++} __packed; ++ ++enum icssg_ietfpe_verify_states { ++ ICSSG_IETFPE_STATE_UNKNOWN = 0, ++ ICSSG_IETFPE_STATE_INITIAL, ++ ICSSG_IETFPE_STATE_VERIFYING, ++ ICSSG_IETFPE_STATE_SUCCEEDED, ++ ICSSG_IETFPE_STATE_FAILED, ++ ICSSG_IETFPE_STATE_DISABLED ++}; ++#endif /* __NET_TI_ICSSG_CONFIG_H */ +diff --git a/drivers/net/ethernet/ti/icssg/icssg_prueth.h b/drivers/net/ethernet/ti/icssg/icssg_prueth.h +index 8512f19a9b4d..e93488a79dbf 100644 +--- a/drivers/net/ethernet/ti/icssg/icssg_prueth.h ++++ b/drivers/net/ethernet/ti/icssg/icssg_prueth.h +@@ -194,4 +194,19 @@ static inline int prueth_emac_slice(struct prueth_emac *emac) + } + } + ++/* Classifier helpers */ ++void icssg_class_set_mac_addr(struct regmap *miig_rt, int slice, u8 *mac); ++void icssg_class_set_host_mac_addr(struct regmap *miig_rt, const u8 *mac); ++void icssg_class_disable(struct regmap *miig_rt, int slice); ++void icssg_class_default(struct regmap *miig_rt, int slice, bool allmulti); ++void icssg_ft1_set_mac_addr(struct regmap *miig_rt, int slice, u8 *mac_addr); ++ ++/* config helpers */ ++void icssg_config_ipg(struct prueth_emac *emac); ++int icssg_config(struct prueth *prueth, struct prueth_emac *emac, ++ int slice); ++int emac_set_port_state(struct prueth_emac *emac, ++ enum icssg_port_state_cmd state); ++void icssg_config_set_speed(struct prueth_emac *emac); ++ + #endif /* __NET_TI_ICSSG_PRUETH_H */ +-- +2.42.0 + diff --git a/recipes-kernel/linux/files/patches-6.1/0019-net-ti-icssg-prueth-Add-icssg-queues-APIs-and-macros.patch b/recipes-kernel/linux/files/patches-6.1/0019-net-ti-icssg-prueth-Add-icssg-queues-APIs-and-macros.patch new file mode 100644 index 000000000..16d1193c9 --- /dev/null +++ b/recipes-kernel/linux/files/patches-6.1/0019-net-ti-icssg-prueth-Add-icssg-queues-APIs-and-macros.patch @@ -0,0 +1,90 @@ +From f791aad7bf10fb5964484f0f18324ad2fea0e60f Mon Sep 17 00:00:00 2001 +From: MD Danish Anwar +Date: Tue, 1 Aug 2023 14:44:22 +0530 +Subject: [PATCH 19/69] net: ti: icssg-prueth: Add icssg queues APIs and macros + +Add icssg_queue.c file. This file introduces macros and APIs related to +ICSSG queues. These will be used by ICSSG Ethernet driver. + +Reviewed-by: Andrew Lunn +Signed-off-by: MD Danish Anwar +[Commit b8d5008f8c51 upstream] +--- + drivers/net/ethernet/ti/icssg/icssg_prueth.h | 5 ++ + drivers/net/ethernet/ti/icssg/icssg_queues.c | 50 ++++++++++++++++++++ + 2 files changed, 55 insertions(+) + create mode 100644 drivers/net/ethernet/ti/icssg/icssg_queues.c + +diff --git a/drivers/net/ethernet/ti/icssg/icssg_prueth.h b/drivers/net/ethernet/ti/icssg/icssg_prueth.h +index e93488a79dbf..42fdf4005010 100644 +--- a/drivers/net/ethernet/ti/icssg/icssg_prueth.h ++++ b/drivers/net/ethernet/ti/icssg/icssg_prueth.h +@@ -209,4 +209,9 @@ int emac_set_port_state(struct prueth_emac *emac, + enum icssg_port_state_cmd state); + void icssg_config_set_speed(struct prueth_emac *emac); + ++/* Buffer queue helpers */ ++int icssg_queue_pop(struct prueth *prueth, u8 queue); ++void icssg_queue_push(struct prueth *prueth, int queue, u16 addr); ++u32 icssg_queue_level(struct prueth *prueth, int queue); ++ + #endif /* __NET_TI_ICSSG_PRUETH_H */ +diff --git a/drivers/net/ethernet/ti/icssg/icssg_queues.c b/drivers/net/ethernet/ti/icssg/icssg_queues.c +new file mode 100644 +index 000000000000..3c34f61ad40b +--- /dev/null ++++ b/drivers/net/ethernet/ti/icssg/icssg_queues.c +@@ -0,0 +1,50 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ICSSG Buffer queue helpers ++ * ++ * Copyright (C) 2021 Texas Instruments Incorporated - https://www.ti.com ++ */ ++ ++#include ++#include "icssg_prueth.h" ++ ++#define ICSSG_QUEUES_MAX 64 ++#define ICSSG_QUEUE_OFFSET 0xd00 ++#define ICSSG_QUEUE_PEEK_OFFSET 0xe00 ++#define ICSSG_QUEUE_CNT_OFFSET 0xe40 ++#define ICSSG_QUEUE_RESET_OFFSET 0xf40 ++ ++int icssg_queue_pop(struct prueth *prueth, u8 queue) ++{ ++ u32 val, cnt; ++ ++ if (queue >= ICSSG_QUEUES_MAX) ++ return -EINVAL; ++ ++ regmap_read(prueth->miig_rt, ICSSG_QUEUE_CNT_OFFSET + 4 * queue, &cnt); ++ if (!cnt) ++ return -EINVAL; ++ ++ regmap_read(prueth->miig_rt, ICSSG_QUEUE_OFFSET + 4 * queue, &val); ++ ++ return val; ++} ++ ++void icssg_queue_push(struct prueth *prueth, int queue, u16 addr) ++{ ++ if (queue >= ICSSG_QUEUES_MAX) ++ return; ++ ++ regmap_write(prueth->miig_rt, ICSSG_QUEUE_OFFSET + 4 * queue, addr); ++} ++ ++u32 icssg_queue_level(struct prueth *prueth, int queue) ++{ ++ u32 reg; ++ ++ if (queue >= ICSSG_QUEUES_MAX) ++ return 0; ++ ++ regmap_read(prueth->miig_rt, ICSSG_QUEUE_CNT_OFFSET + 4 * queue, ®); ++ ++ return reg; ++} +-- +2.42.0 + diff --git a/recipes-kernel/linux/files/patches-6.1/0020-dt-bindings-net-Add-ICSSG-Ethernet.patch b/recipes-kernel/linux/files/patches-6.1/0020-dt-bindings-net-Add-ICSSG-Ethernet.patch new file mode 100644 index 000000000..c8a4bd181 --- /dev/null +++ b/recipes-kernel/linux/files/patches-6.1/0020-dt-bindings-net-Add-ICSSG-Ethernet.patch @@ -0,0 +1,211 @@ +From 56018385d79e77e766aa7d38225a4a96d2bfd43a Mon Sep 17 00:00:00 2001 +From: MD Danish Anwar +Date: Tue, 1 Aug 2023 14:44:23 +0530 +Subject: [PATCH 20/69] dt-bindings: net: Add ICSSG Ethernet + +Add a YAML binding document for the ICSSG Programmable real time unit +based Ethernet hardware. The ICSSG driver uses the PRU and PRUSS consumer +APIs to interface the PRUs and load/run the firmware for supporting +ethernet functionality. + +Reviewed-by: Rob Herring +Signed-off-by: MD Danish Anwar +[Commit 172e604a8c62 upstream] +--- + .../bindings/net/ti,icssg-prueth.yaml | 184 ++++++++++++++++++ + 1 file changed, 184 insertions(+) + create mode 100644 Documentation/devicetree/bindings/net/ti,icssg-prueth.yaml + +diff --git a/Documentation/devicetree/bindings/net/ti,icssg-prueth.yaml b/Documentation/devicetree/bindings/net/ti,icssg-prueth.yaml +new file mode 100644 +index 000000000000..8ec30b3eb760 +--- /dev/null ++++ b/Documentation/devicetree/bindings/net/ti,icssg-prueth.yaml +@@ -0,0 +1,184 @@ ++# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/net/ti,icssg-prueth.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: Texas Instruments ICSSG PRUSS Ethernet ++ ++maintainers: ++ - Md Danish Anwar ++ ++description: ++ Ethernet based on the Programmable Real-Time Unit and Industrial ++ Communication Subsystem. ++ ++allOf: ++ - $ref: /schemas/remoteproc/ti,pru-consumer.yaml# ++ ++properties: ++ compatible: ++ enum: ++ - ti,am654-icssg-prueth # for AM65x SoC family ++ ++ sram: ++ $ref: /schemas/types.yaml#/definitions/phandle ++ description: ++ phandle to MSMC SRAM node ++ ++ dmas: ++ maxItems: 10 ++ ++ dma-names: ++ items: ++ - const: tx0-0 ++ - const: tx0-1 ++ - const: tx0-2 ++ - const: tx0-3 ++ - const: tx1-0 ++ - const: tx1-1 ++ - const: tx1-2 ++ - const: tx1-3 ++ - const: rx0 ++ - const: rx1 ++ ++ ti,mii-g-rt: ++ $ref: /schemas/types.yaml#/definitions/phandle ++ description: ++ phandle to MII_G_RT module's syscon regmap. ++ ++ ti,mii-rt: ++ $ref: /schemas/types.yaml#/definitions/phandle ++ description: ++ phandle to MII_RT module's syscon regmap ++ ++ interrupts: ++ maxItems: 2 ++ description: ++ Interrupt specifiers to TX timestamp IRQ. ++ ++ interrupt-names: ++ items: ++ - const: tx_ts0 ++ - const: tx_ts1 ++ ++ ethernet-ports: ++ type: object ++ additionalProperties: false ++ ++ properties: ++ '#address-cells': ++ const: 1 ++ '#size-cells': ++ const: 0 ++ ++ patternProperties: ++ ^port@[0-1]$: ++ type: object ++ description: ICSSG PRUETH external ports ++ $ref: ethernet-controller.yaml# ++ unevaluatedProperties: false ++ ++ properties: ++ reg: ++ items: ++ - enum: [0, 1] ++ description: ICSSG PRUETH port number ++ ++ interrupts: ++ maxItems: 1 ++ ++ ti,syscon-rgmii-delay: ++ items: ++ - items: ++ - description: phandle to system controller node ++ - description: The offset to ICSSG control register ++ $ref: /schemas/types.yaml#/definitions/phandle-array ++ description: ++ phandle to system controller node and register offset ++ to ICSSG control register for RGMII transmit delay ++ ++ required: ++ - reg ++ anyOf: ++ - required: ++ - port@0 ++ - required: ++ - port@1 ++ ++required: ++ - compatible ++ - sram ++ - dmas ++ - dma-names ++ - ethernet-ports ++ - ti,mii-g-rt ++ - interrupts ++ - interrupt-names ++ ++unevaluatedProperties: false ++ ++examples: ++ - | ++ /* Example k3-am654 base board SR2.0, dual-emac */ ++ pruss2_eth: ethernet { ++ compatible = "ti,am654-icssg-prueth"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&icssg2_rgmii_pins_default>; ++ sram = <&msmc_ram>; ++ ++ ti,prus = <&pru2_0>, <&rtu2_0>, <&tx_pru2_0>, ++ <&pru2_1>, <&rtu2_1>, <&tx_pru2_1>; ++ firmware-name = "ti-pruss/am65x-pru0-prueth-fw.elf", ++ "ti-pruss/am65x-rtu0-prueth-fw.elf", ++ "ti-pruss/am65x-txpru0-prueth-fw.elf", ++ "ti-pruss/am65x-pru1-prueth-fw.elf", ++ "ti-pruss/am65x-rtu1-prueth-fw.elf", ++ "ti-pruss/am65x-txpru1-prueth-fw.elf"; ++ ti,pruss-gp-mux-sel = <2>, /* MII mode */ ++ <2>, ++ <2>, ++ <2>, /* MII mode */ ++ <2>, ++ <2>; ++ dmas = <&main_udmap 0xc300>, /* egress slice 0 */ ++ <&main_udmap 0xc301>, /* egress slice 0 */ ++ <&main_udmap 0xc302>, /* egress slice 0 */ ++ <&main_udmap 0xc303>, /* egress slice 0 */ ++ <&main_udmap 0xc304>, /* egress slice 1 */ ++ <&main_udmap 0xc305>, /* egress slice 1 */ ++ <&main_udmap 0xc306>, /* egress slice 1 */ ++ <&main_udmap 0xc307>, /* egress slice 1 */ ++ <&main_udmap 0x4300>, /* ingress slice 0 */ ++ <&main_udmap 0x4301>; /* ingress slice 1 */ ++ dma-names = "tx0-0", "tx0-1", "tx0-2", "tx0-3", ++ "tx1-0", "tx1-1", "tx1-2", "tx1-3", ++ "rx0", "rx1"; ++ ti,mii-g-rt = <&icssg2_mii_g_rt>; ++ interrupt-parent = <&icssg2_intc>; ++ interrupts = <24 0 2>, <25 1 3>; ++ interrupt-names = "tx_ts0", "tx_ts1"; ++ ethernet-ports { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ pruss2_emac0: port@0 { ++ reg = <0>; ++ phy-handle = <&pruss2_eth0_phy>; ++ phy-mode = "rgmii-id"; ++ interrupts-extended = <&icssg2_intc 24>; ++ ti,syscon-rgmii-delay = <&scm_conf 0x4120>; ++ /* Filled in by bootloader */ ++ local-mac-address = [00 00 00 00 00 00]; ++ }; ++ ++ pruss2_emac1: port@1 { ++ reg = <1>; ++ phy-handle = <&pruss2_eth1_phy>; ++ phy-mode = "rgmii-id"; ++ interrupts-extended = <&icssg2_intc 25>; ++ ti,syscon-rgmii-delay = <&scm_conf 0x4124>; ++ /* Filled in by bootloader */ ++ local-mac-address = [00 00 00 00 00 00]; ++ }; ++ }; ++ }; +-- +2.42.0 + diff --git a/recipes-kernel/linux/files/patches-6.1/0021-net-ti-icssg-prueth-Add-ICSSG-ethernet-driver.patch b/recipes-kernel/linux/files/patches-6.1/0021-net-ti-icssg-prueth-Add-ICSSG-ethernet-driver.patch new file mode 100644 index 000000000..7e08cec5e --- /dev/null +++ b/recipes-kernel/linux/files/patches-6.1/0021-net-ti-icssg-prueth-Add-ICSSG-ethernet-driver.patch @@ -0,0 +1,1958 @@ +From c57193dc2fe8e15c08bcb0532bec24c56563af22 Mon Sep 17 00:00:00 2001 +From: Roger Quadros +Date: Tue, 1 Aug 2023 14:44:24 +0530 +Subject: [PATCH 21/69] net: ti: icssg-prueth: Add ICSSG ethernet driver + +This is the Ethernet driver for TI AM654 Silicon rev. 2 +with the ICSSG PRU Sub-system running dual-EMAC firmware. + +The Programmable Real-time Unit and Industrial Communication Subsystem +Gigabit (PRU_ICSSG) is a low-latency microcontroller subsystem in the TI +SoCs. This subsystem is provided for the use cases like implementation of +custom peripheral interfaces, offloading of tasks from the other +processor cores of the SoC, etc. + +Every ICSSG core has two Programmable Real-Time Unit(PRUs), +two auxiliary Real-Time Transfer Unit (RT_PRUs), and +two Transmit Real-Time Transfer Units (TX_PRUs). Each one of these runs +its own firmware. Every ICSSG core has two MII ports connect to these +PRUs and also a MDIO port. + +The cores can run different firmwares to support different protocols and +features like switch-dev, timestamping, etc. + +It uses System DMA to transfer and receive packets and +shared memory register emulation between the firmware and +driver for control and configuration. + +This patch adds support for basic EMAC functionality with 1Gbps +and 100Mbps link speed. 10M and half duplex mode are not supported +currently as they require IEP, the support for which will be added later. +Support for switch-dev, timestamp, etc. will be added later +by subsequent patch series. + +Signed-off-by: Roger Quadros +Signed-off-by: Vignesh Raghavendra +Signed-off-by: Grygorii Strashko +Reviewed-by: Andrew Lunn +Signed-off-by: MD Danish Anwar +[Commit 128d5874c082 upstream] +--- + drivers/net/ethernet/ti/Kconfig | 13 + + drivers/net/ethernet/ti/Makefile | 8 + + drivers/net/ethernet/ti/icssg/icssg_prueth.c | 1809 ++++++++++++++++++ + drivers/net/ethernet/ti/icssg/icssg_prueth.h | 32 + + 4 files changed, 1862 insertions(+) + create mode 100644 drivers/net/ethernet/ti/icssg/icssg_prueth.c + +diff --git a/drivers/net/ethernet/ti/Kconfig b/drivers/net/ethernet/ti/Kconfig +index fce06663e1e1..63e510b6860f 100644 +--- a/drivers/net/ethernet/ti/Kconfig ++++ b/drivers/net/ethernet/ti/Kconfig +@@ -183,4 +183,17 @@ config CPMAC + help + TI AR7 CPMAC Ethernet support + ++config TI_ICSSG_PRUETH ++ tristate "TI Gigabit PRU Ethernet driver" ++ select PHYLIB ++ depends on PRU_REMOTEPROC ++ depends on ARCH_K3 && OF && TI_K3_UDMA_GLUE_LAYER ++ help ++ Support dual Gigabit Ethernet ports over the ICSSG PRU Subsystem. ++ This subsystem is available starting with the AM65 platform. ++ ++ This driver requires firmware binaries which will run on the PRUs ++ to support the Ethernet operation. Currently, it supports Ethernet ++ with 1G and 100M link speed. ++ + endif # NET_VENDOR_TI +diff --git a/drivers/net/ethernet/ti/Makefile b/drivers/net/ethernet/ti/Makefile +index 75f761efbea7..efb050cbb4a8 100644 +--- a/drivers/net/ethernet/ti/Makefile ++++ b/drivers/net/ethernet/ti/Makefile +@@ -28,3 +28,11 @@ obj-$(CONFIG_TI_K3_AM65_CPSW_NUSS) += ti-am65-cpsw-nuss.o + ti-am65-cpsw-nuss-y := am65-cpsw-nuss.o cpsw_sl.o am65-cpsw-ethtool.o cpsw_ale.o k3-cppi-desc-pool.o am65-cpsw-qos.o + ti-am65-cpsw-nuss-$(CONFIG_TI_K3_AM65_CPSW_SWITCHDEV) += am65-cpsw-switchdev.o + obj-$(CONFIG_TI_K3_AM65_CPTS) += am65-cpts.o ++ ++obj-$(CONFIG_TI_ICSSG_PRUETH) += icssg-prueth.o ++icssg-prueth-y := k3-cppi-desc-pool.o \ ++ icssg/icssg_prueth.o \ ++ icssg/icssg_classifier.o \ ++ icssg/icssg_queues.o \ ++ icssg/icssg_config.o \ ++ icssg/icssg_mii_cfg.o \ +diff --git a/drivers/net/ethernet/ti/icssg/icssg_prueth.c b/drivers/net/ethernet/ti/icssg/icssg_prueth.c +new file mode 100644 +index 000000000000..1869e38f898f +--- /dev/null ++++ b/drivers/net/ethernet/ti/icssg/icssg_prueth.c +@@ -0,0 +1,1809 @@ ++// SPDX-License-Identifier: GPL-2.0 ++ ++/* Texas Instruments ICSSG Ethernet Driver ++ * ++ * Copyright (C) 2018-2022 Texas Instruments Incorporated - https://www.ti.com/ ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "icssg_prueth.h" ++#include "icssg_mii_rt.h" ++#include "../k3-cppi-desc-pool.h" ++ ++#define PRUETH_MODULE_DESCRIPTION "PRUSS ICSSG Ethernet driver" ++ ++/* Netif debug messages possible */ ++#define PRUETH_EMAC_DEBUG (NETIF_MSG_DRV | \ ++ NETIF_MSG_PROBE | \ ++ NETIF_MSG_LINK | \ ++ NETIF_MSG_TIMER | \ ++ NETIF_MSG_IFDOWN | \ ++ NETIF_MSG_IFUP | \ ++ NETIF_MSG_RX_ERR | \ ++ NETIF_MSG_TX_ERR | \ ++ NETIF_MSG_TX_QUEUED | \ ++ NETIF_MSG_INTR | \ ++ NETIF_MSG_TX_DONE | \ ++ NETIF_MSG_RX_STATUS | \ ++ NETIF_MSG_PKTDATA | \ ++ NETIF_MSG_HW | \ ++ NETIF_MSG_WOL) ++ ++#define prueth_napi_to_emac(napi) container_of(napi, struct prueth_emac, napi_rx) ++ ++/* CTRLMMR_ICSSG_RGMII_CTRL register bits */ ++#define ICSSG_CTRL_RGMII_ID_MODE BIT(24) ++ ++static void prueth_cleanup_rx_chns(struct prueth_emac *emac, ++ struct prueth_rx_chn *rx_chn, ++ int max_rflows) ++{ ++ if (rx_chn->desc_pool) ++ k3_cppi_desc_pool_destroy(rx_chn->desc_pool); ++ ++ if (rx_chn->rx_chn) ++ k3_udma_glue_release_rx_chn(rx_chn->rx_chn); ++} ++ ++static void prueth_cleanup_tx_chns(struct prueth_emac *emac) ++{ ++ int i; ++ ++ for (i = 0; i < emac->tx_ch_num; i++) { ++ struct prueth_tx_chn *tx_chn = &emac->tx_chns[i]; ++ ++ if (tx_chn->desc_pool) ++ k3_cppi_desc_pool_destroy(tx_chn->desc_pool); ++ ++ if (tx_chn->tx_chn) ++ k3_udma_glue_release_tx_chn(tx_chn->tx_chn); ++ ++ /* Assume prueth_cleanup_tx_chns() is called at the ++ * end after all channel resources are freed ++ */ ++ memset(tx_chn, 0, sizeof(*tx_chn)); ++ } ++} ++ ++static void prueth_ndev_del_tx_napi(struct prueth_emac *emac, int num) ++{ ++ int i; ++ ++ for (i = 0; i < num; i++) { ++ struct prueth_tx_chn *tx_chn = &emac->tx_chns[i]; ++ ++ if (tx_chn->irq) ++ free_irq(tx_chn->irq, tx_chn); ++ netif_napi_del(&tx_chn->napi_tx); ++ } ++} ++ ++static void prueth_xmit_free(struct prueth_tx_chn *tx_chn, ++ struct cppi5_host_desc_t *desc) ++{ ++ struct cppi5_host_desc_t *first_desc, *next_desc; ++ dma_addr_t buf_dma, next_desc_dma; ++ u32 buf_dma_len; ++ ++ first_desc = desc; ++ next_desc = first_desc; ++ ++ cppi5_hdesc_get_obuf(first_desc, &buf_dma, &buf_dma_len); ++ k3_udma_glue_tx_cppi5_to_dma_addr(tx_chn->tx_chn, &buf_dma); ++ ++ dma_unmap_single(tx_chn->dma_dev, buf_dma, buf_dma_len, ++ DMA_TO_DEVICE); ++ ++ next_desc_dma = cppi5_hdesc_get_next_hbdesc(first_desc); ++ k3_udma_glue_tx_cppi5_to_dma_addr(tx_chn->tx_chn, &next_desc_dma); ++ while (next_desc_dma) { ++ next_desc = k3_cppi_desc_pool_dma2virt(tx_chn->desc_pool, ++ next_desc_dma); ++ cppi5_hdesc_get_obuf(next_desc, &buf_dma, &buf_dma_len); ++ k3_udma_glue_tx_cppi5_to_dma_addr(tx_chn->tx_chn, &buf_dma); ++ ++ dma_unmap_page(tx_chn->dma_dev, buf_dma, buf_dma_len, ++ DMA_TO_DEVICE); ++ ++ next_desc_dma = cppi5_hdesc_get_next_hbdesc(next_desc); ++ k3_udma_glue_tx_cppi5_to_dma_addr(tx_chn->tx_chn, &next_desc_dma); ++ ++ k3_cppi_desc_pool_free(tx_chn->desc_pool, next_desc); ++ } ++ ++ k3_cppi_desc_pool_free(tx_chn->desc_pool, first_desc); ++} ++ ++static int emac_tx_complete_packets(struct prueth_emac *emac, int chn, ++ int budget) ++{ ++ struct net_device *ndev = emac->ndev; ++ struct cppi5_host_desc_t *desc_tx; ++ struct netdev_queue *netif_txq; ++ struct prueth_tx_chn *tx_chn; ++ unsigned int total_bytes = 0; ++ struct sk_buff *skb; ++ dma_addr_t desc_dma; ++ int res, num_tx = 0; ++ void **swdata; ++ ++ tx_chn = &emac->tx_chns[chn]; ++ ++ while (true) { ++ res = k3_udma_glue_pop_tx_chn(tx_chn->tx_chn, &desc_dma); ++ if (res == -ENODATA) ++ break; ++ ++ /* teardown completion */ ++ if (cppi5_desc_is_tdcm(desc_dma)) { ++ if (atomic_dec_and_test(&emac->tdown_cnt)) ++ complete(&emac->tdown_complete); ++ break; ++ } ++ ++ desc_tx = k3_cppi_desc_pool_dma2virt(tx_chn->desc_pool, ++ desc_dma); ++ swdata = cppi5_hdesc_get_swdata(desc_tx); ++ ++ skb = *(swdata); ++ prueth_xmit_free(tx_chn, desc_tx); ++ ++ ndev = skb->dev; ++ ndev->stats.tx_packets++; ++ ndev->stats.tx_bytes += skb->len; ++ total_bytes += skb->len; ++ napi_consume_skb(skb, budget); ++ num_tx++; ++ } ++ ++ if (!num_tx) ++ return 0; ++ ++ netif_txq = netdev_get_tx_queue(ndev, chn); ++ netdev_tx_completed_queue(netif_txq, num_tx, total_bytes); ++ ++ if (netif_tx_queue_stopped(netif_txq)) { ++ /* If the TX queue was stopped, wake it now ++ * if we have enough room. ++ */ ++ __netif_tx_lock(netif_txq, smp_processor_id()); ++ if (netif_running(ndev) && ++ (k3_cppi_desc_pool_avail(tx_chn->desc_pool) >= ++ MAX_SKB_FRAGS)) ++ netif_tx_wake_queue(netif_txq); ++ __netif_tx_unlock(netif_txq); ++ } ++ ++ return num_tx; ++} ++ ++static int emac_napi_tx_poll(struct napi_struct *napi_tx, int budget) ++{ ++ struct prueth_tx_chn *tx_chn = prueth_napi_to_tx_chn(napi_tx); ++ struct prueth_emac *emac = tx_chn->emac; ++ int num_tx_packets; ++ ++ num_tx_packets = emac_tx_complete_packets(emac, tx_chn->id, budget); ++ ++ if (num_tx_packets >= budget) ++ return budget; ++ ++ if (napi_complete_done(napi_tx, num_tx_packets)) ++ enable_irq(tx_chn->irq); ++ ++ return num_tx_packets; ++} ++ ++static irqreturn_t prueth_tx_irq(int irq, void *dev_id) ++{ ++ struct prueth_tx_chn *tx_chn = dev_id; ++ ++ disable_irq_nosync(irq); ++ napi_schedule(&tx_chn->napi_tx); ++ ++ return IRQ_HANDLED; ++} ++ ++static int prueth_ndev_add_tx_napi(struct prueth_emac *emac) ++{ ++ struct prueth *prueth = emac->prueth; ++ int i, ret; ++ ++ for (i = 0; i < emac->tx_ch_num; i++) { ++ struct prueth_tx_chn *tx_chn = &emac->tx_chns[i]; ++ ++ netif_napi_add_tx(emac->ndev, &tx_chn->napi_tx, emac_napi_tx_poll); ++ ret = request_irq(tx_chn->irq, prueth_tx_irq, ++ IRQF_TRIGGER_HIGH, tx_chn->name, ++ tx_chn); ++ if (ret) { ++ netif_napi_del(&tx_chn->napi_tx); ++ dev_err(prueth->dev, "unable to request TX IRQ %d\n", ++ tx_chn->irq); ++ goto fail; ++ } ++ } ++ ++ return 0; ++fail: ++ prueth_ndev_del_tx_napi(emac, i); ++ return ret; ++} ++ ++static int prueth_init_tx_chns(struct prueth_emac *emac) ++{ ++ static const struct k3_ring_cfg ring_cfg = { ++ .elm_size = K3_RINGACC_RING_ELSIZE_8, ++ .mode = K3_RINGACC_RING_MODE_RING, ++ .flags = 0, ++ .size = PRUETH_MAX_TX_DESC, ++ }; ++ struct k3_udma_glue_tx_channel_cfg tx_cfg; ++ struct device *dev = emac->prueth->dev; ++ struct net_device *ndev = emac->ndev; ++ int ret, slice, i; ++ u32 hdesc_size; ++ ++ slice = prueth_emac_slice(emac); ++ if (slice < 0) ++ return slice; ++ ++ init_completion(&emac->tdown_complete); ++ ++ hdesc_size = cppi5_hdesc_calc_size(true, PRUETH_NAV_PS_DATA_SIZE, ++ PRUETH_NAV_SW_DATA_SIZE); ++ memset(&tx_cfg, 0, sizeof(tx_cfg)); ++ tx_cfg.swdata_size = PRUETH_NAV_SW_DATA_SIZE; ++ tx_cfg.tx_cfg = ring_cfg; ++ tx_cfg.txcq_cfg = ring_cfg; ++ ++ for (i = 0; i < emac->tx_ch_num; i++) { ++ struct prueth_tx_chn *tx_chn = &emac->tx_chns[i]; ++ ++ /* To differentiate channels for SLICE0 vs SLICE1 */ ++ snprintf(tx_chn->name, sizeof(tx_chn->name), ++ "tx%d-%d", slice, i); ++ ++ tx_chn->emac = emac; ++ tx_chn->id = i; ++ tx_chn->descs_num = PRUETH_MAX_TX_DESC; ++ ++ tx_chn->tx_chn = ++ k3_udma_glue_request_tx_chn(dev, tx_chn->name, ++ &tx_cfg); ++ if (IS_ERR(tx_chn->tx_chn)) { ++ ret = PTR_ERR(tx_chn->tx_chn); ++ tx_chn->tx_chn = NULL; ++ netdev_err(ndev, ++ "Failed to request tx dma ch: %d\n", ret); ++ goto fail; ++ } ++ ++ tx_chn->dma_dev = k3_udma_glue_tx_get_dma_device(tx_chn->tx_chn); ++ tx_chn->desc_pool = ++ k3_cppi_desc_pool_create_name(tx_chn->dma_dev, ++ tx_chn->descs_num, ++ hdesc_size, ++ tx_chn->name); ++ if (IS_ERR(tx_chn->desc_pool)) { ++ ret = PTR_ERR(tx_chn->desc_pool); ++ tx_chn->desc_pool = NULL; ++ netdev_err(ndev, "Failed to create tx pool: %d\n", ret); ++ goto fail; ++ } ++ ++ tx_chn->irq = k3_udma_glue_tx_get_irq(tx_chn->tx_chn); ++ if (tx_chn->irq <= 0) { ++ ret = -EINVAL; ++ netdev_err(ndev, "failed to get tx irq\n"); ++ goto fail; ++ } ++ ++ snprintf(tx_chn->name, sizeof(tx_chn->name), "%s-tx%d", ++ dev_name(dev), tx_chn->id); ++ } ++ ++ return 0; ++ ++fail: ++ prueth_cleanup_tx_chns(emac); ++ return ret; ++} ++ ++static int prueth_init_rx_chns(struct prueth_emac *emac, ++ struct prueth_rx_chn *rx_chn, ++ char *name, u32 max_rflows, ++ u32 max_desc_num) ++{ ++ struct k3_udma_glue_rx_channel_cfg rx_cfg; ++ struct device *dev = emac->prueth->dev; ++ struct net_device *ndev = emac->ndev; ++ u32 fdqring_id, hdesc_size; ++ int i, ret = 0, slice; ++ ++ slice = prueth_emac_slice(emac); ++ if (slice < 0) ++ return slice; ++ ++ /* To differentiate channels for SLICE0 vs SLICE1 */ ++ snprintf(rx_chn->name, sizeof(rx_chn->name), "%s%d", name, slice); ++ ++ hdesc_size = cppi5_hdesc_calc_size(true, PRUETH_NAV_PS_DATA_SIZE, ++ PRUETH_NAV_SW_DATA_SIZE); ++ memset(&rx_cfg, 0, sizeof(rx_cfg)); ++ rx_cfg.swdata_size = PRUETH_NAV_SW_DATA_SIZE; ++ rx_cfg.flow_id_num = max_rflows; ++ rx_cfg.flow_id_base = -1; /* udmax will auto select flow id base */ ++ ++ /* init all flows */ ++ rx_chn->dev = dev; ++ rx_chn->descs_num = max_desc_num; ++ ++ rx_chn->rx_chn = k3_udma_glue_request_rx_chn(dev, rx_chn->name, ++ &rx_cfg); ++ if (IS_ERR(rx_chn->rx_chn)) { ++ ret = PTR_ERR(rx_chn->rx_chn); ++ rx_chn->rx_chn = NULL; ++ netdev_err(ndev, "Failed to request rx dma ch: %d\n", ret); ++ goto fail; ++ } ++ ++ rx_chn->dma_dev = k3_udma_glue_rx_get_dma_device(rx_chn->rx_chn); ++ rx_chn->desc_pool = k3_cppi_desc_pool_create_name(rx_chn->dma_dev, ++ rx_chn->descs_num, ++ hdesc_size, ++ rx_chn->name); ++ if (IS_ERR(rx_chn->desc_pool)) { ++ ret = PTR_ERR(rx_chn->desc_pool); ++ rx_chn->desc_pool = NULL; ++ netdev_err(ndev, "Failed to create rx pool: %d\n", ret); ++ goto fail; ++ } ++ ++ emac->rx_flow_id_base = k3_udma_glue_rx_get_flow_id_base(rx_chn->rx_chn); ++ netdev_dbg(ndev, "flow id base = %d\n", emac->rx_flow_id_base); ++ ++ fdqring_id = K3_RINGACC_RING_ID_ANY; ++ for (i = 0; i < rx_cfg.flow_id_num; i++) { ++ struct k3_ring_cfg rxring_cfg = { ++ .elm_size = K3_RINGACC_RING_ELSIZE_8, ++ .mode = K3_RINGACC_RING_MODE_RING, ++ .flags = 0, ++ }; ++ struct k3_ring_cfg fdqring_cfg = { ++ .elm_size = K3_RINGACC_RING_ELSIZE_8, ++ .flags = K3_RINGACC_RING_SHARED, ++ }; ++ struct k3_udma_glue_rx_flow_cfg rx_flow_cfg = { ++ .rx_cfg = rxring_cfg, ++ .rxfdq_cfg = fdqring_cfg, ++ .ring_rxq_id = K3_RINGACC_RING_ID_ANY, ++ .src_tag_lo_sel = ++ K3_UDMA_GLUE_SRC_TAG_LO_USE_REMOTE_SRC_TAG, ++ }; ++ ++ rx_flow_cfg.ring_rxfdq0_id = fdqring_id; ++ rx_flow_cfg.rx_cfg.size = max_desc_num; ++ rx_flow_cfg.rxfdq_cfg.size = max_desc_num; ++ rx_flow_cfg.rxfdq_cfg.mode = emac->prueth->pdata.fdqring_mode; ++ ++ ret = k3_udma_glue_rx_flow_init(rx_chn->rx_chn, ++ i, &rx_flow_cfg); ++ if (ret) { ++ netdev_err(ndev, "Failed to init rx flow%d %d\n", ++ i, ret); ++ goto fail; ++ } ++ if (!i) ++ fdqring_id = k3_udma_glue_rx_flow_get_fdq_id(rx_chn->rx_chn, ++ i); ++ rx_chn->irq[i] = k3_udma_glue_rx_get_irq(rx_chn->rx_chn, i); ++ if (rx_chn->irq[i] <= 0) { ++ ret = rx_chn->irq[i]; ++ netdev_err(ndev, "Failed to get rx dma irq"); ++ goto fail; ++ } ++ } ++ ++ return 0; ++ ++fail: ++ prueth_cleanup_rx_chns(emac, rx_chn, max_rflows); ++ return ret; ++} ++ ++static int prueth_dma_rx_push(struct prueth_emac *emac, ++ struct sk_buff *skb, ++ struct prueth_rx_chn *rx_chn) ++{ ++ struct net_device *ndev = emac->ndev; ++ struct cppi5_host_desc_t *desc_rx; ++ u32 pkt_len = skb_tailroom(skb); ++ dma_addr_t desc_dma; ++ dma_addr_t buf_dma; ++ void **swdata; ++ ++ desc_rx = k3_cppi_desc_pool_alloc(rx_chn->desc_pool); ++ if (!desc_rx) { ++ netdev_err(ndev, "rx push: failed to allocate descriptor\n"); ++ return -ENOMEM; ++ } ++ desc_dma = k3_cppi_desc_pool_virt2dma(rx_chn->desc_pool, desc_rx); ++ ++ buf_dma = dma_map_single(rx_chn->dma_dev, skb->data, pkt_len, DMA_FROM_DEVICE); ++ if (unlikely(dma_mapping_error(rx_chn->dma_dev, buf_dma))) { ++ k3_cppi_desc_pool_free(rx_chn->desc_pool, desc_rx); ++ netdev_err(ndev, "rx push: failed to map rx pkt buffer\n"); ++ return -EINVAL; ++ } ++ ++ cppi5_hdesc_init(desc_rx, CPPI5_INFO0_HDESC_EPIB_PRESENT, ++ PRUETH_NAV_PS_DATA_SIZE); ++ k3_udma_glue_rx_dma_to_cppi5_addr(rx_chn->rx_chn, &buf_dma); ++ cppi5_hdesc_attach_buf(desc_rx, buf_dma, skb_tailroom(skb), buf_dma, skb_tailroom(skb)); ++ ++ swdata = cppi5_hdesc_get_swdata(desc_rx); ++ *swdata = skb; ++ ++ return k3_udma_glue_push_rx_chn(rx_chn->rx_chn, 0, ++ desc_rx, desc_dma); ++} ++ ++static int emac_rx_packet(struct prueth_emac *emac, u32 flow_id) ++{ ++ struct prueth_rx_chn *rx_chn = &emac->rx_chns; ++ u32 buf_dma_len, pkt_len, port_id = 0; ++ struct net_device *ndev = emac->ndev; ++ struct cppi5_host_desc_t *desc_rx; ++ struct sk_buff *skb, *new_skb; ++ dma_addr_t desc_dma, buf_dma; ++ void **swdata; ++ int ret; ++ ++ ret = k3_udma_glue_pop_rx_chn(rx_chn->rx_chn, flow_id, &desc_dma); ++ if (ret) { ++ if (ret != -ENODATA) ++ netdev_err(ndev, "rx pop: failed: %d\n", ret); ++ return ret; ++ } ++ ++ if (cppi5_desc_is_tdcm(desc_dma)) /* Teardown ? */ ++ return 0; ++ ++ desc_rx = k3_cppi_desc_pool_dma2virt(rx_chn->desc_pool, desc_dma); ++ ++ swdata = cppi5_hdesc_get_swdata(desc_rx); ++ skb = *swdata; ++ ++ cppi5_hdesc_get_obuf(desc_rx, &buf_dma, &buf_dma_len); ++ k3_udma_glue_rx_cppi5_to_dma_addr(rx_chn->rx_chn, &buf_dma); ++ pkt_len = cppi5_hdesc_get_pktlen(desc_rx); ++ /* firmware adds 4 CRC bytes, strip them */ ++ pkt_len -= 4; ++ cppi5_desc_get_tags_ids(&desc_rx->hdr, &port_id, NULL); ++ ++ dma_unmap_single(rx_chn->dma_dev, buf_dma, buf_dma_len, DMA_FROM_DEVICE); ++ k3_cppi_desc_pool_free(rx_chn->desc_pool, desc_rx); ++ ++ skb->dev = ndev; ++ new_skb = netdev_alloc_skb_ip_align(ndev, PRUETH_MAX_PKT_SIZE); ++ /* if allocation fails we drop the packet but push the ++ * descriptor back to the ring with old skb to prevent a stall ++ */ ++ if (!new_skb) { ++ ndev->stats.rx_dropped++; ++ new_skb = skb; ++ } else { ++ /* send the filled skb up the n/w stack */ ++ skb_put(skb, pkt_len); ++ skb->protocol = eth_type_trans(skb, ndev); ++ napi_gro_receive(&emac->napi_rx, skb); ++ ndev->stats.rx_bytes += pkt_len; ++ ndev->stats.rx_packets++; ++ } ++ ++ /* queue another RX DMA */ ++ ret = prueth_dma_rx_push(emac, new_skb, &emac->rx_chns); ++ if (WARN_ON(ret < 0)) { ++ dev_kfree_skb_any(new_skb); ++ ndev->stats.rx_errors++; ++ ndev->stats.rx_dropped++; ++ } ++ ++ return ret; ++} ++ ++static void prueth_rx_cleanup(void *data, dma_addr_t desc_dma) ++{ ++ struct prueth_rx_chn *rx_chn = data; ++ struct cppi5_host_desc_t *desc_rx; ++ struct sk_buff *skb; ++ dma_addr_t buf_dma; ++ u32 buf_dma_len; ++ void **swdata; ++ ++ desc_rx = k3_cppi_desc_pool_dma2virt(rx_chn->desc_pool, desc_dma); ++ swdata = cppi5_hdesc_get_swdata(desc_rx); ++ skb = *swdata; ++ cppi5_hdesc_get_obuf(desc_rx, &buf_dma, &buf_dma_len); ++ k3_udma_glue_rx_cppi5_to_dma_addr(rx_chn->rx_chn, &buf_dma); ++ ++ dma_unmap_single(rx_chn->dma_dev, buf_dma, buf_dma_len, ++ DMA_FROM_DEVICE); ++ k3_cppi_desc_pool_free(rx_chn->desc_pool, desc_rx); ++ ++ dev_kfree_skb_any(skb); ++} ++ ++/** ++ * emac_ndo_start_xmit - EMAC Transmit function ++ * @skb: SKB pointer ++ * @ndev: EMAC network adapter ++ * ++ * Called by the system to transmit a packet - we queue the packet in ++ * EMAC hardware transmit queue ++ * Doesn't wait for completion we'll check for TX completion in ++ * emac_tx_complete_packets(). ++ * ++ * Return: enum netdev_tx ++ */ ++static enum netdev_tx emac_ndo_start_xmit(struct sk_buff *skb, struct net_device *ndev) ++{ ++ struct cppi5_host_desc_t *first_desc, *next_desc, *cur_desc; ++ struct prueth_emac *emac = netdev_priv(ndev); ++ struct netdev_queue *netif_txq; ++ struct prueth_tx_chn *tx_chn; ++ dma_addr_t desc_dma, buf_dma; ++ int i, ret = 0, q_idx; ++ void **swdata; ++ u32 pkt_len; ++ u32 *epib; ++ ++ pkt_len = skb_headlen(skb); ++ q_idx = skb_get_queue_mapping(skb); ++ ++ tx_chn = &emac->tx_chns[q_idx]; ++ netif_txq = netdev_get_tx_queue(ndev, q_idx); ++ ++ /* Map the linear buffer */ ++ buf_dma = dma_map_single(tx_chn->dma_dev, skb->data, pkt_len, DMA_TO_DEVICE); ++ if (dma_mapping_error(tx_chn->dma_dev, buf_dma)) { ++ netdev_err(ndev, "tx: failed to map skb buffer\n"); ++ ret = NETDEV_TX_OK; ++ goto drop_free_skb; ++ } ++ ++ first_desc = k3_cppi_desc_pool_alloc(tx_chn->desc_pool); ++ if (!first_desc) { ++ netdev_dbg(ndev, "tx: failed to allocate descriptor\n"); ++ dma_unmap_single(tx_chn->dma_dev, buf_dma, pkt_len, DMA_TO_DEVICE); ++ goto drop_stop_q_busy; ++ } ++ ++ cppi5_hdesc_init(first_desc, CPPI5_INFO0_HDESC_EPIB_PRESENT, ++ PRUETH_NAV_PS_DATA_SIZE); ++ cppi5_hdesc_set_pkttype(first_desc, 0); ++ epib = first_desc->epib; ++ epib[0] = 0; ++ epib[1] = 0; ++ ++ /* set dst tag to indicate internal qid at the firmware which is at ++ * bit8..bit15. bit0..bit7 indicates port num for directed ++ * packets in case of switch mode operation ++ */ ++ cppi5_desc_set_tags_ids(&first_desc->hdr, 0, (emac->port_id | (q_idx << 8))); ++ k3_udma_glue_tx_dma_to_cppi5_addr(tx_chn->tx_chn, &buf_dma); ++ cppi5_hdesc_attach_buf(first_desc, buf_dma, pkt_len, buf_dma, pkt_len); ++ swdata = cppi5_hdesc_get_swdata(first_desc); ++ *swdata = skb; ++ ++ /* Handle the case where skb is fragmented in pages */ ++ cur_desc = first_desc; ++ for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { ++ skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; ++ u32 frag_size = skb_frag_size(frag); ++ ++ next_desc = k3_cppi_desc_pool_alloc(tx_chn->desc_pool); ++ if (!next_desc) { ++ netdev_err(ndev, ++ "tx: failed to allocate frag. descriptor\n"); ++ goto free_desc_stop_q_busy; ++ } ++ ++ buf_dma = skb_frag_dma_map(tx_chn->dma_dev, frag, 0, frag_size, ++ DMA_TO_DEVICE); ++ if (dma_mapping_error(tx_chn->dma_dev, buf_dma)) { ++ netdev_err(ndev, "tx: Failed to map skb page\n"); ++ k3_cppi_desc_pool_free(tx_chn->desc_pool, next_desc); ++ ret = NETDEV_TX_OK; ++ goto drop_free_descs; ++ } ++ ++ cppi5_hdesc_reset_hbdesc(next_desc); ++ k3_udma_glue_tx_dma_to_cppi5_addr(tx_chn->tx_chn, &buf_dma); ++ cppi5_hdesc_attach_buf(next_desc, ++ buf_dma, frag_size, buf_dma, frag_size); ++ ++ desc_dma = k3_cppi_desc_pool_virt2dma(tx_chn->desc_pool, ++ next_desc); ++ k3_udma_glue_tx_dma_to_cppi5_addr(tx_chn->tx_chn, &desc_dma); ++ cppi5_hdesc_link_hbdesc(cur_desc, desc_dma); ++ ++ pkt_len += frag_size; ++ cur_desc = next_desc; ++ } ++ WARN_ON_ONCE(pkt_len != skb->len); ++ ++ /* report bql before sending packet */ ++ netdev_tx_sent_queue(netif_txq, pkt_len); ++ ++ cppi5_hdesc_set_pktlen(first_desc, pkt_len); ++ desc_dma = k3_cppi_desc_pool_virt2dma(tx_chn->desc_pool, first_desc); ++ /* cppi5_desc_dump(first_desc, 64); */ ++ ++ skb_tx_timestamp(skb); /* SW timestamp if SKBTX_IN_PROGRESS not set */ ++ ret = k3_udma_glue_push_tx_chn(tx_chn->tx_chn, first_desc, desc_dma); ++ if (ret) { ++ netdev_err(ndev, "tx: push failed: %d\n", ret); ++ goto drop_free_descs; ++ } ++ ++ if (k3_cppi_desc_pool_avail(tx_chn->desc_pool) < MAX_SKB_FRAGS) { ++ netif_tx_stop_queue(netif_txq); ++ /* Barrier, so that stop_queue visible to other cpus */ ++ smp_mb__after_atomic(); ++ ++ if (k3_cppi_desc_pool_avail(tx_chn->desc_pool) >= ++ MAX_SKB_FRAGS) ++ netif_tx_wake_queue(netif_txq); ++ } ++ ++ return NETDEV_TX_OK; ++ ++drop_free_descs: ++ prueth_xmit_free(tx_chn, first_desc); ++ ++drop_free_skb: ++ dev_kfree_skb_any(skb); ++ ++ /* error */ ++ ndev->stats.tx_dropped++; ++ netdev_err(ndev, "tx: error: %d\n", ret); ++ ++ return ret; ++ ++free_desc_stop_q_busy: ++ prueth_xmit_free(tx_chn, first_desc); ++ ++drop_stop_q_busy: ++ netif_tx_stop_queue(netif_txq); ++ return NETDEV_TX_BUSY; ++} ++ ++static void prueth_tx_cleanup(void *data, dma_addr_t desc_dma) ++{ ++ struct prueth_tx_chn *tx_chn = data; ++ struct cppi5_host_desc_t *desc_tx; ++ struct sk_buff *skb; ++ void **swdata; ++ ++ desc_tx = k3_cppi_desc_pool_dma2virt(tx_chn->desc_pool, desc_dma); ++ swdata = cppi5_hdesc_get_swdata(desc_tx); ++ skb = *(swdata); ++ prueth_xmit_free(tx_chn, desc_tx); ++ ++ dev_kfree_skb_any(skb); ++} ++ ++static irqreturn_t prueth_rx_irq(int irq, void *dev_id) ++{ ++ struct prueth_emac *emac = dev_id; ++ ++ disable_irq_nosync(irq); ++ napi_schedule(&emac->napi_rx); ++ ++ return IRQ_HANDLED; ++} ++ ++struct icssg_firmwares { ++ char *pru; ++ char *rtu; ++ char *txpru; ++}; ++ ++static struct icssg_firmwares icssg_emac_firmwares[] = { ++ { ++ .pru = "ti-pruss/am65x-sr2-pru0-prueth-fw.elf", ++ .rtu = "ti-pruss/am65x-sr2-rtu0-prueth-fw.elf", ++ .txpru = "ti-pruss/am65x-sr2-txpru0-prueth-fw.elf", ++ }, ++ { ++ .pru = "ti-pruss/am65x-sr2-pru1-prueth-fw.elf", ++ .rtu = "ti-pruss/am65x-sr2-rtu1-prueth-fw.elf", ++ .txpru = "ti-pruss/am65x-sr2-txpru1-prueth-fw.elf", ++ } ++}; ++ ++static int prueth_emac_start(struct prueth *prueth, struct prueth_emac *emac) ++{ ++ struct icssg_firmwares *firmwares; ++ struct device *dev = prueth->dev; ++ int slice, ret; ++ ++ firmwares = icssg_emac_firmwares; ++ ++ slice = prueth_emac_slice(emac); ++ if (slice < 0) { ++ netdev_err(emac->ndev, "invalid port\n"); ++ return -EINVAL; ++ } ++ ++ ret = icssg_config(prueth, emac, slice); ++ if (ret) ++ return ret; ++ ++ ret = rproc_set_firmware(prueth->pru[slice], firmwares[slice].pru); ++ ret = rproc_boot(prueth->pru[slice]); ++ if (ret) { ++ dev_err(dev, "failed to boot PRU%d: %d\n", slice, ret); ++ return -EINVAL; ++ } ++ ++ ret = rproc_set_firmware(prueth->rtu[slice], firmwares[slice].rtu); ++ ret = rproc_boot(prueth->rtu[slice]); ++ if (ret) { ++ dev_err(dev, "failed to boot RTU%d: %d\n", slice, ret); ++ goto halt_pru; ++ } ++ ++ ret = rproc_set_firmware(prueth->txpru[slice], firmwares[slice].txpru); ++ ret = rproc_boot(prueth->txpru[slice]); ++ if (ret) { ++ dev_err(dev, "failed to boot TX_PRU%d: %d\n", slice, ret); ++ goto halt_rtu; ++ } ++ ++ emac->fw_running = 1; ++ return 0; ++ ++halt_rtu: ++ rproc_shutdown(prueth->rtu[slice]); ++ ++halt_pru: ++ rproc_shutdown(prueth->pru[slice]); ++ ++ return ret; ++} ++ ++static void prueth_emac_stop(struct prueth_emac *emac) ++{ ++ struct prueth *prueth = emac->prueth; ++ int slice; ++ ++ switch (emac->port_id) { ++ case PRUETH_PORT_MII0: ++ slice = ICSS_SLICE0; ++ break; ++ case PRUETH_PORT_MII1: ++ slice = ICSS_SLICE1; ++ break; ++ default: ++ netdev_err(emac->ndev, "invalid port\n"); ++ return; ++ } ++ ++ emac->fw_running = 0; ++ rproc_shutdown(prueth->txpru[slice]); ++ rproc_shutdown(prueth->rtu[slice]); ++ rproc_shutdown(prueth->pru[slice]); ++} ++ ++/* called back by PHY layer if there is change in link state of hw port*/ ++static void emac_adjust_link(struct net_device *ndev) ++{ ++ struct prueth_emac *emac = netdev_priv(ndev); ++ struct phy_device *phydev = ndev->phydev; ++ struct prueth *prueth = emac->prueth; ++ bool new_state = false; ++ unsigned long flags; ++ ++ if (phydev->link) { ++ /* check the mode of operation - full/half duplex */ ++ if (phydev->duplex != emac->duplex) { ++ new_state = true; ++ emac->duplex = phydev->duplex; ++ } ++ if (phydev->speed != emac->speed) { ++ new_state = true; ++ emac->speed = phydev->speed; ++ } ++ if (!emac->link) { ++ new_state = true; ++ emac->link = 1; ++ } ++ } else if (emac->link) { ++ new_state = true; ++ emac->link = 0; ++ ++ /* f/w should support 100 & 1000 */ ++ emac->speed = SPEED_1000; ++ ++ /* half duplex may not be supported by f/w */ ++ emac->duplex = DUPLEX_FULL; ++ } ++ ++ if (new_state) { ++ phy_print_status(phydev); ++ ++ /* update RGMII and MII configuration based on PHY negotiated ++ * values ++ */ ++ if (emac->link) { ++ /* Set the RGMII cfg for gig en and full duplex */ ++ icssg_update_rgmii_cfg(prueth->miig_rt, emac); ++ ++ /* update the Tx IPG based on 100M/1G speed */ ++ spin_lock_irqsave(&emac->lock, flags); ++ icssg_config_ipg(emac); ++ spin_unlock_irqrestore(&emac->lock, flags); ++ icssg_config_set_speed(emac); ++ emac_set_port_state(emac, ICSSG_EMAC_PORT_FORWARD); ++ ++ } else { ++ emac_set_port_state(emac, ICSSG_EMAC_PORT_DISABLE); ++ } ++ } ++ ++ if (emac->link) { ++ /* reactivate the transmit queue */ ++ netif_tx_wake_all_queues(ndev); ++ } else { ++ netif_tx_stop_all_queues(ndev); ++ } ++} ++ ++static int emac_napi_rx_poll(struct napi_struct *napi_rx, int budget) ++{ ++ struct prueth_emac *emac = prueth_napi_to_emac(napi_rx); ++ int rx_flow = PRUETH_RX_FLOW_DATA; ++ int flow = PRUETH_MAX_RX_FLOWS; ++ int num_rx = 0; ++ int cur_budget; ++ int ret; ++ ++ while (flow--) { ++ cur_budget = budget - num_rx; ++ ++ while (cur_budget--) { ++ ret = emac_rx_packet(emac, flow); ++ if (ret) ++ break; ++ num_rx++; ++ } ++ ++ if (num_rx >= budget) ++ break; ++ } ++ ++ if (num_rx < budget && napi_complete_done(napi_rx, num_rx)) ++ enable_irq(emac->rx_chns.irq[rx_flow]); ++ ++ return num_rx; ++} ++ ++static int prueth_prepare_rx_chan(struct prueth_emac *emac, ++ struct prueth_rx_chn *chn, ++ int buf_size) ++{ ++ struct sk_buff *skb; ++ int i, ret; ++ ++ for (i = 0; i < chn->descs_num; i++) { ++ skb = __netdev_alloc_skb_ip_align(NULL, buf_size, GFP_KERNEL); ++ if (!skb) ++ return -ENOMEM; ++ ++ ret = prueth_dma_rx_push(emac, skb, chn); ++ if (ret < 0) { ++ netdev_err(emac->ndev, ++ "cannot submit skb for rx chan %s ret %d\n", ++ chn->name, ret); ++ kfree_skb(skb); ++ return ret; ++ } ++ } ++ ++ return 0; ++} ++ ++static void prueth_reset_tx_chan(struct prueth_emac *emac, int ch_num, ++ bool free_skb) ++{ ++ int i; ++ ++ for (i = 0; i < ch_num; i++) { ++ if (free_skb) ++ k3_udma_glue_reset_tx_chn(emac->tx_chns[i].tx_chn, ++ &emac->tx_chns[i], ++ prueth_tx_cleanup); ++ k3_udma_glue_disable_tx_chn(emac->tx_chns[i].tx_chn); ++ } ++} ++ ++static void prueth_reset_rx_chan(struct prueth_rx_chn *chn, ++ int num_flows, bool disable) ++{ ++ int i; ++ ++ for (i = 0; i < num_flows; i++) ++ k3_udma_glue_reset_rx_chn(chn->rx_chn, i, chn, ++ prueth_rx_cleanup, !!i); ++ if (disable) ++ k3_udma_glue_disable_rx_chn(chn->rx_chn); ++} ++ ++static int emac_phy_connect(struct prueth_emac *emac) ++{ ++ struct prueth *prueth = emac->prueth; ++ struct net_device *ndev = emac->ndev; ++ /* connect PHY */ ++ ndev->phydev = of_phy_connect(emac->ndev, emac->phy_node, ++ &emac_adjust_link, 0, ++ emac->phy_if); ++ if (!ndev->phydev) { ++ dev_err(prueth->dev, "couldn't connect to phy %s\n", ++ emac->phy_node->full_name); ++ return -ENODEV; ++ } ++ ++ /* remove unsupported modes */ ++ phy_remove_link_mode(ndev->phydev, ETHTOOL_LINK_MODE_10baseT_Half_BIT); ++ phy_remove_link_mode(ndev->phydev, ETHTOOL_LINK_MODE_10baseT_Full_BIT); ++ phy_remove_link_mode(ndev->phydev, ETHTOOL_LINK_MODE_100baseT_Half_BIT); ++ phy_remove_link_mode(ndev->phydev, ETHTOOL_LINK_MODE_1000baseT_Half_BIT); ++ phy_remove_link_mode(ndev->phydev, ETHTOOL_LINK_MODE_Pause_BIT); ++ phy_remove_link_mode(ndev->phydev, ETHTOOL_LINK_MODE_Asym_Pause_BIT); ++ ++ if (emac->phy_if == PHY_INTERFACE_MODE_MII) ++ phy_set_max_speed(ndev->phydev, SPEED_100); ++ ++ return 0; ++} ++ ++/** ++ * emac_ndo_open - EMAC device open ++ * @ndev: network adapter device ++ * ++ * Called when system wants to start the interface. ++ * ++ * Return: 0 for a successful open, or appropriate error code ++ */ ++static int emac_ndo_open(struct net_device *ndev) ++{ ++ struct prueth_emac *emac = netdev_priv(ndev); ++ int ret, i, num_data_chn = emac->tx_ch_num; ++ struct prueth *prueth = emac->prueth; ++ int slice = prueth_emac_slice(emac); ++ struct device *dev = prueth->dev; ++ int max_rx_flows; ++ int rx_flow; ++ ++ /* clear SMEM and MSMC settings for all slices */ ++ if (!prueth->emacs_initialized) { ++ memset_io(prueth->msmcram.va, 0, prueth->msmcram.size); ++ memset_io(prueth->shram.va, 0, ICSSG_CONFIG_OFFSET_SLICE1 * PRUETH_NUM_MACS); ++ } ++ ++ /* set h/w MAC as user might have re-configured */ ++ ether_addr_copy(emac->mac_addr, ndev->dev_addr); ++ ++ icssg_class_set_mac_addr(prueth->miig_rt, slice, emac->mac_addr); ++ icssg_ft1_set_mac_addr(prueth->miig_rt, slice, emac->mac_addr); ++ ++ icssg_class_default(prueth->miig_rt, slice, 0); ++ ++ /* Notify the stack of the actual queue counts. */ ++ ret = netif_set_real_num_tx_queues(ndev, num_data_chn); ++ if (ret) { ++ dev_err(dev, "cannot set real number of tx queues\n"); ++ return ret; ++ } ++ ++ init_completion(&emac->cmd_complete); ++ ret = prueth_init_tx_chns(emac); ++ if (ret) { ++ dev_err(dev, "failed to init tx channel: %d\n", ret); ++ return ret; ++ } ++ ++ max_rx_flows = PRUETH_MAX_RX_FLOWS; ++ ret = prueth_init_rx_chns(emac, &emac->rx_chns, "rx", ++ max_rx_flows, PRUETH_MAX_RX_DESC); ++ if (ret) { ++ dev_err(dev, "failed to init rx channel: %d\n", ret); ++ goto cleanup_tx; ++ } ++ ++ ret = prueth_ndev_add_tx_napi(emac); ++ if (ret) ++ goto cleanup_rx; ++ ++ /* we use only the highest priority flow for now i.e. @irq[3] */ ++ rx_flow = PRUETH_RX_FLOW_DATA; ++ ret = request_irq(emac->rx_chns.irq[rx_flow], prueth_rx_irq, ++ IRQF_TRIGGER_HIGH, dev_name(dev), emac); ++ if (ret) { ++ dev_err(dev, "unable to request RX IRQ\n"); ++ goto cleanup_napi; ++ } ++ ++ /* reset and start PRU firmware */ ++ ret = prueth_emac_start(prueth, emac); ++ if (ret) ++ goto free_rx_irq; ++ ++ icssg_mii_update_mtu(prueth->mii_rt, slice, ndev->max_mtu); ++ ++ /* Prepare RX */ ++ ret = prueth_prepare_rx_chan(emac, &emac->rx_chns, PRUETH_MAX_PKT_SIZE); ++ if (ret) ++ goto stop; ++ ++ ret = k3_udma_glue_enable_rx_chn(emac->rx_chns.rx_chn); ++ if (ret) ++ goto reset_rx_chn; ++ ++ for (i = 0; i < emac->tx_ch_num; i++) { ++ ret = k3_udma_glue_enable_tx_chn(emac->tx_chns[i].tx_chn); ++ if (ret) ++ goto reset_tx_chan; ++ } ++ ++ /* Enable NAPI in Tx and Rx direction */ ++ for (i = 0; i < emac->tx_ch_num; i++) ++ napi_enable(&emac->tx_chns[i].napi_tx); ++ napi_enable(&emac->napi_rx); ++ ++ /* start PHY */ ++ phy_start(ndev->phydev); ++ ++ prueth->emacs_initialized++; ++ ++ return 0; ++ ++reset_tx_chan: ++ /* Since interface is not yet up, there is wouldn't be ++ * any SKB for completion. So set false to free_skb ++ */ ++ prueth_reset_tx_chan(emac, i, false); ++reset_rx_chn: ++ prueth_reset_rx_chan(&emac->rx_chns, max_rx_flows, false); ++stop: ++ prueth_emac_stop(emac); ++free_rx_irq: ++ free_irq(emac->rx_chns.irq[rx_flow], emac); ++cleanup_napi: ++ prueth_ndev_del_tx_napi(emac, emac->tx_ch_num); ++cleanup_rx: ++ prueth_cleanup_rx_chns(emac, &emac->rx_chns, max_rx_flows); ++cleanup_tx: ++ prueth_cleanup_tx_chns(emac); ++ ++ return ret; ++} ++ ++/** ++ * emac_ndo_stop - EMAC device stop ++ * @ndev: network adapter device ++ * ++ * Called when system wants to stop or down the interface. ++ * ++ * Return: Always 0 (Success) ++ */ ++static int emac_ndo_stop(struct net_device *ndev) ++{ ++ struct prueth_emac *emac = netdev_priv(ndev); ++ struct prueth *prueth = emac->prueth; ++ int rx_flow = PRUETH_RX_FLOW_DATA; ++ int max_rx_flows; ++ int ret, i; ++ ++ /* inform the upper layers. */ ++ netif_tx_stop_all_queues(ndev); ++ ++ /* block packets from wire */ ++ if (ndev->phydev) ++ phy_stop(ndev->phydev); ++ ++ icssg_class_disable(prueth->miig_rt, prueth_emac_slice(emac)); ++ ++ atomic_set(&emac->tdown_cnt, emac->tx_ch_num); ++ /* ensure new tdown_cnt value is visible */ ++ smp_mb__after_atomic(); ++ /* tear down and disable UDMA channels */ ++ reinit_completion(&emac->tdown_complete); ++ for (i = 0; i < emac->tx_ch_num; i++) ++ k3_udma_glue_tdown_tx_chn(emac->tx_chns[i].tx_chn, false); ++ ++ ret = wait_for_completion_timeout(&emac->tdown_complete, ++ msecs_to_jiffies(1000)); ++ if (!ret) ++ netdev_err(ndev, "tx teardown timeout\n"); ++ ++ prueth_reset_tx_chan(emac, emac->tx_ch_num, true); ++ for (i = 0; i < emac->tx_ch_num; i++) ++ napi_disable(&emac->tx_chns[i].napi_tx); ++ ++ max_rx_flows = PRUETH_MAX_RX_FLOWS; ++ k3_udma_glue_tdown_rx_chn(emac->rx_chns.rx_chn, true); ++ ++ prueth_reset_rx_chan(&emac->rx_chns, max_rx_flows, true); ++ ++ napi_disable(&emac->napi_rx); ++ ++ cancel_work_sync(&emac->rx_mode_work); ++ ++ /* stop PRUs */ ++ prueth_emac_stop(emac); ++ ++ free_irq(emac->rx_chns.irq[rx_flow], emac); ++ prueth_ndev_del_tx_napi(emac, emac->tx_ch_num); ++ prueth_cleanup_tx_chns(emac); ++ ++ prueth_cleanup_rx_chns(emac, &emac->rx_chns, max_rx_flows); ++ prueth_cleanup_tx_chns(emac); ++ ++ prueth->emacs_initialized--; ++ ++ return 0; ++} ++ ++static void emac_ndo_tx_timeout(struct net_device *ndev, unsigned int txqueue) ++{ ++ ndev->stats.tx_errors++; ++} ++ ++static void emac_ndo_set_rx_mode_work(struct work_struct *work) ++{ ++ struct prueth_emac *emac = container_of(work, struct prueth_emac, rx_mode_work); ++ struct net_device *ndev = emac->ndev; ++ bool promisc, allmulti; ++ ++ if (!netif_running(ndev)) ++ return; ++ ++ promisc = ndev->flags & IFF_PROMISC; ++ allmulti = ndev->flags & IFF_ALLMULTI; ++ emac_set_port_state(emac, ICSSG_EMAC_PORT_UC_FLOODING_DISABLE); ++ emac_set_port_state(emac, ICSSG_EMAC_PORT_MC_FLOODING_DISABLE); ++ ++ if (promisc) { ++ emac_set_port_state(emac, ICSSG_EMAC_PORT_UC_FLOODING_ENABLE); ++ emac_set_port_state(emac, ICSSG_EMAC_PORT_MC_FLOODING_ENABLE); ++ return; ++ } ++ ++ if (allmulti) { ++ emac_set_port_state(emac, ICSSG_EMAC_PORT_MC_FLOODING_ENABLE); ++ return; ++ } ++ ++ if (!netdev_mc_empty(ndev)) { ++ emac_set_port_state(emac, ICSSG_EMAC_PORT_MC_FLOODING_ENABLE); ++ return; ++ } ++} ++ ++/** ++ * emac_ndo_set_rx_mode - EMAC set receive mode function ++ * @ndev: The EMAC network adapter ++ * ++ * Called when system wants to set the receive mode of the device. ++ * ++ */ ++static void emac_ndo_set_rx_mode(struct net_device *ndev) ++{ ++ struct prueth_emac *emac = netdev_priv(ndev); ++ ++ queue_work(emac->cmd_wq, &emac->rx_mode_work); ++} ++ ++static int emac_ndo_ioctl(struct net_device *ndev, struct ifreq *ifr, int cmd) ++{ ++ return phy_do_ioctl(ndev, ifr, cmd); ++} ++ ++static const struct net_device_ops emac_netdev_ops = { ++ .ndo_open = emac_ndo_open, ++ .ndo_stop = emac_ndo_stop, ++ .ndo_start_xmit = emac_ndo_start_xmit, ++ .ndo_set_mac_address = eth_mac_addr, ++ .ndo_validate_addr = eth_validate_addr, ++ .ndo_tx_timeout = emac_ndo_tx_timeout, ++ .ndo_set_rx_mode = emac_ndo_set_rx_mode, ++ .ndo_eth_ioctl = emac_ndo_ioctl, ++}; ++ ++/* get emac_port corresponding to eth_node name */ ++static int prueth_node_port(struct device_node *eth_node) ++{ ++ u32 port_id; ++ int ret; ++ ++ ret = of_property_read_u32(eth_node, "reg", &port_id); ++ if (ret) ++ return ret; ++ ++ if (port_id == 0) ++ return PRUETH_PORT_MII0; ++ else if (port_id == 1) ++ return PRUETH_PORT_MII1; ++ else ++ return PRUETH_PORT_INVALID; ++} ++ ++/* get MAC instance corresponding to eth_node name */ ++static int prueth_node_mac(struct device_node *eth_node) ++{ ++ u32 port_id; ++ int ret; ++ ++ ret = of_property_read_u32(eth_node, "reg", &port_id); ++ if (ret) ++ return ret; ++ ++ if (port_id == 0) ++ return PRUETH_MAC0; ++ else if (port_id == 1) ++ return PRUETH_MAC1; ++ else ++ return PRUETH_MAC_INVALID; ++} ++ ++static int prueth_netdev_init(struct prueth *prueth, ++ struct device_node *eth_node) ++{ ++ int ret, num_tx_chn = PRUETH_MAX_TX_QUEUES; ++ struct prueth_emac *emac; ++ struct net_device *ndev; ++ enum prueth_port port; ++ enum prueth_mac mac; ++ ++ port = prueth_node_port(eth_node); ++ if (port == PRUETH_PORT_INVALID) ++ return -EINVAL; ++ ++ mac = prueth_node_mac(eth_node); ++ if (mac == PRUETH_MAC_INVALID) ++ return -EINVAL; ++ ++ ndev = alloc_etherdev_mq(sizeof(*emac), num_tx_chn); ++ if (!ndev) ++ return -ENOMEM; ++ ++ emac = netdev_priv(ndev); ++ emac->prueth = prueth; ++ emac->ndev = ndev; ++ emac->port_id = port; ++ emac->cmd_wq = create_singlethread_workqueue("icssg_cmd_wq"); ++ if (!emac->cmd_wq) { ++ ret = -ENOMEM; ++ goto free_ndev; ++ } ++ INIT_WORK(&emac->rx_mode_work, emac_ndo_set_rx_mode_work); ++ ++ ret = pruss_request_mem_region(prueth->pruss, ++ port == PRUETH_PORT_MII0 ? ++ PRUSS_MEM_DRAM0 : PRUSS_MEM_DRAM1, ++ &emac->dram); ++ if (ret) { ++ dev_err(prueth->dev, "unable to get DRAM: %d\n", ret); ++ ret = -ENOMEM; ++ goto free_wq; ++ } ++ ++ emac->tx_ch_num = 1; ++ ++ SET_NETDEV_DEV(ndev, prueth->dev); ++ spin_lock_init(&emac->lock); ++ mutex_init(&emac->cmd_lock); ++ ++ emac->phy_node = of_parse_phandle(eth_node, "phy-handle", 0); ++ if (!emac->phy_node && !of_phy_is_fixed_link(eth_node)) { ++ dev_err(prueth->dev, "couldn't find phy-handle\n"); ++ ret = -ENODEV; ++ goto free; ++ } else if (of_phy_is_fixed_link(eth_node)) { ++ ret = of_phy_register_fixed_link(eth_node); ++ if (ret) { ++ ret = dev_err_probe(prueth->dev, ret, ++ "failed to register fixed-link phy\n"); ++ goto free; ++ } ++ ++ emac->phy_node = eth_node; ++ } ++ ++ ret = of_get_phy_mode(eth_node, &emac->phy_if); ++ if (ret) { ++ dev_err(prueth->dev, "could not get phy-mode property\n"); ++ goto free; ++ } ++ ++ if (emac->phy_if != PHY_INTERFACE_MODE_MII && ++ !phy_interface_mode_is_rgmii(emac->phy_if)) { ++ dev_err(prueth->dev, "PHY mode unsupported %s\n", phy_modes(emac->phy_if)); ++ ret = -EINVAL; ++ goto free; ++ } ++ ++ /* AM65 SR2.0 has TX Internal delay always enabled by hardware ++ * and it is not possible to disable TX Internal delay. The below ++ * switch case block describes how we handle different phy modes ++ * based on hardware restriction. ++ */ ++ switch (emac->phy_if) { ++ case PHY_INTERFACE_MODE_RGMII_ID: ++ emac->phy_if = PHY_INTERFACE_MODE_RGMII_RXID; ++ break; ++ case PHY_INTERFACE_MODE_RGMII_TXID: ++ emac->phy_if = PHY_INTERFACE_MODE_RGMII; ++ break; ++ case PHY_INTERFACE_MODE_RGMII: ++ case PHY_INTERFACE_MODE_RGMII_RXID: ++ dev_err(prueth->dev, "RGMII mode without TX delay is not supported"); ++ ret = -EINVAL; ++ goto free; ++ default: ++ break; ++ } ++ ++ /* get mac address from DT and set private and netdev addr */ ++ ret = of_get_ethdev_address(eth_node, ndev); ++ if (!is_valid_ether_addr(ndev->dev_addr)) { ++ eth_hw_addr_random(ndev); ++ dev_warn(prueth->dev, "port %d: using random MAC addr: %pM\n", ++ port, ndev->dev_addr); ++ } ++ ether_addr_copy(emac->mac_addr, ndev->dev_addr); ++ ++ ndev->min_mtu = PRUETH_MIN_PKT_SIZE; ++ ndev->max_mtu = PRUETH_MAX_MTU; ++ ndev->netdev_ops = &emac_netdev_ops; ++ ndev->hw_features = NETIF_F_SG; ++ ndev->features = ndev->hw_features; ++ ++ netif_napi_add(ndev, &emac->napi_rx, emac_napi_rx_poll); ++ prueth->emac[mac] = emac; ++ ++ return 0; ++ ++free: ++ pruss_release_mem_region(prueth->pruss, &emac->dram); ++free_wq: ++ destroy_workqueue(emac->cmd_wq); ++free_ndev: ++ emac->ndev = NULL; ++ prueth->emac[mac] = NULL; ++ free_netdev(ndev); ++ ++ return ret; ++} ++ ++static void prueth_netdev_exit(struct prueth *prueth, ++ struct device_node *eth_node) ++{ ++ struct prueth_emac *emac; ++ enum prueth_mac mac; ++ ++ mac = prueth_node_mac(eth_node); ++ if (mac == PRUETH_MAC_INVALID) ++ return; ++ ++ emac = prueth->emac[mac]; ++ if (!emac) ++ return; ++ ++ if (of_phy_is_fixed_link(emac->phy_node)) ++ of_phy_deregister_fixed_link(emac->phy_node); ++ ++ netif_napi_del(&emac->napi_rx); ++ ++ pruss_release_mem_region(prueth->pruss, &emac->dram); ++ destroy_workqueue(emac->cmd_wq); ++ free_netdev(emac->ndev); ++ prueth->emac[mac] = NULL; ++} ++ ++static int prueth_get_cores(struct prueth *prueth, int slice) ++{ ++ struct device *dev = prueth->dev; ++ enum pruss_pru_id pruss_id; ++ struct device_node *np; ++ int idx = -1, ret; ++ ++ np = dev->of_node; ++ ++ switch (slice) { ++ case ICSS_SLICE0: ++ idx = 0; ++ break; ++ case ICSS_SLICE1: ++ idx = 3; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ prueth->pru[slice] = pru_rproc_get(np, idx, &pruss_id); ++ if (IS_ERR(prueth->pru[slice])) { ++ ret = PTR_ERR(prueth->pru[slice]); ++ prueth->pru[slice] = NULL; ++ return dev_err_probe(dev, ret, "unable to get PRU%d\n", slice); ++ } ++ prueth->pru_id[slice] = pruss_id; ++ ++ idx++; ++ prueth->rtu[slice] = pru_rproc_get(np, idx, NULL); ++ if (IS_ERR(prueth->rtu[slice])) { ++ ret = PTR_ERR(prueth->rtu[slice]); ++ prueth->rtu[slice] = NULL; ++ return dev_err_probe(dev, ret, "unable to get RTU%d\n", slice); ++ } ++ ++ idx++; ++ prueth->txpru[slice] = pru_rproc_get(np, idx, NULL); ++ if (IS_ERR(prueth->txpru[slice])) { ++ ret = PTR_ERR(prueth->txpru[slice]); ++ prueth->txpru[slice] = NULL; ++ return dev_err_probe(dev, ret, "unable to get TX_PRU%d\n", slice); ++ } ++ ++ return 0; ++} ++ ++static void prueth_put_cores(struct prueth *prueth, int slice) ++{ ++ if (prueth->txpru[slice]) ++ pru_rproc_put(prueth->txpru[slice]); ++ ++ if (prueth->rtu[slice]) ++ pru_rproc_put(prueth->rtu[slice]); ++ ++ if (prueth->pru[slice]) ++ pru_rproc_put(prueth->pru[slice]); ++} ++ ++static const struct of_device_id prueth_dt_match[]; ++ ++static int prueth_probe(struct platform_device *pdev) ++{ ++ struct device_node *eth_node, *eth_ports_node; ++ struct device_node *eth0_node = NULL; ++ struct device_node *eth1_node = NULL; ++ struct genpool_data_align gp_data = { ++ .align = SZ_64K, ++ }; ++ const struct of_device_id *match; ++ struct device *dev = &pdev->dev; ++ struct device_node *np; ++ struct prueth *prueth; ++ struct pruss *pruss; ++ u32 msmc_ram_size; ++ int i, ret; ++ ++ np = dev->of_node; ++ ++ match = of_match_device(prueth_dt_match, dev); ++ if (!match) ++ return -ENODEV; ++ ++ prueth = devm_kzalloc(dev, sizeof(*prueth), GFP_KERNEL); ++ if (!prueth) ++ return -ENOMEM; ++ ++ dev_set_drvdata(dev, prueth); ++ prueth->pdev = pdev; ++ prueth->pdata = *(const struct prueth_pdata *)match->data; ++ ++ prueth->dev = dev; ++ eth_ports_node = of_get_child_by_name(np, "ethernet-ports"); ++ if (!eth_ports_node) ++ return -ENOENT; ++ ++ for_each_child_of_node(eth_ports_node, eth_node) { ++ u32 reg; ++ ++ if (strcmp(eth_node->name, "port")) ++ continue; ++ ret = of_property_read_u32(eth_node, "reg", ®); ++ if (ret < 0) { ++ dev_err(dev, "%pOF error reading port_id %d\n", ++ eth_node, ret); ++ } ++ ++ of_node_get(eth_node); ++ ++ if (reg == 0) { ++ eth0_node = eth_node; ++ if (!of_device_is_available(eth0_node)) { ++ of_node_put(eth0_node); ++ eth0_node = NULL; ++ } ++ } else if (reg == 1) { ++ eth1_node = eth_node; ++ if (!of_device_is_available(eth1_node)) { ++ of_node_put(eth1_node); ++ eth1_node = NULL; ++ } ++ } else { ++ dev_err(dev, "port reg should be 0 or 1\n"); ++ } ++ } ++ ++ of_node_put(eth_ports_node); ++ ++ /* At least one node must be present and available else we fail */ ++ if (!eth0_node && !eth1_node) { ++ dev_err(dev, "neither port0 nor port1 node available\n"); ++ return -ENODEV; ++ } ++ ++ if (eth0_node == eth1_node) { ++ dev_err(dev, "port0 and port1 can't have same reg\n"); ++ of_node_put(eth0_node); ++ return -ENODEV; ++ } ++ ++ prueth->eth_node[PRUETH_MAC0] = eth0_node; ++ prueth->eth_node[PRUETH_MAC1] = eth1_node; ++ ++ prueth->miig_rt = syscon_regmap_lookup_by_phandle(np, "ti,mii-g-rt"); ++ if (IS_ERR(prueth->miig_rt)) { ++ dev_err(dev, "couldn't get ti,mii-g-rt syscon regmap\n"); ++ return -ENODEV; ++ } ++ ++ prueth->mii_rt = syscon_regmap_lookup_by_phandle(np, "ti,mii-rt"); ++ if (IS_ERR(prueth->mii_rt)) { ++ dev_err(dev, "couldn't get ti,mii-rt syscon regmap\n"); ++ return -ENODEV; ++ } ++ ++ if (eth0_node) { ++ ret = prueth_get_cores(prueth, ICSS_SLICE0); ++ if (ret) ++ goto put_cores; ++ } ++ ++ if (eth1_node) { ++ ret = prueth_get_cores(prueth, ICSS_SLICE1); ++ if (ret) ++ goto put_cores; ++ } ++ ++ pruss = pruss_get(eth0_node ? ++ prueth->pru[ICSS_SLICE0] : prueth->pru[ICSS_SLICE1]); ++ if (IS_ERR(pruss)) { ++ ret = PTR_ERR(pruss); ++ dev_err(dev, "unable to get pruss handle\n"); ++ goto put_cores; ++ } ++ ++ prueth->pruss = pruss; ++ ++ ret = pruss_request_mem_region(pruss, PRUSS_MEM_SHRD_RAM2, ++ &prueth->shram); ++ if (ret) { ++ dev_err(dev, "unable to get PRUSS SHRD RAM2: %d\n", ret); ++ pruss_put(prueth->pruss); ++ } ++ ++ prueth->sram_pool = of_gen_pool_get(np, "sram", 0); ++ if (!prueth->sram_pool) { ++ dev_err(dev, "unable to get SRAM pool\n"); ++ ret = -ENODEV; ++ ++ goto put_mem; ++ } ++ ++ msmc_ram_size = MSMC_RAM_SIZE; ++ ++ /* NOTE: FW bug needs buffer base to be 64KB aligned */ ++ prueth->msmcram.va = ++ (void __iomem *)gen_pool_alloc_algo(prueth->sram_pool, ++ msmc_ram_size, ++ gen_pool_first_fit_align, ++ &gp_data); ++ ++ if (!prueth->msmcram.va) { ++ ret = -ENOMEM; ++ dev_err(dev, "unable to allocate MSMC resource\n"); ++ goto put_mem; ++ } ++ prueth->msmcram.pa = gen_pool_virt_to_phys(prueth->sram_pool, ++ (unsigned long)prueth->msmcram.va); ++ prueth->msmcram.size = msmc_ram_size; ++ memset_io(prueth->msmcram.va, 0, msmc_ram_size); ++ dev_dbg(dev, "sram: pa %llx va %p size %zx\n", prueth->msmcram.pa, ++ prueth->msmcram.va, prueth->msmcram.size); ++ ++ /* setup netdev interfaces */ ++ if (eth0_node) { ++ ret = prueth_netdev_init(prueth, eth0_node); ++ if (ret) { ++ dev_err_probe(dev, ret, "netdev init %s failed\n", ++ eth0_node->name); ++ goto netdev_exit; ++ } ++ } ++ ++ if (eth1_node) { ++ ret = prueth_netdev_init(prueth, eth1_node); ++ if (ret) { ++ dev_err_probe(dev, ret, "netdev init %s failed\n", ++ eth1_node->name); ++ goto netdev_exit; ++ } ++ } ++ ++ /* register the network devices */ ++ if (eth0_node) { ++ ret = register_netdev(prueth->emac[PRUETH_MAC0]->ndev); ++ if (ret) { ++ dev_err(dev, "can't register netdev for port MII0"); ++ goto netdev_exit; ++ } ++ ++ prueth->registered_netdevs[PRUETH_MAC0] = prueth->emac[PRUETH_MAC0]->ndev; ++ ++ emac_phy_connect(prueth->emac[PRUETH_MAC0]); ++ phy_attached_info(prueth->emac[PRUETH_MAC0]->ndev->phydev); ++ } ++ ++ if (eth1_node) { ++ ret = register_netdev(prueth->emac[PRUETH_MAC1]->ndev); ++ if (ret) { ++ dev_err(dev, "can't register netdev for port MII1"); ++ goto netdev_unregister; ++ } ++ ++ prueth->registered_netdevs[PRUETH_MAC1] = prueth->emac[PRUETH_MAC1]->ndev; ++ emac_phy_connect(prueth->emac[PRUETH_MAC1]); ++ phy_attached_info(prueth->emac[PRUETH_MAC1]->ndev->phydev); ++ } ++ ++ dev_info(dev, "TI PRU ethernet driver initialized: %s EMAC mode\n", ++ (!eth0_node || !eth1_node) ? "single" : "dual"); ++ ++ if (eth1_node) ++ of_node_put(eth1_node); ++ if (eth0_node) ++ of_node_put(eth0_node); ++ return 0; ++ ++netdev_unregister: ++ for (i = 0; i < PRUETH_NUM_MACS; i++) { ++ if (!prueth->registered_netdevs[i]) ++ continue; ++ if (prueth->emac[i]->ndev->phydev) { ++ phy_disconnect(prueth->emac[i]->ndev->phydev); ++ prueth->emac[i]->ndev->phydev = NULL; ++ } ++ unregister_netdev(prueth->registered_netdevs[i]); ++ } ++ ++netdev_exit: ++ for (i = 0; i < PRUETH_NUM_MACS; i++) { ++ eth_node = prueth->eth_node[i]; ++ if (!eth_node) ++ continue; ++ ++ prueth_netdev_exit(prueth, eth_node); ++ } ++ ++ gen_pool_free(prueth->sram_pool, ++ (unsigned long)prueth->msmcram.va, msmc_ram_size); ++ ++put_mem: ++ pruss_release_mem_region(prueth->pruss, &prueth->shram); ++ pruss_put(prueth->pruss); ++ ++put_cores: ++ if (eth1_node) { ++ prueth_put_cores(prueth, ICSS_SLICE1); ++ of_node_put(eth1_node); ++ } ++ ++ if (eth0_node) { ++ prueth_put_cores(prueth, ICSS_SLICE0); ++ of_node_put(eth0_node); ++ } ++ ++ return ret; ++} ++ ++static void prueth_remove(struct platform_device *pdev) ++{ ++ struct prueth *prueth = platform_get_drvdata(pdev); ++ struct device_node *eth_node; ++ int i; ++ ++ for (i = 0; i < PRUETH_NUM_MACS; i++) { ++ if (!prueth->registered_netdevs[i]) ++ continue; ++ phy_stop(prueth->emac[i]->ndev->phydev); ++ phy_disconnect(prueth->emac[i]->ndev->phydev); ++ prueth->emac[i]->ndev->phydev = NULL; ++ unregister_netdev(prueth->registered_netdevs[i]); ++ } ++ ++ for (i = 0; i < PRUETH_NUM_MACS; i++) { ++ eth_node = prueth->eth_node[i]; ++ if (!eth_node) ++ continue; ++ ++ prueth_netdev_exit(prueth, eth_node); ++ } ++ ++ gen_pool_free(prueth->sram_pool, ++ (unsigned long)prueth->msmcram.va, ++ MSMC_RAM_SIZE); ++ ++ pruss_release_mem_region(prueth->pruss, &prueth->shram); ++ ++ pruss_put(prueth->pruss); ++ ++ if (prueth->eth_node[PRUETH_MAC1]) ++ prueth_put_cores(prueth, ICSS_SLICE1); ++ ++ if (prueth->eth_node[PRUETH_MAC0]) ++ prueth_put_cores(prueth, ICSS_SLICE0); ++} ++ ++static const struct prueth_pdata am654_icssg_pdata = { ++ .fdqring_mode = K3_RINGACC_RING_MODE_MESSAGE, ++ .quirk_10m_link_issue = 1, ++}; ++ ++static const struct of_device_id prueth_dt_match[] = { ++ { .compatible = "ti,am654-icssg-prueth", .data = &am654_icssg_pdata }, ++ { /* sentinel */ } ++}; ++MODULE_DEVICE_TABLE(of, prueth_dt_match); ++ ++static struct platform_driver prueth_driver = { ++ .probe = prueth_probe, ++ .remove_new = prueth_remove, ++ .driver = { ++ .name = "icssg-prueth", ++ .of_match_table = prueth_dt_match, ++ }, ++}; ++module_platform_driver(prueth_driver); ++ ++MODULE_AUTHOR("Roger Quadros "); ++MODULE_AUTHOR("Md Danish Anwar "); ++MODULE_DESCRIPTION("PRUSS ICSSG Ethernet Driver"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/net/ethernet/ti/icssg/icssg_prueth.h b/drivers/net/ethernet/ti/icssg/icssg_prueth.h +index 42fdf4005010..b3a923e7a5c9 100644 +--- a/drivers/net/ethernet/ti/icssg/icssg_prueth.h ++++ b/drivers/net/ethernet/ti/icssg/icssg_prueth.h +@@ -34,13 +34,42 @@ + + #include + ++#include "icssg_config.h" + #include "icssg_switch_map.h" + ++#define PRUETH_MAX_MTU (2000 - ETH_HLEN - ETH_FCS_LEN) ++#define PRUETH_MIN_PKT_SIZE (VLAN_ETH_ZLEN) ++#define PRUETH_MAX_PKT_SIZE (PRUETH_MAX_MTU + ETH_HLEN + ETH_FCS_LEN) ++ + #define ICSS_SLICE0 0 + #define ICSS_SLICE1 1 + ++#define ICSS_FW_PRU 0 ++#define ICSS_FW_RTU 1 ++ + #define ICSSG_MAX_RFLOWS 8 /* per slice */ + ++/* Firmware status codes */ ++#define ICSS_HS_FW_READY 0x55555555 ++#define ICSS_HS_FW_DEAD 0xDEAD0000 /* lower 16 bits contain error code */ ++ ++/* Firmware command codes */ ++#define ICSS_HS_CMD_BUSY 0x40000000 ++#define ICSS_HS_CMD_DONE 0x80000000 ++#define ICSS_HS_CMD_CANCEL 0x10000000 ++ ++/* Firmware commands */ ++#define ICSS_CMD_SPAD 0x20 ++#define ICSS_CMD_RXTX 0x10 ++#define ICSS_CMD_ADD_FDB 0x1 ++#define ICSS_CMD_DEL_FDB 0x2 ++#define ICSS_CMD_SET_RUN 0x4 ++#define ICSS_CMD_GET_FDB_SLOT 0x5 ++#define ICSS_CMD_ENABLE_VLAN 0x5 ++#define ICSS_CMD_DISABLE_VLAN 0x6 ++#define ICSS_CMD_ADD_FILTER 0x7 ++#define ICSS_CMD_ADD_MAC 0x8 ++ + /* In switch mode there are 3 real ports i.e. 3 mac addrs. + * however Linux sees only the host side port. The other 2 ports + * are the switch ports. +@@ -214,4 +243,7 @@ int icssg_queue_pop(struct prueth *prueth, u8 queue); + void icssg_queue_push(struct prueth *prueth, int queue, u16 addr); + u32 icssg_queue_level(struct prueth *prueth, int queue); + ++#define prueth_napi_to_tx_chn(pnapi) \ ++ container_of(pnapi, struct prueth_tx_chn, napi_tx) ++ + #endif /* __NET_TI_ICSSG_PRUETH_H */ +-- +2.42.0 + diff --git a/recipes-kernel/linux/files/patches-6.1/0022-net-ti-icssg-prueth-Add-ICSSG-Stats.patch b/recipes-kernel/linux/files/patches-6.1/0022-net-ti-icssg-prueth-Add-ICSSG-Stats.patch new file mode 100644 index 000000000..9ec127a1c --- /dev/null +++ b/recipes-kernel/linux/files/patches-6.1/0022-net-ti-icssg-prueth-Add-ICSSG-Stats.patch @@ -0,0 +1,332 @@ +From 418f844ec22a0ce8ff89e5b1ad3a3524bef54a0f Mon Sep 17 00:00:00 2001 +From: MD Danish Anwar +Date: Tue, 1 Aug 2023 14:44:25 +0530 +Subject: [PATCH 22/69] net: ti: icssg-prueth: Add ICSSG Stats + +Add icssg_stats.c to help dump, icssg related driver statistics. + +ICSSG has hardware registers for providing statistics like total rx bytes, +total tx bytes, etc. These registers are of 32 bits and hence in case of 1G +link, they overflows in around 32 seconds. The behaviour of these registers +is such that they don't roll back to 0 after overflow but rather stay at +UINT_MAX. + +These registers support a feature where the value written to them is +subtracted from the register. This feature can be utilized to fix the +overflowing of stats. + +This solution uses a Workqueues based solution where a function gets +called before the registers overflow (every 25 seconds in 1G link, 25000 +seconds in 100M link), this function saves the register +values in local variables and writes the last read value to the +register. So any update during the read will be taken care of. + +Signed-off-by: MD Danish Anwar +[Commit c1e10d5dc7a1 upstream] +--- + drivers/net/ethernet/ti/Makefile | 1 + + drivers/net/ethernet/ti/icssg/icssg_prueth.c | 8 + + drivers/net/ethernet/ti/icssg/icssg_prueth.h | 8 + + drivers/net/ethernet/ti/icssg/icssg_stats.c | 44 ++++++ + drivers/net/ethernet/ti/icssg/icssg_stats.h | 158 +++++++++++++++++++ + 5 files changed, 219 insertions(+) + create mode 100644 drivers/net/ethernet/ti/icssg/icssg_stats.c + create mode 100644 drivers/net/ethernet/ti/icssg/icssg_stats.h + +diff --git a/drivers/net/ethernet/ti/Makefile b/drivers/net/ethernet/ti/Makefile +index efb050cbb4a8..03d9b2b36b5f 100644 +--- a/drivers/net/ethernet/ti/Makefile ++++ b/drivers/net/ethernet/ti/Makefile +@@ -36,3 +36,4 @@ icssg-prueth-y := k3-cppi-desc-pool.o \ + icssg/icssg_queues.o \ + icssg/icssg_config.o \ + icssg/icssg_mii_cfg.o \ ++ icssg/icssg_stats.o \ +diff --git a/drivers/net/ethernet/ti/icssg/icssg_prueth.c b/drivers/net/ethernet/ti/icssg/icssg_prueth.c +index 1869e38f898f..d0bb4db11b30 100644 +--- a/drivers/net/ethernet/ti/icssg/icssg_prueth.c ++++ b/drivers/net/ethernet/ti/icssg/icssg_prueth.c +@@ -8,6 +8,7 @@ + + #include + #include ++#include + #include + #include + #include +@@ -1090,6 +1091,8 @@ static int emac_ndo_open(struct net_device *ndev) + + prueth->emacs_initialized++; + ++ queue_work(system_long_wq, &emac->stats_work.work); ++ + return 0; + + reset_tx_chan: +@@ -1164,6 +1167,9 @@ static int emac_ndo_stop(struct net_device *ndev) + + cancel_work_sync(&emac->rx_mode_work); + ++ /* Destroying the queued work in ndo_stop() */ ++ cancel_delayed_work_sync(&emac->stats_work); ++ + /* stop PRUs */ + prueth_emac_stop(emac); + +@@ -1313,6 +1319,8 @@ static int prueth_netdev_init(struct prueth *prueth, + } + INIT_WORK(&emac->rx_mode_work, emac_ndo_set_rx_mode_work); + ++ INIT_DELAYED_WORK(&emac->stats_work, emac_stats_work_handler); ++ + ret = pruss_request_mem_region(prueth->pruss, + port == PRUETH_PORT_MII0 ? + PRUSS_MEM_DRAM0 : PRUSS_MEM_DRAM1, +diff --git a/drivers/net/ethernet/ti/icssg/icssg_prueth.h b/drivers/net/ethernet/ti/icssg/icssg_prueth.h +index b3a923e7a5c9..f13de0d2e90b 100644 +--- a/drivers/net/ethernet/ti/icssg/icssg_prueth.h ++++ b/drivers/net/ethernet/ti/icssg/icssg_prueth.h +@@ -49,6 +49,9 @@ + + #define ICSSG_MAX_RFLOWS 8 /* per slice */ + ++/* Number of ICSSG related stats */ ++#define ICSSG_NUM_STATS 60 ++ + /* Firmware status codes */ + #define ICSS_HS_FW_READY 0x55555555 + #define ICSS_HS_FW_DEAD 0xDEAD0000 /* lower 16 bits contain error code */ +@@ -153,6 +156,9 @@ struct prueth_emac { + struct workqueue_struct *cmd_wq; + + struct pruss_mem_region dram; ++ ++ struct delayed_work stats_work; ++ u64 stats[ICSSG_NUM_STATS]; + }; + + /** +@@ -246,4 +252,6 @@ u32 icssg_queue_level(struct prueth *prueth, int queue); + #define prueth_napi_to_tx_chn(pnapi) \ + container_of(pnapi, struct prueth_tx_chn, napi_tx) + ++void emac_stats_work_handler(struct work_struct *work); ++void emac_update_hardware_stats(struct prueth_emac *emac); + #endif /* __NET_TI_ICSSG_PRUETH_H */ +diff --git a/drivers/net/ethernet/ti/icssg/icssg_stats.c b/drivers/net/ethernet/ti/icssg/icssg_stats.c +new file mode 100644 +index 000000000000..25deb368a3f0 +--- /dev/null ++++ b/drivers/net/ethernet/ti/icssg/icssg_stats.c +@@ -0,0 +1,44 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* Texas Instruments ICSSG Ethernet driver ++ * ++ * Copyright (C) 2018-2021 Texas Instruments Incorporated - https://www.ti.com/ ++ * ++ */ ++ ++#include "icssg_prueth.h" ++#include "icssg_stats.h" ++#include ++ ++static u32 stats_base[] = { 0x54c, /* Slice 0 stats start */ ++ 0xb18, /* Slice 1 stats start */ ++}; ++ ++void emac_update_hardware_stats(struct prueth_emac *emac) ++{ ++ struct prueth *prueth = emac->prueth; ++ int slice = prueth_emac_slice(emac); ++ u32 base = stats_base[slice]; ++ u32 val; ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(icssg_all_stats); i++) { ++ regmap_read(prueth->miig_rt, ++ base + icssg_all_stats[i].offset, ++ &val); ++ regmap_write(prueth->miig_rt, ++ base + icssg_all_stats[i].offset, ++ val); ++ ++ emac->stats[i] += val; ++ } ++} ++ ++void emac_stats_work_handler(struct work_struct *work) ++{ ++ struct prueth_emac *emac = container_of(work, struct prueth_emac, ++ stats_work.work); ++ emac_update_hardware_stats(emac); ++ ++ queue_delayed_work(system_long_wq, &emac->stats_work, ++ msecs_to_jiffies((STATS_TIME_LIMIT_1G_MS * 1000) / emac->speed)); ++} +diff --git a/drivers/net/ethernet/ti/icssg/icssg_stats.h b/drivers/net/ethernet/ti/icssg/icssg_stats.h +new file mode 100644 +index 000000000000..999a4a91276c +--- /dev/null ++++ b/drivers/net/ethernet/ti/icssg/icssg_stats.h +@@ -0,0 +1,158 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* Texas Instruments ICSSG Ethernet driver ++ * ++ * Copyright (C) 2018-2022 Texas Instruments Incorporated - https://www.ti.com/ ++ * ++ */ ++ ++#ifndef __NET_TI_ICSSG_STATS_H ++#define __NET_TI_ICSSG_STATS_H ++ ++#include "icssg_prueth.h" ++ ++#define STATS_TIME_LIMIT_1G_MS 25000 /* 25 seconds @ 1G */ ++ ++struct miig_stats_regs { ++ /* Rx */ ++ u32 rx_packets; ++ u32 rx_broadcast_frames; ++ u32 rx_multicast_frames; ++ u32 rx_crc_errors; ++ u32 rx_mii_error_frames; ++ u32 rx_odd_nibble_frames; ++ u32 rx_frame_max_size; ++ u32 rx_max_size_error_frames; ++ u32 rx_frame_min_size; ++ u32 rx_min_size_error_frames; ++ u32 rx_over_errors; ++ u32 rx_class0_hits; ++ u32 rx_class1_hits; ++ u32 rx_class2_hits; ++ u32 rx_class3_hits; ++ u32 rx_class4_hits; ++ u32 rx_class5_hits; ++ u32 rx_class6_hits; ++ u32 rx_class7_hits; ++ u32 rx_class8_hits; ++ u32 rx_class9_hits; ++ u32 rx_class10_hits; ++ u32 rx_class11_hits; ++ u32 rx_class12_hits; ++ u32 rx_class13_hits; ++ u32 rx_class14_hits; ++ u32 rx_class15_hits; ++ u32 rx_smd_frags; ++ u32 rx_bucket1_size; ++ u32 rx_bucket2_size; ++ u32 rx_bucket3_size; ++ u32 rx_bucket4_size; ++ u32 rx_64B_frames; ++ u32 rx_bucket1_frames; ++ u32 rx_bucket2_frames; ++ u32 rx_bucket3_frames; ++ u32 rx_bucket4_frames; ++ u32 rx_bucket5_frames; ++ u32 rx_bytes; ++ u32 rx_tx_total_bytes; ++ /* Tx */ ++ u32 tx_packets; ++ u32 tx_broadcast_frames; ++ u32 tx_multicast_frames; ++ u32 tx_odd_nibble_frames; ++ u32 tx_underflow_errors; ++ u32 tx_frame_max_size; ++ u32 tx_max_size_error_frames; ++ u32 tx_frame_min_size; ++ u32 tx_min_size_error_frames; ++ u32 tx_bucket1_size; ++ u32 tx_bucket2_size; ++ u32 tx_bucket3_size; ++ u32 tx_bucket4_size; ++ u32 tx_64B_frames; ++ u32 tx_bucket1_frames; ++ u32 tx_bucket2_frames; ++ u32 tx_bucket3_frames; ++ u32 tx_bucket4_frames; ++ u32 tx_bucket5_frames; ++ u32 tx_bytes; ++}; ++ ++#define ICSSG_STATS(field, stats_type) \ ++{ \ ++ #field, \ ++ offsetof(struct miig_stats_regs, field), \ ++ stats_type \ ++} ++ ++struct icssg_stats { ++ char name[ETH_GSTRING_LEN]; ++ u32 offset; ++ bool standard_stats; ++}; ++ ++static const struct icssg_stats icssg_all_stats[] = { ++ /* Rx */ ++ ICSSG_STATS(rx_packets, true), ++ ICSSG_STATS(rx_broadcast_frames, false), ++ ICSSG_STATS(rx_multicast_frames, true), ++ ICSSG_STATS(rx_crc_errors, true), ++ ICSSG_STATS(rx_mii_error_frames, false), ++ ICSSG_STATS(rx_odd_nibble_frames, false), ++ ICSSG_STATS(rx_frame_max_size, true), ++ ICSSG_STATS(rx_max_size_error_frames, false), ++ ICSSG_STATS(rx_frame_min_size, true), ++ ICSSG_STATS(rx_min_size_error_frames, false), ++ ICSSG_STATS(rx_over_errors, true), ++ ICSSG_STATS(rx_class0_hits, false), ++ ICSSG_STATS(rx_class1_hits, false), ++ ICSSG_STATS(rx_class2_hits, false), ++ ICSSG_STATS(rx_class3_hits, false), ++ ICSSG_STATS(rx_class4_hits, false), ++ ICSSG_STATS(rx_class5_hits, false), ++ ICSSG_STATS(rx_class6_hits, false), ++ ICSSG_STATS(rx_class7_hits, false), ++ ICSSG_STATS(rx_class8_hits, false), ++ ICSSG_STATS(rx_class9_hits, false), ++ ICSSG_STATS(rx_class10_hits, false), ++ ICSSG_STATS(rx_class11_hits, false), ++ ICSSG_STATS(rx_class12_hits, false), ++ ICSSG_STATS(rx_class13_hits, false), ++ ICSSG_STATS(rx_class14_hits, false), ++ ICSSG_STATS(rx_class15_hits, false), ++ ICSSG_STATS(rx_smd_frags, false), ++ ICSSG_STATS(rx_bucket1_size, true), ++ ICSSG_STATS(rx_bucket2_size, true), ++ ICSSG_STATS(rx_bucket3_size, true), ++ ICSSG_STATS(rx_bucket4_size, true), ++ ICSSG_STATS(rx_64B_frames, true), ++ ICSSG_STATS(rx_bucket1_frames, true), ++ ICSSG_STATS(rx_bucket2_frames, true), ++ ICSSG_STATS(rx_bucket3_frames, true), ++ ICSSG_STATS(rx_bucket4_frames, true), ++ ICSSG_STATS(rx_bucket5_frames, true), ++ ICSSG_STATS(rx_bytes, true), ++ ICSSG_STATS(rx_tx_total_bytes, false), ++ /* Tx */ ++ ICSSG_STATS(tx_packets, true), ++ ICSSG_STATS(tx_broadcast_frames, false), ++ ICSSG_STATS(tx_multicast_frames, false), ++ ICSSG_STATS(tx_odd_nibble_frames, false), ++ ICSSG_STATS(tx_underflow_errors, false), ++ ICSSG_STATS(tx_frame_max_size, true), ++ ICSSG_STATS(tx_max_size_error_frames, false), ++ ICSSG_STATS(tx_frame_min_size, true), ++ ICSSG_STATS(tx_min_size_error_frames, false), ++ ICSSG_STATS(tx_bucket1_size, true), ++ ICSSG_STATS(tx_bucket2_size, true), ++ ICSSG_STATS(tx_bucket3_size, true), ++ ICSSG_STATS(tx_bucket4_size, true), ++ ICSSG_STATS(tx_64B_frames, true), ++ ICSSG_STATS(tx_bucket1_frames, true), ++ ICSSG_STATS(tx_bucket2_frames, true), ++ ICSSG_STATS(tx_bucket3_frames, true), ++ ICSSG_STATS(tx_bucket4_frames, true), ++ ICSSG_STATS(tx_bucket5_frames, true), ++ ICSSG_STATS(tx_bytes, true), ++}; ++ ++#endif /* __NET_TI_ICSSG_STATS_H */ +-- +2.42.0 + diff --git a/recipes-kernel/linux/files/patches-6.1/0023-net-ti-icssg-prueth-Add-Standard-network-staticstics.patch b/recipes-kernel/linux/files/patches-6.1/0023-net-ti-icssg-prueth-Add-Standard-network-staticstics.patch new file mode 100644 index 000000000..5bd44e392 --- /dev/null +++ b/recipes-kernel/linux/files/patches-6.1/0023-net-ti-icssg-prueth-Add-Standard-network-staticstics.patch @@ -0,0 +1,98 @@ +From aa50dcaa7632e9bb5e8367acb3c59fe60b4cf249 Mon Sep 17 00:00:00 2001 +From: MD Danish Anwar +Date: Tue, 1 Aug 2023 14:44:26 +0530 +Subject: [PATCH 23/69] net: ti: icssg-prueth: Add Standard network staticstics + +Implement .ndo_get_stats64 to dump standard network interface +statistics for ICSSG ethernet driver. + +Signed-off-by: MD Danish Anwar +[Commit c2f67d192351 upstream] +--- + drivers/net/ethernet/ti/icssg/icssg_prueth.c | 22 ++++++++++++++++++++ + drivers/net/ethernet/ti/icssg/icssg_prueth.h | 2 ++ + drivers/net/ethernet/ti/icssg/icssg_stats.c | 13 ++++++++++++ + 3 files changed, 37 insertions(+) + +diff --git a/drivers/net/ethernet/ti/icssg/icssg_prueth.c b/drivers/net/ethernet/ti/icssg/icssg_prueth.c +index d0bb4db11b30..e641b6ce9415 100644 +--- a/drivers/net/ethernet/ti/icssg/icssg_prueth.c ++++ b/drivers/net/ethernet/ti/icssg/icssg_prueth.c +@@ -1240,6 +1240,27 @@ static int emac_ndo_ioctl(struct net_device *ndev, struct ifreq *ifr, int cmd) + return phy_do_ioctl(ndev, ifr, cmd); + } + ++static void emac_ndo_get_stats64(struct net_device *ndev, ++ struct rtnl_link_stats64 *stats) ++{ ++ struct prueth_emac *emac = netdev_priv(ndev); ++ ++ emac_update_hardware_stats(emac); ++ ++ stats->rx_packets = emac_get_stat_by_name(emac, "rx_packets"); ++ stats->rx_bytes = emac_get_stat_by_name(emac, "rx_bytes"); ++ stats->tx_packets = emac_get_stat_by_name(emac, "tx_packets"); ++ stats->tx_bytes = emac_get_stat_by_name(emac, "tx_bytes"); ++ stats->rx_crc_errors = emac_get_stat_by_name(emac, "rx_crc_errors"); ++ stats->rx_over_errors = emac_get_stat_by_name(emac, "rx_over_errors"); ++ stats->multicast = emac_get_stat_by_name(emac, "rx_multicast_frames"); ++ ++ stats->rx_errors = ndev->stats.rx_errors; ++ stats->rx_dropped = ndev->stats.rx_dropped; ++ stats->tx_errors = ndev->stats.tx_errors; ++ stats->tx_dropped = ndev->stats.tx_dropped; ++} ++ + static const struct net_device_ops emac_netdev_ops = { + .ndo_open = emac_ndo_open, + .ndo_stop = emac_ndo_stop, +@@ -1249,6 +1270,7 @@ static const struct net_device_ops emac_netdev_ops = { + .ndo_tx_timeout = emac_ndo_tx_timeout, + .ndo_set_rx_mode = emac_ndo_set_rx_mode, + .ndo_eth_ioctl = emac_ndo_ioctl, ++ .ndo_get_stats64 = emac_ndo_get_stats64, + }; + + /* get emac_port corresponding to eth_node name */ +diff --git a/drivers/net/ethernet/ti/icssg/icssg_prueth.h b/drivers/net/ethernet/ti/icssg/icssg_prueth.h +index f13de0d2e90b..e58cd8db7ba0 100644 +--- a/drivers/net/ethernet/ti/icssg/icssg_prueth.h ++++ b/drivers/net/ethernet/ti/icssg/icssg_prueth.h +@@ -51,6 +51,7 @@ + + /* Number of ICSSG related stats */ + #define ICSSG_NUM_STATS 60 ++#define ICSSG_NUM_STANDARD_STATS 31 + + /* Firmware status codes */ + #define ICSS_HS_FW_READY 0x55555555 +@@ -254,4 +255,5 @@ u32 icssg_queue_level(struct prueth *prueth, int queue); + + void emac_stats_work_handler(struct work_struct *work); + void emac_update_hardware_stats(struct prueth_emac *emac); ++int emac_get_stat_by_name(struct prueth_emac *emac, char *stat_name); + #endif /* __NET_TI_ICSSG_PRUETH_H */ +diff --git a/drivers/net/ethernet/ti/icssg/icssg_stats.c b/drivers/net/ethernet/ti/icssg/icssg_stats.c +index 25deb368a3f0..bb0b33927e3b 100644 +--- a/drivers/net/ethernet/ti/icssg/icssg_stats.c ++++ b/drivers/net/ethernet/ti/icssg/icssg_stats.c +@@ -42,3 +42,16 @@ void emac_stats_work_handler(struct work_struct *work) + queue_delayed_work(system_long_wq, &emac->stats_work, + msecs_to_jiffies((STATS_TIME_LIMIT_1G_MS * 1000) / emac->speed)); + } ++ ++int emac_get_stat_by_name(struct prueth_emac *emac, char *stat_name) ++{ ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(icssg_all_stats); i++) { ++ if (!strcmp(icssg_all_stats[i].name, stat_name)) ++ return emac->stats[icssg_all_stats[i].offset / sizeof(u32)]; ++ } ++ ++ netdev_err(emac->ndev, "Invalid stats %s\n", stat_name); ++ return -EINVAL; ++} +-- +2.42.0 + diff --git a/recipes-kernel/linux/files/patches-6.1/0024-net-ti-icssg-prueth-Add-ethtool-ops-for-ICSSG-Ethern.patch b/recipes-kernel/linux/files/patches-6.1/0024-net-ti-icssg-prueth-Add-ethtool-ops-for-ICSSG-Ethern.patch new file mode 100644 index 000000000..c93724d94 --- /dev/null +++ b/recipes-kernel/linux/files/patches-6.1/0024-net-ti-icssg-prueth-Add-ethtool-ops-for-ICSSG-Ethern.patch @@ -0,0 +1,259 @@ +From bd13210b0cc62acc30de43391cde4a7002e2e4eb Mon Sep 17 00:00:00 2001 +From: MD Danish Anwar +Date: Tue, 1 Aug 2023 14:44:27 +0530 +Subject: [PATCH 24/69] net: ti: icssg-prueth: Add ethtool ops for ICSSG + Ethernet driver + +Add icssg_ethtool.c file. This file will be used for dumping statistics +via ethtool for ICSSG ethernet driver. + +Reviewed-by: Andrew Lunn +Signed-off-by: MD Danish Anwar +[Commit 8fb86b0dcaed upstream] +--- + drivers/net/ethernet/ti/Makefile | 1 + + drivers/net/ethernet/ti/icssg/icssg_ethtool.c | 188 ++++++++++++++++++ + drivers/net/ethernet/ti/icssg/icssg_prueth.c | 1 + + drivers/net/ethernet/ti/icssg/icssg_prueth.h | 3 + + 4 files changed, 193 insertions(+) + create mode 100644 drivers/net/ethernet/ti/icssg/icssg_ethtool.c + +diff --git a/drivers/net/ethernet/ti/Makefile b/drivers/net/ethernet/ti/Makefile +index 03d9b2b36b5f..9176d79c36e1 100644 +--- a/drivers/net/ethernet/ti/Makefile ++++ b/drivers/net/ethernet/ti/Makefile +@@ -37,3 +37,4 @@ icssg-prueth-y := k3-cppi-desc-pool.o \ + icssg/icssg_config.o \ + icssg/icssg_mii_cfg.o \ + icssg/icssg_stats.o \ ++ icssg/icssg_ethtool.o +diff --git a/drivers/net/ethernet/ti/icssg/icssg_ethtool.c b/drivers/net/ethernet/ti/icssg/icssg_ethtool.c +new file mode 100644 +index 000000000000..02c312f01d10 +--- /dev/null ++++ b/drivers/net/ethernet/ti/icssg/icssg_ethtool.c +@@ -0,0 +1,188 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* Texas Instruments ICSSG Ethernet driver ++ * ++ * Copyright (C) 2018-2022 Texas Instruments Incorporated - https://www.ti.com/ ++ * ++ */ ++ ++#include "icssg_prueth.h" ++#include "icssg_stats.h" ++ ++static void emac_get_drvinfo(struct net_device *ndev, ++ struct ethtool_drvinfo *info) ++{ ++ struct prueth_emac *emac = netdev_priv(ndev); ++ struct prueth *prueth = emac->prueth; ++ ++ strscpy(info->driver, dev_driver_string(prueth->dev), ++ sizeof(info->driver)); ++ strscpy(info->bus_info, dev_name(prueth->dev), sizeof(info->bus_info)); ++} ++ ++static u32 emac_get_msglevel(struct net_device *ndev) ++{ ++ struct prueth_emac *emac = netdev_priv(ndev); ++ ++ return emac->msg_enable; ++} ++ ++static void emac_set_msglevel(struct net_device *ndev, u32 value) ++{ ++ struct prueth_emac *emac = netdev_priv(ndev); ++ ++ emac->msg_enable = value; ++} ++ ++static int emac_get_link_ksettings(struct net_device *ndev, ++ struct ethtool_link_ksettings *ecmd) ++{ ++ return phy_ethtool_get_link_ksettings(ndev, ecmd); ++} ++ ++static int emac_set_link_ksettings(struct net_device *ndev, ++ const struct ethtool_link_ksettings *ecmd) ++{ ++ return phy_ethtool_set_link_ksettings(ndev, ecmd); ++} ++ ++static int emac_get_eee(struct net_device *ndev, struct ethtool_eee *edata) ++{ ++ if (!ndev->phydev) ++ return -EOPNOTSUPP; ++ ++ return phy_ethtool_get_eee(ndev->phydev, edata); ++} ++ ++static int emac_set_eee(struct net_device *ndev, struct ethtool_eee *edata) ++{ ++ if (!ndev->phydev) ++ return -EOPNOTSUPP; ++ ++ return phy_ethtool_set_eee(ndev->phydev, edata); ++} ++ ++static int emac_nway_reset(struct net_device *ndev) ++{ ++ return phy_ethtool_nway_reset(ndev); ++} ++ ++static int emac_get_sset_count(struct net_device *ndev, int stringset) ++{ ++ switch (stringset) { ++ case ETH_SS_STATS: ++ return ICSSG_NUM_ETHTOOL_STATS; ++ default: ++ return -EOPNOTSUPP; ++ } ++} ++ ++static void emac_get_strings(struct net_device *ndev, u32 stringset, u8 *data) ++{ ++ u8 *p = data; ++ int i; ++ ++ switch (stringset) { ++ case ETH_SS_STATS: ++ for (i = 0; i < ARRAY_SIZE(icssg_all_stats); i++) { ++ if (!icssg_all_stats[i].standard_stats) { ++ memcpy(p, icssg_all_stats[i].name, ++ ETH_GSTRING_LEN); ++ p += ETH_GSTRING_LEN; ++ } ++ } ++ break; ++ default: ++ break; ++ } ++} ++ ++static void emac_get_ethtool_stats(struct net_device *ndev, ++ struct ethtool_stats *stats, u64 *data) ++{ ++ struct prueth_emac *emac = netdev_priv(ndev); ++ int i; ++ ++ emac_update_hardware_stats(emac); ++ ++ for (i = 0; i < ARRAY_SIZE(icssg_all_stats); i++) ++ if (!icssg_all_stats[i].standard_stats) ++ *(data++) = emac->stats[i]; ++} ++ ++static int emac_set_channels(struct net_device *ndev, ++ struct ethtool_channels *ch) ++{ ++ struct prueth_emac *emac = netdev_priv(ndev); ++ ++ /* Check if interface is up. Can change the num queues when ++ * the interface is down. ++ */ ++ if (netif_running(emac->ndev)) ++ return -EBUSY; ++ ++ emac->tx_ch_num = ch->tx_count; ++ ++ return 0; ++} ++ ++static void emac_get_channels(struct net_device *ndev, ++ struct ethtool_channels *ch) ++{ ++ struct prueth_emac *emac = netdev_priv(ndev); ++ ++ ch->max_rx = 1; ++ ch->max_tx = PRUETH_MAX_TX_QUEUES; ++ ch->rx_count = 1; ++ ch->tx_count = emac->tx_ch_num; ++} ++ ++static const struct ethtool_rmon_hist_range emac_rmon_ranges[] = { ++ { 0, 64}, ++ { 65, 128}, ++ { 129, 256}, ++ { 257, 512}, ++ { 513, PRUETH_MAX_PKT_SIZE}, ++ {} ++}; ++ ++static void emac_get_rmon_stats(struct net_device *ndev, ++ struct ethtool_rmon_stats *rmon_stats, ++ const struct ethtool_rmon_hist_range **ranges) ++{ ++ struct prueth_emac *emac = netdev_priv(ndev); ++ ++ *ranges = emac_rmon_ranges; ++ ++ rmon_stats->undersize_pkts = emac_get_stat_by_name(emac, "rx_bucket1_frames") - ++ emac_get_stat_by_name(emac, "rx_64B_frames"); ++ ++ rmon_stats->hist[0] = emac_get_stat_by_name(emac, "rx_bucket1_frames"); ++ rmon_stats->hist[1] = emac_get_stat_by_name(emac, "rx_bucket2_frames"); ++ rmon_stats->hist[2] = emac_get_stat_by_name(emac, "rx_bucket3_frames"); ++ rmon_stats->hist[3] = emac_get_stat_by_name(emac, "rx_bucket4_frames"); ++ rmon_stats->hist[4] = emac_get_stat_by_name(emac, "rx_bucket5_frames"); ++ ++ rmon_stats->hist_tx[0] = emac_get_stat_by_name(emac, "tx_bucket1_frames"); ++ rmon_stats->hist_tx[1] = emac_get_stat_by_name(emac, "tx_bucket2_frames"); ++ rmon_stats->hist_tx[2] = emac_get_stat_by_name(emac, "tx_bucket3_frames"); ++ rmon_stats->hist_tx[3] = emac_get_stat_by_name(emac, "tx_bucket4_frames"); ++ rmon_stats->hist_tx[4] = emac_get_stat_by_name(emac, "tx_bucket5_frames"); ++} ++ ++const struct ethtool_ops icssg_ethtool_ops = { ++ .get_drvinfo = emac_get_drvinfo, ++ .get_msglevel = emac_get_msglevel, ++ .set_msglevel = emac_set_msglevel, ++ .get_sset_count = emac_get_sset_count, ++ .get_ethtool_stats = emac_get_ethtool_stats, ++ .get_strings = emac_get_strings, ++ .get_channels = emac_get_channels, ++ .set_channels = emac_set_channels, ++ .get_link_ksettings = emac_get_link_ksettings, ++ .set_link_ksettings = emac_set_link_ksettings, ++ .get_link = ethtool_op_get_link, ++ .get_eee = emac_get_eee, ++ .set_eee = emac_set_eee, ++ .nway_reset = emac_nway_reset, ++ .get_rmon_stats = emac_get_rmon_stats, ++}; +diff --git a/drivers/net/ethernet/ti/icssg/icssg_prueth.c b/drivers/net/ethernet/ti/icssg/icssg_prueth.c +index e641b6ce9415..80721d82f6c5 100644 +--- a/drivers/net/ethernet/ti/icssg/icssg_prueth.c ++++ b/drivers/net/ethernet/ti/icssg/icssg_prueth.c +@@ -1421,6 +1421,7 @@ static int prueth_netdev_init(struct prueth *prueth, + ndev->min_mtu = PRUETH_MIN_PKT_SIZE; + ndev->max_mtu = PRUETH_MAX_MTU; + ndev->netdev_ops = &emac_netdev_ops; ++ ndev->ethtool_ops = &icssg_ethtool_ops; + ndev->hw_features = NETIF_F_SG; + ndev->features = ndev->hw_features; + +diff --git a/drivers/net/ethernet/ti/icssg/icssg_prueth.h b/drivers/net/ethernet/ti/icssg/icssg_prueth.h +index e58cd8db7ba0..a8ce4d01ef16 100644 +--- a/drivers/net/ethernet/ti/icssg/icssg_prueth.h ++++ b/drivers/net/ethernet/ti/icssg/icssg_prueth.h +@@ -52,6 +52,7 @@ + /* Number of ICSSG related stats */ + #define ICSSG_NUM_STATS 60 + #define ICSSG_NUM_STANDARD_STATS 31 ++#define ICSSG_NUM_ETHTOOL_STATS (ICSSG_NUM_STATS - ICSSG_NUM_STANDARD_STATS) + + /* Firmware status codes */ + #define ICSS_HS_FW_READY 0x55555555 +@@ -230,6 +231,8 @@ static inline int prueth_emac_slice(struct prueth_emac *emac) + } + } + ++extern const struct ethtool_ops icssg_ethtool_ops; ++ + /* Classifier helpers */ + void icssg_class_set_mac_addr(struct regmap *miig_rt, int slice, u8 *mac); + void icssg_class_set_host_mac_addr(struct regmap *miig_rt, const u8 *mac); +-- +2.42.0 + diff --git a/recipes-kernel/linux/files/patches-6.1/0025-net-ti-icssg-prueth-Add-Power-management-support.patch b/recipes-kernel/linux/files/patches-6.1/0025-net-ti-icssg-prueth-Add-Power-management-support.patch new file mode 100644 index 000000000..1b63c89ca --- /dev/null +++ b/recipes-kernel/linux/files/patches-6.1/0025-net-ti-icssg-prueth-Add-Power-management-support.patch @@ -0,0 +1,93 @@ +From da07f513b914edc19511097f58cd3780f62d2907 Mon Sep 17 00:00:00 2001 +From: MD Danish Anwar +Date: Tue, 1 Aug 2023 14:44:28 +0530 +Subject: [PATCH 25/69] net: ti: icssg-prueth: Add Power management support + +Add suspend / resume APIs to support power management in ICSSG ethernet +driver. + +Reviewed-by: Andrew Lunn +Signed-off-by: MD Danish Anwar +[Commit a46750a13bb0 upstream] +--- + drivers/net/ethernet/ti/icssg/icssg_prueth.c | 57 ++++++++++++++++++++ + 1 file changed, 57 insertions(+) + +diff --git a/drivers/net/ethernet/ti/icssg/icssg_prueth.c b/drivers/net/ethernet/ti/icssg/icssg_prueth.c +index 80721d82f6c5..47b941fb0198 100644 +--- a/drivers/net/ethernet/ti/icssg/icssg_prueth.c ++++ b/drivers/net/ethernet/ti/icssg/icssg_prueth.c +@@ -1813,6 +1813,62 @@ static void prueth_remove(struct platform_device *pdev) + prueth_put_cores(prueth, ICSS_SLICE0); + } + ++#ifdef CONFIG_PM_SLEEP ++static int prueth_suspend(struct device *dev) ++{ ++ struct prueth *prueth = dev_get_drvdata(dev); ++ struct net_device *ndev; ++ int i, ret; ++ ++ for (i = 0; i < PRUETH_NUM_MACS; i++) { ++ ndev = prueth->registered_netdevs[i]; ++ ++ if (!ndev) ++ continue; ++ ++ if (netif_running(ndev)) { ++ netif_device_detach(ndev); ++ ret = emac_ndo_stop(ndev); ++ if (ret < 0) { ++ netdev_err(ndev, "failed to stop: %d", ret); ++ return ret; ++ } ++ } ++ } ++ ++ return 0; ++} ++ ++static int prueth_resume(struct device *dev) ++{ ++ struct prueth *prueth = dev_get_drvdata(dev); ++ struct net_device *ndev; ++ int i, ret; ++ ++ for (i = 0; i < PRUETH_NUM_MACS; i++) { ++ ndev = prueth->registered_netdevs[i]; ++ ++ if (!ndev) ++ continue; ++ ++ if (netif_running(ndev)) { ++ ret = emac_ndo_open(ndev); ++ if (ret < 0) { ++ netdev_err(ndev, "failed to start: %d", ret); ++ return ret; ++ } ++ netif_device_attach(ndev); ++ } ++ } ++ ++ return 0; ++} ++#endif /* CONFIG_PM_SLEEP */ ++ ++static const struct dev_pm_ops prueth_dev_pm_ops = { ++ SET_SYSTEM_SLEEP_PM_OPS(prueth_suspend, prueth_resume) ++}; ++ + static const struct prueth_pdata am654_icssg_pdata = { + .fdqring_mode = K3_RINGACC_RING_MODE_MESSAGE, + .quirk_10m_link_issue = 1, +@@ -1830,6 +1886,7 @@ static struct platform_driver prueth_driver = { + .driver = { + .name = "icssg-prueth", + .of_match_table = prueth_dt_match, ++ .pm = &prueth_dev_pm_ops, + }, + }; + module_platform_driver(prueth_driver); +-- +2.42.0 + diff --git a/recipes-kernel/linux/files/patches-6.1/0026-dt-bindings-net-Add-ICSS-IEP.patch b/recipes-kernel/linux/files/patches-6.1/0026-dt-bindings-net-Add-ICSS-IEP.patch new file mode 100644 index 000000000..16b845449 --- /dev/null +++ b/recipes-kernel/linux/files/patches-6.1/0026-dt-bindings-net-Add-ICSS-IEP.patch @@ -0,0 +1,72 @@ +From 08b74ccdccbc15f6bfd411f263cd2bad9f2b7608 Mon Sep 17 00:00:00 2001 +From: MD Danish Anwar +Date: Thu, 24 Aug 2023 17:16:14 +0530 +Subject: [PATCH 26/69] dt-bindings: net: Add ICSS IEP + +Add a DT binding document for the ICSS Industrial Ethernet Peripheral(IEP) +hardware. IEP supports packet timestamping, PTP and PPS. + +Reviewed-by: Conor Dooley +Reviewed-by: Roger Quadros +Reviewed-by: Simon Horman +Signed-off-by: MD Danish Anwar +[Commit f0035689c036 upstream] +--- + .../devicetree/bindings/net/ti,icss-iep.yaml | 45 +++++++++++++++++++ + 1 file changed, 45 insertions(+) + create mode 100644 Documentation/devicetree/bindings/net/ti,icss-iep.yaml + +diff --git a/Documentation/devicetree/bindings/net/ti,icss-iep.yaml b/Documentation/devicetree/bindings/net/ti,icss-iep.yaml +new file mode 100644 +index 000000000000..f5c22d6dcaee +--- /dev/null ++++ b/Documentation/devicetree/bindings/net/ti,icss-iep.yaml +@@ -0,0 +1,45 @@ ++# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/net/ti,icss-iep.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: Texas Instruments ICSS Industrial Ethernet Peripheral (IEP) module ++ ++maintainers: ++ - Md Danish Anwar ++ ++properties: ++ compatible: ++ oneOf: ++ - items: ++ - enum: ++ - ti,am642-icss-iep ++ - ti,j721e-icss-iep ++ - const: ti,am654-icss-iep ++ ++ - const: ti,am654-icss-iep ++ ++ ++ reg: ++ maxItems: 1 ++ ++ clocks: ++ maxItems: 1 ++ description: phandle to the IEP source clock ++ ++required: ++ - compatible ++ - reg ++ - clocks ++ ++additionalProperties: false ++ ++examples: ++ - | ++ /* AM65x */ ++ icssg0_iep0: iep@2e000 { ++ compatible = "ti,am654-icss-iep"; ++ reg = <0x2e000 0x1000>; ++ clocks = <&icssg0_iepclk_mux>; ++ }; +-- +2.42.0 + diff --git a/recipes-kernel/linux/files/patches-6.1/0027-dt-bindings-net-Add-IEP-property-in-ICSSG.patch b/recipes-kernel/linux/files/patches-6.1/0027-dt-bindings-net-Add-IEP-property-in-ICSSG.patch new file mode 100644 index 000000000..de7375ab1 --- /dev/null +++ b/recipes-kernel/linux/files/patches-6.1/0027-dt-bindings-net-Add-IEP-property-in-ICSSG.patch @@ -0,0 +1,49 @@ +From aa3a270aa720b5c05f5f338e527c06c910a85873 Mon Sep 17 00:00:00 2001 +From: MD Danish Anwar +Date: Thu, 24 Aug 2023 17:16:15 +0530 +Subject: [PATCH 27/69] dt-bindings: net: Add IEP property in ICSSG + +Add IEP property in ICSSG hardware DT binding document. +ICSSG uses IEP (Industrial Ethernet Peripheral) to support timestamping +of ethernet packets, PTP and PPS. + +Reviewed-by: Conor Dooley +Reviewed-by: Roger Quadros +Reviewed-by: Simon Horman +Signed-off-by: MD Danish Anwar +Reviewed-by: Rob Herring +[Commit b12056278378 upstream] +--- + .../devicetree/bindings/net/ti,icssg-prueth.yaml | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/Documentation/devicetree/bindings/net/ti,icssg-prueth.yaml b/Documentation/devicetree/bindings/net/ti,icssg-prueth.yaml +index 8ec30b3eb760..311c570165f9 100644 +--- a/Documentation/devicetree/bindings/net/ti,icssg-prueth.yaml ++++ b/Documentation/devicetree/bindings/net/ti,icssg-prueth.yaml +@@ -52,6 +52,14 @@ properties: + description: + phandle to MII_RT module's syscon regmap + ++ ti,iep: ++ $ref: /schemas/types.yaml#/definitions/phandle-array ++ maxItems: 2 ++ items: ++ maxItems: 1 ++ description: ++ phandle to IEP (Industrial Ethernet Peripheral) for ICSSG ++ + interrupts: + maxItems: 2 + description: +@@ -155,6 +163,7 @@ examples: + "tx1-0", "tx1-1", "tx1-2", "tx1-3", + "rx0", "rx1"; + ti,mii-g-rt = <&icssg2_mii_g_rt>; ++ ti,iep = <&icssg2_iep0>, <&icssg2_iep1>; + interrupt-parent = <&icssg2_intc>; + interrupts = <24 0 2>, <25 1 3>; + interrupt-names = "tx_ts0", "tx_ts1"; +-- +2.42.0 + diff --git a/recipes-kernel/linux/files/patches-6.1/0028-net-ti-icss-iep-Add-IEP-driver.patch b/recipes-kernel/linux/files/patches-6.1/0028-net-ti-icss-iep-Add-IEP-driver.patch new file mode 100644 index 000000000..44374aa1e --- /dev/null +++ b/recipes-kernel/linux/files/patches-6.1/0028-net-ti-icss-iep-Add-IEP-driver.patch @@ -0,0 +1,1046 @@ +From e47bad5c1736842f71b0483fc9493bf3de75adcb Mon Sep 17 00:00:00 2001 +From: Roger Quadros +Date: Thu, 24 Aug 2023 17:16:16 +0530 +Subject: [PATCH 28/69] net: ti: icss-iep: Add IEP driver + +Add a driver for Industrial Ethernet Peripheral (IEP) block of PRUSS to +support timestamping of ethernet packets and thus support PTP and PPS +for PRU ethernet ports. + +Signed-off-by: Roger Quadros +Signed-off-by: Lokesh Vutla +Signed-off-by: Murali Karicheri +Signed-off-by: Vignesh Raghavendra +Reviewed-by: Simon Horman +Signed-off-by: MD Danish Anwar +[Commit c1e0230eeaab upstream] +--- + drivers/net/ethernet/ti/Kconfig | 11 + + drivers/net/ethernet/ti/Makefile | 1 + + drivers/net/ethernet/ti/icssg/icss_iep.c | 939 +++++++++++++++++++++++ + drivers/net/ethernet/ti/icssg/icss_iep.h | 38 + + 4 files changed, 989 insertions(+) + create mode 100644 drivers/net/ethernet/ti/icssg/icss_iep.c + create mode 100644 drivers/net/ethernet/ti/icssg/icss_iep.h + +diff --git a/drivers/net/ethernet/ti/Kconfig b/drivers/net/ethernet/ti/Kconfig +index 63e510b6860f..1af5a90720ec 100644 +--- a/drivers/net/ethernet/ti/Kconfig ++++ b/drivers/net/ethernet/ti/Kconfig +@@ -196,4 +196,15 @@ config TI_ICSSG_PRUETH + to support the Ethernet operation. Currently, it supports Ethernet + with 1G and 100M link speed. + ++config TI_ICSS_IEP ++ tristate "TI PRU ICSS IEP driver" ++ depends on TI_PRUSS ++ default TI_PRUSS ++ help ++ This driver enables support for the PRU-ICSS Industrial Ethernet ++ Peripheral within a PRU-ICSS subsystem present on various TI SoCs. ++ ++ To compile this driver as a module, choose M here. The module ++ will be called icss_iep. ++ + endif # NET_VENDOR_TI +diff --git a/drivers/net/ethernet/ti/Makefile b/drivers/net/ethernet/ti/Makefile +index 9176d79c36e1..34fd7a716ba6 100644 +--- a/drivers/net/ethernet/ti/Makefile ++++ b/drivers/net/ethernet/ti/Makefile +@@ -38,3 +38,4 @@ icssg-prueth-y := k3-cppi-desc-pool.o \ + icssg/icssg_mii_cfg.o \ + icssg/icssg_stats.o \ + icssg/icssg_ethtool.o ++obj-$(CONFIG_TI_ICSS_IEP) += icssg/icss_iep.o +diff --git a/drivers/net/ethernet/ti/icssg/icss_iep.c b/drivers/net/ethernet/ti/icssg/icss_iep.c +new file mode 100644 +index 000000000000..bcc056bf45da +--- /dev/null ++++ b/drivers/net/ethernet/ti/icssg/icss_iep.c +@@ -0,0 +1,939 @@ ++// SPDX-License-Identifier: GPL-2.0 ++ ++/* Texas Instruments ICSSG Industrial Ethernet Peripheral (IEP) Driver ++ * ++ * Copyright (C) 2023 Texas Instruments Incorporated - https://www.ti.com ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "icss_iep.h" ++ ++#define IEP_MAX_DEF_INC 0xf ++#define IEP_MAX_COMPEN_INC 0xfff ++#define IEP_MAX_COMPEN_COUNT 0xffffff ++ ++#define IEP_GLOBAL_CFG_CNT_ENABLE BIT(0) ++#define IEP_GLOBAL_CFG_DEFAULT_INC_MASK GENMASK(7, 4) ++#define IEP_GLOBAL_CFG_DEFAULT_INC_SHIFT 4 ++#define IEP_GLOBAL_CFG_COMPEN_INC_MASK GENMASK(19, 8) ++#define IEP_GLOBAL_CFG_COMPEN_INC_SHIFT 8 ++ ++#define IEP_GLOBAL_STATUS_CNT_OVF BIT(0) ++ ++#define IEP_CMP_CFG_SHADOW_EN BIT(17) ++#define IEP_CMP_CFG_CMP0_RST_CNT_EN BIT(0) ++#define IEP_CMP_CFG_CMP_EN(cmp) (GENMASK(16, 1) & (1 << ((cmp) + 1))) ++ ++#define IEP_CMP_STATUS(cmp) (1 << (cmp)) ++ ++#define IEP_SYNC_CTRL_SYNC_EN BIT(0) ++#define IEP_SYNC_CTRL_SYNC_N_EN(n) (GENMASK(2, 1) & (BIT(1) << (n))) ++ ++#define IEP_MIN_CMP 0 ++#define IEP_MAX_CMP 15 ++ ++#define ICSS_IEP_64BIT_COUNTER_SUPPORT BIT(0) ++#define ICSS_IEP_SLOW_COMPEN_REG_SUPPORT BIT(1) ++#define ICSS_IEP_SHADOW_MODE_SUPPORT BIT(2) ++ ++#define LATCH_INDEX(ts_index) ((ts_index) + 6) ++#define IEP_CAP_CFG_CAPNR_1ST_EVENT_EN(n) BIT(LATCH_INDEX(n)) ++#define IEP_CAP_CFG_CAP_ASYNC_EN(n) BIT(LATCH_INDEX(n) + 10) ++ ++enum { ++ ICSS_IEP_GLOBAL_CFG_REG, ++ ICSS_IEP_GLOBAL_STATUS_REG, ++ ICSS_IEP_COMPEN_REG, ++ ICSS_IEP_SLOW_COMPEN_REG, ++ ICSS_IEP_COUNT_REG0, ++ ICSS_IEP_COUNT_REG1, ++ ICSS_IEP_CAPTURE_CFG_REG, ++ ICSS_IEP_CAPTURE_STAT_REG, ++ ++ ICSS_IEP_CAP6_RISE_REG0, ++ ICSS_IEP_CAP6_RISE_REG1, ++ ++ ICSS_IEP_CAP7_RISE_REG0, ++ ICSS_IEP_CAP7_RISE_REG1, ++ ++ ICSS_IEP_CMP_CFG_REG, ++ ICSS_IEP_CMP_STAT_REG, ++ ICSS_IEP_CMP0_REG0, ++ ICSS_IEP_CMP0_REG1, ++ ICSS_IEP_CMP1_REG0, ++ ICSS_IEP_CMP1_REG1, ++ ++ ICSS_IEP_CMP8_REG0, ++ ICSS_IEP_CMP8_REG1, ++ ICSS_IEP_SYNC_CTRL_REG, ++ ICSS_IEP_SYNC0_STAT_REG, ++ ICSS_IEP_SYNC1_STAT_REG, ++ ICSS_IEP_SYNC_PWIDTH_REG, ++ ICSS_IEP_SYNC0_PERIOD_REG, ++ ICSS_IEP_SYNC1_DELAY_REG, ++ ICSS_IEP_SYNC_START_REG, ++ ICSS_IEP_MAX_REGS, ++}; ++ ++/** ++ * struct icss_iep_plat_data - Plat data to handle SoC variants ++ * @config: Regmap configuration data ++ * @reg_offs: register offsets to capture offset differences across SoCs ++ * @flags: Flags to represent IEP properties ++ */ ++struct icss_iep_plat_data { ++ struct regmap_config *config; ++ u32 reg_offs[ICSS_IEP_MAX_REGS]; ++ u32 flags; ++}; ++ ++struct icss_iep { ++ struct device *dev; ++ void __iomem *base; ++ const struct icss_iep_plat_data *plat_data; ++ struct regmap *map; ++ struct device_node *client_np; ++ unsigned long refclk_freq; ++ int clk_tick_time; /* one refclk tick time in ns */ ++ struct ptp_clock_info ptp_info; ++ struct ptp_clock *ptp_clock; ++ struct mutex ptp_clk_mutex; /* PHC access serializer */ ++ spinlock_t irq_lock; /* CMP IRQ vs icss_iep_ptp_enable access */ ++ u32 def_inc; ++ s16 slow_cmp_inc; ++ u32 slow_cmp_count; ++ const struct icss_iep_clockops *ops; ++ void *clockops_data; ++ u32 cycle_time_ns; ++ u32 perout_enabled; ++ bool pps_enabled; ++ int cap_cmp_irq; ++ u64 period; ++ u32 latch_enable; ++}; ++ ++/** ++ * icss_iep_get_count_hi() - Get the upper 32 bit IEP counter ++ * @iep: Pointer to structure representing IEP. ++ * ++ * Return: upper 32 bit IEP counter ++ */ ++int icss_iep_get_count_hi(struct icss_iep *iep) ++{ ++ u32 val = 0; ++ ++ if (iep && (iep->plat_data->flags & ICSS_IEP_64BIT_COUNTER_SUPPORT)) ++ val = readl(iep->base + iep->plat_data->reg_offs[ICSS_IEP_COUNT_REG1]); ++ ++ return val; ++} ++EXPORT_SYMBOL_GPL(icss_iep_get_count_hi); ++ ++/** ++ * icss_iep_get_count_low() - Get the lower 32 bit IEP counter ++ * @iep: Pointer to structure representing IEP. ++ * ++ * Return: lower 32 bit IEP counter ++ */ ++int icss_iep_get_count_low(struct icss_iep *iep) ++{ ++ u32 val = 0; ++ ++ if (iep) ++ val = readl(iep->base + iep->plat_data->reg_offs[ICSS_IEP_COUNT_REG0]); ++ ++ return val; ++} ++EXPORT_SYMBOL_GPL(icss_iep_get_count_low); ++ ++/** ++ * icss_iep_get_ptp_clock_idx() - Get PTP clock index using IEP driver ++ * @iep: Pointer to structure representing IEP. ++ * ++ * Return: PTP clock index, -1 if not registered ++ */ ++int icss_iep_get_ptp_clock_idx(struct icss_iep *iep) ++{ ++ if (!iep || !iep->ptp_clock) ++ return -1; ++ return ptp_clock_index(iep->ptp_clock); ++} ++EXPORT_SYMBOL_GPL(icss_iep_get_ptp_clock_idx); ++ ++static void icss_iep_set_counter(struct icss_iep *iep, u64 ns) ++{ ++ if (iep->plat_data->flags & ICSS_IEP_64BIT_COUNTER_SUPPORT) ++ writel(upper_32_bits(ns), iep->base + ++ iep->plat_data->reg_offs[ICSS_IEP_COUNT_REG1]); ++ writel(upper_32_bits(ns), iep->base + iep->plat_data->reg_offs[ICSS_IEP_COUNT_REG0]); ++} ++ ++static void icss_iep_update_to_next_boundary(struct icss_iep *iep, u64 start_ns); ++ ++/** ++ * icss_iep_settime() - Set time of the PTP clock using IEP driver ++ * @iep: Pointer to structure representing IEP. ++ * @ns: Time to be set in nanoseconds ++ * ++ * This API uses writel() instead of regmap_write() for write operations as ++ * regmap_write() is too slow and this API is time sensitive. ++ */ ++static void icss_iep_settime(struct icss_iep *iep, u64 ns) ++{ ++ unsigned long flags; ++ ++ if (iep->ops && iep->ops->settime) { ++ iep->ops->settime(iep->clockops_data, ns); ++ return; ++ } ++ ++ spin_lock_irqsave(&iep->irq_lock, flags); ++ if (iep->pps_enabled || iep->perout_enabled) ++ writel(0, iep->base + iep->plat_data->reg_offs[ICSS_IEP_SYNC_CTRL_REG]); ++ ++ icss_iep_set_counter(iep, ns); ++ ++ if (iep->pps_enabled || iep->perout_enabled) { ++ icss_iep_update_to_next_boundary(iep, ns); ++ writel(IEP_SYNC_CTRL_SYNC_N_EN(0) | IEP_SYNC_CTRL_SYNC_EN, ++ iep->base + iep->plat_data->reg_offs[ICSS_IEP_SYNC_CTRL_REG]); ++ } ++ spin_unlock_irqrestore(&iep->irq_lock, flags); ++} ++ ++/** ++ * icss_iep_gettime() - Get time of the PTP clock using IEP driver ++ * @iep: Pointer to structure representing IEP. ++ * @sts: Pointer to structure representing PTP system timestamp. ++ * ++ * This API uses readl() instead of regmap_read() for read operations as ++ * regmap_read() is too slow and this API is time sensitive. ++ * ++ * Return: The current timestamp of the PTP clock using IEP driver ++ */ ++static u64 icss_iep_gettime(struct icss_iep *iep, ++ struct ptp_system_timestamp *sts) ++{ ++ u32 ts_hi = 0, ts_lo; ++ unsigned long flags; ++ ++ if (iep->ops && iep->ops->gettime) ++ return iep->ops->gettime(iep->clockops_data, sts); ++ ++ /* use local_irq_x() to make it work for both RT/non-RT */ ++ local_irq_save(flags); ++ ++ /* no need to play with hi-lo, hi is latched when lo is read */ ++ ptp_read_system_prets(sts); ++ ts_lo = readl(iep->base + iep->plat_data->reg_offs[ICSS_IEP_COUNT_REG0]); ++ ptp_read_system_postts(sts); ++ if (iep->plat_data->flags & ICSS_IEP_64BIT_COUNTER_SUPPORT) ++ ts_hi = readl(iep->base + iep->plat_data->reg_offs[ICSS_IEP_COUNT_REG1]); ++ ++ local_irq_restore(flags); ++ ++ return (u64)ts_lo | (u64)ts_hi << 32; ++} ++ ++static void icss_iep_enable(struct icss_iep *iep) ++{ ++ regmap_update_bits(iep->map, ICSS_IEP_GLOBAL_CFG_REG, ++ IEP_GLOBAL_CFG_CNT_ENABLE, ++ IEP_GLOBAL_CFG_CNT_ENABLE); ++} ++ ++static void icss_iep_disable(struct icss_iep *iep) ++{ ++ regmap_update_bits(iep->map, ICSS_IEP_GLOBAL_CFG_REG, ++ IEP_GLOBAL_CFG_CNT_ENABLE, ++ 0); ++} ++ ++static void icss_iep_enable_shadow_mode(struct icss_iep *iep) ++{ ++ u32 cycle_time; ++ int cmp; ++ ++ cycle_time = iep->cycle_time_ns - iep->def_inc; ++ ++ icss_iep_disable(iep); ++ ++ /* disable shadow mode */ ++ regmap_update_bits(iep->map, ICSS_IEP_CMP_CFG_REG, ++ IEP_CMP_CFG_SHADOW_EN, 0); ++ ++ /* enable shadow mode */ ++ regmap_update_bits(iep->map, ICSS_IEP_CMP_CFG_REG, ++ IEP_CMP_CFG_SHADOW_EN, IEP_CMP_CFG_SHADOW_EN); ++ ++ /* clear counters */ ++ icss_iep_set_counter(iep, 0); ++ ++ /* clear overflow status */ ++ regmap_update_bits(iep->map, ICSS_IEP_GLOBAL_STATUS_REG, ++ IEP_GLOBAL_STATUS_CNT_OVF, ++ IEP_GLOBAL_STATUS_CNT_OVF); ++ ++ /* clear compare status */ ++ for (cmp = IEP_MIN_CMP; cmp < IEP_MAX_CMP; cmp++) { ++ regmap_update_bits(iep->map, ICSS_IEP_CMP_STAT_REG, ++ IEP_CMP_STATUS(cmp), IEP_CMP_STATUS(cmp)); ++ } ++ ++ /* enable reset counter on CMP0 event */ ++ regmap_update_bits(iep->map, ICSS_IEP_CMP_CFG_REG, ++ IEP_CMP_CFG_CMP0_RST_CNT_EN, ++ IEP_CMP_CFG_CMP0_RST_CNT_EN); ++ /* enable compare */ ++ regmap_update_bits(iep->map, ICSS_IEP_CMP_CFG_REG, ++ IEP_CMP_CFG_CMP_EN(0), ++ IEP_CMP_CFG_CMP_EN(0)); ++ ++ /* set CMP0 value to cycle time */ ++ regmap_write(iep->map, ICSS_IEP_CMP0_REG0, cycle_time); ++ if (iep->plat_data->flags & ICSS_IEP_64BIT_COUNTER_SUPPORT) ++ regmap_write(iep->map, ICSS_IEP_CMP0_REG1, cycle_time); ++ ++ icss_iep_set_counter(iep, 0); ++ icss_iep_enable(iep); ++} ++ ++static void icss_iep_set_default_inc(struct icss_iep *iep, u8 def_inc) ++{ ++ regmap_update_bits(iep->map, ICSS_IEP_GLOBAL_CFG_REG, ++ IEP_GLOBAL_CFG_DEFAULT_INC_MASK, ++ def_inc << IEP_GLOBAL_CFG_DEFAULT_INC_SHIFT); ++} ++ ++static void icss_iep_set_compensation_inc(struct icss_iep *iep, u16 compen_inc) ++{ ++ struct device *dev = regmap_get_device(iep->map); ++ ++ if (compen_inc > IEP_MAX_COMPEN_INC) { ++ dev_err(dev, "%s: too high compensation inc %d\n", ++ __func__, compen_inc); ++ compen_inc = IEP_MAX_COMPEN_INC; ++ } ++ ++ regmap_update_bits(iep->map, ICSS_IEP_GLOBAL_CFG_REG, ++ IEP_GLOBAL_CFG_COMPEN_INC_MASK, ++ compen_inc << IEP_GLOBAL_CFG_COMPEN_INC_SHIFT); ++} ++ ++static void icss_iep_set_compensation_count(struct icss_iep *iep, ++ u32 compen_count) ++{ ++ struct device *dev = regmap_get_device(iep->map); ++ ++ if (compen_count > IEP_MAX_COMPEN_COUNT) { ++ dev_err(dev, "%s: too high compensation count %d\n", ++ __func__, compen_count); ++ compen_count = IEP_MAX_COMPEN_COUNT; ++ } ++ ++ regmap_write(iep->map, ICSS_IEP_COMPEN_REG, compen_count); ++} ++ ++static void icss_iep_set_slow_compensation_count(struct icss_iep *iep, ++ u32 compen_count) ++{ ++ regmap_write(iep->map, ICSS_IEP_SLOW_COMPEN_REG, compen_count); ++} ++ ++/* PTP PHC operations */ ++static int icss_iep_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm) ++{ ++ struct icss_iep *iep = container_of(ptp, struct icss_iep, ptp_info); ++ s32 ppb = scaled_ppm_to_ppb(scaled_ppm); ++ u32 cyc_count; ++ u16 cmp_inc; ++ ++ mutex_lock(&iep->ptp_clk_mutex); ++ ++ /* ppb is amount of frequency we want to adjust in 1GHz (billion) ++ * e.g. 100ppb means we need to speed up clock by 100Hz ++ * i.e. at end of 1 second (1 billion ns) clock time, we should be ++ * counting 100 more ns. ++ * We use IEP slow compensation to achieve continuous freq. adjustment. ++ * There are 2 parts. Cycle time and adjustment per cycle. ++ * Simplest case would be 1 sec Cycle time. Then adjustment ++ * pre cycle would be (def_inc + ppb) value. ++ * Cycle time will have to be chosen based on how worse the ppb is. ++ * e.g. smaller the ppb, cycle time has to be large. ++ * The minimum adjustment we can do is +-1ns per cycle so let's ++ * reduce the cycle time to get 1ns per cycle adjustment. ++ * 1ppb = 1sec cycle time & 1ns adjust ++ * 1000ppb = 1/1000 cycle time & 1ns adjust per cycle ++ */ ++ ++ if (iep->cycle_time_ns) ++ iep->slow_cmp_inc = iep->clk_tick_time; /* 4ns adj per cycle */ ++ else ++ iep->slow_cmp_inc = 1; /* 1ns adjust per cycle */ ++ ++ if (ppb < 0) { ++ iep->slow_cmp_inc = -iep->slow_cmp_inc; ++ ppb = -ppb; ++ } ++ ++ cyc_count = NSEC_PER_SEC; /* 1s cycle time @1GHz */ ++ cyc_count /= ppb; /* cycle time per ppb */ ++ ++ /* slow_cmp_count is decremented every clock cycle, e.g. @250MHz */ ++ if (!iep->cycle_time_ns) ++ cyc_count /= iep->clk_tick_time; ++ iep->slow_cmp_count = cyc_count; ++ ++ /* iep->clk_tick_time is def_inc */ ++ cmp_inc = iep->clk_tick_time + iep->slow_cmp_inc; ++ icss_iep_set_compensation_inc(iep, cmp_inc); ++ icss_iep_set_slow_compensation_count(iep, iep->slow_cmp_count); ++ ++ mutex_unlock(&iep->ptp_clk_mutex); ++ ++ return 0; ++} ++ ++static int icss_iep_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta) ++{ ++ struct icss_iep *iep = container_of(ptp, struct icss_iep, ptp_info); ++ s64 ns; ++ ++ mutex_lock(&iep->ptp_clk_mutex); ++ if (iep->ops && iep->ops->adjtime) { ++ iep->ops->adjtime(iep->clockops_data, delta); ++ } else { ++ ns = icss_iep_gettime(iep, NULL); ++ ns += delta; ++ icss_iep_settime(iep, ns); ++ } ++ mutex_unlock(&iep->ptp_clk_mutex); ++ ++ return 0; ++} ++ ++static int icss_iep_ptp_gettimeex(struct ptp_clock_info *ptp, ++ struct timespec64 *ts, ++ struct ptp_system_timestamp *sts) ++{ ++ struct icss_iep *iep = container_of(ptp, struct icss_iep, ptp_info); ++ u64 ns; ++ ++ mutex_lock(&iep->ptp_clk_mutex); ++ ns = icss_iep_gettime(iep, sts); ++ *ts = ns_to_timespec64(ns); ++ mutex_unlock(&iep->ptp_clk_mutex); ++ ++ return 0; ++} ++ ++static int icss_iep_ptp_settime(struct ptp_clock_info *ptp, ++ const struct timespec64 *ts) ++{ ++ struct icss_iep *iep = container_of(ptp, struct icss_iep, ptp_info); ++ u64 ns; ++ ++ mutex_lock(&iep->ptp_clk_mutex); ++ ns = timespec64_to_ns(ts); ++ icss_iep_settime(iep, ns); ++ mutex_unlock(&iep->ptp_clk_mutex); ++ ++ return 0; ++} ++ ++static void icss_iep_update_to_next_boundary(struct icss_iep *iep, u64 start_ns) ++{ ++ u64 ns, p_ns; ++ u32 offset; ++ ++ ns = icss_iep_gettime(iep, NULL); ++ if (start_ns < ns) ++ start_ns = ns; ++ p_ns = iep->period; ++ /* Round up to next period boundary */ ++ start_ns += p_ns - 1; ++ offset = do_div(start_ns, p_ns); ++ start_ns = start_ns * p_ns; ++ /* If it is too close to update, shift to next boundary */ ++ if (p_ns - offset < 10) ++ start_ns += p_ns; ++ ++ regmap_write(iep->map, ICSS_IEP_CMP1_REG0, lower_32_bits(start_ns)); ++ if (iep->plat_data->flags & ICSS_IEP_64BIT_COUNTER_SUPPORT) ++ regmap_write(iep->map, ICSS_IEP_CMP1_REG1, upper_32_bits(start_ns)); ++} ++ ++static int icss_iep_perout_enable_hw(struct icss_iep *iep, ++ struct ptp_perout_request *req, int on) ++{ ++ int ret; ++ u64 cmp; ++ ++ if (iep->ops && iep->ops->perout_enable) { ++ ret = iep->ops->perout_enable(iep->clockops_data, req, on, &cmp); ++ if (ret) ++ return ret; ++ ++ if (on) { ++ /* Configure CMP */ ++ regmap_write(iep->map, ICSS_IEP_CMP1_REG0, lower_32_bits(cmp)); ++ if (iep->plat_data->flags & ICSS_IEP_64BIT_COUNTER_SUPPORT) ++ regmap_write(iep->map, ICSS_IEP_CMP1_REG1, upper_32_bits(cmp)); ++ /* Configure SYNC, 1ms pulse width */ ++ regmap_write(iep->map, ICSS_IEP_SYNC_PWIDTH_REG, 1000000); ++ regmap_write(iep->map, ICSS_IEP_SYNC0_PERIOD_REG, 0); ++ regmap_write(iep->map, ICSS_IEP_SYNC_START_REG, 0); ++ regmap_write(iep->map, ICSS_IEP_SYNC_CTRL_REG, 0); /* one-shot mode */ ++ /* Enable CMP 1 */ ++ regmap_update_bits(iep->map, ICSS_IEP_CMP_CFG_REG, ++ IEP_CMP_CFG_CMP_EN(1), IEP_CMP_CFG_CMP_EN(1)); ++ } else { ++ /* Disable CMP 1 */ ++ regmap_update_bits(iep->map, ICSS_IEP_CMP_CFG_REG, ++ IEP_CMP_CFG_CMP_EN(1), 0); ++ ++ /* clear regs */ ++ regmap_write(iep->map, ICSS_IEP_CMP1_REG0, 0); ++ if (iep->plat_data->flags & ICSS_IEP_64BIT_COUNTER_SUPPORT) ++ regmap_write(iep->map, ICSS_IEP_CMP1_REG1, 0); ++ } ++ } else { ++ if (on) { ++ u64 start_ns; ++ ++ iep->period = ((u64)req->period.sec * NSEC_PER_SEC) + ++ req->period.nsec; ++ start_ns = ((u64)req->period.sec * NSEC_PER_SEC) ++ + req->period.nsec; ++ icss_iep_update_to_next_boundary(iep, start_ns); ++ ++ /* Enable Sync in single shot mode */ ++ regmap_write(iep->map, ICSS_IEP_SYNC_CTRL_REG, ++ IEP_SYNC_CTRL_SYNC_N_EN(0) | IEP_SYNC_CTRL_SYNC_EN); ++ /* Enable CMP 1 */ ++ regmap_update_bits(iep->map, ICSS_IEP_CMP_CFG_REG, ++ IEP_CMP_CFG_CMP_EN(1), IEP_CMP_CFG_CMP_EN(1)); ++ } else { ++ /* Disable CMP 1 */ ++ regmap_update_bits(iep->map, ICSS_IEP_CMP_CFG_REG, ++ IEP_CMP_CFG_CMP_EN(1), 0); ++ ++ /* clear CMP regs */ ++ regmap_write(iep->map, ICSS_IEP_CMP1_REG0, 0); ++ if (iep->plat_data->flags & ICSS_IEP_64BIT_COUNTER_SUPPORT) ++ regmap_write(iep->map, ICSS_IEP_CMP1_REG1, 0); ++ ++ /* Disable sync */ ++ regmap_write(iep->map, ICSS_IEP_SYNC_CTRL_REG, 0); ++ } ++ } ++ ++ return 0; ++} ++ ++static int icss_iep_perout_enable(struct icss_iep *iep, ++ struct ptp_perout_request *req, int on) ++{ ++ unsigned long flags; ++ int ret = 0; ++ ++ mutex_lock(&iep->ptp_clk_mutex); ++ ++ if (iep->pps_enabled) { ++ ret = -EBUSY; ++ goto exit; ++ } ++ ++ if (iep->perout_enabled == !!on) ++ goto exit; ++ ++ spin_lock_irqsave(&iep->irq_lock, flags); ++ ret = icss_iep_perout_enable_hw(iep, req, on); ++ if (!ret) ++ iep->perout_enabled = !!on; ++ spin_unlock_irqrestore(&iep->irq_lock, flags); ++ ++exit: ++ mutex_unlock(&iep->ptp_clk_mutex); ++ ++ return ret; ++} ++ ++static int icss_iep_pps_enable(struct icss_iep *iep, int on) ++{ ++ struct ptp_clock_request rq; ++ struct timespec64 ts; ++ unsigned long flags; ++ int ret = 0; ++ u64 ns; ++ ++ mutex_lock(&iep->ptp_clk_mutex); ++ ++ if (iep->perout_enabled) { ++ ret = -EBUSY; ++ goto exit; ++ } ++ ++ if (iep->pps_enabled == !!on) ++ goto exit; ++ ++ spin_lock_irqsave(&iep->irq_lock, flags); ++ ++ rq.perout.index = 0; ++ if (on) { ++ ns = icss_iep_gettime(iep, NULL); ++ ts = ns_to_timespec64(ns); ++ rq.perout.period.sec = 1; ++ rq.perout.period.nsec = 0; ++ rq.perout.start.sec = ts.tv_sec + 2; ++ rq.perout.start.nsec = 0; ++ ret = icss_iep_perout_enable_hw(iep, &rq.perout, on); ++ } else { ++ ret = icss_iep_perout_enable_hw(iep, &rq.perout, on); ++ } ++ ++ if (!ret) ++ iep->pps_enabled = !!on; ++ ++ spin_unlock_irqrestore(&iep->irq_lock, flags); ++ ++exit: ++ mutex_unlock(&iep->ptp_clk_mutex); ++ ++ return ret; ++} ++ ++static int icss_iep_extts_enable(struct icss_iep *iep, u32 index, int on) ++{ ++ u32 val, cap, ret = 0; ++ ++ mutex_lock(&iep->ptp_clk_mutex); ++ ++ if (iep->ops && iep->ops->extts_enable) { ++ ret = iep->ops->extts_enable(iep->clockops_data, index, on); ++ goto exit; ++ } ++ ++ if (((iep->latch_enable & BIT(index)) >> index) == on) ++ goto exit; ++ ++ regmap_read(iep->map, ICSS_IEP_CAPTURE_CFG_REG, &val); ++ cap = IEP_CAP_CFG_CAP_ASYNC_EN(index) | IEP_CAP_CFG_CAPNR_1ST_EVENT_EN(index); ++ if (on) { ++ val |= cap; ++ iep->latch_enable |= BIT(index); ++ } else { ++ val &= ~cap; ++ iep->latch_enable &= ~BIT(index); ++ } ++ regmap_write(iep->map, ICSS_IEP_CAPTURE_CFG_REG, val); ++ ++exit: ++ mutex_unlock(&iep->ptp_clk_mutex); ++ ++ return ret; ++} ++ ++static int icss_iep_ptp_enable(struct ptp_clock_info *ptp, ++ struct ptp_clock_request *rq, int on) ++{ ++ struct icss_iep *iep = container_of(ptp, struct icss_iep, ptp_info); ++ ++ switch (rq->type) { ++ case PTP_CLK_REQ_PEROUT: ++ return icss_iep_perout_enable(iep, &rq->perout, on); ++ case PTP_CLK_REQ_PPS: ++ return icss_iep_pps_enable(iep, on); ++ case PTP_CLK_REQ_EXTTS: ++ return icss_iep_extts_enable(iep, rq->extts.index, on); ++ default: ++ break; ++ } ++ ++ return -EOPNOTSUPP; ++} ++ ++static struct ptp_clock_info icss_iep_ptp_info = { ++ .owner = THIS_MODULE, ++ .name = "ICSS IEP timer", ++ .max_adj = 10000000, ++ .adjfine = icss_iep_ptp_adjfine, ++ .adjtime = icss_iep_ptp_adjtime, ++ .gettimex64 = icss_iep_ptp_gettimeex, ++ .settime64 = icss_iep_ptp_settime, ++ .enable = icss_iep_ptp_enable, ++}; ++ ++struct icss_iep *icss_iep_get_idx(struct device_node *np, int idx) ++{ ++ struct platform_device *pdev; ++ struct device_node *iep_np; ++ struct icss_iep *iep; ++ ++ iep_np = of_parse_phandle(np, "ti,iep", idx); ++ if (!iep_np || !of_device_is_available(iep_np)) ++ return ERR_PTR(-ENODEV); ++ ++ pdev = of_find_device_by_node(iep_np); ++ of_node_put(iep_np); ++ ++ if (!pdev) ++ /* probably IEP not yet probed */ ++ return ERR_PTR(-EPROBE_DEFER); ++ ++ iep = platform_get_drvdata(pdev); ++ if (!iep) ++ return ERR_PTR(-EPROBE_DEFER); ++ ++ device_lock(iep->dev); ++ if (iep->client_np) { ++ device_unlock(iep->dev); ++ dev_err(iep->dev, "IEP is already acquired by %s", ++ iep->client_np->name); ++ return ERR_PTR(-EBUSY); ++ } ++ iep->client_np = np; ++ device_unlock(iep->dev); ++ get_device(iep->dev); ++ ++ return iep; ++} ++EXPORT_SYMBOL_GPL(icss_iep_get_idx); ++ ++struct icss_iep *icss_iep_get(struct device_node *np) ++{ ++ return icss_iep_get_idx(np, 0); ++} ++EXPORT_SYMBOL_GPL(icss_iep_get); ++ ++void icss_iep_put(struct icss_iep *iep) ++{ ++ device_lock(iep->dev); ++ iep->client_np = NULL; ++ device_unlock(iep->dev); ++ put_device(iep->dev); ++} ++EXPORT_SYMBOL_GPL(icss_iep_put); ++ ++int icss_iep_init(struct icss_iep *iep, const struct icss_iep_clockops *clkops, ++ void *clockops_data, u32 cycle_time_ns) ++{ ++ int ret = 0; ++ ++ iep->cycle_time_ns = cycle_time_ns; ++ iep->clk_tick_time = iep->def_inc; ++ iep->ops = clkops; ++ iep->clockops_data = clockops_data; ++ icss_iep_set_default_inc(iep, iep->def_inc); ++ icss_iep_set_compensation_inc(iep, iep->def_inc); ++ icss_iep_set_compensation_count(iep, 0); ++ regmap_write(iep->map, ICSS_IEP_SYNC_PWIDTH_REG, iep->refclk_freq / 10); /* 100 ms pulse */ ++ regmap_write(iep->map, ICSS_IEP_SYNC0_PERIOD_REG, 0); ++ if (iep->plat_data->flags & ICSS_IEP_SLOW_COMPEN_REG_SUPPORT) ++ icss_iep_set_slow_compensation_count(iep, 0); ++ ++ if (!(iep->plat_data->flags & ICSS_IEP_64BIT_COUNTER_SUPPORT) || ++ !(iep->plat_data->flags & ICSS_IEP_SLOW_COMPEN_REG_SUPPORT)) ++ goto skip_perout; ++ ++ if (iep->ops && iep->ops->perout_enable) { ++ iep->ptp_info.n_per_out = 1; ++ iep->ptp_info.pps = 1; ++ } ++ ++ if (iep->ops && iep->ops->extts_enable) ++ iep->ptp_info.n_ext_ts = 2; ++ ++skip_perout: ++ if (cycle_time_ns) ++ icss_iep_enable_shadow_mode(iep); ++ else ++ icss_iep_enable(iep); ++ icss_iep_settime(iep, ktime_get_real_ns()); ++ ++ iep->ptp_clock = ptp_clock_register(&iep->ptp_info, iep->dev); ++ if (IS_ERR(iep->ptp_clock)) { ++ ret = PTR_ERR(iep->ptp_clock); ++ iep->ptp_clock = NULL; ++ dev_err(iep->dev, "Failed to register ptp clk %d\n", ret); ++ } ++ ++ return ret; ++} ++EXPORT_SYMBOL_GPL(icss_iep_init); ++ ++int icss_iep_exit(struct icss_iep *iep) ++{ ++ if (iep->ptp_clock) { ++ ptp_clock_unregister(iep->ptp_clock); ++ iep->ptp_clock = NULL; ++ } ++ icss_iep_disable(iep); ++ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(icss_iep_exit); ++ ++static int icss_iep_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct icss_iep *iep; ++ struct clk *iep_clk; ++ ++ iep = devm_kzalloc(dev, sizeof(*iep), GFP_KERNEL); ++ if (!iep) ++ return -ENOMEM; ++ ++ iep->dev = dev; ++ iep->base = devm_platform_ioremap_resource(pdev, 0); ++ if (IS_ERR(iep->base)) ++ return -ENODEV; ++ ++ iep_clk = devm_clk_get(dev, NULL); ++ if (IS_ERR(iep_clk)) ++ return PTR_ERR(iep_clk); ++ ++ iep->refclk_freq = clk_get_rate(iep_clk); ++ ++ iep->def_inc = NSEC_PER_SEC / iep->refclk_freq; /* ns per clock tick */ ++ if (iep->def_inc > IEP_MAX_DEF_INC) { ++ dev_err(dev, "Failed to set def_inc %d. IEP_clock is too slow to be supported\n", ++ iep->def_inc); ++ return -EINVAL; ++ } ++ ++ iep->plat_data = device_get_match_data(dev); ++ if (!iep->plat_data) ++ return -EINVAL; ++ ++ iep->map = devm_regmap_init(dev, NULL, iep, iep->plat_data->config); ++ if (IS_ERR(iep->map)) { ++ dev_err(dev, "Failed to create regmap for IEP %ld\n", ++ PTR_ERR(iep->map)); ++ return PTR_ERR(iep->map); ++ } ++ ++ iep->ptp_info = icss_iep_ptp_info; ++ mutex_init(&iep->ptp_clk_mutex); ++ spin_lock_init(&iep->irq_lock); ++ dev_set_drvdata(dev, iep); ++ icss_iep_disable(iep); ++ ++ return 0; ++} ++ ++static bool am654_icss_iep_valid_reg(struct device *dev, unsigned int reg) ++{ ++ switch (reg) { ++ case ICSS_IEP_GLOBAL_CFG_REG ... ICSS_IEP_SYNC_START_REG: ++ return true; ++ default: ++ return false; ++ } ++ ++ return false; ++} ++ ++static int icss_iep_regmap_write(void *context, unsigned int reg, ++ unsigned int val) ++{ ++ struct icss_iep *iep = context; ++ ++ writel(val, iep->base + iep->plat_data->reg_offs[reg]); ++ ++ return 0; ++} ++ ++static int icss_iep_regmap_read(void *context, unsigned int reg, ++ unsigned int *val) ++{ ++ struct icss_iep *iep = context; ++ ++ *val = readl(iep->base + iep->plat_data->reg_offs[reg]); ++ ++ return 0; ++} ++ ++static struct regmap_config am654_icss_iep_regmap_config = { ++ .name = "icss iep", ++ .reg_stride = 1, ++ .reg_write = icss_iep_regmap_write, ++ .reg_read = icss_iep_regmap_read, ++ .writeable_reg = am654_icss_iep_valid_reg, ++ .readable_reg = am654_icss_iep_valid_reg, ++ .fast_io = 1, ++}; ++ ++static const struct icss_iep_plat_data am654_icss_iep_plat_data = { ++ .flags = ICSS_IEP_64BIT_COUNTER_SUPPORT | ++ ICSS_IEP_SLOW_COMPEN_REG_SUPPORT | ++ ICSS_IEP_SHADOW_MODE_SUPPORT, ++ .reg_offs = { ++ [ICSS_IEP_GLOBAL_CFG_REG] = 0x00, ++ [ICSS_IEP_COMPEN_REG] = 0x08, ++ [ICSS_IEP_SLOW_COMPEN_REG] = 0x0C, ++ [ICSS_IEP_COUNT_REG0] = 0x10, ++ [ICSS_IEP_COUNT_REG1] = 0x14, ++ [ICSS_IEP_CAPTURE_CFG_REG] = 0x18, ++ [ICSS_IEP_CAPTURE_STAT_REG] = 0x1c, ++ ++ [ICSS_IEP_CAP6_RISE_REG0] = 0x50, ++ [ICSS_IEP_CAP6_RISE_REG1] = 0x54, ++ ++ [ICSS_IEP_CAP7_RISE_REG0] = 0x60, ++ [ICSS_IEP_CAP7_RISE_REG1] = 0x64, ++ ++ [ICSS_IEP_CMP_CFG_REG] = 0x70, ++ [ICSS_IEP_CMP_STAT_REG] = 0x74, ++ [ICSS_IEP_CMP0_REG0] = 0x78, ++ [ICSS_IEP_CMP0_REG1] = 0x7c, ++ [ICSS_IEP_CMP1_REG0] = 0x80, ++ [ICSS_IEP_CMP1_REG1] = 0x84, ++ ++ [ICSS_IEP_CMP8_REG0] = 0xc0, ++ [ICSS_IEP_CMP8_REG1] = 0xc4, ++ [ICSS_IEP_SYNC_CTRL_REG] = 0x180, ++ [ICSS_IEP_SYNC0_STAT_REG] = 0x188, ++ [ICSS_IEP_SYNC1_STAT_REG] = 0x18c, ++ [ICSS_IEP_SYNC_PWIDTH_REG] = 0x190, ++ [ICSS_IEP_SYNC0_PERIOD_REG] = 0x194, ++ [ICSS_IEP_SYNC1_DELAY_REG] = 0x198, ++ [ICSS_IEP_SYNC_START_REG] = 0x19c, ++ }, ++ .config = &am654_icss_iep_regmap_config, ++}; ++ ++static const struct of_device_id icss_iep_of_match[] = { ++ { ++ .compatible = "ti,am654-icss-iep", ++ .data = &am654_icss_iep_plat_data, ++ }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, icss_iep_of_match); ++ ++static struct platform_driver icss_iep_driver = { ++ .driver = { ++ .name = "icss-iep", ++ .of_match_table = icss_iep_of_match, ++ }, ++ .probe = icss_iep_probe, ++}; ++module_platform_driver(icss_iep_driver); ++ ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("TI ICSS IEP driver"); ++MODULE_AUTHOR("Roger Quadros "); ++MODULE_AUTHOR("Md Danish Anwar "); +diff --git a/drivers/net/ethernet/ti/icssg/icss_iep.h b/drivers/net/ethernet/ti/icssg/icss_iep.h +new file mode 100644 +index 000000000000..9eee44ae4990 +--- /dev/null ++++ b/drivers/net/ethernet/ti/icssg/icss_iep.h +@@ -0,0 +1,38 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* Texas Instruments ICSSG Industrial Ethernet Peripheral (IEP) Driver ++ * ++ * Copyright (C) 2023 Texas Instruments Incorporated - https://www.ti.com/ ++ * ++ */ ++ ++#ifndef __NET_TI_ICSS_IEP_H ++#define __NET_TI_ICSS_IEP_H ++ ++#include ++#include ++#include ++ ++struct icss_iep; ++ ++/* Firmware specific clock operations */ ++struct icss_iep_clockops { ++ void (*settime)(void *clockops_data, u64 ns); ++ void (*adjtime)(void *clockops_data, s64 delta); ++ u64 (*gettime)(void *clockops_data, struct ptp_system_timestamp *sts); ++ int (*perout_enable)(void *clockops_data, ++ struct ptp_perout_request *req, int on, ++ u64 *cmp); ++ int (*extts_enable)(void *clockops_data, u32 index, int on); ++}; ++ ++struct icss_iep *icss_iep_get(struct device_node *np); ++struct icss_iep *icss_iep_get_idx(struct device_node *np, int idx); ++void icss_iep_put(struct icss_iep *iep); ++int icss_iep_init(struct icss_iep *iep, const struct icss_iep_clockops *clkops, ++ void *clockops_data, u32 cycle_time_ns); ++int icss_iep_exit(struct icss_iep *iep); ++int icss_iep_get_count_low(struct icss_iep *iep); ++int icss_iep_get_count_hi(struct icss_iep *iep); ++int icss_iep_get_ptp_clock_idx(struct icss_iep *iep); ++ ++#endif /* __NET_TI_ICSS_IEP_H */ +-- +2.42.0 + diff --git a/recipes-kernel/linux/files/patches-6.1/0029-net-ti-icssg-prueth-add-packet-timestamping-and-ptp-.patch b/recipes-kernel/linux/files/patches-6.1/0029-net-ti-icssg-prueth-add-packet-timestamping-and-ptp-.patch new file mode 100644 index 000000000..8975b5666 --- /dev/null +++ b/recipes-kernel/linux/files/patches-6.1/0029-net-ti-icssg-prueth-add-packet-timestamping-and-ptp-.patch @@ -0,0 +1,797 @@ +From b197b2560dd78ef62e798d698c5e021eb7983c53 Mon Sep 17 00:00:00 2001 +From: Roger Quadros +Date: Thu, 24 Aug 2023 17:16:17 +0530 +Subject: [PATCH 29/69] net: ti: icssg-prueth: add packet timestamping and ptp + support + +Add packet timestamping TS and PTP PHC clock support. + +For AM65x and AM64x: + - IEP1 is not used + - IEP0 is configured in shadow mode with 1ms cycle and shared between +Linux and FW. It provides time and TS in number cycles, so special +conversation in ns is required. + - IEP0 shared between PRUeth ports. + - IEP0 supports PPS, periodic output. + - IEP0 settime() and enabling PPS required FW interraction. + - RX TS provided with each packet in CPPI5 descriptor. + - TX TS returned through separate ICSSG hw queues for each port. TX TS +readiness is signaled by INTC IRQ. Only one packet at time can be requested +for TX TS. + +Signed-off-by: Roger Quadros +Co-developed-by: Grygorii Strashko +Signed-off-by: Grygorii Strashko +Signed-off-by: Vignesh Raghavendra +Reviewed-by: Simon Horman +Signed-off-by: MD Danish Anwar +[Commit 186734c15886 upstream] +--- + drivers/net/ethernet/ti/Kconfig | 1 + + drivers/net/ethernet/ti/icssg/icss_iep.h | 1 + + drivers/net/ethernet/ti/icssg/icssg_ethtool.c | 21 + + drivers/net/ethernet/ti/icssg/icssg_prueth.c | 424 +++++++++++++++++- + drivers/net/ethernet/ti/icssg/icssg_prueth.h | 26 +- + 5 files changed, 467 insertions(+), 6 deletions(-) + +diff --git a/drivers/net/ethernet/ti/Kconfig b/drivers/net/ethernet/ti/Kconfig +index 1af5a90720ec..88b5b1b47779 100644 +--- a/drivers/net/ethernet/ti/Kconfig ++++ b/drivers/net/ethernet/ti/Kconfig +@@ -186,6 +186,7 @@ config CPMAC + config TI_ICSSG_PRUETH + tristate "TI Gigabit PRU Ethernet driver" + select PHYLIB ++ select TI_ICSS_IEP + depends on PRU_REMOTEPROC + depends on ARCH_K3 && OF && TI_K3_UDMA_GLUE_LAYER + help +diff --git a/drivers/net/ethernet/ti/icssg/icss_iep.h b/drivers/net/ethernet/ti/icssg/icss_iep.h +index 9eee44ae4990..9c7f4d0a0916 100644 +--- a/drivers/net/ethernet/ti/icssg/icss_iep.h ++++ b/drivers/net/ethernet/ti/icssg/icss_iep.h +@@ -13,6 +13,7 @@ + #include + + struct icss_iep; ++extern const struct icss_iep_clockops prueth_iep_clockops; + + /* Firmware specific clock operations */ + struct icss_iep_clockops { +diff --git a/drivers/net/ethernet/ti/icssg/icssg_ethtool.c b/drivers/net/ethernet/ti/icssg/icssg_ethtool.c +index 02c312f01d10..a27ec1dcc8d5 100644 +--- a/drivers/net/ethernet/ti/icssg/icssg_ethtool.c ++++ b/drivers/net/ethernet/ti/icssg/icssg_ethtool.c +@@ -109,6 +109,26 @@ static void emac_get_ethtool_stats(struct net_device *ndev, + *(data++) = emac->stats[i]; + } + ++static int emac_get_ts_info(struct net_device *ndev, ++ struct ethtool_ts_info *info) ++{ ++ struct prueth_emac *emac = netdev_priv(ndev); ++ ++ info->so_timestamping = ++ SOF_TIMESTAMPING_TX_HARDWARE | ++ SOF_TIMESTAMPING_TX_SOFTWARE | ++ SOF_TIMESTAMPING_RX_HARDWARE | ++ SOF_TIMESTAMPING_RX_SOFTWARE | ++ SOF_TIMESTAMPING_SOFTWARE | ++ SOF_TIMESTAMPING_RAW_HARDWARE; ++ ++ info->phc_index = icss_iep_get_ptp_clock_idx(emac->iep); ++ info->tx_types = BIT(HWTSTAMP_TX_OFF) | BIT(HWTSTAMP_TX_ON); ++ info->rx_filters = BIT(HWTSTAMP_FILTER_NONE) | BIT(HWTSTAMP_FILTER_ALL); ++ ++ return 0; ++} ++ + static int emac_set_channels(struct net_device *ndev, + struct ethtool_channels *ch) + { +@@ -176,6 +196,7 @@ const struct ethtool_ops icssg_ethtool_ops = { + .get_sset_count = emac_get_sset_count, + .get_ethtool_stats = emac_get_ethtool_stats, + .get_strings = emac_get_strings, ++ .get_ts_info = emac_get_ts_info, + .get_channels = emac_get_channels, + .set_channels = emac_set_channels, + .get_link_ksettings = emac_get_link_ksettings, +diff --git a/drivers/net/ethernet/ti/icssg/icssg_prueth.c b/drivers/net/ethernet/ti/icssg/icssg_prueth.c +index 47b941fb0198..1bcb4e174652 100644 +--- a/drivers/net/ethernet/ti/icssg/icssg_prueth.c ++++ b/drivers/net/ethernet/ti/icssg/icssg_prueth.c +@@ -56,6 +56,8 @@ + /* CTRLMMR_ICSSG_RGMII_CTRL register bits */ + #define ICSSG_CTRL_RGMII_ID_MODE BIT(24) + ++#define IEP_DEFAULT_CYCLE_TIME_NS 1000000 /* 1 ms */ ++ + static void prueth_cleanup_rx_chns(struct prueth_emac *emac, + struct prueth_rx_chn *rx_chn, + int max_rflows) +@@ -471,6 +473,37 @@ static int prueth_dma_rx_push(struct prueth_emac *emac, + desc_rx, desc_dma); + } + ++static u64 icssg_ts_to_ns(u32 hi_sw, u32 hi, u32 lo, u32 cycle_time_ns) ++{ ++ u32 iepcount_lo, iepcount_hi, hi_rollover_count; ++ u64 ns; ++ ++ iepcount_lo = lo & GENMASK(19, 0); ++ iepcount_hi = (hi & GENMASK(11, 0)) << 12 | lo >> 20; ++ hi_rollover_count = hi >> 11; ++ ++ ns = ((u64)hi_rollover_count) << 23 | (iepcount_hi + hi_sw); ++ ns = ns * cycle_time_ns + iepcount_lo; ++ ++ return ns; ++} ++ ++static void emac_rx_timestamp(struct prueth_emac *emac, ++ struct sk_buff *skb, u32 *psdata) ++{ ++ struct skb_shared_hwtstamps *ssh; ++ u64 ns; ++ ++ u32 hi_sw = readl(emac->prueth->shram.va + ++ TIMESYNC_FW_WC_COUNT_HI_SW_OFFSET_OFFSET); ++ ns = icssg_ts_to_ns(hi_sw, psdata[1], psdata[0], ++ IEP_DEFAULT_CYCLE_TIME_NS); ++ ++ ssh = skb_hwtstamps(skb); ++ memset(ssh, 0, sizeof(*ssh)); ++ ssh->hwtstamp = ns_to_ktime(ns); ++} ++ + static int emac_rx_packet(struct prueth_emac *emac, u32 flow_id) + { + struct prueth_rx_chn *rx_chn = &emac->rx_chns; +@@ -480,6 +513,7 @@ static int emac_rx_packet(struct prueth_emac *emac, u32 flow_id) + struct sk_buff *skb, *new_skb; + dma_addr_t desc_dma, buf_dma; + void **swdata; ++ u32 *psdata; + int ret; + + ret = k3_udma_glue_pop_rx_chn(rx_chn->rx_chn, flow_id, &desc_dma); +@@ -497,6 +531,11 @@ static int emac_rx_packet(struct prueth_emac *emac, u32 flow_id) + swdata = cppi5_hdesc_get_swdata(desc_rx); + skb = *swdata; + ++ psdata = cppi5_hdesc_get_psdata(desc_rx); ++ /* RX HW timestamp */ ++ if (emac->rx_ts_enabled) ++ emac_rx_timestamp(emac, skb, psdata); ++ + cppi5_hdesc_get_obuf(desc_rx, &buf_dma, &buf_dma_len); + k3_udma_glue_rx_cppi5_to_dma_addr(rx_chn->rx_chn, &buf_dma); + pkt_len = cppi5_hdesc_get_pktlen(desc_rx); +@@ -557,6 +596,86 @@ static void prueth_rx_cleanup(void *data, dma_addr_t desc_dma) + dev_kfree_skb_any(skb); + } + ++static int emac_get_tx_ts(struct prueth_emac *emac, ++ struct emac_tx_ts_response *rsp) ++{ ++ struct prueth *prueth = emac->prueth; ++ int slice = prueth_emac_slice(emac); ++ int addr; ++ ++ addr = icssg_queue_pop(prueth, slice == 0 ? ++ ICSSG_TS_POP_SLICE0 : ICSSG_TS_POP_SLICE1); ++ if (addr < 0) ++ return addr; ++ ++ memcpy_fromio(rsp, prueth->shram.va + addr, sizeof(*rsp)); ++ /* return buffer back for to pool */ ++ icssg_queue_push(prueth, slice == 0 ? ++ ICSSG_TS_PUSH_SLICE0 : ICSSG_TS_PUSH_SLICE1, addr); ++ ++ return 0; ++} ++ ++static void tx_ts_work(struct prueth_emac *emac) ++{ ++ struct skb_shared_hwtstamps ssh; ++ struct emac_tx_ts_response tsr; ++ struct sk_buff *skb; ++ int ret = 0; ++ u32 hi_sw; ++ u64 ns; ++ ++ /* There may be more than one pending requests */ ++ while (1) { ++ ret = emac_get_tx_ts(emac, &tsr); ++ if (ret) /* nothing more */ ++ break; ++ ++ if (tsr.cookie >= PRUETH_MAX_TX_TS_REQUESTS || ++ !emac->tx_ts_skb[tsr.cookie]) { ++ netdev_err(emac->ndev, "Invalid TX TS cookie 0x%x\n", ++ tsr.cookie); ++ break; ++ } ++ ++ skb = emac->tx_ts_skb[tsr.cookie]; ++ emac->tx_ts_skb[tsr.cookie] = NULL; /* free slot */ ++ if (!skb) { ++ netdev_err(emac->ndev, "Driver Bug! got NULL skb\n"); ++ break; ++ } ++ ++ hi_sw = readl(emac->prueth->shram.va + ++ TIMESYNC_FW_WC_COUNT_HI_SW_OFFSET_OFFSET); ++ ns = icssg_ts_to_ns(hi_sw, tsr.hi_ts, tsr.lo_ts, ++ IEP_DEFAULT_CYCLE_TIME_NS); ++ ++ memset(&ssh, 0, sizeof(ssh)); ++ ssh.hwtstamp = ns_to_ktime(ns); ++ ++ skb_tstamp_tx(skb, &ssh); ++ dev_consume_skb_any(skb); ++ ++ if (atomic_dec_and_test(&emac->tx_ts_pending)) /* no more? */ ++ break; ++ } ++} ++ ++static int prueth_tx_ts_cookie_get(struct prueth_emac *emac) ++{ ++ int i; ++ ++ /* search and get the next free slot */ ++ for (i = 0; i < PRUETH_MAX_TX_TS_REQUESTS; i++) { ++ if (!emac->tx_ts_skb[i]) { ++ emac->tx_ts_skb[i] = ERR_PTR(-EBUSY); /* reserve slot */ ++ return i; ++ } ++ } ++ ++ return -EBUSY; ++} ++ + /** + * emac_ndo_start_xmit - EMAC Transmit function + * @skb: SKB pointer +@@ -577,6 +696,8 @@ static enum netdev_tx emac_ndo_start_xmit(struct sk_buff *skb, struct net_device + struct prueth_tx_chn *tx_chn; + dma_addr_t desc_dma, buf_dma; + int i, ret = 0, q_idx; ++ bool in_tx_ts = 0; ++ int tx_ts_cookie; + void **swdata; + u32 pkt_len; + u32 *epib; +@@ -608,6 +729,18 @@ static enum netdev_tx emac_ndo_start_xmit(struct sk_buff *skb, struct net_device + epib = first_desc->epib; + epib[0] = 0; + epib[1] = 0; ++ if (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP && ++ emac->tx_ts_enabled) { ++ tx_ts_cookie = prueth_tx_ts_cookie_get(emac); ++ if (tx_ts_cookie >= 0) { ++ skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; ++ /* Request TX timestamp */ ++ epib[0] = (u32)tx_ts_cookie; ++ epib[1] = 0x80000000; /* TX TS request */ ++ emac->tx_ts_skb[tx_ts_cookie] = skb_get(skb); ++ in_tx_ts = 1; ++ } ++ } + + /* set dst tag to indicate internal qid at the firmware which is at + * bit8..bit15. bit0..bit7 indicates port num for directed +@@ -629,7 +762,7 @@ static enum netdev_tx emac_ndo_start_xmit(struct sk_buff *skb, struct net_device + if (!next_desc) { + netdev_err(ndev, + "tx: failed to allocate frag. descriptor\n"); +- goto free_desc_stop_q_busy; ++ goto free_desc_stop_q_busy_cleanup_tx_ts; + } + + buf_dma = skb_frag_dma_map(tx_chn->dma_dev, frag, 0, frag_size, +@@ -638,7 +771,7 @@ static enum netdev_tx emac_ndo_start_xmit(struct sk_buff *skb, struct net_device + netdev_err(ndev, "tx: Failed to map skb page\n"); + k3_cppi_desc_pool_free(tx_chn->desc_pool, next_desc); + ret = NETDEV_TX_OK; +- goto drop_free_descs; ++ goto cleanup_tx_ts; + } + + cppi5_hdesc_reset_hbdesc(next_desc); +@@ -670,6 +803,9 @@ static enum netdev_tx emac_ndo_start_xmit(struct sk_buff *skb, struct net_device + goto drop_free_descs; + } + ++ if (in_tx_ts) ++ atomic_inc(&emac->tx_ts_pending); ++ + if (k3_cppi_desc_pool_avail(tx_chn->desc_pool) < MAX_SKB_FRAGS) { + netif_tx_stop_queue(netif_txq); + /* Barrier, so that stop_queue visible to other cpus */ +@@ -682,6 +818,12 @@ static enum netdev_tx emac_ndo_start_xmit(struct sk_buff *skb, struct net_device + + return NETDEV_TX_OK; + ++cleanup_tx_ts: ++ if (in_tx_ts) { ++ dev_kfree_skb_any(emac->tx_ts_skb[tx_ts_cookie]); ++ emac->tx_ts_skb[tx_ts_cookie] = NULL; ++ } ++ + drop_free_descs: + prueth_xmit_free(tx_chn, first_desc); + +@@ -694,7 +836,11 @@ static enum netdev_tx emac_ndo_start_xmit(struct sk_buff *skb, struct net_device + + return ret; + +-free_desc_stop_q_busy: ++free_desc_stop_q_busy_cleanup_tx_ts: ++ if (in_tx_ts) { ++ dev_kfree_skb_any(emac->tx_ts_skb[tx_ts_cookie]); ++ emac->tx_ts_skb[tx_ts_cookie] = NULL; ++ } + prueth_xmit_free(tx_chn, first_desc); + + drop_stop_q_busy: +@@ -717,6 +863,16 @@ static void prueth_tx_cleanup(void *data, dma_addr_t desc_dma) + dev_kfree_skb_any(skb); + } + ++static irqreturn_t prueth_tx_ts_irq(int irq, void *dev_id) ++{ ++ struct prueth_emac *emac = dev_id; ++ ++ /* currently only TX timestamp is being returned */ ++ tx_ts_work(emac); ++ ++ return IRQ_HANDLED; ++} ++ + static irqreturn_t prueth_rx_irq(int irq, void *dev_id) + { + struct prueth_emac *emac = dev_id; +@@ -820,6 +976,18 @@ static void prueth_emac_stop(struct prueth_emac *emac) + rproc_shutdown(prueth->pru[slice]); + } + ++static void prueth_cleanup_tx_ts(struct prueth_emac *emac) ++{ ++ int i; ++ ++ for (i = 0; i < PRUETH_MAX_TX_TS_REQUESTS; i++) { ++ if (emac->tx_ts_skb[i]) { ++ dev_kfree_skb_any(emac->tx_ts_skb[i]); ++ emac->tx_ts_skb[i] = NULL; ++ } ++ } ++} ++ + /* called back by PHY layer if there is change in link state of hw port*/ + static void emac_adjust_link(struct net_device *ndev) + { +@@ -881,6 +1049,7 @@ static void emac_adjust_link(struct net_device *ndev) + netif_tx_wake_all_queues(ndev); + } else { + netif_tx_stop_all_queues(ndev); ++ prueth_cleanup_tx_ts(emac); + } + } + +@@ -992,6 +1161,139 @@ static int emac_phy_connect(struct prueth_emac *emac) + return 0; + } + ++static u64 prueth_iep_gettime(void *clockops_data, struct ptp_system_timestamp *sts) ++{ ++ u32 hi_rollover_count, hi_rollover_count_r; ++ struct prueth_emac *emac = clockops_data; ++ struct prueth *prueth = emac->prueth; ++ void __iomem *fw_hi_r_count_addr; ++ void __iomem *fw_count_hi_addr; ++ u32 iepcount_hi, iepcount_hi_r; ++ unsigned long flags; ++ u32 iepcount_lo; ++ u64 ts = 0; ++ ++ fw_count_hi_addr = prueth->shram.va + TIMESYNC_FW_WC_COUNT_HI_SW_OFFSET_OFFSET; ++ fw_hi_r_count_addr = prueth->shram.va + TIMESYNC_FW_WC_HI_ROLLOVER_COUNT_OFFSET; ++ ++ local_irq_save(flags); ++ do { ++ iepcount_hi = icss_iep_get_count_hi(emac->iep); ++ iepcount_hi += readl(fw_count_hi_addr); ++ hi_rollover_count = readl(fw_hi_r_count_addr); ++ ptp_read_system_prets(sts); ++ iepcount_lo = icss_iep_get_count_low(emac->iep); ++ ptp_read_system_postts(sts); ++ ++ iepcount_hi_r = icss_iep_get_count_hi(emac->iep); ++ iepcount_hi_r += readl(fw_count_hi_addr); ++ hi_rollover_count_r = readl(fw_hi_r_count_addr); ++ } while ((iepcount_hi_r != iepcount_hi) || ++ (hi_rollover_count != hi_rollover_count_r)); ++ local_irq_restore(flags); ++ ++ ts = ((u64)hi_rollover_count) << 23 | iepcount_hi; ++ ts = ts * (u64)IEP_DEFAULT_CYCLE_TIME_NS + iepcount_lo; ++ ++ return ts; ++} ++ ++static void prueth_iep_settime(void *clockops_data, u64 ns) ++{ ++ struct icssg_setclock_desc __iomem *sc_descp; ++ struct prueth_emac *emac = clockops_data; ++ struct icssg_setclock_desc sc_desc; ++ u64 cyclecount; ++ u32 cycletime; ++ int timeout; ++ ++ if (!emac->fw_running) ++ return; ++ ++ sc_descp = emac->prueth->shram.va + TIMESYNC_FW_WC_SETCLOCK_DESC_OFFSET; ++ ++ cycletime = IEP_DEFAULT_CYCLE_TIME_NS; ++ cyclecount = ns / cycletime; ++ ++ memset(&sc_desc, 0, sizeof(sc_desc)); ++ sc_desc.margin = cycletime - 1000; ++ sc_desc.cyclecounter0_set = cyclecount & GENMASK(31, 0); ++ sc_desc.cyclecounter1_set = (cyclecount & GENMASK(63, 32)) >> 32; ++ sc_desc.iepcount_set = ns % cycletime; ++ sc_desc.CMP0_current = cycletime - 4; //Count from 0 to (cycle time)-4 ++ ++ memcpy_toio(sc_descp, &sc_desc, sizeof(sc_desc)); ++ ++ writeb(1, &sc_descp->request); ++ ++ timeout = 5; /* fw should take 2-3 ms */ ++ while (timeout--) { ++ if (readb(&sc_descp->acknowledgment)) ++ return; ++ ++ usleep_range(500, 1000); ++ } ++ ++ dev_err(emac->prueth->dev, "settime timeout\n"); ++} ++ ++static int prueth_perout_enable(void *clockops_data, ++ struct ptp_perout_request *req, int on, ++ u64 *cmp) ++{ ++ struct prueth_emac *emac = clockops_data; ++ u32 reduction_factor = 0, offset = 0; ++ struct timespec64 ts; ++ u64 ns_period; ++ ++ if (!on) ++ return 0; ++ ++ /* Any firmware specific stuff for PPS/PEROUT handling */ ++ ts.tv_sec = req->period.sec; ++ ts.tv_nsec = req->period.nsec; ++ ns_period = timespec64_to_ns(&ts); ++ ++ /* f/w doesn't support period less than cycle time */ ++ if (ns_period < IEP_DEFAULT_CYCLE_TIME_NS) ++ return -ENXIO; ++ ++ reduction_factor = ns_period / IEP_DEFAULT_CYCLE_TIME_NS; ++ offset = ns_period % IEP_DEFAULT_CYCLE_TIME_NS; ++ ++ /* f/w requires at least 1uS within a cycle so CMP ++ * can trigger after SYNC is enabled ++ */ ++ if (offset < 5 * NSEC_PER_USEC) ++ offset = 5 * NSEC_PER_USEC; ++ ++ /* if offset is close to cycle time then we will miss ++ * the CMP event for last tick when IEP rolls over. ++ * In normal mode, IEP tick is 4ns. ++ * In slow compensation it could be 0ns or 8ns at ++ * every slow compensation cycle. ++ */ ++ if (offset > IEP_DEFAULT_CYCLE_TIME_NS - 8) ++ offset = IEP_DEFAULT_CYCLE_TIME_NS - 8; ++ ++ /* we're in shadow mode so need to set upper 32-bits */ ++ *cmp = (u64)offset << 32; ++ ++ writel(reduction_factor, emac->prueth->shram.va + ++ TIMESYNC_FW_WC_SYNCOUT_REDUCTION_FACTOR_OFFSET); ++ ++ writel(0, emac->prueth->shram.va + ++ TIMESYNC_FW_WC_SYNCOUT_START_TIME_CYCLECOUNT_OFFSET); ++ ++ return 0; ++} ++ ++const struct icss_iep_clockops prueth_iep_clockops = { ++ .settime = prueth_iep_settime, ++ .gettime = prueth_iep_gettime, ++ .perout_enable = prueth_perout_enable, ++}; ++ + /** + * emac_ndo_open - EMAC device open + * @ndev: network adapter device +@@ -1066,10 +1368,20 @@ static int emac_ndo_open(struct net_device *ndev) + + icssg_mii_update_mtu(prueth->mii_rt, slice, ndev->max_mtu); + ++ if (!prueth->emacs_initialized) { ++ ret = icss_iep_init(emac->iep, &prueth_iep_clockops, ++ emac, IEP_DEFAULT_CYCLE_TIME_NS); ++ } ++ ++ ret = request_threaded_irq(emac->tx_ts_irq, NULL, prueth_tx_ts_irq, ++ IRQF_ONESHOT, dev_name(dev), emac); ++ if (ret) ++ goto stop; ++ + /* Prepare RX */ + ret = prueth_prepare_rx_chan(emac, &emac->rx_chns, PRUETH_MAX_PKT_SIZE); + if (ret) +- goto stop; ++ goto free_tx_ts_irq; + + ret = k3_udma_glue_enable_rx_chn(emac->rx_chns.rx_chn); + if (ret) +@@ -1102,6 +1414,8 @@ static int emac_ndo_open(struct net_device *ndev) + prueth_reset_tx_chan(emac, i, false); + reset_rx_chn: + prueth_reset_rx_chan(&emac->rx_chns, max_rx_flows, false); ++free_tx_ts_irq: ++ free_irq(emac->tx_ts_irq, emac); + stop: + prueth_emac_stop(emac); + free_rx_irq: +@@ -1173,6 +1487,14 @@ static int emac_ndo_stop(struct net_device *ndev) + /* stop PRUs */ + prueth_emac_stop(emac); + ++ if (prueth->emacs_initialized == 1) ++ icss_iep_exit(emac->iep); ++ ++ /* stop PRUs */ ++ prueth_emac_stop(emac); ++ ++ free_irq(emac->tx_ts_irq, emac); ++ + free_irq(emac->rx_chns.irq[rx_flow], emac); + prueth_ndev_del_tx_napi(emac, emac->tx_ch_num); + prueth_cleanup_tx_chns(emac); +@@ -1235,8 +1557,79 @@ static void emac_ndo_set_rx_mode(struct net_device *ndev) + queue_work(emac->cmd_wq, &emac->rx_mode_work); + } + ++static int emac_set_ts_config(struct net_device *ndev, struct ifreq *ifr) ++{ ++ struct prueth_emac *emac = netdev_priv(ndev); ++ struct hwtstamp_config config; ++ ++ if (copy_from_user(&config, ifr->ifr_data, sizeof(config))) ++ return -EFAULT; ++ ++ switch (config.tx_type) { ++ case HWTSTAMP_TX_OFF: ++ emac->tx_ts_enabled = 0; ++ break; ++ case HWTSTAMP_TX_ON: ++ emac->tx_ts_enabled = 1; ++ break; ++ default: ++ return -ERANGE; ++ } ++ ++ switch (config.rx_filter) { ++ case HWTSTAMP_FILTER_NONE: ++ emac->rx_ts_enabled = 0; ++ break; ++ case HWTSTAMP_FILTER_ALL: ++ case HWTSTAMP_FILTER_SOME: ++ case HWTSTAMP_FILTER_PTP_V1_L4_EVENT: ++ case HWTSTAMP_FILTER_PTP_V1_L4_SYNC: ++ case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ: ++ case HWTSTAMP_FILTER_PTP_V2_L4_EVENT: ++ case HWTSTAMP_FILTER_PTP_V2_L4_SYNC: ++ case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ: ++ case HWTSTAMP_FILTER_PTP_V2_L2_EVENT: ++ case HWTSTAMP_FILTER_PTP_V2_L2_SYNC: ++ case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ: ++ case HWTSTAMP_FILTER_PTP_V2_EVENT: ++ case HWTSTAMP_FILTER_PTP_V2_SYNC: ++ case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ: ++ case HWTSTAMP_FILTER_NTP_ALL: ++ emac->rx_ts_enabled = 1; ++ config.rx_filter = HWTSTAMP_FILTER_ALL; ++ break; ++ default: ++ return -ERANGE; ++ } ++ ++ return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ? ++ -EFAULT : 0; ++} ++ ++static int emac_get_ts_config(struct net_device *ndev, struct ifreq *ifr) ++{ ++ struct prueth_emac *emac = netdev_priv(ndev); ++ struct hwtstamp_config config; ++ ++ config.flags = 0; ++ config.tx_type = emac->tx_ts_enabled ? HWTSTAMP_TX_ON : HWTSTAMP_TX_OFF; ++ config.rx_filter = emac->rx_ts_enabled ? HWTSTAMP_FILTER_ALL : HWTSTAMP_FILTER_NONE; ++ ++ return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ? ++ -EFAULT : 0; ++} ++ + static int emac_ndo_ioctl(struct net_device *ndev, struct ifreq *ifr, int cmd) + { ++ switch (cmd) { ++ case SIOCGHWTSTAMP: ++ return emac_get_ts_config(ndev, ifr); ++ case SIOCSHWTSTAMP: ++ return emac_set_ts_config(ndev, ifr); ++ default: ++ break; ++ } ++ + return phy_do_ioctl(ndev, ifr, cmd); + } + +@@ -1316,6 +1709,7 @@ static int prueth_netdev_init(struct prueth *prueth, + struct prueth_emac *emac; + struct net_device *ndev; + enum prueth_port port; ++ const char *irq_name; + enum prueth_mac mac; + + port = prueth_node_port(eth_node); +@@ -1355,6 +1749,15 @@ static int prueth_netdev_init(struct prueth *prueth, + + emac->tx_ch_num = 1; + ++ irq_name = "tx_ts0"; ++ if (emac->port_id == PRUETH_PORT_MII1) ++ irq_name = "tx_ts1"; ++ emac->tx_ts_irq = platform_get_irq_byname_optional(prueth->pdev, irq_name); ++ if (emac->tx_ts_irq < 0) { ++ ret = dev_err_probe(prueth->dev, emac->tx_ts_irq, "could not get tx_ts_irq\n"); ++ goto free; ++ } ++ + SET_NETDEV_DEV(ndev, prueth->dev); + spin_lock_init(&emac->lock); + mutex_init(&emac->cmd_lock); +@@ -1680,6 +2083,13 @@ static int prueth_probe(struct platform_device *pdev) + dev_dbg(dev, "sram: pa %llx va %p size %zx\n", prueth->msmcram.pa, + prueth->msmcram.va, prueth->msmcram.size); + ++ prueth->iep0 = icss_iep_get_idx(np, 0); ++ if (IS_ERR(prueth->iep0)) { ++ ret = dev_err_probe(dev, PTR_ERR(prueth->iep0), "iep0 get failed\n"); ++ prueth->iep0 = NULL; ++ goto free_pool; ++ } ++ + /* setup netdev interfaces */ + if (eth0_node) { + ret = prueth_netdev_init(prueth, eth0_node); +@@ -1688,6 +2098,7 @@ static int prueth_probe(struct platform_device *pdev) + eth0_node->name); + goto netdev_exit; + } ++ prueth->emac[PRUETH_MAC0]->iep = prueth->iep0; + } + + if (eth1_node) { +@@ -1697,6 +2108,8 @@ static int prueth_probe(struct platform_device *pdev) + eth1_node->name); + goto netdev_exit; + } ++ ++ prueth->emac[PRUETH_MAC1]->iep = prueth->iep0; + } + + /* register the network devices */ +@@ -1754,6 +2167,7 @@ static int prueth_probe(struct platform_device *pdev) + prueth_netdev_exit(prueth, eth_node); + } + ++free_pool: + gen_pool_free(prueth->sram_pool, + (unsigned long)prueth->msmcram.va, msmc_ram_size); + +@@ -1798,6 +2212,8 @@ static void prueth_remove(struct platform_device *pdev) + prueth_netdev_exit(prueth, eth_node); + } + ++ icss_iep_put(prueth->iep0); ++ + gen_pool_free(prueth->sram_pool, + (unsigned long)prueth->msmcram.va, + MSMC_RAM_SIZE); +diff --git a/drivers/net/ethernet/ti/icssg/icssg_prueth.h b/drivers/net/ethernet/ti/icssg/icssg_prueth.h +index a8ce4d01ef16..a56ab4cdc83c 100644 +--- a/drivers/net/ethernet/ti/icssg/icssg_prueth.h ++++ b/drivers/net/ethernet/ti/icssg/icssg_prueth.h +@@ -35,6 +35,7 @@ + #include + + #include "icssg_config.h" ++#include "icss_iep.h" + #include "icssg_switch_map.h" + + #define PRUETH_MAX_MTU (2000 - ETH_HLEN - ETH_FCS_LEN) +@@ -122,6 +123,8 @@ struct prueth_rx_chn { + */ + #define PRUETH_MAX_TX_QUEUES 4 + ++#define PRUETH_MAX_TX_TS_REQUESTS 50 /* Max simultaneous TX_TS requests */ ++ + /* data for each emac port */ + struct prueth_emac { + bool fw_running; +@@ -139,6 +142,9 @@ struct prueth_emac { + struct device_node *phy_node; + phy_interface_t phy_if; + enum prueth_port port_id; ++ struct icss_iep *iep; ++ unsigned int rx_ts_enabled : 1; ++ unsigned int tx_ts_enabled : 1; + + /* DMA related */ + struct prueth_tx_chn tx_chns[PRUETH_MAX_TX_QUEUES]; +@@ -150,7 +156,15 @@ struct prueth_emac { + + spinlock_t lock; /* serialize access */ + +- unsigned long state; ++ /* TX HW Timestamping */ ++ /* TX TS cookie will be index to the tx_ts_skb array */ ++ struct sk_buff *tx_ts_skb[PRUETH_MAX_TX_TS_REQUESTS]; ++ atomic_t tx_ts_pending; ++ int tx_ts_irq; ++ ++ u8 cmd_seq; ++ /* shutdown related */ ++ u32 cmd_data[4]; + struct completion cmd_complete; + /* Mutex to serialize access to firmware command interface */ + struct mutex cmd_lock; +@@ -193,6 +207,7 @@ struct prueth_pdata { + * @pdata: pointer to platform data for ICSSG driver + * @icssg_hwcmdseq: seq counter or HWQ messages + * @emacs_initialized: num of EMACs/ext ports that are up/running ++ * @iep0: pointer to IEP0 device + */ + struct prueth { + struct device *dev; +@@ -214,8 +229,15 @@ struct prueth { + struct platform_device *pdev; + struct prueth_pdata pdata; + u8 icssg_hwcmdseq; +- + int emacs_initialized; ++ struct icss_iep *iep0; ++}; ++ ++struct emac_tx_ts_response { ++ u32 reserved[2]; ++ u32 cookie; ++ u32 lo_ts; ++ u32 hi_ts; + }; + + /* get PRUSS SLICE number from prueth_emac */ +-- +2.42.0 + diff --git a/recipes-kernel/linux/files/patches-6.1/0030-net-ti-icssg-prueth-am65x-SR2.0-add-10M-full-duplex-.patch b/recipes-kernel/linux/files/patches-6.1/0030-net-ti-icssg-prueth-am65x-SR2.0-add-10M-full-duplex-.patch new file mode 100644 index 000000000..da8ed044a --- /dev/null +++ b/recipes-kernel/linux/files/patches-6.1/0030-net-ti-icssg-prueth-am65x-SR2.0-add-10M-full-duplex-.patch @@ -0,0 +1,194 @@ +From 578efae0594de5a0fc526b26eabc5c764d17d321 Mon Sep 17 00:00:00 2001 +From: Grygorii Strashko +Date: Thu, 24 Aug 2023 17:16:18 +0530 +Subject: [PATCH 30/69] net: ti: icssg-prueth: am65x SR2.0 add 10M full duplex + support + +For AM65x SR2.0 it's required to enable IEP1 in raw 64bit mode which is +used by PRU FW to monitor the link and apply w/a for 10M link issue. +Note. No public errata available yet. + +Without this w/a the PRU FW will stuck if link state changes under TX +traffic pressure. + +Hence, add support for 10M full duplex for AM65x SR2.0: + - add new IEP API to enable IEP, but without PTP support + - add pdata quirk_10m_link_issue to enable 10M link issue w/a. + +Signed-off-by: Grygorii Strashko +Signed-off-by: Vignesh Raghavendra +Reviewed-by: Roger Quadros +Reviewed-by: Simon Horman +Reviewed-by: Jacob Keller +Signed-off-by: MD Danish Anwar +[Commit 443a2367ba3c upstream] +--- + drivers/net/ethernet/ti/icssg/icss_iep.c | 26 +++++++++++++++++++ + drivers/net/ethernet/ti/icssg/icss_iep.h | 2 ++ + drivers/net/ethernet/ti/icssg/icssg_config.c | 7 +++++ + drivers/net/ethernet/ti/icssg/icssg_prueth.c | 27 ++++++++++++++++++-- + drivers/net/ethernet/ti/icssg/icssg_prueth.h | 2 ++ + 5 files changed, 62 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/ethernet/ti/icssg/icss_iep.c b/drivers/net/ethernet/ti/icssg/icss_iep.c +index bcc056bf45da..4cf2a52e4378 100644 +--- a/drivers/net/ethernet/ti/icssg/icss_iep.c ++++ b/drivers/net/ethernet/ti/icssg/icss_iep.c +@@ -727,6 +727,32 @@ void icss_iep_put(struct icss_iep *iep) + } + EXPORT_SYMBOL_GPL(icss_iep_put); + ++void icss_iep_init_fw(struct icss_iep *iep) ++{ ++ /* start IEP for FW use in raw 64bit mode, no PTP support */ ++ iep->clk_tick_time = iep->def_inc; ++ iep->cycle_time_ns = 0; ++ iep->ops = NULL; ++ iep->clockops_data = NULL; ++ icss_iep_set_default_inc(iep, iep->def_inc); ++ icss_iep_set_compensation_inc(iep, iep->def_inc); ++ icss_iep_set_compensation_count(iep, 0); ++ regmap_write(iep->map, ICSS_IEP_SYNC_PWIDTH_REG, iep->refclk_freq / 10); /* 100 ms pulse */ ++ regmap_write(iep->map, ICSS_IEP_SYNC0_PERIOD_REG, 0); ++ if (iep->plat_data->flags & ICSS_IEP_SLOW_COMPEN_REG_SUPPORT) ++ icss_iep_set_slow_compensation_count(iep, 0); ++ ++ icss_iep_enable(iep); ++ icss_iep_settime(iep, 0); ++} ++EXPORT_SYMBOL_GPL(icss_iep_init_fw); ++ ++void icss_iep_exit_fw(struct icss_iep *iep) ++{ ++ icss_iep_disable(iep); ++} ++EXPORT_SYMBOL_GPL(icss_iep_exit_fw); ++ + int icss_iep_init(struct icss_iep *iep, const struct icss_iep_clockops *clkops, + void *clockops_data, u32 cycle_time_ns) + { +diff --git a/drivers/net/ethernet/ti/icssg/icss_iep.h b/drivers/net/ethernet/ti/icssg/icss_iep.h +index 9c7f4d0a0916..803a4b714893 100644 +--- a/drivers/net/ethernet/ti/icssg/icss_iep.h ++++ b/drivers/net/ethernet/ti/icssg/icss_iep.h +@@ -35,5 +35,7 @@ int icss_iep_exit(struct icss_iep *iep); + int icss_iep_get_count_low(struct icss_iep *iep); + int icss_iep_get_count_hi(struct icss_iep *iep); + int icss_iep_get_ptp_clock_idx(struct icss_iep *iep); ++void icss_iep_init_fw(struct icss_iep *iep); ++void icss_iep_exit_fw(struct icss_iep *iep); + + #endif /* __NET_TI_ICSS_IEP_H */ +diff --git a/drivers/net/ethernet/ti/icssg/icssg_config.c b/drivers/net/ethernet/ti/icssg/icssg_config.c +index ab648d3efe85..933b84666574 100644 +--- a/drivers/net/ethernet/ti/icssg/icssg_config.c ++++ b/drivers/net/ethernet/ti/icssg/icssg_config.c +@@ -210,6 +210,10 @@ void icssg_config_ipg(struct prueth_emac *emac) + case SPEED_100: + icssg_mii_update_ipg(prueth->mii_rt, slice, MII_RT_TX_IPG_100M); + break; ++ case SPEED_10: ++ /* IPG for 10M is same as 100M */ ++ icssg_mii_update_ipg(prueth->mii_rt, slice, MII_RT_TX_IPG_100M); ++ break; + default: + /* Other links speeds not supported */ + netdev_err(emac->ndev, "Unsupported link speed\n"); +@@ -440,6 +444,9 @@ void icssg_config_set_speed(struct prueth_emac *emac) + case SPEED_100: + fw_speed = FW_LINK_SPEED_100M; + break; ++ case SPEED_10: ++ fw_speed = FW_LINK_SPEED_10M; ++ break; + default: + /* Other links speeds not supported */ + netdev_err(emac->ndev, "Unsupported link speed\n"); +diff --git a/drivers/net/ethernet/ti/icssg/icssg_prueth.c b/drivers/net/ethernet/ti/icssg/icssg_prueth.c +index 1bcb4e174652..410612f43cbd 100644 +--- a/drivers/net/ethernet/ti/icssg/icssg_prueth.c ++++ b/drivers/net/ethernet/ti/icssg/icssg_prueth.c +@@ -1149,7 +1149,6 @@ static int emac_phy_connect(struct prueth_emac *emac) + + /* remove unsupported modes */ + phy_remove_link_mode(ndev->phydev, ETHTOOL_LINK_MODE_10baseT_Half_BIT); +- phy_remove_link_mode(ndev->phydev, ETHTOOL_LINK_MODE_10baseT_Full_BIT); + phy_remove_link_mode(ndev->phydev, ETHTOOL_LINK_MODE_100baseT_Half_BIT); + phy_remove_link_mode(ndev->phydev, ETHTOOL_LINK_MODE_1000baseT_Half_BIT); + phy_remove_link_mode(ndev->phydev, ETHTOOL_LINK_MODE_Pause_BIT); +@@ -2090,13 +2089,29 @@ static int prueth_probe(struct platform_device *pdev) + goto free_pool; + } + ++ prueth->iep1 = icss_iep_get_idx(np, 1); ++ if (IS_ERR(prueth->iep1)) { ++ ret = dev_err_probe(dev, PTR_ERR(prueth->iep1), "iep1 get failed\n"); ++ icss_iep_put(prueth->iep0); ++ prueth->iep0 = NULL; ++ prueth->iep1 = NULL; ++ goto free_pool; ++ } ++ ++ if (prueth->pdata.quirk_10m_link_issue) { ++ /* Enable IEP1 for FW in 64bit mode as W/A for 10M FD link detect issue under TX ++ * traffic. ++ */ ++ icss_iep_init_fw(prueth->iep1); ++ } ++ + /* setup netdev interfaces */ + if (eth0_node) { + ret = prueth_netdev_init(prueth, eth0_node); + if (ret) { + dev_err_probe(dev, ret, "netdev init %s failed\n", + eth0_node->name); +- goto netdev_exit; ++ goto exit_iep; + } + prueth->emac[PRUETH_MAC0]->iep = prueth->iep0; + } +@@ -2167,6 +2182,10 @@ static int prueth_probe(struct platform_device *pdev) + prueth_netdev_exit(prueth, eth_node); + } + ++exit_iep: ++ if (prueth->pdata.quirk_10m_link_issue) ++ icss_iep_exit_fw(prueth->iep1); ++ + free_pool: + gen_pool_free(prueth->sram_pool, + (unsigned long)prueth->msmcram.va, msmc_ram_size); +@@ -2212,6 +2231,10 @@ static void prueth_remove(struct platform_device *pdev) + prueth_netdev_exit(prueth, eth_node); + } + ++ if (prueth->pdata.quirk_10m_link_issue) ++ icss_iep_exit_fw(prueth->iep1); ++ ++ icss_iep_put(prueth->iep1); + icss_iep_put(prueth->iep0); + + gen_pool_free(prueth->sram_pool, +diff --git a/drivers/net/ethernet/ti/icssg/icssg_prueth.h b/drivers/net/ethernet/ti/icssg/icssg_prueth.h +index a56ab4cdc83c..3fe80a8758d3 100644 +--- a/drivers/net/ethernet/ti/icssg/icssg_prueth.h ++++ b/drivers/net/ethernet/ti/icssg/icssg_prueth.h +@@ -208,6 +208,7 @@ struct prueth_pdata { + * @icssg_hwcmdseq: seq counter or HWQ messages + * @emacs_initialized: num of EMACs/ext ports that are up/running + * @iep0: pointer to IEP0 device ++ * @iep1: pointer to IEP1 device + */ + struct prueth { + struct device *dev; +@@ -231,6 +232,7 @@ struct prueth { + u8 icssg_hwcmdseq; + int emacs_initialized; + struct icss_iep *iep0; ++ struct icss_iep *iep1; + }; + + struct emac_tx_ts_response { +-- +2.42.0 + diff --git a/recipes-kernel/linux/files/patches-6.1/0031-dt-bindings-net-Add-documentation-for-Half-duplex-su.patch b/recipes-kernel/linux/files/patches-6.1/0031-dt-bindings-net-Add-documentation-for-Half-duplex-su.patch new file mode 100644 index 000000000..ebfceba1c --- /dev/null +++ b/recipes-kernel/linux/files/patches-6.1/0031-dt-bindings-net-Add-documentation-for-Half-duplex-su.patch @@ -0,0 +1,46 @@ +From 89526c887fec90db10adbbbde9d183198274206a Mon Sep 17 00:00:00 2001 +From: MD Danish Anwar +Date: Wed, 13 Sep 2023 14:40:10 +0530 +Subject: [PATCH 31/69] dt-bindings: net: Add documentation for Half duplex + support. + +In order to support half-duplex operation at 10M and 100M link speeds, the +PHY collision detection signal (COL) should be routed to ICSSG +GPIO pin (PRGx_PRU0/1_GPI10) so that firmware can detect collision signal +and apply the CSMA/CD algorithm applicable for half duplex operation. A DT +property, "ti,half-duplex-capable" is introduced for this purpose. If +board has PHY COL pin conencted to PRGx_PRU1_GPIO10, this DT property can +be added to eth node of ICSSG, MII port to support half duplex operation at +that port. + +Reviewed-by: Roger Quadros +Signed-off-by: MD Danish Anwar +Reviewed-by: Rob Herring +Acked-by: Conor Dooley +Reviewed-by: Andrew Lunn +[To be merged in 6.7] +--- + Documentation/devicetree/bindings/net/ti,icssg-prueth.yaml | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/Documentation/devicetree/bindings/net/ti,icssg-prueth.yaml b/Documentation/devicetree/bindings/net/ti,icssg-prueth.yaml +index 311c570165f9..216826c8ab08 100644 +--- a/Documentation/devicetree/bindings/net/ti,icssg-prueth.yaml ++++ b/Documentation/devicetree/bindings/net/ti,icssg-prueth.yaml +@@ -106,6 +106,13 @@ properties: + phandle to system controller node and register offset + to ICSSG control register for RGMII transmit delay + ++ ti,half-duplex-capable: ++ type: boolean ++ description: ++ Indicates that the PHY output pin COL is routed to ICSSG GPIO pin ++ (PRGx_PRU0/1_GPIO10) as input so that the ICSSG MII port is ++ capable of half duplex operations. ++ + required: + - reg + anyOf: +-- +2.42.0 + diff --git a/recipes-kernel/linux/files/patches-6.1/0032-net-ti-icssg-prueth-Add-support-for-half-duplex-oper.patch b/recipes-kernel/linux/files/patches-6.1/0032-net-ti-icssg-prueth-Add-support-for-half-duplex-oper.patch new file mode 100644 index 000000000..a40ad6f8b --- /dev/null +++ b/recipes-kernel/linux/files/patches-6.1/0032-net-ti-icssg-prueth-Add-support-for-half-duplex-oper.patch @@ -0,0 +1,131 @@ +From 34b92f3384230edc8f7d24e51e35834b462e9fcf Mon Sep 17 00:00:00 2001 +From: MD Danish Anwar +Date: Wed, 13 Sep 2023 14:40:11 +0530 +Subject: [PATCH 32/69] net: ti: icssg-prueth: Add support for half duplex + operation + +This patch adds support for half duplex operation at 10M and 100M link +speeds for AM654x/AM64x devices. +- Driver configures rand_seed, a random number, in DMEM HD_RAND_SEED_OFFSET +field, which will be used by firmware for Back off time calculation. +- Driver informs FW about half duplex link operation in DMEM +PORT_LINK_SPEED_OFFSET field by setting bit 7 for 10/100M HD. + +Hence, the half duplex operation depends on board design the +"ti,half-duplex-capable" property has to be enabled for ICSS-G ports if HW +is capable to perform half duplex. + +Reviewed-by: Andrew Lunn +Reviewed-by: Roger Quadros +Signed-off-by: MD Danish Anwar +[To be merged in 6.7] +--- + drivers/net/ethernet/ti/icssg/icssg_config.c | 14 ++++++++++++++ + drivers/net/ethernet/ti/icssg/icssg_prueth.c | 17 +++++++++++++++-- + drivers/net/ethernet/ti/icssg/icssg_prueth.h | 2 ++ + 3 files changed, 31 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/ethernet/ti/icssg/icssg_config.c b/drivers/net/ethernet/ti/icssg/icssg_config.c +index 933b84666574..c1da70f247d4 100644 +--- a/drivers/net/ethernet/ti/icssg/icssg_config.c ++++ b/drivers/net/ethernet/ti/icssg/icssg_config.c +@@ -433,6 +433,17 @@ int emac_set_port_state(struct prueth_emac *emac, + return ret; + } + ++void icssg_config_half_duplex(struct prueth_emac *emac) ++{ ++ u32 val; ++ ++ if (!emac->half_duplex) ++ return; ++ ++ val = get_random_u32(); ++ writel(val, emac->dram.va + HD_RAND_SEED_OFFSET); ++} ++ + void icssg_config_set_speed(struct prueth_emac *emac) + { + u8 fw_speed; +@@ -453,5 +464,8 @@ void icssg_config_set_speed(struct prueth_emac *emac) + return; + } + ++ if (emac->duplex == DUPLEX_HALF) ++ fw_speed |= FW_LINK_SPEED_HD; ++ + writeb(fw_speed, emac->dram.va + PORT_LINK_SPEED_OFFSET); + } +diff --git a/drivers/net/ethernet/ti/icssg/icssg_prueth.c b/drivers/net/ethernet/ti/icssg/icssg_prueth.c +index 410612f43cbd..e736652567cd 100644 +--- a/drivers/net/ethernet/ti/icssg/icssg_prueth.c ++++ b/drivers/net/ethernet/ti/icssg/icssg_prueth.c +@@ -1029,6 +1029,8 @@ static void emac_adjust_link(struct net_device *ndev) + * values + */ + if (emac->link) { ++ if (emac->duplex == DUPLEX_HALF) ++ icssg_config_half_duplex(emac); + /* Set the RGMII cfg for gig en and full duplex */ + icssg_update_rgmii_cfg(prueth->miig_rt, emac); + +@@ -1147,9 +1149,13 @@ static int emac_phy_connect(struct prueth_emac *emac) + return -ENODEV; + } + ++ if (!emac->half_duplex) { ++ dev_dbg(prueth->dev, "half duplex mode is not supported\n"); ++ phy_remove_link_mode(ndev->phydev, ETHTOOL_LINK_MODE_10baseT_Half_BIT); ++ phy_remove_link_mode(ndev->phydev, ETHTOOL_LINK_MODE_100baseT_Half_BIT); ++ } ++ + /* remove unsupported modes */ +- phy_remove_link_mode(ndev->phydev, ETHTOOL_LINK_MODE_10baseT_Half_BIT); +- phy_remove_link_mode(ndev->phydev, ETHTOOL_LINK_MODE_100baseT_Half_BIT); + phy_remove_link_mode(ndev->phydev, ETHTOOL_LINK_MODE_1000baseT_Half_BIT); + phy_remove_link_mode(ndev->phydev, ETHTOOL_LINK_MODE_Pause_BIT); + phy_remove_link_mode(ndev->phydev, ETHTOOL_LINK_MODE_Asym_Pause_BIT); +@@ -2113,6 +2119,10 @@ static int prueth_probe(struct platform_device *pdev) + eth0_node->name); + goto exit_iep; + } ++ ++ if (of_find_property(eth0_node, "ti,half-duplex-capable", NULL)) ++ prueth->emac[PRUETH_MAC0]->half_duplex = 1; ++ + prueth->emac[PRUETH_MAC0]->iep = prueth->iep0; + } + +@@ -2124,6 +2134,9 @@ static int prueth_probe(struct platform_device *pdev) + goto netdev_exit; + } + ++ if (of_find_property(eth1_node, "ti,half-duplex-capable", NULL)) ++ prueth->emac[PRUETH_MAC1]->half_duplex = 1; ++ + prueth->emac[PRUETH_MAC1]->iep = prueth->iep0; + } + +diff --git a/drivers/net/ethernet/ti/icssg/icssg_prueth.h b/drivers/net/ethernet/ti/icssg/icssg_prueth.h +index 3fe80a8758d3..8b6d6b497010 100644 +--- a/drivers/net/ethernet/ti/icssg/icssg_prueth.h ++++ b/drivers/net/ethernet/ti/icssg/icssg_prueth.h +@@ -145,6 +145,7 @@ struct prueth_emac { + struct icss_iep *iep; + unsigned int rx_ts_enabled : 1; + unsigned int tx_ts_enabled : 1; ++ unsigned int half_duplex : 1; + + /* DMA related */ + struct prueth_tx_chn tx_chns[PRUETH_MAX_TX_QUEUES]; +@@ -271,6 +272,7 @@ int icssg_config(struct prueth *prueth, struct prueth_emac *emac, + int emac_set_port_state(struct prueth_emac *emac, + enum icssg_port_state_cmd state); + void icssg_config_set_speed(struct prueth_emac *emac); ++void icssg_config_half_duplex(struct prueth_emac *emac); + + /* Buffer queue helpers */ + int icssg_queue_pop(struct prueth *prueth, u8 queue); +-- +2.42.0 + diff --git a/recipes-kernel/linux/files/patches-6.1/0033-dmaengine-ti-k3-udma-Add-system-suspend-resume-suppo.patch b/recipes-kernel/linux/files/patches-6.1/0033-dmaengine-ti-k3-udma-Add-system-suspend-resume-suppo.patch new file mode 100644 index 000000000..e0789daca --- /dev/null +++ b/recipes-kernel/linux/files/patches-6.1/0033-dmaengine-ti-k3-udma-Add-system-suspend-resume-suppo.patch @@ -0,0 +1,119 @@ +From e1e66f81faee06494419ecc617a64f6244f3e2e3 Mon Sep 17 00:00:00 2001 +From: Vignesh Raghavendra +Date: Wed, 29 Mar 2023 21:23:49 +0530 +Subject: [PATCH 33/69] dmaengine: ti: k3-udma: Add system suspend/resume + support + +The K3 platforms configure the DMA resources with the +help of the TI's System Firmware's Device Manager(DM) +over TISCI. The group of DMA related Resource Manager[1] +TISCI messages includes: INTA, RINGACC, UDMAP, and PSI-L. +This configuration however, does not persist in the DM +after leaving from Suspend-to-RAM state. We have to restore +the DMA channel configuration over TISCI for all configured +channels when returning from suspend. + +The TISCI resource management calls for each DMA type (UDMA, +PKTDMA, BCDMA) happen in device_free_chan_resources() and +device_alloc_chan_resources(). In pm_suspend() we store +the current udma_chan_config for channels that still have +attached clients and call device_free_chan_resources(). +In pm_resume() restore the udma_channel_config from backup +and call device_alloc_chan_resources() for those channels. + +Drivers like CPSW that use k3-udma-glue already do their own +DMA resource management so use the late system suspend/resume hooks. + +[1] https://software-dl.ti.com/tisci/esd/latest/2_tisci_msgs/index.html#resource-management-rm + +[g-vlaev@ti.com: Supend only channels with clients] + +Signed-off-by: Vignesh Raghavendra +[g-vlaev@ti.com: Add patch description and config backup] +Signed-off-by: Georgi Vlaev +Acked-by: Peter Ujfalusi +[Commit fbe05149e40b upstream] +--- + drivers/dma/ti/k3-udma.c | 54 ++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 54 insertions(+) + +diff --git a/drivers/dma/ti/k3-udma.c b/drivers/dma/ti/k3-udma.c +index b86b809eb1f7..b0286df3383d 100644 +--- a/drivers/dma/ti/k3-udma.c ++++ b/drivers/dma/ti/k3-udma.c +@@ -303,6 +303,8 @@ struct udma_chan { + + /* Channel configuration parameters */ + struct udma_chan_config config; ++ /* Channel configuration parameters (backup) */ ++ struct udma_chan_config backup_config; + + /* dmapool for packet mode descriptors */ + bool use_dma_pool; +@@ -5504,11 +5506,63 @@ static int udma_probe(struct platform_device *pdev) + return ret; + } + ++static int udma_pm_suspend(struct device *dev) ++{ ++ struct udma_dev *ud = dev_get_drvdata(dev); ++ struct dma_device *dma_dev = &ud->ddev; ++ struct dma_chan *chan; ++ struct udma_chan *uc; ++ ++ list_for_each_entry(chan, &dma_dev->channels, device_node) { ++ if (chan->client_count) { ++ uc = to_udma_chan(chan); ++ /* backup the channel configuration */ ++ memcpy(&uc->backup_config, &uc->config, ++ sizeof(struct udma_chan_config)); ++ dev_dbg(dev, "Suspending channel %s\n", ++ dma_chan_name(chan)); ++ ud->ddev.device_free_chan_resources(chan); ++ } ++ } ++ ++ return 0; ++} ++ ++static int udma_pm_resume(struct device *dev) ++{ ++ struct udma_dev *ud = dev_get_drvdata(dev); ++ struct dma_device *dma_dev = &ud->ddev; ++ struct dma_chan *chan; ++ struct udma_chan *uc; ++ int ret; ++ ++ list_for_each_entry(chan, &dma_dev->channels, device_node) { ++ if (chan->client_count) { ++ uc = to_udma_chan(chan); ++ /* restore the channel configuration */ ++ memcpy(&uc->config, &uc->backup_config, ++ sizeof(struct udma_chan_config)); ++ dev_dbg(dev, "Resuming channel %s\n", ++ dma_chan_name(chan)); ++ ret = ud->ddev.device_alloc_chan_resources(chan); ++ if (ret) ++ return ret; ++ } ++ } ++ ++ return 0; ++} ++ ++static const struct dev_pm_ops udma_pm_ops = { ++ SET_LATE_SYSTEM_SLEEP_PM_OPS(udma_pm_suspend, udma_pm_resume) ++}; ++ + static struct platform_driver udma_driver = { + .driver = { + .name = "ti-udma", + .of_match_table = udma_of_match, + .suppress_bind_attrs = true, ++ .pm = &udma_pm_ops, + }, + .probe = udma_probe, + }; +-- +2.42.0 + diff --git a/recipes-kernel/linux/files/patches-6.1/0034-dmaengine-ti-k3-udma-Fix-BCDMA-for-case-w-o-BCHAN.patch b/recipes-kernel/linux/files/patches-6.1/0034-dmaengine-ti-k3-udma-Fix-BCDMA-for-case-w-o-BCHAN.patch new file mode 100644 index 000000000..9c3df8272 --- /dev/null +++ b/recipes-kernel/linux/files/patches-6.1/0034-dmaengine-ti-k3-udma-Fix-BCDMA-for-case-w-o-BCHAN.patch @@ -0,0 +1,32 @@ +From 2ec60db21595993e29f6ca36dd794ee3c0fb363d Mon Sep 17 00:00:00 2001 +From: Vignesh Raghavendra +Date: Tue, 13 Dec 2022 22:13:01 +0530 +Subject: [PATCH 34/69] dmaengine: ti: k3-udma: Fix BCDMA for case w/o BCHAN + +Reusing loop iterator fails if BCHAN is not present as iterator is +uninitialized + +Signed-off-by: Vignesh Raghavendra +[Commit 4c7f3ca1745e upstream] +--- + drivers/dma/ti/k3-udma.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/dma/ti/k3-udma.c b/drivers/dma/ti/k3-udma.c +index b0286df3383d..bbc26c18a590 100644 +--- a/drivers/dma/ti/k3-udma.c ++++ b/drivers/dma/ti/k3-udma.c +@@ -4784,7 +4784,10 @@ static int bcdma_setup_resources(struct udma_dev *ud) + irq_res.desc[i].num = rm_res->desc[i].num; + } + } ++ } else { ++ i = 0; + } ++ + if (ud->tchan_cnt) { + rm_res = tisci_rm->rm_ranges[RM_RANGE_TCHAN]; + if (IS_ERR(rm_res)) { +-- +2.42.0 + diff --git a/recipes-kernel/linux/files/patches-6.1/0035-soc-ti-k3-ringacc-remove-non-fatal-probe-deferral-lo.patch b/recipes-kernel/linux/files/patches-6.1/0035-soc-ti-k3-ringacc-remove-non-fatal-probe-deferral-lo.patch new file mode 100644 index 000000000..96dbd25e2 --- /dev/null +++ b/recipes-kernel/linux/files/patches-6.1/0035-soc-ti-k3-ringacc-remove-non-fatal-probe-deferral-lo.patch @@ -0,0 +1,35 @@ +From 24352a05187317d7e08181bd5691b9be62f19a81 Mon Sep 17 00:00:00 2001 +From: Jayesh Choudhary +Date: Fri, 28 Jul 2023 11:03:56 +0530 +Subject: [PATCH 35/69] soc: ti: k3-ringacc: remove non-fatal probe deferral + log + +Drop the non-fatal probe deferral log for getting MSI domain. +This makes the kernel log clean and we do not get recurring logs +stating: "Failed to get MSI domain". + +Signed-off-by: Jayesh Choudhary +[Commit e50a76355c1d upstream] +--- + drivers/soc/ti/k3-ringacc.c | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +diff --git a/drivers/soc/ti/k3-ringacc.c b/drivers/soc/ti/k3-ringacc.c +index f7bf18b8229a..10a180be75dc 100644 +--- a/drivers/soc/ti/k3-ringacc.c ++++ b/drivers/soc/ti/k3-ringacc.c +@@ -1358,10 +1358,8 @@ static int k3_ringacc_init(struct platform_device *pdev, + + dev->msi.domain = of_msi_get_domain(dev, dev->of_node, + DOMAIN_BUS_TI_SCI_INTA_MSI); +- if (!dev->msi.domain) { +- dev_err(dev, "Failed to get MSI domain\n"); ++ if (!dev->msi.domain) + return -EPROBE_DEFER; +- } + + ret = k3_ringacc_probe_dt(ringacc); + if (ret) +-- +2.42.0 + diff --git a/recipes-kernel/linux/files/patches-6.1/0036-dmaengine-ti-k3-udma-remove-non-fatal-probe-deferral.patch b/recipes-kernel/linux/files/patches-6.1/0036-dmaengine-ti-k3-udma-remove-non-fatal-probe-deferral.patch new file mode 100644 index 000000000..670060ff1 --- /dev/null +++ b/recipes-kernel/linux/files/patches-6.1/0036-dmaengine-ti-k3-udma-remove-non-fatal-probe-deferral.patch @@ -0,0 +1,32 @@ +From 17ff98dfb8894975c69f06bd1f1090afb195f4b0 Mon Sep 17 00:00:00 2001 +From: Jayesh Choudhary +Date: Tue, 17 Jan 2023 10:48:55 +0530 +Subject: [PATCH 36/69] dmaengine: ti: k3-udma: remove non-fatal probe deferral + log + +Drop the non-fatal probe deferral log for getting MSI domain. +This makes the kernel log clean and we do not get recurring logs +stating: "Failed to get MSI domain". + +Signed-off-by: Jayesh Choudhary +Acked-by: Peter Ujfalusi +[Commit ad4ce0789033 upstream] +--- + drivers/dma/ti/k3-udma.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/drivers/dma/ti/k3-udma.c b/drivers/dma/ti/k3-udma.c +index bbc26c18a590..3aa8b9b4321d 100644 +--- a/drivers/dma/ti/k3-udma.c ++++ b/drivers/dma/ti/k3-udma.c +@@ -5362,7 +5362,6 @@ static int udma_probe(struct platform_device *pdev) + dev->msi.domain = of_msi_get_domain(dev, dev->of_node, + DOMAIN_BUS_TI_SCI_INTA_MSI); + if (!dev->msi.domain) { +- dev_err(dev, "Failed to get MSI domain\n"); + return -EPROBE_DEFER; + } + +-- +2.42.0 + diff --git a/recipes-kernel/linux/files/patches-6.1/0037-mmc-sdhci_am654-Use-dev_err_probe-for-mmc_of_parse-r.patch b/recipes-kernel/linux/files/patches-6.1/0037-mmc-sdhci_am654-Use-dev_err_probe-for-mmc_of_parse-r.patch new file mode 100644 index 000000000..ebe6c638b --- /dev/null +++ b/recipes-kernel/linux/files/patches-6.1/0037-mmc-sdhci_am654-Use-dev_err_probe-for-mmc_of_parse-r.patch @@ -0,0 +1,33 @@ +From 5aee34cbfff8645ab549db404ad29166355faa9f Mon Sep 17 00:00:00 2001 +From: Matthias Schiffer +Date: Tue, 1 Nov 2022 11:52:42 +0100 +Subject: [PATCH 37/69] mmc: sdhci_am654: Use dev_err_probe() for + mmc_of_parse() return code + +Checking phandle references like mmc-pwrseq can result in -EPROBE_DEFER. + +Signed-off-by: Matthias Schiffer +Acked-by: Adrian Hunter +Link: https://lore.kernel.org/r/20221101105242.2019036-1-matthias.schiffer@ew.tq-group.com +Signed-off-by: Ulf Hansson +[Commit 654993b3e1eb upstream] +--- + drivers/mmc/host/sdhci_am654.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/mmc/host/sdhci_am654.c b/drivers/mmc/host/sdhci_am654.c +index 8e22b375247e..672d37ea98d0 100644 +--- a/drivers/mmc/host/sdhci_am654.c ++++ b/drivers/mmc/host/sdhci_am654.c +@@ -834,7 +834,7 @@ static int sdhci_am654_probe(struct platform_device *pdev) + + ret = mmc_of_parse(host->mmc); + if (ret) { +- dev_err(dev, "parsing dt failed (%d)\n", ret); ++ dev_err_probe(dev, ret, "parsing dt failed\n"); + goto pm_runtime_put; + } + +-- +2.42.0 + diff --git a/recipes-kernel/linux/files/patches-6.1/0038-mmc-sdhci_am654-Add-support-for-PM-suspend-resume.patch b/recipes-kernel/linux/files/patches-6.1/0038-mmc-sdhci_am654-Add-support-for-PM-suspend-resume.patch new file mode 100644 index 000000000..49945b326 --- /dev/null +++ b/recipes-kernel/linux/files/patches-6.1/0038-mmc-sdhci_am654-Add-support-for-PM-suspend-resume.patch @@ -0,0 +1,233 @@ +From 56439874cedd3fd18d2bfdb318d44f02fedcb390 Mon Sep 17 00:00:00 2001 +From: Aswath Govindraju +Date: Fri, 31 Mar 2023 15:46:18 +0530 +Subject: [PATCH 38/69] mmc: sdhci_am654: Add support for PM suspend/resume + +Add support for suspend/resume and pm_runtime resume/suspend. + +Signed-off-by: Aswath Govindraju +Signed-off-by: Georgi Vlaev +Signed-off-by: Vignesh Raghavendra +[Commit 9d2e77ff2bd3 upstream] +--- + drivers/mmc/host/sdhci_am654.c | 147 +++++++++++++++++++++++++++++---- + 1 file changed, 131 insertions(+), 16 deletions(-) + +diff --git a/drivers/mmc/host/sdhci_am654.c b/drivers/mmc/host/sdhci_am654.c +index 672d37ea98d0..7cdf0f54e3a5 100644 +--- a/drivers/mmc/host/sdhci_am654.c ++++ b/drivers/mmc/host/sdhci_am654.c +@@ -85,6 +85,7 @@ + #define DRIVER_STRENGTH_40_OHM 0x4 + + #define CLOCK_TOO_SLOW_HZ 50000000 ++#define SDHCI_AM654_AUTOSUSPEND_DELAY -1 + + /* Command Queue Host Controller Interface Base address */ + #define SDHCI_AM654_CQE_BASE_ADDR 0x200 +@@ -808,16 +809,10 @@ static int sdhci_am654_probe(struct platform_device *pdev) + + pltfm_host->clk = clk_xin; + +- /* Clocks are enabled using pm_runtime */ +- pm_runtime_enable(dev); +- ret = pm_runtime_resume_and_get(dev); +- if (ret) +- goto pm_runtime_disable; +- + base = devm_platform_ioremap_resource(pdev, 1); + if (IS_ERR(base)) { + ret = PTR_ERR(base); +- goto pm_runtime_put; ++ goto err_pltfm_free; + } + + sdhci_am654->base = devm_regmap_init_mmio(dev, base, +@@ -825,31 +820,47 @@ static int sdhci_am654_probe(struct platform_device *pdev) + if (IS_ERR(sdhci_am654->base)) { + dev_err(dev, "Failed to initialize regmap\n"); + ret = PTR_ERR(sdhci_am654->base); +- goto pm_runtime_put; ++ goto err_pltfm_free; + } + + ret = sdhci_am654_get_of_property(pdev, sdhci_am654); + if (ret) +- goto pm_runtime_put; ++ goto err_pltfm_free; + + ret = mmc_of_parse(host->mmc); + if (ret) { + dev_err_probe(dev, ret, "parsing dt failed\n"); +- goto pm_runtime_put; ++ goto err_pltfm_free; + } + + host->mmc_host_ops.execute_tuning = sdhci_am654_execute_tuning; + ++ pm_runtime_get_noresume(dev); ++ ret = pm_runtime_set_active(dev); ++ if (ret) ++ goto pm_put; ++ pm_runtime_enable(dev); ++ ret = clk_prepare_enable(pltfm_host->clk); ++ if (ret) ++ goto pm_disable; ++ + ret = sdhci_am654_init(host); + if (ret) +- goto pm_runtime_put; ++ goto clk_disable; + ++ /* Setting up autosuspend */ ++ pm_runtime_set_autosuspend_delay(dev, SDHCI_AM654_AUTOSUSPEND_DELAY); ++ pm_runtime_use_autosuspend(dev); ++ pm_runtime_mark_last_busy(dev); ++ pm_runtime_put_autosuspend(dev); + return 0; + +-pm_runtime_put: +- pm_runtime_put_sync(dev); +-pm_runtime_disable: ++clk_disable: ++ clk_disable_unprepare(pltfm_host->clk); ++pm_disable: + pm_runtime_disable(dev); ++pm_put: ++ pm_runtime_put_noidle(dev); + err_pltfm_free: + sdhci_pltfm_free(pdev); + return ret; +@@ -858,23 +869,127 @@ static int sdhci_am654_probe(struct platform_device *pdev) + static int sdhci_am654_remove(struct platform_device *pdev) + { + struct sdhci_host *host = platform_get_drvdata(pdev); ++ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + int ret; + +- sdhci_remove_host(host, true); +- ret = pm_runtime_put_sync(&pdev->dev); ++ ret = pm_runtime_resume_and_get(&pdev->dev); + if (ret < 0) + return ret; + ++ sdhci_remove_host(host, true); ++ clk_disable_unprepare(pltfm_host->clk); + pm_runtime_disable(&pdev->dev); ++ pm_runtime_put_noidle(&pdev->dev); + sdhci_pltfm_free(pdev); ++ return 0; ++} ++ ++#ifdef CONFIG_PM ++static int sdhci_am654_restore(struct sdhci_host *host) ++{ ++ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); ++ struct sdhci_am654_data *sdhci_am654 = sdhci_pltfm_priv(pltfm_host); ++ u32 ctl_cfg_2 = 0; ++ u32 val; ++ int ret; ++ ++ if (sdhci_am654->flags & DLL_CALIB) { ++ regmap_read(sdhci_am654->base, PHY_STAT1, &val); ++ if (~val & CALDONE_MASK) { ++ /* Calibrate IO lines */ ++ regmap_update_bits(sdhci_am654->base, PHY_CTRL1, ++ PDB_MASK, PDB_MASK); ++ ret = regmap_read_poll_timeout(sdhci_am654->base, ++ PHY_STAT1, val, ++ val & CALDONE_MASK, ++ 1, 20); ++ if (ret) ++ return ret; ++ } ++ } ++ ++ /* Enable pins by setting IO mux to 0 */ ++ if (sdhci_am654->flags & IOMUX_PRESENT) ++ regmap_update_bits(sdhci_am654->base, PHY_CTRL1, ++ IOMUX_ENABLE_MASK, 0); + ++ /* Set slot type based on SD or eMMC */ ++ if (host->mmc->caps & MMC_CAP_NONREMOVABLE) ++ ctl_cfg_2 = SLOTTYPE_EMBEDDED; ++ ++ regmap_update_bits(sdhci_am654->base, CTL_CFG_2, SLOTTYPE_MASK, ++ ctl_cfg_2); ++ ++ regmap_read(sdhci_am654->base, CTL_CFG_3, &val); ++ if (~val & TUNINGFORSDR50_MASK) ++ /* Enable tuning for SDR50 */ ++ regmap_update_bits(sdhci_am654->base, CTL_CFG_3, TUNINGFORSDR50_MASK, ++ TUNINGFORSDR50_MASK); ++ ++ return 0; ++} ++ ++static int sdhci_am654_runtime_suspend(struct device *dev) ++{ ++ struct sdhci_host *host = dev_get_drvdata(dev); ++ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); ++ int ret; ++ ++ if (host->tuning_mode != SDHCI_TUNING_MODE_3) ++ mmc_retune_needed(host->mmc); ++ ++ ret = cqhci_suspend(host->mmc); ++ if (ret) ++ return ret; ++ ++ ret = sdhci_runtime_suspend_host(host); ++ if (ret) ++ return ret; ++ ++ /* disable the clock */ ++ clk_disable_unprepare(pltfm_host->clk); + return 0; + } + ++static int sdhci_am654_runtime_resume(struct device *dev) ++{ ++ struct sdhci_host *host = dev_get_drvdata(dev); ++ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); ++ int ret; ++ ++ /* Enable the clock */ ++ ret = clk_prepare_enable(pltfm_host->clk); ++ if (ret) ++ return ret; ++ ++ ret = sdhci_am654_restore(host); ++ if (ret) ++ return ret; ++ ++ ret = sdhci_runtime_resume_host(host, 0); ++ if (ret) ++ return ret; ++ ++ ret = cqhci_resume(host->mmc); ++ if (ret) ++ return ret; ++ ++ return 0; ++} ++#endif ++ ++static const struct dev_pm_ops sdhci_am654_dev_pm_ops = { ++ SET_RUNTIME_PM_OPS(sdhci_am654_runtime_suspend, ++ sdhci_am654_runtime_resume, NULL) ++ SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, ++ pm_runtime_force_resume) ++}; ++ + static struct platform_driver sdhci_am654_driver = { + .driver = { + .name = "sdhci-am654", + .probe_type = PROBE_PREFER_ASYNCHRONOUS, ++ .pm = &sdhci_am654_dev_pm_ops, + .of_match_table = sdhci_am654_of_match, + }, + .probe = sdhci_am654_probe, +-- +2.42.0 + diff --git a/recipes-kernel/linux/files/patches-6.1/0039-dt-bindings-watchdog-ti-rti-wdt-Add-support-for-WDIO.patch b/recipes-kernel/linux/files/patches-6.1/0039-dt-bindings-watchdog-ti-rti-wdt-Add-support-for-WDIO.patch new file mode 100644 index 000000000..cdec0a9cc --- /dev/null +++ b/recipes-kernel/linux/files/patches-6.1/0039-dt-bindings-watchdog-ti-rti-wdt-Add-support-for-WDIO.patch @@ -0,0 +1,77 @@ +From 15c7e95d53c17140e8934f56d7edfcf7d2e479c4 Mon Sep 17 00:00:00 2001 +From: Li Hua Qian +Date: Tue, 18 Jul 2023 10:10:05 +0800 +Subject: [PATCH 39/69] dt-bindings: watchdog: ti,rti-wdt: Add support for + WDIOF_CARDRESET + +TI RTI (Real Time Interrupt) Watchdog doesn't support to record the +watchdog cause. Add a reserved memory to know the last reboot was caused +by the watchdog card. In the reserved memory, some specific info will be +saved to indicate whether the watchdog reset was triggered in last +boot. + +Signed-off-by: Li Hua Qian +Reviewed-by: Krzysztof Kozlowski +Reviewed-by: Guenter Roeck +Link: https://lore.kernel.org/r/20230718021007.1338761-2-huaqian.li@siemens.com +Signed-off-by: Guenter Roeck +Signed-off-by: Wim Van Sebroeck +[Commit 11efe9e3f80a upstream] +--- + .../bindings/watchdog/ti,rti-wdt.yaml | 28 ++++++++++++++++++- + 1 file changed, 27 insertions(+), 1 deletion(-) + +diff --git a/Documentation/devicetree/bindings/watchdog/ti,rti-wdt.yaml b/Documentation/devicetree/bindings/watchdog/ti,rti-wdt.yaml +index 2f33635876ff..794219eb5bbc 100644 +--- a/Documentation/devicetree/bindings/watchdog/ti,rti-wdt.yaml ++++ b/Documentation/devicetree/bindings/watchdog/ti,rti-wdt.yaml +@@ -34,6 +34,20 @@ properties: + power-domains: + maxItems: 1 + ++ memory-region: ++ maxItems: 1 ++ description: ++ Contains the watchdog reserved memory. It is optional. ++ In the reserved memory, the specified values, which are ++ PON_REASON_SOF_NUM(0xBBBBCCCC), PON_REASON_MAGIC_NUM(0xDDDDDDDD), ++ and PON_REASON_EOF_NUM(0xCCCCBBBB), are pre-stored at the first ++ 3 * 4 bytes to tell that last boot was caused by watchdog reset. ++ Once the PON reason is captured by driver(rti_wdt.c), the driver ++ is supposed to wipe the whole memory region. Surely, if this ++ property is set, at least 12 bytes reserved memory starting from ++ specific memory address(0xa220000) should be set. More please ++ refer to example. ++ + required: + - compatible + - reg +@@ -47,7 +61,18 @@ examples: + /* + * RTI WDT in main domain on J721e SoC. Assigned clocks are used to + * select the source clock for the watchdog, forcing it to tick with +- * a 32kHz clock in this case. ++ * a 32kHz clock in this case. Add a reserved memory(optional) to keep ++ * the watchdog reset cause persistent, which was be written in 12 bytes ++ * starting from 0xa2200000 by RTI Watchdog Firmware, then make it ++ * possible to get watchdog reset cause in driver. ++ * ++ * Reserved memory should be defined as follows: ++ * reserved-memory { ++ * wdt_reset_memory_region: wdt-memory@a2200000 { ++ * reg = <0x00 0xa2200000 0x00 0x1000>; ++ * no-map; ++ * }; ++ * } + */ + #include + +@@ -58,4 +83,5 @@ examples: + power-domains = <&k3_pds 252 TI_SCI_PD_EXCLUSIVE>; + assigned-clocks = <&k3_clks 252 1>; + assigned-clock-parents = <&k3_clks 252 5>; ++ memory-region = <&wdt_reset_memory_region>; + }; +-- +2.42.0 + diff --git a/recipes-kernel/linux/files/patches-6.1/0040-watchdog-rit_wdt-Add-support-for-WDIOF_CARDRESET.patch b/recipes-kernel/linux/files/patches-6.1/0040-watchdog-rit_wdt-Add-support-for-WDIOF_CARDRESET.patch new file mode 100644 index 000000000..1e9148a99 --- /dev/null +++ b/recipes-kernel/linux/files/patches-6.1/0040-watchdog-rit_wdt-Add-support-for-WDIOF_CARDRESET.patch @@ -0,0 +1,106 @@ +From d8f5df968a8c78ca7bb3191a4a593c9f284c906f Mon Sep 17 00:00:00 2001 +From: Li Hua Qian +Date: Tue, 18 Jul 2023 10:10:07 +0800 +Subject: [PATCH 40/69] watchdog:rit_wdt: Add support for WDIOF_CARDRESET + +This patch adds the WDIOF_CARDRESET support for the platform watchdog +whose hardware does not support this feature, to know if the board +reboot is due to a watchdog reset. + +This is done via reserved memory(RAM), which indicates if specific +info saved, triggering the watchdog reset in last boot. + +Signed-off-by: Li Hua Qian +Reviewed-by: Guenter Roeck +Link: https://lore.kernel.org/r/20230718021007.1338761-4-huaqian.li@siemens.com +[groeck: vaddr == NULL --> !vaddr] +Signed-off-by: Guenter Roeck +Signed-off-by: Wim Van Sebroeck +[Commit f20ca595ae23 upstream] +--- + drivers/watchdog/rti_wdt.c | 48 ++++++++++++++++++++++++++++++++++++++ + 1 file changed, 48 insertions(+) + +diff --git a/drivers/watchdog/rti_wdt.c b/drivers/watchdog/rti_wdt.c +index 6e9253761fc1..bc13e7687f04 100644 +--- a/drivers/watchdog/rti_wdt.c ++++ b/drivers/watchdog/rti_wdt.c +@@ -14,6 +14,8 @@ + #include + #include + #include ++#include ++#include + #include + #include + #include +@@ -52,6 +54,11 @@ + + #define DWDST BIT(1) + ++#define PON_REASON_SOF_NUM 0xBBBBCCCC ++#define PON_REASON_MAGIC_NUM 0xDDDDDDDD ++#define PON_REASON_EOF_NUM 0xCCCCBBBB ++#define RESERVED_MEM_MIN_SIZE 12 ++ + static int heartbeat = DEFAULT_HEARTBEAT; + + /* +@@ -198,6 +205,11 @@ static int rti_wdt_probe(struct platform_device *pdev) + struct rti_wdt_device *wdt; + struct clk *clk; + u32 last_ping = 0; ++ struct device_node *node; ++ u32 reserved_mem_size; ++ struct resource res; ++ u32 *vaddr; ++ u64 paddr; + + wdt = devm_kzalloc(dev, sizeof(*wdt), GFP_KERNEL); + if (!wdt) +@@ -284,6 +296,42 @@ static int rti_wdt_probe(struct platform_device *pdev) + } + } + ++ node = of_parse_phandle(pdev->dev.of_node, "memory-region", 0); ++ if (node) { ++ ret = of_address_to_resource(node, 0, &res); ++ if (ret) { ++ dev_err(dev, "No memory address assigned to the region.\n"); ++ goto err_iomap; ++ } ++ ++ /* ++ * If reserved memory is defined for watchdog reset cause. ++ * Readout the Power-on(PON) reason and pass to bootstatus. ++ */ ++ paddr = res.start; ++ reserved_mem_size = resource_size(&res); ++ if (reserved_mem_size < RESERVED_MEM_MIN_SIZE) { ++ dev_err(dev, "The size of reserved memory is too small.\n"); ++ ret = -EINVAL; ++ goto err_iomap; ++ } ++ ++ vaddr = memremap(paddr, reserved_mem_size, MEMREMAP_WB); ++ if (!vaddr) { ++ dev_err(dev, "Failed to map memory-region.\n"); ++ ret = -ENOMEM; ++ goto err_iomap; ++ } ++ ++ if (vaddr[0] == PON_REASON_SOF_NUM && ++ vaddr[1] == PON_REASON_MAGIC_NUM && ++ vaddr[2] == PON_REASON_EOF_NUM) { ++ wdd->bootstatus |= WDIOF_CARDRESET; ++ } ++ memset(vaddr, 0, reserved_mem_size); ++ memunmap(vaddr); ++ } ++ + watchdog_init_timeout(wdd, heartbeat, dev); + + ret = watchdog_register_device(wdd); +-- +2.42.0 + diff --git a/recipes-kernel/linux/files/patches-6.1/0041-arm64-dts-ti-Add-reserved-memory-for-watchdog.patch b/recipes-kernel/linux/files/patches-6.1/0041-arm64-dts-ti-Add-reserved-memory-for-watchdog.patch new file mode 100644 index 000000000..ba6940d65 --- /dev/null +++ b/recipes-kernel/linux/files/patches-6.1/0041-arm64-dts-ti-Add-reserved-memory-for-watchdog.patch @@ -0,0 +1,46 @@ +From fc9510221becdc7ac723ddb98475519cae937d41 Mon Sep 17 00:00:00 2001 +From: Li Hua Qian +Date: Mon, 12 Jun 2023 16:21:36 +0800 +Subject: [PATCH 41/69] arm64: dts: ti: Add reserved memory for watchdog + +This patch adds a reserved memory for the TI AM65X platform watchdog to +reserve the specific info, triggering the watchdog reset in last boot, +to know if the board reboot is due to a watchdog reset. + +Signed-off-by: Li Hua Qian +[Taken from https://lore.kernel.org/linux-watchdog/20230718021007.1338761-3-huaqian.li@siemens.com/] +--- + arch/arm64/boot/dts/ti/k3-am65-iot2050-common.dtsi | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/arch/arm64/boot/dts/ti/k3-am65-iot2050-common.dtsi b/arch/arm64/boot/dts/ti/k3-am65-iot2050-common.dtsi +index 180bfb2a9ddf..46e7cc73b972 100644 +--- a/arch/arm64/boot/dts/ti/k3-am65-iot2050-common.dtsi ++++ b/arch/arm64/boot/dts/ti/k3-am65-iot2050-common.dtsi +@@ -64,6 +64,12 @@ rtos_ipc_memory_region: ipc-memories@a2000000 { + alignment = <0x1000>; + no-map; + }; ++ ++ /* To reserve the power-on(PON) reason for watchdog reset */ ++ wdt_reset_memory_region: wdt-memory@a2200000 { ++ reg = <0x00 0xa2200000 0x00 0x1000>; ++ no-map; ++ }; + }; + + leds { +@@ -772,6 +778,10 @@ &mcu_r5fss0_core1 { + mboxes = <&mailbox0_cluster1 &mbox_mcu_r5fss0_core1>; + }; + ++&mcu_rti1 { ++ memory-region = <&wdt_reset_memory_region>; ++}; ++ + &icssg0_mdio { + status = "disabled"; + }; +-- +2.42.0 + diff --git a/recipes-kernel/linux/files/patches-6.1/0042-arm64-dts-ti-k3-am65-main-Add-ICSSG-IEP-nodes.patch b/recipes-kernel/linux/files/patches-6.1/0042-arm64-dts-ti-k3-am65-main-Add-ICSSG-IEP-nodes.patch new file mode 100644 index 000000000..5ca9d2c23 --- /dev/null +++ b/recipes-kernel/linux/files/patches-6.1/0042-arm64-dts-ti-k3-am65-main-Add-ICSSG-IEP-nodes.patch @@ -0,0 +1,81 @@ +From 22be52e12f44b60f931d8214d67297444d2cd1fb Mon Sep 17 00:00:00 2001 +From: MD Danish Anwar +Date: Fri, 13 Oct 2023 16:31:48 +0530 +Subject: [PATCH 42/69] arm64: dts: ti: k3-am65-main: Add ICSSG IEP nodes + +The ICSSG IP on AM65x SoCs have two Industrial Ethernet Peripherals (IEPs) +to manage/generate Industrial Ethernet functions such as time stamping. +Each IEP sub-module is sourced from an internal clock mux that can be +sourced from either of the IP instance's ICSSG_IEP_GCLK or ICSSG_ICLK. +Add the IEP nodes for all the ICSSG instances. + +Signed-off-by: MD Danish Anwar +[Taken from https://lore.kernel.org/all/20231013110150.4142508-1-danishanwar@ti.com/] +--- + arch/arm64/boot/dts/ti/k3-am65-main.dtsi | 36 ++++++++++++++++++++++++ + 1 file changed, 36 insertions(+) + +diff --git a/arch/arm64/boot/dts/ti/k3-am65-main.dtsi b/arch/arm64/boot/dts/ti/k3-am65-main.dtsi +index ebb1c5ce7aec..a3edfec481ce 100644 +--- a/arch/arm64/boot/dts/ti/k3-am65-main.dtsi ++++ b/arch/arm64/boot/dts/ti/k3-am65-main.dtsi +@@ -967,6 +967,18 @@ icssg0_iepclk_mux: iepclk-mux@30 { + }; + }; + ++ icssg0_iep0: iep@2e000 { ++ compatible = "ti,am654-icss-iep"; ++ reg = <0x2e000 0x1000>; ++ clocks = <&icssg0_iepclk_mux>; ++ }; ++ ++ icssg0_iep1: iep@2f000 { ++ compatible = "ti,am654-icss-iep"; ++ reg = <0x2f000 0x1000>; ++ clocks = <&icssg0_iepclk_mux>; ++ }; ++ + icssg0_mii_rt: mii-rt@32000 { + compatible = "ti,pruss-mii", "syscon"; + reg = <0x32000 0x100>; +@@ -1108,6 +1120,18 @@ icssg1_iepclk_mux: iepclk-mux@30 { + }; + }; + ++ icssg1_iep0: iep@2e000 { ++ compatible = "ti,am654-icss-iep"; ++ reg = <0x2e000 0x1000>; ++ clocks = <&icssg1_iepclk_mux>; ++ }; ++ ++ icssg1_iep1: iep@2f000 { ++ compatible = "ti,am654-icss-iep"; ++ reg = <0x2f000 0x1000>; ++ clocks = <&icssg1_iepclk_mux>; ++ }; ++ + icssg1_mii_rt: mii-rt@32000 { + compatible = "ti,pruss-mii", "syscon"; + reg = <0x32000 0x100>; +@@ -1249,6 +1273,18 @@ icssg2_iepclk_mux: iepclk-mux@30 { + }; + }; + ++ icssg2_iep0: iep@2e000 { ++ compatible = "ti,am654-icss-iep"; ++ reg = <0x2e000 0x1000>; ++ clocks = <&icssg2_iepclk_mux>; ++ }; ++ ++ icssg2_iep1: iep@2f000 { ++ compatible = "ti,am654-icss-iep"; ++ reg = <0x2f000 0x1000>; ++ clocks = <&icssg2_iepclk_mux>; ++ }; ++ + icssg2_mii_rt: mii-rt@32000 { + compatible = "ti,pruss-mii", "syscon"; + reg = <0x32000 0x100>; +-- +2.42.0 + diff --git a/recipes-kernel/linux/files/patches-6.1/0043-irqchip-irq-pruss-intc-Fix-enabling-of-intc-events.patch b/recipes-kernel/linux/files/patches-6.1/0043-irqchip-irq-pruss-intc-Fix-enabling-of-intc-events.patch new file mode 100644 index 000000000..861019e0d --- /dev/null +++ b/recipes-kernel/linux/files/patches-6.1/0043-irqchip-irq-pruss-intc-Fix-enabling-of-intc-events.patch @@ -0,0 +1,131 @@ +From 82d2ee0f48f260574b03c9091192fefea4ff8788 Mon Sep 17 00:00:00 2001 +From: Suman Anna +Date: Tue, 19 Sep 2023 11:48:58 +0530 +Subject: [PATCH 43/69] irqchip/irq-pruss-intc: Fix enabling of intc events + +PRUSS INTC events are enabled by default once IRQ events are mapped to +channel:host pair. This may cause issues with undesirable IRQs triggering +even before a PRU IRQ is requested which are silently processed by +pruss_intc_irq_handler(). + +Fix it by masking all events by default except those which are routed to +various PRU cores (Host IRQs 0, 1; 10 through 19 on K3 SoCs), and any +other reserved IRQs routed to other processors. The unmasking of IRQs is +the responsibility of Linux IRQ core when IRQ is actually requested. + +Fixes: 04e2d1e06978 ("irqchip/irq-pruss-intc: Add a PRUSS irqchip driver for PRUSS interrupts") + +Signed-off-by: Grygorii Strashko +Signed-off-by: Suman Anna +Signed-off-by: MD Danish Anwar +[Taken from https://lore.kernel.org/all/20230919061900.369300-1-danishanwar@ti.com/] +--- + drivers/irqchip/irq-pruss-intc.c | 24 ++++++++++++++++++------ + 1 file changed, 18 insertions(+), 6 deletions(-) + +diff --git a/drivers/irqchip/irq-pruss-intc.c b/drivers/irqchip/irq-pruss-intc.c +index fa8d89b02ec0..58f835c2ffa4 100644 +--- a/drivers/irqchip/irq-pruss-intc.c ++++ b/drivers/irqchip/irq-pruss-intc.c +@@ -101,6 +101,7 @@ struct pruss_intc_match_data { + * @soc_config: cached PRUSS INTC IP configuration data + * @dev: PRUSS INTC device pointer + * @lock: mutex to serialize interrupts mapping ++ * @irqs_reserved: bit-mask of reserved host interrupts + */ + struct pruss_intc { + struct pruss_intc_map_record event_channel[MAX_PRU_SYS_EVENTS]; +@@ -111,6 +112,7 @@ struct pruss_intc { + const struct pruss_intc_match_data *soc_config; + struct device *dev; + struct mutex lock; /* PRUSS INTC lock */ ++ u8 irqs_reserved; + }; + + /** +@@ -178,6 +180,7 @@ static void pruss_intc_update_hmr(struct pruss_intc *intc, u8 ch, u8 host) + static void pruss_intc_map(struct pruss_intc *intc, unsigned long hwirq) + { + struct device *dev = intc->dev; ++ bool enable_hwirq = false; + u8 ch, host, reg_idx; + u32 val; + +@@ -187,6 +190,9 @@ static void pruss_intc_map(struct pruss_intc *intc, unsigned long hwirq) + + ch = intc->event_channel[hwirq].value; + host = intc->channel_host[ch].value; ++ enable_hwirq = (host < FIRST_PRU_HOST_INT || ++ host >= FIRST_PRU_HOST_INT + MAX_NUM_HOST_IRQS || ++ intc->irqs_reserved & BIT(host - FIRST_PRU_HOST_INT)); + + pruss_intc_update_cmr(intc, hwirq, ch); + +@@ -194,8 +200,10 @@ static void pruss_intc_map(struct pruss_intc *intc, unsigned long hwirq) + val = BIT(hwirq % 32); + + /* clear and enable system event */ +- pruss_intc_write_reg(intc, PRU_INTC_ESR(reg_idx), val); + pruss_intc_write_reg(intc, PRU_INTC_SECR(reg_idx), val); ++ /* unmask only events going to various PRU and other cores by default */ ++ if (enable_hwirq) ++ pruss_intc_write_reg(intc, PRU_INTC_ESR(reg_idx), val); + + if (++intc->channel_host[ch].ref_count == 1) { + pruss_intc_update_hmr(intc, ch, host); +@@ -204,7 +212,8 @@ static void pruss_intc_map(struct pruss_intc *intc, unsigned long hwirq) + pruss_intc_write_reg(intc, PRU_INTC_HIEISR, host); + } + +- dev_dbg(dev, "mapped system_event = %lu channel = %d host = %d", ++ dev_dbg(dev, "mapped%s system_event = %lu channel = %d host = %d", ++ enable_hwirq ? " and enabled" : "", + hwirq, ch, host); + + mutex_unlock(&intc->lock); +@@ -268,11 +277,14 @@ static void pruss_intc_init(struct pruss_intc *intc) + + /* + * configure polarity (SIPR register) to active high and +- * type (SITR register) to level interrupt for all system events ++ * type (SITR register) to level interrupt for all system events, ++ * and disable and clear all the system events + */ + for (i = 0; i < num_event_type_regs; i++) { + pruss_intc_write_reg(intc, PRU_INTC_SIPR(i), 0xffffffff); + pruss_intc_write_reg(intc, PRU_INTC_SITR(i), 0); ++ pruss_intc_write_reg(intc, PRU_INTC_ECR(i), 0xffffffff); ++ pruss_intc_write_reg(intc, PRU_INTC_SECR(i), 0xffffffff); + } + + /* clear all interrupt channel map registers, 4 events per register */ +@@ -521,7 +533,7 @@ static int pruss_intc_probe(struct platform_device *pdev) + struct pruss_intc *intc; + struct pruss_host_irq_data *host_data; + int i, irq, ret; +- u8 max_system_events, irqs_reserved = 0; ++ u8 max_system_events; + + data = of_device_get_match_data(dev); + if (!data) +@@ -542,7 +554,7 @@ static int pruss_intc_probe(struct platform_device *pdev) + return PTR_ERR(intc->base); + + ret = of_property_read_u8(dev->of_node, "ti,irqs-reserved", +- &irqs_reserved); ++ &intc->irqs_reserved); + + /* + * The irqs-reserved is used only for some SoC's therefore not having +@@ -561,7 +573,7 @@ static int pruss_intc_probe(struct platform_device *pdev) + return -ENOMEM; + + for (i = 0; i < MAX_NUM_HOST_IRQS; i++) { +- if (irqs_reserved & BIT(i)) ++ if (intc->irqs_reserved & BIT(i)) + continue; + + irq = platform_get_irq_byname(pdev, irq_names[i]); +-- +2.42.0 + diff --git a/recipes-kernel/linux/files/patches-6.1/0044-irqchip-irq-pruss-intc-Fix-listed-IRQ-type-in-proc-i.patch b/recipes-kernel/linux/files/patches-6.1/0044-irqchip-irq-pruss-intc-Fix-listed-IRQ-type-in-proc-i.patch new file mode 100644 index 000000000..ceee11c44 --- /dev/null +++ b/recipes-kernel/linux/files/patches-6.1/0044-irqchip-irq-pruss-intc-Fix-listed-IRQ-type-in-proc-i.patch @@ -0,0 +1,57 @@ +From 0589c82907a60a77d4a908e0d651a332bb9a9f90 Mon Sep 17 00:00:00 2001 +From: Grygorii Strashko +Date: Tue, 19 Sep 2023 11:48:59 +0530 +Subject: [PATCH 44/69] irqchip/irq-pruss-intc: Fix listed IRQ type in + /proc/interrupts + +The PRUSS INTC driver doesn't have .irq_set_type() callback implemented and +supports only IRQ_TYPE_LEVEL_HIGH. This resulted in the IRQ properties not +being updated properly and the PRUSS INTC IRQs were listed incorrectly in +/proc/interrupts as Edge. + +Example: + 218: 0 4b220000.interrupt-controller 26 Edge pru10 + +Fix this by adding a simple .irq_set_type() implementation which checks the +requested IRQ triggering type. + +Fixes: 04e2d1e06978 ("irqchip/irq-pruss-intc: Add a PRUSS irqchip driver for PRUSS interrupts") + +Signed-off-by: Grygorii Strashko +Signed-off-by: Suman Anna +Signed-off-by: MD Danish Anwar +[Taken from https://lore.kernel.org/all/20230919061900.369300-1-danishanwar@ti.com/] +--- + drivers/irqchip/irq-pruss-intc.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/drivers/irqchip/irq-pruss-intc.c b/drivers/irqchip/irq-pruss-intc.c +index 58f835c2ffa4..fbf570c374da 100644 +--- a/drivers/irqchip/irq-pruss-intc.c ++++ b/drivers/irqchip/irq-pruss-intc.c +@@ -373,6 +373,14 @@ static int pruss_intc_irq_set_irqchip_state(struct irq_data *data, + return 0; + } + ++static int pruss_intc_irq_irq_set_type(struct irq_data *data, unsigned int type) ++{ ++ if (type != IRQ_TYPE_LEVEL_HIGH) ++ return -EINVAL; ++ ++ return 0; ++} ++ + static struct irq_chip pruss_irqchip = { + .name = "pruss-intc", + .irq_ack = pruss_intc_irq_ack, +@@ -382,6 +390,7 @@ static struct irq_chip pruss_irqchip = { + .irq_release_resources = pruss_intc_irq_relres, + .irq_get_irqchip_state = pruss_intc_irq_get_irqchip_state, + .irq_set_irqchip_state = pruss_intc_irq_set_irqchip_state, ++ .irq_set_type = pruss_intc_irq_irq_set_type, + }; + + static int pruss_intc_validate_mapping(struct pruss_intc *intc, int event, +-- +2.42.0 + diff --git a/recipes-kernel/linux/files/patches-6.1/0045-irqchip-irq-pruss-intc-Fix-processing-of-IEP-interru.patch b/recipes-kernel/linux/files/patches-6.1/0045-irqchip-irq-pruss-intc-Fix-processing-of-IEP-interru.patch new file mode 100644 index 000000000..15a5b97b6 --- /dev/null +++ b/recipes-kernel/linux/files/patches-6.1/0045-irqchip-irq-pruss-intc-Fix-processing-of-IEP-interru.patch @@ -0,0 +1,103 @@ +From 418d5affa3785e3ac9d6294c33c9b72f65f1d1bc Mon Sep 17 00:00:00 2001 +From: Suman Anna +Date: Tue, 19 Sep 2023 11:49:00 +0530 +Subject: [PATCH 45/69] irqchip/irq-pruss-intc: Fix processing of IEP + interrupts + +It was discovered that IEP capture/compare IRQs (event #7 on all SoCs +and event #56 on K3 SoCs) are always triggered twice when PPS is +generated and CMP hit event detected by IEP. + +An example of the problem is: + pruss_intc_irq_handler + generic_handle_irq + handle_level_irq + mask_ack_irq -> IRQ 7 masked and asked in INTC, + but it's not yet cleared on HW level + handle_irq_event() + + icss_iep_cap_cmp_handler() -> IRQ 7 is actually processed in HW + irq_finalize_oneshot() + unmask_irq() + pruss_intc_irq_unmask() -> IRQ 7 status is still observed as set + +The solution is to actually ack these IRQs from pruss_intc_irq_unmask() +after the IRQ source is cleared in HW. + +No public errata available for this yet. + +Fixes: 04e2d1e06978 ("irqchip/irq-pruss-intc: Add a PRUSS irqchip driver for PRUSS interrupts") + +Signed-off-by: Grygorii Strashko +Signed-off-by: Suman Anna +Signed-off-by: MD Danish Anwar +[Taken from https://lore.kernel.org/all/20230919061900.369300-1-danishanwar@ti.com/] +--- + drivers/irqchip/irq-pruss-intc.c | 14 ++++++++++++++ + 1 file changed, 14 insertions(+) + +diff --git a/drivers/irqchip/irq-pruss-intc.c b/drivers/irqchip/irq-pruss-intc.c +index fbf570c374da..61c5604921d5 100644 +--- a/drivers/irqchip/irq-pruss-intc.c ++++ b/drivers/irqchip/irq-pruss-intc.c +@@ -70,6 +70,8 @@ + #define MAX_PRU_SYS_EVENTS 160 + #define MAX_PRU_CHANNELS 20 + ++#define MAX_PRU_INT_EVENTS 64 ++ + /** + * struct pruss_intc_map_record - keeps track of actual mapping state + * @value: The currently mapped value (channel or host) +@@ -85,10 +87,13 @@ struct pruss_intc_map_record { + * @num_system_events: number of input system events handled by the PRUSS INTC + * @num_host_events: number of host events (which is equal to number of + * channels) supported by the PRUSS INTC ++ * @quirky_events: bitmask of events that need quirky IRQ handling (limited to ++ * (internal sources only for now, so 64 bits suffice) + */ + struct pruss_intc_match_data { + u8 num_system_events; + u8 num_host_events; ++ u64 quirky_events; + }; + + /** +@@ -304,6 +309,10 @@ static void pruss_intc_irq_ack(struct irq_data *data) + struct pruss_intc *intc = irq_data_get_irq_chip_data(data); + unsigned int hwirq = data->hwirq; + ++ if (hwirq < MAX_PRU_INT_EVENTS && ++ intc->soc_config->quirky_events & BIT_ULL(hwirq)) ++ return; ++ + pruss_intc_write_reg(intc, PRU_INTC_SICR, hwirq); + } + +@@ -320,6 +329,9 @@ static void pruss_intc_irq_unmask(struct irq_data *data) + struct pruss_intc *intc = irq_data_get_irq_chip_data(data); + unsigned int hwirq = data->hwirq; + ++ if (hwirq < MAX_PRU_INT_EVENTS && ++ intc->soc_config->quirky_events & BIT_ULL(hwirq)) ++ pruss_intc_write_reg(intc, PRU_INTC_SICR, hwirq); + pruss_intc_write_reg(intc, PRU_INTC_EISR, hwirq); + } + +@@ -644,11 +656,13 @@ static int pruss_intc_remove(struct platform_device *pdev) + static const struct pruss_intc_match_data pruss_intc_data = { + .num_system_events = 64, + .num_host_events = 10, ++ .quirky_events = BIT_ULL(7), /* IEP capture/compare event */ + }; + + static const struct pruss_intc_match_data icssg_intc_data = { + .num_system_events = 160, + .num_host_events = 20, ++ .quirky_events = BIT_ULL(7) | BIT_ULL(56), /* IEP{0,1} capture/compare events */ + }; + + static const struct of_device_id pruss_intc_of_match[] = { +-- +2.42.0 + diff --git a/recipes-kernel/linux/files/patches-6.1/0046-arm64-dts-ti-k3-am65-main-Add-PRU-system-events-for-.patch b/recipes-kernel/linux/files/patches-6.1/0046-arm64-dts-ti-k3-am65-main-Add-PRU-system-events-for-.patch new file mode 100644 index 000000000..4bfafd48f --- /dev/null +++ b/recipes-kernel/linux/files/patches-6.1/0046-arm64-dts-ti-k3-am65-main-Add-PRU-system-events-for-.patch @@ -0,0 +1,159 @@ +From e42182b41c1f3a14aa2a825b72159e5e952db125 Mon Sep 17 00:00:00 2001 +From: Suman Anna +Date: Mon, 7 Aug 2023 16:48:54 +0530 +Subject: [PATCH 46/69] arm64: dts: ti: k3-am65-main: Add PRU system events for + virtio + +A PRU system event "vring" has been added to each PRU and RTU +node in each of the ICSSG0, ICSSG1 and ICSSG2 remote processor +subsystems to enable the virtio/rpmsg communication between MPU +and that PRU/RTU core. The additions are done in the base +k3-am65-main.dtsi, and so are inherited by all the K3 AM65x +boards. + +The PRU system events is the preferred approach over using TI +mailboxes, as it eliminates an external peripheral access from +the PRU/RTU-side, and keeps the interrupt generation internal to +the ICSSG. The difference from MPU would be minimal in using one +versus the other. + +Mailboxes can still be used if desired, but currently there is +no support on firmware-side for K3 SoCs to use mailboxes. Either +approach would require that an appropriate firmware image is +loaded/booted on the PRU. + +Signed-off-by: Suman Anna +Signed-off-by: Kishon Vijay Abraham I +Signed-off-by: MD Danish Anwar +[Taken from https://lore.kernel.org/all/20230807111855.2614761-1-danishanwar@ti.com/] +--- + arch/arm64/boot/dts/ti/k3-am65-main.dtsi | 36 ++++++++++++++++++++++++ + 1 file changed, 36 insertions(+) + +diff --git a/arch/arm64/boot/dts/ti/k3-am65-main.dtsi b/arch/arm64/boot/dts/ti/k3-am65-main.dtsi +index a3edfec481ce..5d862f4f45cf 100644 +--- a/arch/arm64/boot/dts/ti/k3-am65-main.dtsi ++++ b/arch/arm64/boot/dts/ti/k3-am65-main.dtsi +@@ -1015,6 +1015,9 @@ pru0_0: pru@34000 { + <0x22400 0x100>; + reg-names = "iram", "control", "debug"; + firmware-name = "am65x-pru0_0-fw"; ++ interrupt-parent = <&icssg0_intc>; ++ interrupts = <16 2 2>; ++ interrupt-names = "vring"; + }; + + rtu0_0: rtu@4000 { +@@ -1024,6 +1027,9 @@ rtu0_0: rtu@4000 { + <0x23400 0x100>; + reg-names = "iram", "control", "debug"; + firmware-name = "am65x-rtu0_0-fw"; ++ interrupt-parent = <&icssg0_intc>; ++ interrupts = <20 4 4>; ++ interrupt-names = "vring"; + }; + + tx_pru0_0: txpru@a000 { +@@ -1042,6 +1048,9 @@ pru0_1: pru@38000 { + <0x24400 0x100>; + reg-names = "iram", "control", "debug"; + firmware-name = "am65x-pru0_1-fw"; ++ interrupt-parent = <&icssg0_intc>; ++ interrupts = <18 3 3>; ++ interrupt-names = "vring"; + }; + + rtu0_1: rtu@6000 { +@@ -1051,6 +1060,9 @@ rtu0_1: rtu@6000 { + <0x23c00 0x100>; + reg-names = "iram", "control", "debug"; + firmware-name = "am65x-rtu0_1-fw"; ++ interrupt-parent = <&icssg0_intc>; ++ interrupts = <22 5 5>; ++ interrupt-names = "vring"; + }; + + tx_pru0_1: txpru@c000 { +@@ -1168,6 +1180,9 @@ pru1_0: pru@34000 { + <0x22400 0x100>; + reg-names = "iram", "control", "debug"; + firmware-name = "am65x-pru1_0-fw"; ++ interrupt-parent = <&icssg1_intc>; ++ interrupts = <16 2 2>; ++ interrupt-names = "vring"; + }; + + rtu1_0: rtu@4000 { +@@ -1177,6 +1192,9 @@ rtu1_0: rtu@4000 { + <0x23400 0x100>; + reg-names = "iram", "control", "debug"; + firmware-name = "am65x-rtu1_0-fw"; ++ interrupt-parent = <&icssg1_intc>; ++ interrupts = <20 4 4>; ++ interrupt-names = "vring"; + }; + + tx_pru1_0: txpru@a000 { +@@ -1195,6 +1213,9 @@ pru1_1: pru@38000 { + <0x24400 0x100>; + reg-names = "iram", "control", "debug"; + firmware-name = "am65x-pru1_1-fw"; ++ interrupt-parent = <&icssg1_intc>; ++ interrupts = <18 3 3>; ++ interrupt-names = "vring"; + }; + + rtu1_1: rtu@6000 { +@@ -1204,6 +1225,9 @@ rtu1_1: rtu@6000 { + <0x23c00 0x100>; + reg-names = "iram", "control", "debug"; + firmware-name = "am65x-rtu1_1-fw"; ++ interrupt-parent = <&icssg1_intc>; ++ interrupts = <22 5 5>; ++ interrupt-names = "vring"; + }; + + tx_pru1_1: txpru@c000 { +@@ -1321,6 +1345,9 @@ pru2_0: pru@34000 { + <0x22400 0x100>; + reg-names = "iram", "control", "debug"; + firmware-name = "am65x-pru2_0-fw"; ++ interrupt-parent = <&icssg2_intc>; ++ interrupts = <16 2 2>; ++ interrupt-names = "vring"; + }; + + rtu2_0: rtu@4000 { +@@ -1330,6 +1357,9 @@ rtu2_0: rtu@4000 { + <0x23400 0x100>; + reg-names = "iram", "control", "debug"; + firmware-name = "am65x-rtu2_0-fw"; ++ interrupt-parent = <&icssg2_intc>; ++ interrupts = <20 4 4>; ++ interrupt-names = "vring"; + }; + + tx_pru2_0: txpru@a000 { +@@ -1348,6 +1378,9 @@ pru2_1: pru@38000 { + <0x24400 0x100>; + reg-names = "iram", "control", "debug"; + firmware-name = "am65x-pru2_1-fw"; ++ interrupt-parent = <&icssg2_intc>; ++ interrupts = <18 3 3>; ++ interrupt-names = "vring"; + }; + + rtu2_1: rtu@6000 { +@@ -1357,6 +1390,9 @@ rtu2_1: rtu@6000 { + <0x23c00 0x100>; + reg-names = "iram", "control", "debug"; + firmware-name = "am65x-rtu2_1-fw"; ++ interrupt-parent = <&icssg2_intc>; ++ interrupts = <22 5 5>; ++ interrupt-names = "vring"; + }; + + tx_pru2_1: txpru@c000 { +-- +2.42.0 + diff --git a/recipes-kernel/linux/files/patches-6.1/0047-dmaengine-ti-k3-udma-glue-do-not-create-glue-dma-dev.patch b/recipes-kernel/linux/files/patches-6.1/0047-dmaengine-ti-k3-udma-glue-do-not-create-glue-dma-dev.patch new file mode 100644 index 000000000..018f4e1ef --- /dev/null +++ b/recipes-kernel/linux/files/patches-6.1/0047-dmaengine-ti-k3-udma-glue-do-not-create-glue-dma-dev.patch @@ -0,0 +1,126 @@ +From ce2883f9d7959f2c92248c97121d04eea1784394 Mon Sep 17 00:00:00 2001 +From: Grygorii Strashko +Date: Wed, 5 Apr 2023 10:41:12 +0530 +Subject: [PATCH 47/69] dmaengine: ti: k3-udma-glue: do not create glue dma + devices for udma channels + +In case K3 DMA glue layer is using UDMA channels (AM65/J721E/J7200) it +doesn't need to create own DMA devices per RX/TX channels as they are never +used and just waste resources. The UDMA based platforms are coherent and +UDMA device iteslf is used for DMA memory management. + +Hence, update K3 DMA glue layer to create K3 DMA glue DMA devices per RX/TX +channels only in case of PKTDMA (AM64) where coherency configurable per DMA +channel. + +Signed-off-by: Grygorii Strashko +Signed-off-by: Siddharth Vadapalli +[Taken from https://lore.kernel.org/all/20230405051112.1364277-1-s-vadapalli@ti.com/] +--- + drivers/dma/ti/k3-udma-glue.c | 73 ++++++++++++++++++----------------- + 1 file changed, 37 insertions(+), 36 deletions(-) + +diff --git a/drivers/dma/ti/k3-udma-glue.c b/drivers/dma/ti/k3-udma-glue.c +index 4f1aeb81e9c7..3ad57ad91c91 100644 +--- a/drivers/dma/ti/k3-udma-glue.c ++++ b/drivers/dma/ti/k3-udma-glue.c +@@ -292,19 +292,19 @@ struct k3_udma_glue_tx_channel *k3_udma_glue_request_tx_chn(struct device *dev, + } + tx_chn->udma_tchan_id = xudma_tchan_get_id(tx_chn->udma_tchanx); + +- tx_chn->common.chan_dev.class = &k3_udma_glue_devclass; +- tx_chn->common.chan_dev.parent = xudma_get_device(tx_chn->common.udmax); +- dev_set_name(&tx_chn->common.chan_dev, "tchan%d-0x%04x", +- tx_chn->udma_tchan_id, tx_chn->common.dst_thread); +- ret = device_register(&tx_chn->common.chan_dev); +- if (ret) { +- dev_err(dev, "Channel Device registration failed %d\n", ret); +- put_device(&tx_chn->common.chan_dev); +- tx_chn->common.chan_dev.parent = NULL; +- goto err; +- } +- + if (xudma_is_pktdma(tx_chn->common.udmax)) { ++ tx_chn->common.chan_dev.class = &k3_udma_glue_devclass; ++ tx_chn->common.chan_dev.parent = xudma_get_device(tx_chn->common.udmax); ++ dev_set_name(&tx_chn->common.chan_dev, "tchan%d-0x%04x", ++ tx_chn->udma_tchan_id, tx_chn->common.dst_thread); ++ ret = device_register(&tx_chn->common.chan_dev); ++ if (ret) { ++ dev_err(dev, "Channel Device registration failed %d\n", ret); ++ put_device(&tx_chn->common.chan_dev); ++ tx_chn->common.chan_dev.parent = NULL; ++ goto err; ++ } ++ + /* prepare the channel device as coherent */ + tx_chn->common.chan_dev.dma_coherent = true; + dma_coerce_mask_and_coherent(&tx_chn->common.chan_dev, +@@ -911,19 +911,19 @@ k3_udma_glue_request_rx_chn_priv(struct device *dev, const char *name, + } + rx_chn->udma_rchan_id = xudma_rchan_get_id(rx_chn->udma_rchanx); + +- rx_chn->common.chan_dev.class = &k3_udma_glue_devclass; +- rx_chn->common.chan_dev.parent = xudma_get_device(rx_chn->common.udmax); +- dev_set_name(&rx_chn->common.chan_dev, "rchan%d-0x%04x", +- rx_chn->udma_rchan_id, rx_chn->common.src_thread); +- ret = device_register(&rx_chn->common.chan_dev); +- if (ret) { +- dev_err(dev, "Channel Device registration failed %d\n", ret); +- put_device(&rx_chn->common.chan_dev); +- rx_chn->common.chan_dev.parent = NULL; +- goto err; +- } +- + if (xudma_is_pktdma(rx_chn->common.udmax)) { ++ rx_chn->common.chan_dev.class = &k3_udma_glue_devclass; ++ rx_chn->common.chan_dev.parent = xudma_get_device(rx_chn->common.udmax); ++ dev_set_name(&rx_chn->common.chan_dev, "rchan%d-0x%04x", ++ rx_chn->udma_rchan_id, rx_chn->common.src_thread); ++ ret = device_register(&rx_chn->common.chan_dev); ++ if (ret) { ++ dev_err(dev, "Channel Device registration failed %d\n", ret); ++ put_device(&rx_chn->common.chan_dev); ++ rx_chn->common.chan_dev.parent = NULL; ++ goto err; ++ } ++ + /* prepare the channel device as coherent */ + rx_chn->common.chan_dev.dma_coherent = true; + dma_coerce_mask_and_coherent(&rx_chn->common.chan_dev, +@@ -1043,19 +1043,20 @@ k3_udma_glue_request_remote_rx_chn(struct device *dev, const char *name, + goto err; + } + +- rx_chn->common.chan_dev.class = &k3_udma_glue_devclass; +- rx_chn->common.chan_dev.parent = xudma_get_device(rx_chn->common.udmax); +- dev_set_name(&rx_chn->common.chan_dev, "rchan_remote-0x%04x", +- rx_chn->common.src_thread); +- ret = device_register(&rx_chn->common.chan_dev); +- if (ret) { +- dev_err(dev, "Channel Device registration failed %d\n", ret); +- put_device(&rx_chn->common.chan_dev); +- rx_chn->common.chan_dev.parent = NULL; +- goto err; +- } +- + if (xudma_is_pktdma(rx_chn->common.udmax)) { ++ rx_chn->common.chan_dev.class = &k3_udma_glue_devclass; ++ rx_chn->common.chan_dev.parent = xudma_get_device(rx_chn->common.udmax); ++ dev_set_name(&rx_chn->common.chan_dev, "rchan_remote-0x%04x", ++ rx_chn->common.src_thread); ++ ++ ret = device_register(&rx_chn->common.chan_dev); ++ if (ret) { ++ dev_err(dev, "Channel Device registration failed %d\n", ret); ++ put_device(&rx_chn->common.chan_dev); ++ rx_chn->common.chan_dev.parent = NULL; ++ goto err; ++ } ++ + /* prepare the channel device as coherent */ + rx_chn->common.chan_dev.dma_coherent = true; + dma_coerce_mask_and_coherent(&rx_chn->common.chan_dev, +-- +2.42.0 + diff --git a/recipes-kernel/linux/files/patches-6.1/0048-tee-optee-Fix-supplicant-based-device-enumeration.patch b/recipes-kernel/linux/files/patches-6.1/0048-tee-optee-Fix-supplicant-based-device-enumeration.patch new file mode 100644 index 000000000..538aaee30 --- /dev/null +++ b/recipes-kernel/linux/files/patches-6.1/0048-tee-optee-Fix-supplicant-based-device-enumeration.patch @@ -0,0 +1,131 @@ +From 5336de53abdf2dd507090e36bd1be6d4a4623ee5 Mon Sep 17 00:00:00 2001 +From: Sumit Garg +Date: Fri, 28 Jul 2023 19:18:32 +0530 +Subject: [PATCH 48/69] tee: optee: Fix supplicant based device enumeration + +Currently supplicant dependent optee device enumeration only registers +devices whenever tee-supplicant is invoked for the first time. But it +forgets to remove devices when tee-supplicant daemon stops running and +closes its context gracefully. This leads to following error for fTPM +driver during reboot/shutdown: + +[ 73.466791] tpm tpm0: ftpm_tee_tpm_op_send: SUBMIT_COMMAND invoke error: 0xffff3024 + +Fix this by separating supplicant dependent devices so that the +user-space service can detach supplicant devices before closing the +supplicant. While at it use the global system workqueue for OP-TEE bus +scanning work rather than our own custom one. + +Reported-by: Jan Kiszka +Link: https://github.com/OP-TEE/optee_os/issues/6094 +Fixes: 5f178bb71e3a ("optee: enable support for multi-stage bus enumeration") +Signed-off-by: Sumit Garg +Tested-by: Masahisa Kojima +[Taken from https://lore.kernel.org/all/20230728134832.326467-1-sumit.garg@linaro.org/] +--- + drivers/tee/optee/core.c | 13 ++----------- + drivers/tee/optee/device.c | 13 ++++++++++--- + drivers/tee/optee/optee_private.h | 2 -- + 3 files changed, 12 insertions(+), 16 deletions(-) + +diff --git a/drivers/tee/optee/core.c b/drivers/tee/optee/core.c +index daf07737c4fd..52c08055826b 100644 +--- a/drivers/tee/optee/core.c ++++ b/drivers/tee/optee/core.c +@@ -15,7 +15,6 @@ + #include + #include + #include +-#include + #include "optee_private.h" + + int optee_pool_op_alloc_helper(struct tee_shm_pool *pool, struct tee_shm *shm, +@@ -110,12 +109,7 @@ int optee_open(struct tee_context *ctx, bool cap_memref_null) + + if (!optee->scan_bus_done) { + INIT_WORK(&optee->scan_bus_work, optee_bus_scan); +- optee->scan_bus_wq = create_workqueue("optee_bus_scan"); +- if (!optee->scan_bus_wq) { +- kfree(ctxdata); +- return -ECHILD; +- } +- queue_work(optee->scan_bus_wq, &optee->scan_bus_work); ++ schedule_work(&optee->scan_bus_work); + optee->scan_bus_done = true; + } + } +@@ -158,10 +152,7 @@ void optee_release_supp(struct tee_context *ctx) + struct optee *optee = tee_get_drvdata(ctx->teedev); + + optee_release_helper(ctx, optee_close_session_helper); +- if (optee->scan_bus_wq) { +- destroy_workqueue(optee->scan_bus_wq); +- optee->scan_bus_wq = NULL; +- } ++ + optee_supp_release(&optee->supp); + } + +diff --git a/drivers/tee/optee/device.c b/drivers/tee/optee/device.c +index 64f0e047c23d..78fc0a15c463 100644 +--- a/drivers/tee/optee/device.c ++++ b/drivers/tee/optee/device.c +@@ -60,9 +60,10 @@ static void optee_release_device(struct device *dev) + kfree(optee_device); + } + +-static int optee_register_device(const uuid_t *device_uuid) ++static int optee_register_device(const uuid_t *device_uuid, u32 func) + { + struct tee_client_device *optee_device = NULL; ++ const char *dev_name_fmt = NULL; + int rc; + + optee_device = kzalloc(sizeof(*optee_device), GFP_KERNEL); +@@ -71,7 +72,13 @@ static int optee_register_device(const uuid_t *device_uuid) + + optee_device->dev.bus = &tee_bus_type; + optee_device->dev.release = optee_release_device; +- if (dev_set_name(&optee_device->dev, "optee-ta-%pUb", device_uuid)) { ++ ++ if (func == PTA_CMD_GET_DEVICES_SUPP) ++ dev_name_fmt = "optee-ta-supp-%pUb"; ++ else ++ dev_name_fmt = "optee-ta-%pUb"; ++ ++ if (dev_set_name(&optee_device->dev, dev_name_fmt, device_uuid)) { + kfree(optee_device); + return -ENOMEM; + } +@@ -142,7 +149,7 @@ static int __optee_enumerate_devices(u32 func) + num_devices = shm_size / sizeof(uuid_t); + + for (idx = 0; idx < num_devices; idx++) { +- rc = optee_register_device(&device_uuid[idx]); ++ rc = optee_register_device(&device_uuid[idx], func); + if (rc) + goto out_shm; + } +diff --git a/drivers/tee/optee/optee_private.h b/drivers/tee/optee/optee_private.h +index 04ae58892608..7e9b3e7cd26b 100644 +--- a/drivers/tee/optee/optee_private.h ++++ b/drivers/tee/optee/optee_private.h +@@ -154,7 +154,6 @@ struct optee_ops { + * @pool: shared memory pool + * @rpc_param_count: If > 0 number of RPC parameters to make room for + * @scan_bus_done flag if device registation was already done. +- * @scan_bus_wq workqueue to scan optee bus and register optee drivers + * @scan_bus_work workq to scan optee bus and register optee drivers + */ + struct optee { +@@ -173,7 +172,6 @@ struct optee { + struct tee_shm_pool *pool; + unsigned int rpc_param_count; + bool scan_bus_done; +- struct workqueue_struct *scan_bus_wq; + struct work_struct scan_bus_work; + }; + +-- +2.42.0 + diff --git a/recipes-kernel/linux/files/patches-6.1/0049-efivarfs-expose-used-and-total-size.patch b/recipes-kernel/linux/files/patches-6.1/0049-efivarfs-expose-used-and-total-size.patch new file mode 100644 index 000000000..97d42ad77 --- /dev/null +++ b/recipes-kernel/linux/files/patches-6.1/0049-efivarfs-expose-used-and-total-size.patch @@ -0,0 +1,183 @@ +From 9cc9f3feaf4746fc49ed2c21f354140f5774ae23 Mon Sep 17 00:00:00 2001 +From: Anisse Astier +Date: Wed, 17 May 2023 17:38:12 +0200 +Subject: [PATCH 49/69] efivarfs: expose used and total size + +When writing EFI variables, one might get errors with no other message +on why it fails. Being able to see how much is used by EFI variables +helps analyzing such issues. + +Since this is not a conventional filesystem, block size is intentionally +set to 1 instead of PAGE_SIZE. + +x86 quirks of reserved size are taken into account; so that available +and free size can be different, further helping debugging space issues. + +With this patch, one can see the remaining space in EFI variable storage +via efivarfs, like this: + + $ df -h /sys/firmware/efi/efivars/ + Filesystem Size Used Avail Use% Mounted on + efivarfs 176K 106K 66K 62% /sys/firmware/efi/efivars + +Signed-off-by: Anisse Astier +[ardb: - rename efi_reserved_space() to efivar_reserved_space() + - whitespace/coding style tweaks] +Signed-off-by: Ard Biesheuvel +[Commit d86ff3333cb1 upstream] +--- + arch/x86/platform/efi/quirks.c | 8 +++++++ + drivers/firmware/efi/efi.c | 1 + + drivers/firmware/efi/vars.c | 12 +++++++++++ + fs/efivarfs/super.c | 39 +++++++++++++++++++++++++++++++++- + include/linux/efi.h | 11 ++++++++++ + 5 files changed, 70 insertions(+), 1 deletion(-) + +diff --git a/arch/x86/platform/efi/quirks.c b/arch/x86/platform/efi/quirks.c +index b0b848d6933a..f0cc00032751 100644 +--- a/arch/x86/platform/efi/quirks.c ++++ b/arch/x86/platform/efi/quirks.c +@@ -114,6 +114,14 @@ void efi_delete_dummy_variable(void) + EFI_VARIABLE_RUNTIME_ACCESS, 0, NULL); + } + ++u64 efivar_reserved_space(void) ++{ ++ if (efi_no_storage_paranoia) ++ return 0; ++ return EFI_MIN_RESERVE; ++} ++EXPORT_SYMBOL_GPL(efivar_reserved_space); ++ + /* + * In the nonblocking case we do not attempt to perform garbage + * collection if we do not have enough free space. Rather, we do the +diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c +index b43e5e6ddaf6..db3c0ce08e44 100644 +--- a/drivers/firmware/efi/efi.c ++++ b/drivers/firmware/efi/efi.c +@@ -190,6 +190,7 @@ static int generic_ops_register(void) + generic_ops.get_variable = efi.get_variable; + generic_ops.get_next_variable = efi.get_next_variable; + generic_ops.query_variable_store = efi_query_variable_store; ++ generic_ops.query_variable_info = efi.query_variable_info; + + if (efi_rt_services_supported(EFI_RT_SUPPORTED_SET_VARIABLE)) { + generic_ops.set_variable = efi.set_variable; +diff --git a/drivers/firmware/efi/vars.c b/drivers/firmware/efi/vars.c +index 0ba9f18312f5..de36d4e4bd95 100644 +--- a/drivers/firmware/efi/vars.c ++++ b/drivers/firmware/efi/vars.c +@@ -241,3 +241,15 @@ efi_status_t efivar_set_variable(efi_char16_t *name, efi_guid_t *vendor, + return status; + } + EXPORT_SYMBOL_NS_GPL(efivar_set_variable, EFIVAR); ++ ++efi_status_t efivar_query_variable_info(u32 attr, ++ u64 *storage_space, ++ u64 *remaining_space, ++ u64 *max_variable_size) ++{ ++ if (!__efivars->ops->query_variable_info) ++ return EFI_UNSUPPORTED; ++ return __efivars->ops->query_variable_info(attr, storage_space, ++ remaining_space, max_variable_size); ++} ++EXPORT_SYMBOL_NS_GPL(efivar_query_variable_info, EFIVAR); +diff --git a/fs/efivarfs/super.c b/fs/efivarfs/super.c +index 6780fc81cc11..0994446a3544 100644 +--- a/fs/efivarfs/super.c ++++ b/fs/efivarfs/super.c +@@ -13,6 +13,7 @@ + #include + #include + #include ++#include + + #include "internal.h" + +@@ -23,8 +24,44 @@ static void efivarfs_evict_inode(struct inode *inode) + clear_inode(inode); + } + ++static int efivarfs_statfs(struct dentry *dentry, struct kstatfs *buf) ++{ ++ const u32 attr = EFI_VARIABLE_NON_VOLATILE | ++ EFI_VARIABLE_BOOTSERVICE_ACCESS | ++ EFI_VARIABLE_RUNTIME_ACCESS; ++ u64 storage_space, remaining_space, max_variable_size; ++ efi_status_t status; ++ ++ status = efivar_query_variable_info(attr, &storage_space, &remaining_space, ++ &max_variable_size); ++ if (status != EFI_SUCCESS) ++ return efi_status_to_err(status); ++ ++ /* ++ * This is not a normal filesystem, so no point in pretending it has a block ++ * size; we declare f_bsize to 1, so that we can then report the exact value ++ * sent by EFI QueryVariableInfo in f_blocks and f_bfree ++ */ ++ buf->f_bsize = 1; ++ buf->f_namelen = NAME_MAX; ++ buf->f_blocks = storage_space; ++ buf->f_bfree = remaining_space; ++ buf->f_type = dentry->d_sb->s_magic; ++ ++ /* ++ * In f_bavail we declare the free space that the kernel will allow writing ++ * when the storage_paranoia x86 quirk is active. To use more, users ++ * should boot the kernel with efi_no_storage_paranoia. ++ */ ++ if (remaining_space > efivar_reserved_space()) ++ buf->f_bavail = remaining_space - efivar_reserved_space(); ++ else ++ buf->f_bavail = 0; ++ ++ return 0; ++} + static const struct super_operations efivarfs_ops = { +- .statfs = simple_statfs, ++ .statfs = efivarfs_statfs, + .drop_inode = generic_delete_inode, + .evict_inode = efivarfs_evict_inode, + }; +diff --git a/include/linux/efi.h b/include/linux/efi.h +index 4e1bfee9675d..b8cd4db7a1bf 100644 +--- a/include/linux/efi.h ++++ b/include/linux/efi.h +@@ -1045,6 +1045,7 @@ struct efivar_operations { + efi_set_variable_t *set_variable; + efi_set_variable_t *set_variable_nonblocking; + efi_query_variable_store_t *query_variable_store; ++ efi_query_variable_info_t *query_variable_info; + }; + + struct efivars { +@@ -1053,6 +1054,12 @@ struct efivars { + const struct efivar_operations *ops; + }; + ++#ifdef CONFIG_X86 ++u64 __attribute_const__ efivar_reserved_space(void); ++#else ++static inline u64 efivar_reserved_space(void) { return 0; } ++#endif ++ + /* + * The maximum size of VariableName + Data = 1024 + * Therefore, it's reasonable to save that much +@@ -1087,6 +1094,10 @@ efi_status_t efivar_set_variable_locked(efi_char16_t *name, efi_guid_t *vendor, + efi_status_t efivar_set_variable(efi_char16_t *name, efi_guid_t *vendor, + u32 attr, unsigned long data_size, void *data); + ++efi_status_t efivar_query_variable_info(u32 attr, u64 *storage_space, ++ u64 *remaining_space, ++ u64 *max_variable_size); ++ + #if IS_ENABLED(CONFIG_EFI_CAPSULE_LOADER) + extern bool efi_capsule_pending(int *reset_type); + +-- +2.42.0 + diff --git a/recipes-kernel/linux/files/patches-6.1/0050-efi-efivars-drop-kobject-from-efivars_register.patch b/recipes-kernel/linux/files/patches-6.1/0050-efi-efivars-drop-kobject-from-efivars_register.patch new file mode 100644 index 000000000..b12edb539 --- /dev/null +++ b/recipes-kernel/linux/files/patches-6.1/0050-efi-efivars-drop-kobject-from-efivars_register.patch @@ -0,0 +1,150 @@ +From bc19dc8ccd5e93dd978f304b01790094e0a75ca0 Mon Sep 17 00:00:00 2001 +From: Johan Hovold +Date: Tue, 17 Jan 2023 13:43:09 +0100 +Subject: [PATCH 50/69] efi: efivars: drop kobject from efivars_register() + +Since commit 0f5b2c69a4cb ("efi: vars: Remove deprecated 'efivars' sysfs +interface") and the removal of the sysfs interface there are no users of +the efivars kobject. + +Drop the kobject argument from efivars_register() and add a new +efivar_is_available() helper in favour of the old efivars_kobject(). + +Note that the new helper uses the prefix 'efivar' (i.e. without an 's') +for consistency with efivar_supports_writes() and the rest of the +interface (except the registration functions). + +For the benefit of drivers with optional EFI support, also provide a +dummy implementation of efivar_is_available(). + +Signed-off-by: Johan Hovold +Signed-off-by: Ard Biesheuvel +[Commit ade7fd908d710 upstream] +--- + drivers/firmware/efi/efi.c | 2 +- + drivers/firmware/efi/vars.c | 19 ++++++------------- + drivers/firmware/google/gsmi.c | 2 +- + fs/efivarfs/super.c | 2 +- + include/linux/efi.h | 11 +++++++---- + 5 files changed, 16 insertions(+), 20 deletions(-) + +diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c +index db3c0ce08e44..54dda4309892 100644 +--- a/drivers/firmware/efi/efi.c ++++ b/drivers/firmware/efi/efi.c +@@ -196,7 +196,7 @@ static int generic_ops_register(void) + generic_ops.set_variable = efi.set_variable; + generic_ops.set_variable_nonblocking = efi.set_variable_nonblocking; + } +- return efivars_register(&generic_efivars, &generic_ops, efi_kobj); ++ return efivars_register(&generic_efivars, &generic_ops); + } + + static void generic_ops_unregister(void) +diff --git a/drivers/firmware/efi/vars.c b/drivers/firmware/efi/vars.c +index de36d4e4bd95..26a05bf37fdd 100644 +--- a/drivers/firmware/efi/vars.c ++++ b/drivers/firmware/efi/vars.c +@@ -40,37 +40,30 @@ static efi_status_t check_var_size(bool nonblocking, u32 attributes, + } + + /** +- * efivars_kobject - get the kobject for the registered efivars ++ * efivar_is_available - check if efivars is available + * +- * If efivars_register() has not been called we return NULL, +- * otherwise return the kobject used at registration time. ++ * @return true iff evivars is currently registered + */ +-struct kobject *efivars_kobject(void) ++bool efivar_is_available(void) + { +- if (!__efivars) +- return NULL; +- +- return __efivars->kobject; ++ return __efivars != NULL; + } +-EXPORT_SYMBOL_GPL(efivars_kobject); ++EXPORT_SYMBOL_GPL(efivar_is_available); + + /** + * efivars_register - register an efivars + * @efivars: efivars to register + * @ops: efivars operations +- * @kobject: @efivars-specific kobject + * + * Only a single efivars can be registered at any time. + */ + int efivars_register(struct efivars *efivars, +- const struct efivar_operations *ops, +- struct kobject *kobject) ++ const struct efivar_operations *ops) + { + if (down_interruptible(&efivars_lock)) + return -EINTR; + + efivars->ops = ops; +- efivars->kobject = kobject; + + __efivars = efivars; + +diff --git a/drivers/firmware/google/gsmi.c b/drivers/firmware/google/gsmi.c +index 871bedf533a8..96ea1fa76d35 100644 +--- a/drivers/firmware/google/gsmi.c ++++ b/drivers/firmware/google/gsmi.c +@@ -1030,7 +1030,7 @@ static __init int gsmi_init(void) + } + + #ifdef CONFIG_EFI +- ret = efivars_register(&efivars, &efivar_ops, gsmi_kobj); ++ ret = efivars_register(&efivars, &efivar_ops); + if (ret) { + printk(KERN_INFO "gsmi: Failed to register efivars\n"); + sysfs_remove_files(gsmi_kobj, gsmi_attrs); +diff --git a/fs/efivarfs/super.c b/fs/efivarfs/super.c +index 0994446a3544..36d5fcf2591e 100644 +--- a/fs/efivarfs/super.c ++++ b/fs/efivarfs/super.c +@@ -290,7 +290,7 @@ static struct file_system_type efivarfs_type = { + + static __init int efivarfs_init(void) + { +- if (!efivars_kobject()) ++ if (!efivar_is_available()) + return -ENODEV; + + return register_filesystem(&efivarfs_type); +diff --git a/include/linux/efi.h b/include/linux/efi.h +index b8cd4db7a1bf..953575e29da6 100644 +--- a/include/linux/efi.h ++++ b/include/linux/efi.h +@@ -1050,7 +1050,6 @@ struct efivar_operations { + + struct efivars { + struct kset *kset; +- struct kobject *kobject; + const struct efivar_operations *ops; + }; + +@@ -1070,10 +1069,14 @@ static inline u64 efivar_reserved_space(void) { return 0; } + #define EFI_VAR_NAME_LEN 1024 + + int efivars_register(struct efivars *efivars, +- const struct efivar_operations *ops, +- struct kobject *kobject); ++ const struct efivar_operations *ops); + int efivars_unregister(struct efivars *efivars); +-struct kobject *efivars_kobject(void); ++ ++#ifdef CONFIG_EFI ++bool efivar_is_available(void); ++#else ++static inline bool efivar_is_available(void) { return false; } ++#endif + + int efivar_supports_writes(void); + +-- +2.42.0 + diff --git a/recipes-kernel/linux/files/patches-6.1/0051-efi-expose-efivar-generic-ops-register-function.patch b/recipes-kernel/linux/files/patches-6.1/0051-efi-expose-efivar-generic-ops-register-function.patch new file mode 100644 index 000000000..7e06daf0d --- /dev/null +++ b/recipes-kernel/linux/files/patches-6.1/0051-efi-expose-efivar-generic-ops-register-function.patch @@ -0,0 +1,59 @@ +From 3cafc0f65156a234e4e4cd7d725e0ada90c6570c Mon Sep 17 00:00:00 2001 +From: Masahisa Kojima +Date: Mon, 7 Aug 2023 11:53:38 +0900 +Subject: [PATCH 51/69] efi: expose efivar generic ops register function + +This is a preparation for supporting efivar operations +provided by other than efi subsystem. +Both register and unregister functions are exposed +so that non-efi subsystem can revert the efi generic +operation. + +Acked-by: Sumit Garg +Co-developed-by: Ilias Apalodimas +Signed-off-by: Ilias Apalodimas +Signed-off-by: Masahisa Kojima +[Taken from https://lore.kernel.org/all/20230807025343.1939-1-masahisa.kojima@linaro.org/] +--- + drivers/firmware/efi/efi.c | 12 ++++++++++++ + include/linux/efi.h | 3 +++ + 2 files changed, 15 insertions(+) + +diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c +index 54dda4309892..65850e445f93 100644 +--- a/drivers/firmware/efi/efi.c ++++ b/drivers/firmware/efi/efi.c +@@ -204,6 +204,18 @@ static void generic_ops_unregister(void) + efivars_unregister(&generic_efivars); + } + ++void efivars_generic_ops_register(void) ++{ ++ generic_ops_register(); ++} ++EXPORT_SYMBOL_GPL(efivars_generic_ops_register); ++ ++void efivars_generic_ops_unregister(void) ++{ ++ generic_ops_unregister(); ++} ++EXPORT_SYMBOL_GPL(efivars_generic_ops_unregister); ++ + #ifdef CONFIG_EFI_CUSTOM_SSDT_OVERLAYS + #define EFIVAR_SSDT_NAME_MAX 16UL + static char efivar_ssdt[EFIVAR_SSDT_NAME_MAX] __initdata; +diff --git a/include/linux/efi.h b/include/linux/efi.h +index 953575e29da6..f19abc71995b 100644 +--- a/include/linux/efi.h ++++ b/include/linux/efi.h +@@ -1370,4 +1370,7 @@ struct linux_efi_initrd { + /* Header of a populated EFI secret area */ + #define EFI_SECRET_TABLE_HEADER_GUID EFI_GUID(0x1e74f542, 0x71dd, 0x4d66, 0x96, 0x3e, 0xef, 0x42, 0x87, 0xff, 0x17, 0x3b) + ++void efivars_generic_ops_register(void); ++void efivars_generic_ops_unregister(void); ++ + #endif /* _LINUX_EFI_H */ +-- +2.42.0 + diff --git a/recipes-kernel/linux/files/patches-6.1/0052-efi-Add-EFI_ACCESS_DENIED-status-code.patch b/recipes-kernel/linux/files/patches-6.1/0052-efi-Add-EFI_ACCESS_DENIED-status-code.patch new file mode 100644 index 000000000..021ed450e --- /dev/null +++ b/recipes-kernel/linux/files/patches-6.1/0052-efi-Add-EFI_ACCESS_DENIED-status-code.patch @@ -0,0 +1,31 @@ +From ce4c217a50308297f605c211ddf5492187c92436 Mon Sep 17 00:00:00 2001 +From: Masahisa Kojima +Date: Mon, 7 Aug 2023 11:53:39 +0900 +Subject: [PATCH 52/69] efi: Add EFI_ACCESS_DENIED status code + +This commit adds the EFI_ACCESS_DENIED status code. + +Acked-by: Sumit Garg +Co-developed-by: Ilias Apalodimas +Signed-off-by: Ilias Apalodimas +Signed-off-by: Masahisa Kojima +[Taken from https://lore.kernel.org/all/20230807025343.1939-1-masahisa.kojima@linaro.org/] +--- + include/linux/efi.h | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/include/linux/efi.h b/include/linux/efi.h +index f19abc71995b..776c362b086b 100644 +--- a/include/linux/efi.h ++++ b/include/linux/efi.h +@@ -39,6 +39,7 @@ + #define EFI_WRITE_PROTECTED ( 8 | (1UL << (BITS_PER_LONG-1))) + #define EFI_OUT_OF_RESOURCES ( 9 | (1UL << (BITS_PER_LONG-1))) + #define EFI_NOT_FOUND (14 | (1UL << (BITS_PER_LONG-1))) ++#define EFI_ACCESS_DENIED (15 | (1UL << (BITS_PER_LONG-1))) + #define EFI_TIMEOUT (18 | (1UL << (BITS_PER_LONG-1))) + #define EFI_ABORTED (21 | (1UL << (BITS_PER_LONG-1))) + #define EFI_SECURITY_VIOLATION (26 | (1UL << (BITS_PER_LONG-1))) +-- +2.42.0 + diff --git a/recipes-kernel/linux/files/patches-6.1/0053-efi-Add-tee-based-EFI-variable-driver.patch b/recipes-kernel/linux/files/patches-6.1/0053-efi-Add-tee-based-EFI-variable-driver.patch new file mode 100644 index 000000000..1dc29b063 --- /dev/null +++ b/recipes-kernel/linux/files/patches-6.1/0053-efi-Add-tee-based-EFI-variable-driver.patch @@ -0,0 +1,940 @@ +From f1537556435cb125d9f2ed91e519e710d2b15738 Mon Sep 17 00:00:00 2001 +From: Masahisa Kojima +Date: Mon, 7 Aug 2023 11:53:40 +0900 +Subject: [PATCH 53/69] efi: Add tee-based EFI variable driver + +When the flash is not owned by the non-secure world, accessing the EFI +variables is straightforward and done via EFI Runtime Variable Services. +In this case, critical variables for system integrity and security +are normally stored in the dedicated secure storage and only accessible +from the secure world. + +On the other hand, the small embedded devices don't have the special +dedicated secure storage. The eMMC device with an RPMB partition is +becoming more common, we can use an RPMB partition to store the +EFI Variables. + +The eMMC device is typically owned by the non-secure world(linux in +this case). There is an existing solution utilizing eMMC RPMB partition +for EFI Variables, it is implemented by interacting with +TEE(OP-TEE in this case), StandaloneMM(as EFI Variable Service Pseudo TA), +eMMC driver and tee-supplicant. The last piece is the tee-based +variable access driver to interact with TEE and StandaloneMM. + +So let's add the kernel functions needed. + +This feature is implemented as a kernel module. +StMM PTA has TA_FLAG_DEVICE_ENUM_SUPP flag when registered to OP-TEE +so that this tee_stmm_efi module is probed after tee-supplicant starts, +since "SetVariable" EFI Runtime Variable Service requires to +interact with tee-supplicant. + +Acked-by: Sumit Garg +Co-developed-by: Ilias Apalodimas +Signed-off-by: Ilias Apalodimas +Signed-off-by: Masahisa Kojima +[Taken from https://lore.kernel.org/all/20230807025343.1939-1-masahisa.kojima@linaro.org/] +--- + drivers/firmware/efi/Kconfig | 15 + + drivers/firmware/efi/Makefile | 1 + + drivers/firmware/efi/stmm/mm_communication.h | 236 +++++++ + drivers/firmware/efi/stmm/tee_stmm_efi.c | 612 +++++++++++++++++++ + 4 files changed, 864 insertions(+) + create mode 100644 drivers/firmware/efi/stmm/mm_communication.h + create mode 100644 drivers/firmware/efi/stmm/tee_stmm_efi.c + +diff --git a/drivers/firmware/efi/Kconfig b/drivers/firmware/efi/Kconfig +index 6787ed8dfacf..fafcfb651085 100644 +--- a/drivers/firmware/efi/Kconfig ++++ b/drivers/firmware/efi/Kconfig +@@ -332,3 +332,18 @@ config UEFI_CPER_X86 + bool + depends on UEFI_CPER && X86 + default y ++ ++config TEE_STMM_EFI ++ tristate "TEE-based EFI runtime variable service driver" ++ depends on EFI && OPTEE && !EFI_VARS_PSTORE ++ help ++ Select this config option if TEE is compiled to include StandAloneMM ++ as a separate secure partition. It has the ability to check and store ++ EFI variables on an RPMB or any other non-volatile medium used by ++ StandAloneMM. ++ ++ Enabling this will change the EFI runtime services from the firmware ++ provided functions to TEE calls. ++ ++ To compile this driver as a module, choose M here: the module ++ will be called tee_stmm_efi. +diff --git a/drivers/firmware/efi/Makefile b/drivers/firmware/efi/Makefile +index 8d151e332584..d0171a121c0f 100644 +--- a/drivers/firmware/efi/Makefile ++++ b/drivers/firmware/efi/Makefile +@@ -46,3 +46,4 @@ obj-$(CONFIG_EFI_CAPSULE_LOADER) += capsule-loader.o + obj-$(CONFIG_EFI_EARLYCON) += earlycon.o + obj-$(CONFIG_UEFI_CPER_ARM) += cper-arm.o + obj-$(CONFIG_UEFI_CPER_X86) += cper-x86.o ++obj-$(CONFIG_TEE_STMM_EFI) += stmm/tee_stmm_efi.o +diff --git a/drivers/firmware/efi/stmm/mm_communication.h b/drivers/firmware/efi/stmm/mm_communication.h +new file mode 100644 +index 000000000000..52a1f32cd1eb +--- /dev/null ++++ b/drivers/firmware/efi/stmm/mm_communication.h +@@ -0,0 +1,236 @@ ++/* SPDX-License-Identifier: GPL-2.0+ */ ++/* ++ * Headers for EFI variable service via StandAloneMM, EDK2 application running ++ * in OP-TEE. Most of the structs and defines resemble the EDK2 naming. ++ * ++ * Copyright (c) 2017, Intel Corporation. All rights reserved. ++ * Copyright (C) 2020 Linaro Ltd. ++ */ ++ ++#ifndef _MM_COMMUNICATION_H_ ++#define _MM_COMMUNICATION_H_ ++ ++/* ++ * Interface to the pseudo Trusted Application (TA), which provides a ++ * communication channel with the Standalone MM (Management Mode) ++ * Secure Partition running at Secure-EL0 ++ */ ++ ++#define PTA_STMM_CMD_COMMUNICATE 0 ++ ++/* ++ * Defined in OP-TEE, this UUID is used to identify the pseudo-TA. ++ * OP-TEE is using big endian GUIDs while UEFI uses little endian ones ++ */ ++#define PTA_STMM_UUID \ ++ UUID_INIT(0xed32d533, 0x99e6, 0x4209, \ ++ 0x9c, 0xc0, 0x2d, 0x72, 0xcd, 0xd9, 0x98, 0xa7) ++ ++#define EFI_MM_VARIABLE_GUID \ ++ EFI_GUID(0xed32d533, 0x99e6, 0x4209, \ ++ 0x9c, 0xc0, 0x2d, 0x72, 0xcd, 0xd9, 0x98, 0xa7) ++ ++/** ++ * struct efi_mm_communicate_header - Header used for SMM variable communication ++ ++ * @header_guid: header use for disambiguation of content ++ * @message_len: length of the message. Does not include the size of the ++ * header ++ * @data: payload of the message ++ * ++ * Defined in the PI spec as EFI_MM_COMMUNICATE_HEADER. ++ * To avoid confusion in interpreting frames, the communication buffer should ++ * always begin with efi_mm_communicate_header. ++ */ ++struct efi_mm_communicate_header { ++ efi_guid_t header_guid; ++ size_t message_len; ++ u8 data[]; ++} __packed; ++ ++#define MM_COMMUNICATE_HEADER_SIZE \ ++ (sizeof(struct efi_mm_communicate_header)) ++ ++/* SPM return error codes */ ++#define ARM_SVC_SPM_RET_SUCCESS 0 ++#define ARM_SVC_SPM_RET_NOT_SUPPORTED -1 ++#define ARM_SVC_SPM_RET_INVALID_PARAMS -2 ++#define ARM_SVC_SPM_RET_DENIED -3 ++#define ARM_SVC_SPM_RET_NO_MEMORY -5 ++ ++#define SMM_VARIABLE_FUNCTION_GET_VARIABLE 1 ++/* ++ * The payload for this function is ++ * SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME. ++ */ ++#define SMM_VARIABLE_FUNCTION_GET_NEXT_VARIABLE_NAME 2 ++/* ++ * The payload for this function is SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE. ++ */ ++#define SMM_VARIABLE_FUNCTION_SET_VARIABLE 3 ++/* ++ * The payload for this function is ++ * SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO. ++ */ ++#define SMM_VARIABLE_FUNCTION_QUERY_VARIABLE_INFO 4 ++/* ++ * It is a notify event, no extra payload for this function. ++ */ ++#define SMM_VARIABLE_FUNCTION_READY_TO_BOOT 5 ++/* ++ * It is a notify event, no extra payload for this function. ++ */ ++#define SMM_VARIABLE_FUNCTION_EXIT_BOOT_SERVICE 6 ++/* ++ * The payload for this function is VARIABLE_INFO_ENTRY. ++ * The GUID in EFI_SMM_COMMUNICATE_HEADER is gEfiSmmVariableProtocolGuid. ++ */ ++#define SMM_VARIABLE_FUNCTION_GET_STATISTICS 7 ++/* ++ * The payload for this function is SMM_VARIABLE_COMMUNICATE_LOCK_VARIABLE ++ */ ++#define SMM_VARIABLE_FUNCTION_LOCK_VARIABLE 8 ++ ++#define SMM_VARIABLE_FUNCTION_VAR_CHECK_VARIABLE_PROPERTY_SET 9 ++ ++#define SMM_VARIABLE_FUNCTION_VAR_CHECK_VARIABLE_PROPERTY_GET 10 ++ ++#define SMM_VARIABLE_FUNCTION_GET_PAYLOAD_SIZE 11 ++/* ++ * The payload for this function is ++ * SMM_VARIABLE_COMMUNICATE_RUNTIME_VARIABLE_CACHE_CONTEXT ++ */ ++#define SMM_VARIABLE_FUNCTION_INIT_RUNTIME_VARIABLE_CACHE_CONTEXT 12 ++ ++#define SMM_VARIABLE_FUNCTION_SYNC_RUNTIME_CACHE 13 ++/* ++ * The payload for this function is ++ * SMM_VARIABLE_COMMUNICATE_GET_RUNTIME_CACHE_INFO ++ */ ++#define SMM_VARIABLE_FUNCTION_GET_RUNTIME_CACHE_INFO 14 ++ ++/** ++ * struct smm_variable_communicate_header - Used for SMM variable communication ++ ++ * @function: function to call in Smm. ++ * @ret_status: return status ++ * @data: payload ++ */ ++struct smm_variable_communicate_header { ++ size_t function; ++ efi_status_t ret_status; ++ u8 data[]; ++}; ++ ++#define MM_VARIABLE_COMMUNICATE_SIZE \ ++ (sizeof(struct smm_variable_communicate_header)) ++ ++/** ++ * struct smm_variable_access - Used to communicate with StMM by ++ * SetVariable and GetVariable. ++ ++ * @guid: vendor GUID ++ * @data_size: size of EFI variable data ++ * @name_size: size of EFI name ++ * @attr: attributes ++ * @name: variable name ++ * ++ */ ++struct smm_variable_access { ++ efi_guid_t guid; ++ size_t data_size; ++ size_t name_size; ++ u32 attr; ++ u16 name[]; ++}; ++ ++#define MM_VARIABLE_ACCESS_HEADER_SIZE \ ++ (sizeof(struct smm_variable_access)) ++/** ++ * struct smm_variable_payload_size - Used to get the max allowed ++ * payload used in StMM. ++ * ++ * @size: size to fill in ++ * ++ */ ++struct smm_variable_payload_size { ++ size_t size; ++}; ++ ++/** ++ * struct smm_variable_getnext - Used to communicate with StMM for ++ * GetNextVariableName. ++ * ++ * @guid: vendor GUID ++ * @name_size: size of the name of the variable ++ * @name: variable name ++ * ++ */ ++struct smm_variable_getnext { ++ efi_guid_t guid; ++ size_t name_size; ++ u16 name[]; ++}; ++ ++#define MM_VARIABLE_GET_NEXT_HEADER_SIZE \ ++ (sizeof(struct smm_variable_getnext)) ++ ++/** ++ * struct smm_variable_query_info - Used to communicate with StMM for ++ * QueryVariableInfo. ++ * ++ * @max_variable_storage: max available storage ++ * @remaining_variable_storage: remaining available storage ++ * @max_variable_size: max variable supported size ++ * @attr: attributes to query storage for ++ * ++ */ ++struct smm_variable_query_info { ++ u64 max_variable_storage; ++ u64 remaining_variable_storage; ++ u64 max_variable_size; ++ u32 attr; ++}; ++ ++#define VAR_CHECK_VARIABLE_PROPERTY_REVISION 0x0001 ++#define VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY BIT(0) ++/** ++ * struct var_check_property - Used to store variable properties in StMM ++ * ++ * @revision: magic revision number for variable property checking ++ * @property: properties mask for the variable used in StMM. ++ * Currently RO flag is supported ++ * @attributes: variable attributes used in StMM checking when properties ++ * for a variable are enabled ++ * @minsize: minimum allowed size for variable payload checked against ++ * smm_variable_access->datasize in StMM ++ * @maxsize: maximum allowed size for variable payload checked against ++ * smm_variable_access->datasize in StMM ++ * ++ */ ++struct var_check_property { ++ u16 revision; ++ u16 property; ++ u32 attributes; ++ size_t minsize; ++ size_t maxsize; ++}; ++ ++/** ++ * struct smm_variable_var_check_property - Used to communicate variable ++ * properties with StMM ++ * ++ * @guid: vendor GUID ++ * @name_size: size of EFI name ++ * @property: variable properties struct ++ * @name: variable name ++ * ++ */ ++struct smm_variable_var_check_property { ++ efi_guid_t guid; ++ size_t name_size; ++ struct var_check_property property; ++ u16 name[]; ++}; ++ ++#endif /* _MM_COMMUNICATION_H_ */ +diff --git a/drivers/firmware/efi/stmm/tee_stmm_efi.c b/drivers/firmware/efi/stmm/tee_stmm_efi.c +new file mode 100644 +index 000000000000..e03475966dc1 +--- /dev/null ++++ b/drivers/firmware/efi/stmm/tee_stmm_efi.c +@@ -0,0 +1,612 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * EFI variable service via TEE ++ * ++ * Copyright (C) 2022 Linaro ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include "mm_communication.h" ++ ++static struct efivars tee_efivars; ++static struct efivar_operations tee_efivar_ops; ++ ++static size_t max_buffer_size; /* comm + var + func + data */ ++static size_t max_payload_size; /* func + data */ ++ ++struct tee_stmm_efi_private { ++ struct tee_context *ctx; ++ u32 session; ++ struct device *dev; ++}; ++ ++static struct tee_stmm_efi_private pvt_data; ++ ++/* UUID of the stmm PTA */ ++static const struct tee_client_device_id tee_stmm_efi_id_table[] = { ++ {PTA_STMM_UUID}, ++ {} ++}; ++ ++static int tee_ctx_match(struct tee_ioctl_version_data *ver, const void *data) ++{ ++ /* currently only OP-TEE is supported as a communication path */ ++ if (ver->impl_id == TEE_IMPL_ID_OPTEE) ++ return 1; ++ else ++ return 0; ++} ++ ++/** ++ * tee_mm_communicate() - Pass a buffer to StandaloneMM running in TEE ++ * ++ * @comm_buf: locally allocated communication buffer ++ * @dsize: buffer size ++ * Return: status code ++ */ ++static efi_status_t tee_mm_communicate(void *comm_buf, size_t dsize) ++{ ++ size_t buf_size; ++ struct efi_mm_communicate_header *mm_hdr; ++ struct tee_ioctl_invoke_arg arg; ++ struct tee_param param[4]; ++ struct tee_shm *shm = NULL; ++ int rc; ++ ++ if (!comm_buf) ++ return EFI_INVALID_PARAMETER; ++ ++ mm_hdr = (struct efi_mm_communicate_header *)comm_buf; ++ buf_size = mm_hdr->message_len + sizeof(efi_guid_t) + sizeof(size_t); ++ ++ if (dsize != buf_size) ++ return EFI_INVALID_PARAMETER; ++ ++ shm = tee_shm_register_kernel_buf(pvt_data.ctx, comm_buf, buf_size); ++ if (IS_ERR(shm)) { ++ dev_err(pvt_data.dev, "Unable to register shared memory\n"); ++ return EFI_UNSUPPORTED; ++ } ++ ++ memset(&arg, 0, sizeof(arg)); ++ arg.func = PTA_STMM_CMD_COMMUNICATE; ++ arg.session = pvt_data.session; ++ arg.num_params = 4; ++ ++ memset(param, 0, sizeof(param)); ++ param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT; ++ param[0].u.memref.size = buf_size; ++ param[0].u.memref.shm = shm; ++ param[1].attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT; ++ param[2].attr = TEE_IOCTL_PARAM_ATTR_TYPE_NONE; ++ param[3].attr = TEE_IOCTL_PARAM_ATTR_TYPE_NONE; ++ ++ rc = tee_client_invoke_func(pvt_data.ctx, &arg, param); ++ tee_shm_free(shm); ++ ++ if (rc < 0 || arg.ret != 0) { ++ dev_err(pvt_data.dev, ++ "PTA_STMM_CMD_COMMUNICATE invoke error: 0x%x\n", arg.ret); ++ return EFI_DEVICE_ERROR; ++ } ++ ++ switch (param[1].u.value.a) { ++ case ARM_SVC_SPM_RET_SUCCESS: ++ return EFI_SUCCESS; ++ ++ case ARM_SVC_SPM_RET_INVALID_PARAMS: ++ return EFI_INVALID_PARAMETER; ++ ++ case ARM_SVC_SPM_RET_DENIED: ++ return EFI_ACCESS_DENIED; ++ ++ case ARM_SVC_SPM_RET_NO_MEMORY: ++ return EFI_OUT_OF_RESOURCES; ++ ++ default: ++ return EFI_ACCESS_DENIED; ++ } ++} ++ ++/** ++ * mm_communicate() - Adjust the communication buffer to StandAlonneMM and send ++ * it to TEE ++ * ++ * @comm_buf: locally allocated communication buffer, buffer should ++ * be enough big to have some headers and payload ++ * @payload_size: payload size ++ * Return: status code ++ */ ++static efi_status_t mm_communicate(u8 *comm_buf, size_t payload_size) ++{ ++ size_t dsize; ++ efi_status_t ret; ++ struct efi_mm_communicate_header *mm_hdr; ++ struct smm_variable_communicate_header *var_hdr; ++ ++ dsize = payload_size + MM_COMMUNICATE_HEADER_SIZE + ++ MM_VARIABLE_COMMUNICATE_SIZE; ++ mm_hdr = (struct efi_mm_communicate_header *)comm_buf; ++ var_hdr = (struct smm_variable_communicate_header *)mm_hdr->data; ++ ++ ret = tee_mm_communicate(comm_buf, dsize); ++ if (ret != EFI_SUCCESS) { ++ dev_err(pvt_data.dev, "%s failed!\n", __func__); ++ return ret; ++ } ++ ++ return var_hdr->ret_status; ++} ++ ++/** ++ * setup_mm_hdr() - Allocate a buffer for StandAloneMM and initialize the ++ * header data. ++ * ++ * @dptr: pointer address to store allocated buffer ++ * @payload_size: payload size ++ * @func: standAloneMM function number ++ * @ret: EFI return code ++ * Return: pointer to corresponding StandAloneMM function buffer or NULL ++ */ ++static void *setup_mm_hdr(u8 **dptr, size_t payload_size, size_t func, ++ efi_status_t *ret) ++{ ++ const efi_guid_t mm_var_guid = EFI_MM_VARIABLE_GUID; ++ struct efi_mm_communicate_header *mm_hdr; ++ struct smm_variable_communicate_header *var_hdr; ++ u8 *comm_buf; ++ ++ /* In the init function we initialize max_buffer_size with ++ * get_max_payload(). So skip the test if max_buffer_size is initialized ++ * StandAloneMM will perform similar checks and drop the buffer if it's ++ * too long ++ */ ++ if (max_buffer_size && ++ max_buffer_size < (MM_COMMUNICATE_HEADER_SIZE + ++ MM_VARIABLE_COMMUNICATE_SIZE + payload_size)) { ++ *ret = EFI_INVALID_PARAMETER; ++ return NULL; ++ } ++ ++ comm_buf = kzalloc(MM_COMMUNICATE_HEADER_SIZE + ++ MM_VARIABLE_COMMUNICATE_SIZE + payload_size, ++ GFP_KERNEL); ++ if (!comm_buf) { ++ *ret = EFI_OUT_OF_RESOURCES; ++ return NULL; ++ } ++ ++ mm_hdr = (struct efi_mm_communicate_header *)comm_buf; ++ memcpy(&mm_hdr->header_guid, &mm_var_guid, sizeof(mm_hdr->header_guid)); ++ mm_hdr->message_len = MM_VARIABLE_COMMUNICATE_SIZE + payload_size; ++ ++ var_hdr = (struct smm_variable_communicate_header *)mm_hdr->data; ++ var_hdr->function = func; ++ if (dptr) ++ *dptr = comm_buf; ++ *ret = EFI_SUCCESS; ++ ++ return var_hdr->data; ++} ++ ++/** ++ * get_max_payload() - Get variable payload size from StandAloneMM. ++ * ++ * @size: size of the variable in storage ++ * Return: status code ++ */ ++static efi_status_t get_max_payload(size_t *size) ++{ ++ struct smm_variable_payload_size *var_payload = NULL; ++ size_t payload_size; ++ u8 *comm_buf = NULL; ++ efi_status_t ret; ++ ++ if (!size) ++ return EFI_INVALID_PARAMETER; ++ ++ payload_size = sizeof(*var_payload); ++ var_payload = setup_mm_hdr(&comm_buf, payload_size, ++ SMM_VARIABLE_FUNCTION_GET_PAYLOAD_SIZE, ++ &ret); ++ if (!var_payload) ++ return EFI_OUT_OF_RESOURCES; ++ ++ ret = mm_communicate(comm_buf, payload_size); ++ if (ret != EFI_SUCCESS) ++ goto out; ++ ++ /* Make sure the buffer is big enough for storing variables */ ++ if (var_payload->size < MM_VARIABLE_ACCESS_HEADER_SIZE + 0x20) { ++ ret = EFI_DEVICE_ERROR; ++ goto out; ++ } ++ *size = var_payload->size; ++ /* ++ * There seems to be a bug in EDK2 miscalculating the boundaries and ++ * size checks, so deduct 2 more bytes to fulfill this requirement. Fix ++ * it up here to ensure backwards compatibility with older versions ++ * (cf. StandaloneMmPkg/Drivers/StandaloneMmCpu/AArch64/EventHandle.c. ++ * sizeof (EFI_MM_COMMUNICATE_HEADER) instead the size minus the ++ * flexible array member). ++ * ++ * size is guaranteed to be > 2 due to checks on the beginning. ++ */ ++ *size -= 2; ++out: ++ kfree(comm_buf); ++ return ret; ++} ++ ++static efi_status_t get_property_int(u16 *name, size_t name_size, ++ const efi_guid_t *vendor, ++ struct var_check_property *var_property) ++{ ++ struct smm_variable_var_check_property *smm_property; ++ size_t payload_size; ++ u8 *comm_buf = NULL; ++ efi_status_t ret; ++ ++ memset(var_property, 0, sizeof(*var_property)); ++ payload_size = sizeof(*smm_property) + name_size; ++ if (payload_size > max_payload_size) ++ return EFI_INVALID_PARAMETER; ++ ++ smm_property = setup_mm_hdr( ++ &comm_buf, payload_size, ++ SMM_VARIABLE_FUNCTION_VAR_CHECK_VARIABLE_PROPERTY_GET, &ret); ++ if (!smm_property) ++ return EFI_OUT_OF_RESOURCES; ++ ++ memcpy(&smm_property->guid, vendor, sizeof(smm_property->guid)); ++ smm_property->name_size = name_size; ++ memcpy(smm_property->name, name, name_size); ++ ++ ret = mm_communicate(comm_buf, payload_size); ++ /* ++ * Currently only R/O property is supported in StMM. ++ * Variables that are not set to R/O will not set the property in StMM ++ * and the call will return EFI_NOT_FOUND. We are setting the ++ * properties to 0x0 so checking against that is enough for the ++ * EFI_NOT_FOUND case. ++ */ ++ if (ret == EFI_NOT_FOUND) ++ ret = EFI_SUCCESS; ++ if (ret != EFI_SUCCESS) ++ goto out; ++ memcpy(var_property, &smm_property->property, sizeof(*var_property)); ++ ++out: ++ kfree(comm_buf); ++ return ret; ++} ++ ++static efi_status_t tee_get_variable(u16 *name, efi_guid_t *vendor, ++ u32 *attributes, unsigned long *data_size, ++ void *data) ++{ ++ struct var_check_property var_property; ++ struct smm_variable_access *var_acc; ++ size_t payload_size; ++ size_t name_size; ++ size_t tmp_dsize; ++ u8 *comm_buf = NULL; ++ efi_status_t ret; ++ ++ if (!name || !vendor || !data_size) ++ return EFI_INVALID_PARAMETER; ++ ++ name_size = (ucs2_strnlen(name, EFI_VAR_NAME_LEN) + 1) * sizeof(u16); ++ if (name_size > max_payload_size - MM_VARIABLE_ACCESS_HEADER_SIZE) ++ return EFI_INVALID_PARAMETER; ++ ++ /* Trim output buffer size */ ++ tmp_dsize = *data_size; ++ if (name_size + tmp_dsize > ++ max_payload_size - MM_VARIABLE_ACCESS_HEADER_SIZE) { ++ tmp_dsize = max_payload_size - MM_VARIABLE_ACCESS_HEADER_SIZE - ++ name_size; ++ } ++ ++ payload_size = MM_VARIABLE_ACCESS_HEADER_SIZE + name_size + tmp_dsize; ++ var_acc = setup_mm_hdr(&comm_buf, payload_size, ++ SMM_VARIABLE_FUNCTION_GET_VARIABLE, &ret); ++ if (!var_acc) ++ return EFI_OUT_OF_RESOURCES; ++ ++ /* Fill in contents */ ++ memcpy(&var_acc->guid, vendor, sizeof(var_acc->guid)); ++ var_acc->data_size = tmp_dsize; ++ var_acc->name_size = name_size; ++ var_acc->attr = attributes ? *attributes : 0; ++ memcpy(var_acc->name, name, name_size); ++ ++ ret = mm_communicate(comm_buf, payload_size); ++ if (ret == EFI_SUCCESS || ret == EFI_BUFFER_TOO_SMALL) ++ /* Update with reported data size for trimmed case */ ++ *data_size = var_acc->data_size; ++ if (ret != EFI_SUCCESS) ++ goto out; ++ ++ ret = get_property_int(name, name_size, vendor, &var_property); ++ if (ret != EFI_SUCCESS) ++ goto out; ++ ++ if (attributes) ++ *attributes = var_acc->attr; ++ ++ if (!data) { ++ ret = EFI_INVALID_PARAMETER; ++ goto out; ++ } ++ memcpy(data, (u8 *)var_acc->name + var_acc->name_size, ++ var_acc->data_size); ++out: ++ kfree(comm_buf); ++ return ret; ++} ++ ++static efi_status_t tee_get_next_variable(unsigned long *name_size, ++ efi_char16_t *name, efi_guid_t *guid) ++{ ++ struct smm_variable_getnext *var_getnext; ++ size_t payload_size; ++ size_t out_name_size; ++ size_t in_name_size; ++ u8 *comm_buf = NULL; ++ efi_status_t ret; ++ ++ if (!name_size || !name || !guid) ++ return EFI_INVALID_PARAMETER; ++ ++ out_name_size = *name_size; ++ in_name_size = (ucs2_strnlen(name, EFI_VAR_NAME_LEN) + 1) * sizeof(u16); ++ ++ if (out_name_size < in_name_size) ++ return EFI_INVALID_PARAMETER; ++ ++ if (in_name_size > max_payload_size - MM_VARIABLE_GET_NEXT_HEADER_SIZE) ++ return EFI_INVALID_PARAMETER; ++ ++ /* Trim output buffer size */ ++ if (out_name_size > max_payload_size - MM_VARIABLE_GET_NEXT_HEADER_SIZE) ++ out_name_size = ++ max_payload_size - MM_VARIABLE_GET_NEXT_HEADER_SIZE; ++ ++ payload_size = MM_VARIABLE_GET_NEXT_HEADER_SIZE + out_name_size; ++ var_getnext = setup_mm_hdr(&comm_buf, payload_size, ++ SMM_VARIABLE_FUNCTION_GET_NEXT_VARIABLE_NAME, ++ &ret); ++ if (!var_getnext) ++ return EFI_OUT_OF_RESOURCES; ++ ++ /* Fill in contents */ ++ memcpy(&var_getnext->guid, guid, sizeof(var_getnext->guid)); ++ var_getnext->name_size = out_name_size; ++ memcpy(var_getnext->name, name, in_name_size); ++ memset((u8 *)var_getnext->name + in_name_size, 0x0, ++ out_name_size - in_name_size); ++ ++ ret = mm_communicate(comm_buf, payload_size); ++ if (ret == EFI_SUCCESS || ret == EFI_BUFFER_TOO_SMALL) { ++ /* Update with reported data size for trimmed case */ ++ *name_size = var_getnext->name_size; ++ } ++ if (ret != EFI_SUCCESS) ++ goto out; ++ ++ memcpy(guid, &var_getnext->guid, sizeof(*guid)); ++ memcpy(name, var_getnext->name, var_getnext->name_size); ++ ++out: ++ kfree(comm_buf); ++ return ret; ++} ++ ++static efi_status_t tee_set_variable(efi_char16_t *name, efi_guid_t *vendor, ++ u32 attributes, unsigned long data_size, ++ void *data) ++{ ++ efi_status_t ret; ++ struct var_check_property var_property; ++ struct smm_variable_access *var_acc; ++ size_t payload_size; ++ size_t name_size; ++ u8 *comm_buf = NULL; ++ ++ if (!name || name[0] == 0 || !vendor) ++ return EFI_INVALID_PARAMETER; ++ ++ if (data_size > 0 && !data) ++ return EFI_INVALID_PARAMETER; ++ ++ /* Check payload size */ ++ name_size = (ucs2_strnlen(name, EFI_VAR_NAME_LEN) + 1) * sizeof(u16); ++ payload_size = MM_VARIABLE_ACCESS_HEADER_SIZE + name_size + data_size; ++ if (payload_size > max_payload_size) ++ return EFI_INVALID_PARAMETER; ++ ++ /* ++ * Allocate the buffer early, before switching to RW (if needed) ++ * so we won't need to account for any failures in reading/setting ++ * the properties, if the allocation fails ++ */ ++ var_acc = setup_mm_hdr(&comm_buf, payload_size, ++ SMM_VARIABLE_FUNCTION_SET_VARIABLE, &ret); ++ if (!var_acc) ++ return EFI_OUT_OF_RESOURCES; ++ ++ /* ++ * The API has the ability to override RO flags. If no RO check was ++ * requested switch the variable to RW for the duration of this call ++ */ ++ ret = get_property_int(name, name_size, vendor, &var_property); ++ if (ret != EFI_SUCCESS) { ++ dev_err(pvt_data.dev, "Getting variable property failed\n"); ++ goto out; ++ } ++ ++ if (var_property.property & VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY) { ++ ret = EFI_WRITE_PROTECTED; ++ goto out; ++ } ++ ++ /* Fill in contents */ ++ memcpy(&var_acc->guid, vendor, sizeof(var_acc->guid)); ++ var_acc->data_size = data_size; ++ var_acc->name_size = name_size; ++ var_acc->attr = attributes; ++ memcpy(var_acc->name, name, name_size); ++ memcpy((u8 *)var_acc->name + name_size, data, data_size); ++ ++ ret = mm_communicate(comm_buf, payload_size); ++ dev_dbg(pvt_data.dev, "Set Variable %s %d %lx\n", __FILE__, __LINE__, ret); ++out: ++ kfree(comm_buf); ++ return ret; ++} ++ ++static efi_status_t tee_set_variable_nonblocking(efi_char16_t *name, ++ efi_guid_t *vendor, ++ u32 attributes, ++ unsigned long data_size, ++ void *data) ++{ ++ return EFI_UNSUPPORTED; ++} ++ ++static efi_status_t tee_query_variable_info(u32 attributes, ++ u64 *max_variable_storage_size, ++ u64 *remain_variable_storage_size, ++ u64 *max_variable_size) ++{ ++ struct smm_variable_query_info *mm_query_info; ++ size_t payload_size; ++ efi_status_t ret; ++ u8 *comm_buf; ++ ++ payload_size = sizeof(*mm_query_info); ++ mm_query_info = setup_mm_hdr(&comm_buf, payload_size, ++ SMM_VARIABLE_FUNCTION_QUERY_VARIABLE_INFO, ++ &ret); ++ if (!mm_query_info) ++ return EFI_OUT_OF_RESOURCES; ++ ++ mm_query_info->attr = attributes; ++ ret = mm_communicate(comm_buf, payload_size); ++ if (ret != EFI_SUCCESS) ++ goto out; ++ *max_variable_storage_size = mm_query_info->max_variable_storage; ++ *remain_variable_storage_size = ++ mm_query_info->remaining_variable_storage; ++ *max_variable_size = mm_query_info->max_variable_size; ++ ++out: ++ kfree(comm_buf); ++ return ret; ++} ++ ++static void tee_stmm_efi_close_context(void *data) ++{ ++ tee_client_close_context(pvt_data.ctx); ++} ++ ++static void tee_stmm_efi_close_session(void *data) ++{ ++ tee_client_close_session(pvt_data.ctx, pvt_data.session); ++} ++ ++static int tee_stmm_efi_probe(struct device *dev) ++{ ++ struct tee_ioctl_open_session_arg sess_arg; ++ efi_status_t ret; ++ int rc; ++ ++ /* Open context with TEE driver */ ++ pvt_data.ctx = tee_client_open_context(NULL, tee_ctx_match, NULL, NULL); ++ if (IS_ERR(pvt_data.ctx)) ++ return -ENODEV; ++ ++ rc = devm_add_action_or_reset(dev, tee_stmm_efi_close_context, NULL); ++ if (rc) ++ return rc; ++ ++ /* Open session with StMM PTA */ ++ memset(&sess_arg, 0, sizeof(sess_arg)); ++ export_uuid(sess_arg.uuid, &tee_stmm_efi_id_table[0].uuid); ++ rc = tee_client_open_session(pvt_data.ctx, &sess_arg, NULL); ++ if ((rc < 0) || (sess_arg.ret != 0)) { ++ dev_err(dev, "tee_client_open_session failed, err: %x\n", ++ sess_arg.ret); ++ return -EINVAL; ++ } ++ pvt_data.session = sess_arg.session; ++ pvt_data.dev = dev; ++ rc = devm_add_action_or_reset(dev, tee_stmm_efi_close_session, NULL); ++ if (rc) ++ return rc; ++ ++ ret = get_max_payload(&max_payload_size); ++ if (ret != EFI_SUCCESS) ++ return -EIO; ++ ++ max_buffer_size = MM_COMMUNICATE_HEADER_SIZE + ++ MM_VARIABLE_COMMUNICATE_SIZE + ++ max_payload_size; ++ ++ tee_efivar_ops.get_variable = tee_get_variable; ++ tee_efivar_ops.get_next_variable = tee_get_next_variable; ++ tee_efivar_ops.set_variable = tee_set_variable; ++ tee_efivar_ops.set_variable_nonblocking = tee_set_variable_nonblocking; ++ tee_efivar_ops.query_variable_store = efi_query_variable_store; ++ tee_efivar_ops.query_variable_info = tee_query_variable_info; ++ ++ efivars_generic_ops_unregister(); ++ pr_info("Use tee-based EFI runtime variable services\n"); ++ efivars_register(&tee_efivars, &tee_efivar_ops); ++ ++ return 0; ++} ++ ++static int tee_stmm_efi_remove(struct device *dev) ++{ ++ efivars_unregister(&tee_efivars); ++ efivars_generic_ops_register(); ++ ++ return 0; ++} ++ ++MODULE_DEVICE_TABLE(tee, tee_stmm_efi_id_table); ++ ++static struct tee_client_driver tee_stmm_efi_driver = { ++ .id_table = tee_stmm_efi_id_table, ++ .driver = { ++ .name = "tee-stmm-efi", ++ .bus = &tee_bus_type, ++ .probe = tee_stmm_efi_probe, ++ .remove = tee_stmm_efi_remove, ++ }, ++}; ++ ++static int __init tee_stmm_efi_mod_init(void) ++{ ++ return driver_register(&tee_stmm_efi_driver.driver); ++} ++ ++static void __exit tee_stmm_efi_mod_exit(void) ++{ ++ driver_unregister(&tee_stmm_efi_driver.driver); ++} ++ ++module_init(tee_stmm_efi_mod_init); ++module_exit(tee_stmm_efi_mod_exit); ++ ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("Ilias Apalodimas "); ++MODULE_AUTHOR("Masahisa Kojima "); ++MODULE_DESCRIPTION("TEE based EFI runtime variable service driver"); +-- +2.42.0 + diff --git a/recipes-kernel/linux/files/patches-6.1/0054-arm64-dts-ti-k3-am65-main-fix-DSS-irq-trigger-type.patch b/recipes-kernel/linux/files/patches-6.1/0054-arm64-dts-ti-k3-am65-main-fix-DSS-irq-trigger-type.patch new file mode 100644 index 000000000..7842c911c --- /dev/null +++ b/recipes-kernel/linux/files/patches-6.1/0054-arm64-dts-ti-k3-am65-main-fix-DSS-irq-trigger-type.patch @@ -0,0 +1,39 @@ +From 5cc4072def9f9abe3851b6034937ab123e88ff1d Mon Sep 17 00:00:00 2001 +From: Tomi Valkeinen +Date: Mon, 31 May 2021 16:31:35 +0530 +Subject: [PATCH 54/69] arm64: dts: ti: k3-am65-main: fix DSS irq trigger type + +DSS irq trigger type is set to IRQ_TYPE_EDGE_RISING. For some reason this +results in double the amount of expected interrupts, e.g. for normal +page flipping test the number of interrupts per second is 2 * fps. It is +as if the IRQ would trigger on both edges. + +In any case, it's better to use IRQ_TYPE_LEVEL_HIGH, like the other +devices do, which seems to fix this problem. + +Signed-off-by: Tomi Valkeinen +Signed-off-by: Jyri Sarha +Signed-off-by: Nikhil Devshatwar +Signed-off-by: Vignesh Raghavendra +Tested-by: Praneeth Bajjuri +[Taken from TI 5.10 SDK] +--- + arch/arm64/boot/dts/ti/k3-am65-main.dtsi | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/ti/k3-am65-main.dtsi b/arch/arm64/boot/dts/ti/k3-am65-main.dtsi +index 5d862f4f45cf..231634fdc469 100644 +--- a/arch/arm64/boot/dts/ti/k3-am65-main.dtsi ++++ b/arch/arm64/boot/dts/ti/k3-am65-main.dtsi +@@ -856,7 +856,7 @@ dss: dss@4a00000 { + assigned-clocks = <&k3_clks 67 2>; + assigned-clock-parents = <&k3_clks 67 5>; + +- interrupts = ; ++ interrupts = ; + + dma-coherent; + +-- +2.42.0 + diff --git a/recipes-kernel/linux/files/patches-6.1/0055-mmc-sdhci_am654-Disable-data-error-interrupts-while-.patch b/recipes-kernel/linux/files/patches-6.1/0055-mmc-sdhci_am654-Disable-data-error-interrupts-while-.patch new file mode 100644 index 000000000..bbaf4b637 --- /dev/null +++ b/recipes-kernel/linux/files/patches-6.1/0055-mmc-sdhci_am654-Disable-data-error-interrupts-while-.patch @@ -0,0 +1,58 @@ +From 49f344a4e615d1da7e68a05fb6c63ddc4feaf0b8 Mon Sep 17 00:00:00 2001 +From: Aswath Govindraju +Date: Wed, 13 Apr 2022 18:44:03 +0530 +Subject: [PATCH 55/69] mmc: sdhci_am654: Disable data error interrupts while + tuning + +Data end bit errors, data CRC errors and data timeout errors are expected +while tuning and are to ignored. Therefore, disable these data error +interrupts before entering tuning. + +Signed-off-by: Aswath Govindraju +Signed-off-by: Vignesh Raghavendra +[Taken from TI 6.1 SDK] +--- + drivers/mmc/host/sdhci_am654.c | 19 ++++++++++++++++++- + 1 file changed, 18 insertions(+), 1 deletion(-) + +diff --git a/drivers/mmc/host/sdhci_am654.c b/drivers/mmc/host/sdhci_am654.c +index 7cdf0f54e3a5..596e80d3d4c0 100644 +--- a/drivers/mmc/host/sdhci_am654.c ++++ b/drivers/mmc/host/sdhci_am654.c +@@ -390,8 +390,18 @@ static void sdhci_am654_reset(struct sdhci_host *host, u8 mask) + static int sdhci_am654_execute_tuning(struct mmc_host *mmc, u32 opcode) + { + struct sdhci_host *host = mmc_priv(mmc); +- int err = sdhci_execute_tuning(mmc, opcode); ++ int err; ++ bool dcrc_was_enabled = false; ++ ++ if (host->ier & SDHCI_INT_DATA_CRC) { ++ host->ier &= ~SDHCI_INT_DATA_CRC | ~SDHCI_INT_DATA_END_BIT | ++ ~SDHCI_INT_DATA_TIMEOUT; ++ dcrc_was_enabled = true; ++ sdhci_writel(host, host->ier, SDHCI_INT_ENABLE); ++ sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE); ++ } + ++ err = sdhci_execute_tuning(mmc, opcode); + if (err) + return err; + /* +@@ -400,6 +410,13 @@ static int sdhci_am654_execute_tuning(struct mmc_host *mmc, u32 opcode) + */ + sdhci_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA); + ++ /* Reenable forbidden interrupt */ ++ if (dcrc_was_enabled) { ++ host->ier |= SDHCI_INT_DATA_CRC | SDHCI_INT_DATA_END_BIT | SDHCI_INT_DATA_TIMEOUT; ++ sdhci_writel(host, host->ier, SDHCI_INT_ENABLE); ++ sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE); ++ } ++ + return 0; + } + +-- +2.42.0 + diff --git a/recipes-kernel/linux/files/patches-6.1/0056-drivers-mmc-host-sdhci_am654-fix-start-loop-index.patch b/recipes-kernel/linux/files/patches-6.1/0056-drivers-mmc-host-sdhci_am654-fix-start-loop-index.patch new file mode 100644 index 000000000..c3e0a765b --- /dev/null +++ b/recipes-kernel/linux/files/patches-6.1/0056-drivers-mmc-host-sdhci_am654-fix-start-loop-index.patch @@ -0,0 +1,33 @@ +From 9596f89bf3c2d56e2547aae0c9ff4c708da5b507 Mon Sep 17 00:00:00 2001 +From: Nitin Yadav +Date: Mon, 28 Nov 2022 16:25:36 +0530 +Subject: [PATCH 56/69] drivers: mmc: host: sdhci_am654: fix start loop index + +ti,otap-del-sel-legacy/ti,itap-del-sel-legacy passed +from DT are currently ignored for all SD/MMC and eMMC +modes. +Fix this by making start loop index to MMC_TIMING_LEGACY. + +Fixes: 8ee5fc0e0b3be ("mmc: sdhci_am654: Update OTAPDLY writes") +Signed-off-by: Nitin Yadav +[Taken from TI 6.1 SDK] +--- + drivers/mmc/host/sdhci_am654.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/mmc/host/sdhci_am654.c b/drivers/mmc/host/sdhci_am654.c +index 596e80d3d4c0..64d9bb545dcc 100644 +--- a/drivers/mmc/host/sdhci_am654.c ++++ b/drivers/mmc/host/sdhci_am654.c +@@ -615,7 +615,7 @@ static int sdhci_am654_get_otap_delay(struct sdhci_host *host, + return 0; + } + +- for (i = MMC_TIMING_MMC_HS; i <= MMC_TIMING_MMC_HS400; i++) { ++ for (i = MMC_TIMING_LEGACY; i <= MMC_TIMING_MMC_HS400; i++) { + + ret = device_property_read_u32(dev, td[i].otap_binding, + &sdhci_am654->otap_del_sel[i]); +-- +2.42.0 + diff --git a/recipes-kernel/linux/files/patches-6.1/0057-drivers-mmc-host-sdhci_am654-update-OTAP-and-ITAP-de.patch b/recipes-kernel/linux/files/patches-6.1/0057-drivers-mmc-host-sdhci_am654-update-OTAP-and-ITAP-de.patch new file mode 100644 index 000000000..b2b1a7e1e --- /dev/null +++ b/recipes-kernel/linux/files/patches-6.1/0057-drivers-mmc-host-sdhci_am654-update-OTAP-and-ITAP-de.patch @@ -0,0 +1,46 @@ +From 78140c257ccee4b383d38e1b6c5603df7cb8a55e Mon Sep 17 00:00:00 2001 +From: Nitin Yadav +Date: Mon, 28 Nov 2022 16:25:37 +0530 +Subject: [PATCH 57/69] drivers: mmc: host: sdhci_am654: update OTAP and ITAP + delay + +Linux is fail to detect class U1 UHS SD cards (such as microcenter) +due to incorrect OTAP and ITAP delay select values. Update OTAP and +ITAP delay select values and masks based on recommeded RIOT values. + +Signed-off-by: Nitin Yadav +[Taken from TI 6.1 SDK] +--- + drivers/mmc/host/sdhci_am654.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/drivers/mmc/host/sdhci_am654.c b/drivers/mmc/host/sdhci_am654.c +index 64d9bb545dcc..6d7681956b19 100644 +--- a/drivers/mmc/host/sdhci_am654.c ++++ b/drivers/mmc/host/sdhci_am654.c +@@ -311,6 +311,7 @@ static void sdhci_j721e_4bit_set_clock(struct sdhci_host *host, + struct sdhci_am654_data *sdhci_am654 = sdhci_pltfm_priv(pltfm_host); + unsigned char timing = host->mmc->ios.timing; + u32 otap_del_sel; ++ u32 itap_del_sel; + u32 mask, val; + + /* Setup DLL Output TAP delay */ +@@ -322,7 +323,14 @@ static void sdhci_j721e_4bit_set_clock(struct sdhci_host *host, + mask = OTAPDLYENA_MASK | OTAPDLYSEL_MASK; + val = (0x1 << OTAPDLYENA_SHIFT) | + (otap_del_sel << OTAPDLYSEL_SHIFT); ++ ++ itap_del_sel = sdhci_am654->itap_del_sel[timing]; ++ mask |= ITAPDLYSEL_MASK | ITAPDLYENA_MASK; ++ val |= (1 << ITAPDLYENA_SHIFT) | (itap_del_sel << ITAPDLYSEL_SHIFT); ++ regmap_update_bits(sdhci_am654->base, PHY_CTRL4, ITAPCHGWIN_MASK, ++ 1 << ITAPCHGWIN_SHIFT); + regmap_update_bits(sdhci_am654->base, PHY_CTRL4, mask, val); ++ regmap_update_bits(sdhci_am654->base, PHY_CTRL4, ITAPCHGWIN_MASK, 0); + + regmap_update_bits(sdhci_am654->base, PHY_CTRL5, CLKBUFSEL_MASK, + sdhci_am654->clkbuf_sel); +-- +2.42.0 + diff --git a/recipes-kernel/linux/files/patches-6.1/0058-PCI-keystone-Convert-to-using-hierarchy-domain-for-l.patch b/recipes-kernel/linux/files/patches-6.1/0058-PCI-keystone-Convert-to-using-hierarchy-domain-for-l.patch new file mode 100644 index 000000000..eaeaec277 --- /dev/null +++ b/recipes-kernel/linux/files/patches-6.1/0058-PCI-keystone-Convert-to-using-hierarchy-domain-for-l.patch @@ -0,0 +1,322 @@ +From 1b0f62f6a1dccdd27dcd906328270e47770b968f Mon Sep 17 00:00:00 2001 +From: Kishon Vijay Abraham I +Date: Tue, 11 Jul 2023 18:02:22 +0530 +Subject: [PATCH 58/69] PCI: keystone: Convert to using hierarchy domain for + legacy interrupts + +K2G provides separate IRQ lines for each of the four legacy interrupts. +Model this using hierarchy domain instead of linear domain with chained +IRQ handler. + +Signed-off-by: Kishon Vijay Abraham I +Signed-off-by: Achal Verma +Link: https://lore.kernel.org/linux-pci/20210325090026.8843-5-kishon@ti.com/ +Signed-off-by: Vignesh Raghavendra +[Taken from TI 6.1 SDK] +--- + drivers/pci/controller/dwc/pci-keystone.c | 211 ++++++++++++---------- + 1 file changed, 120 insertions(+), 91 deletions(-) + +diff --git a/drivers/pci/controller/dwc/pci-keystone.c b/drivers/pci/controller/dwc/pci-keystone.c +index 78818853af9e..44545536641d 100644 +--- a/drivers/pci/controller/dwc/pci-keystone.c ++++ b/drivers/pci/controller/dwc/pci-keystone.c +@@ -69,6 +69,7 @@ + + #define IRQ_STATUS(n) (0x184 + ((n) << 4)) + #define IRQ_ENABLE_SET(n) (0x188 + ((n) << 4)) ++#define IRQ_ENABLE_CLR(n) (0x18c + ((n) << 4)) + #define INTx_EN BIT(0) + + #define ERR_IRQ_STATUS 0x1c4 +@@ -116,7 +117,6 @@ struct keystone_pcie { + struct dw_pcie *pci; + /* PCI Device ID */ + u32 device_id; +- int legacy_host_irqs[PCI_NUM_INTX]; + struct device_node *legacy_intc_np; + + int msi_host_irq; +@@ -125,7 +125,6 @@ struct keystone_pcie { + struct phy **phy; + struct device_link **link; + struct device_node *msi_intc_np; +- struct irq_domain *legacy_irq_domain; + struct device_node *np; + + /* Application register space */ +@@ -253,24 +252,6 @@ static int ks_pcie_msi_host_init(struct dw_pcie_rp *pp) + return dw_pcie_allocate_domains(pp); + } + +-static void ks_pcie_handle_legacy_irq(struct keystone_pcie *ks_pcie, +- int offset) +-{ +- struct dw_pcie *pci = ks_pcie->pci; +- struct device *dev = pci->dev; +- u32 pending; +- +- pending = ks_pcie_app_readl(ks_pcie, IRQ_STATUS(offset)); +- +- if (BIT(0) & pending) { +- dev_dbg(dev, ": irq: irq_offset %d", offset); +- generic_handle_domain_irq(ks_pcie->legacy_irq_domain, offset); +- } +- +- /* EOI the INTx interrupt */ +- ks_pcie_app_writel(ks_pcie, IRQ_EOI, offset); +-} +- + static void ks_pcie_enable_error_irq(struct keystone_pcie *ks_pcie) + { + ks_pcie_app_writel(ks_pcie, ERR_IRQ_ENABLE_SET, ERR_IRQ_ALL); +@@ -308,39 +289,120 @@ static irqreturn_t ks_pcie_handle_error_irq(struct keystone_pcie *ks_pcie) + return IRQ_HANDLED; + } + +-static void ks_pcie_ack_legacy_irq(struct irq_data *d) ++void ks_pcie_irq_eoi(struct irq_data *data) + { ++ struct keystone_pcie *ks_pcie = irq_data_get_irq_chip_data(data); ++ irq_hw_number_t hwirq = data->hwirq; ++ ++ ks_pcie_app_writel(ks_pcie, IRQ_EOI, hwirq); ++ irq_chip_eoi_parent(data); + } + +-static void ks_pcie_mask_legacy_irq(struct irq_data *d) ++void ks_pcie_irq_enable(struct irq_data *data) + { ++ struct keystone_pcie *ks_pcie = irq_data_get_irq_chip_data(data); ++ irq_hw_number_t hwirq = data->hwirq; ++ ++ ks_pcie_app_writel(ks_pcie, IRQ_ENABLE_SET(hwirq), INTx_EN); ++ irq_chip_enable_parent(data); + } + +-static void ks_pcie_unmask_legacy_irq(struct irq_data *d) ++void ks_pcie_irq_disable(struct irq_data *data) + { ++ struct keystone_pcie *ks_pcie = irq_data_get_irq_chip_data(data); ++ irq_hw_number_t hwirq = data->hwirq; ++ ++ ks_pcie_app_writel(ks_pcie, IRQ_ENABLE_CLR(hwirq), INTx_EN); ++ irq_chip_disable_parent(data); + } + + static struct irq_chip ks_pcie_legacy_irq_chip = { +- .name = "Keystone-PCI-Legacy-IRQ", +- .irq_ack = ks_pcie_ack_legacy_irq, +- .irq_mask = ks_pcie_mask_legacy_irq, +- .irq_unmask = ks_pcie_unmask_legacy_irq, ++ .name = "Keystone-PCI-Legacy-IRQ", ++ .irq_enable = ks_pcie_irq_enable, ++ .irq_disable = ks_pcie_irq_disable, ++ .irq_eoi = ks_pcie_irq_eoi, ++ .irq_mask = irq_chip_mask_parent, ++ .irq_unmask = irq_chip_unmask_parent, ++ .irq_retrigger = irq_chip_retrigger_hierarchy, ++ .irq_set_type = irq_chip_set_type_parent, ++ .irq_set_affinity = irq_chip_set_affinity_parent, + }; + +-static int ks_pcie_init_legacy_irq_map(struct irq_domain *d, +- unsigned int irq, +- irq_hw_number_t hw_irq) ++static int ks_pcie_legacy_irq_domain_alloc(struct irq_domain *domain, unsigned int virq, ++ unsigned int nr_irqs, void *data) + { +- irq_set_chip_and_handler(irq, &ks_pcie_legacy_irq_chip, +- handle_level_irq); +- irq_set_chip_data(irq, d->host_data); ++ struct keystone_pcie *ks_pcie = domain->host_data; ++ struct device_node *np = ks_pcie->legacy_intc_np; ++ struct irq_fwspec parent_fwspec, *fwspec = data; ++ struct of_phandle_args out_irq; ++ int ret; ++ ++ if (nr_irqs != 1) ++ return -EINVAL; ++ ++ /* ++ * Get the correct interrupt from legacy-interrupt-controller node ++ * corresponding to INTA/INTB/INTC/INTD (passed in fwspec->param[0]) ++ * after performing mapping specified in "interrupt-map". ++ * interrupt-map = <0 0 0 1 &pcie_intc0 0>, INTA (4th cell in ++ * interrupt-map) corresponds to 1st entry in "interrupts" (6th cell ++ * in interrupt-map) ++ */ ++ ret = of_irq_parse_one(np, fwspec->param[0], &out_irq); ++ if (ret < 0) { ++ pr_err("Failed to parse interrupt node\n"); ++ return ret; ++ } ++ ++ of_phandle_args_to_fwspec(np, out_irq.args, out_irq.args_count, &parent_fwspec); ++ ++ ret = irq_domain_alloc_irqs_parent(domain, virq, 1, &parent_fwspec); ++ if (ret < 0) { ++ pr_err("Failed to allocate parent irq %u: %d\n", ++ parent_fwspec.param[0], ret); ++ return ret; ++ } ++ ++ ret = irq_domain_set_hwirq_and_chip(domain, virq, fwspec->param[0], ++ &ks_pcie_legacy_irq_chip, ks_pcie); ++ if (ret < 0) { ++ pr_err("Failed to set hwirq and chip\n"); ++ goto err_set_hwirq_and_chip; ++ } + + return 0; ++ ++err_set_hwirq_and_chip: ++ irq_domain_free_irqs_parent(domain, virq, 1); ++ ++ return ret; ++} ++ ++static int ks_pcie_irq_domain_translate(struct irq_domain *domain, ++ struct irq_fwspec *fwspec, ++ unsigned long *hwirq, ++ unsigned int *type) ++{ ++ if (is_of_node(fwspec->fwnode)) { ++ if (fwspec->param_count != 2) ++ return -EINVAL; ++ ++ if (fwspec->param[0] >= PCI_NUM_INTX) ++ return -EINVAL; ++ ++ *hwirq = fwspec->param[0]; ++ *type = fwspec->param[1]; ++ ++ return 0; ++ } ++ ++ return -EINVAL; + } + + static const struct irq_domain_ops ks_pcie_legacy_irq_domain_ops = { +- .map = ks_pcie_init_legacy_irq_map, +- .xlate = irq_domain_xlate_onetwocell, ++ .alloc = ks_pcie_legacy_irq_domain_alloc, ++ .free = irq_domain_free_irqs_common, ++ .translate = ks_pcie_irq_domain_translate, + }; + + /** +@@ -605,34 +667,6 @@ static void ks_pcie_msi_irq_handler(struct irq_desc *desc) + chained_irq_exit(chip, desc); + } + +-/** +- * ks_pcie_legacy_irq_handler() - Handle legacy interrupt +- * @desc: Pointer to irq descriptor +- * +- * Traverse through pending legacy interrupts and invoke handler for each. Also +- * takes care of interrupt controller level mask/ack operation. +- */ +-static void ks_pcie_legacy_irq_handler(struct irq_desc *desc) +-{ +- unsigned int irq = irq_desc_get_irq(desc); +- struct keystone_pcie *ks_pcie = irq_desc_get_handler_data(desc); +- struct dw_pcie *pci = ks_pcie->pci; +- struct device *dev = pci->dev; +- u32 irq_offset = irq - ks_pcie->legacy_host_irqs[0]; +- struct irq_chip *chip = irq_desc_get_chip(desc); +- +- dev_dbg(dev, ": Handling legacy irq %d\n", irq); +- +- /* +- * The chained irq handler installation would have replaced normal +- * interrupt driver handler so we need to take care of mask/unmask and +- * ack operation. +- */ +- chained_irq_enter(chip, desc); +- ks_pcie_handle_legacy_irq(ks_pcie, irq_offset); +- chained_irq_exit(chip, desc); +-} +- + static int ks_pcie_config_msi_irq(struct keystone_pcie *ks_pcie) + { + struct device *dev = ks_pcie->pci->dev; +@@ -692,20 +726,33 @@ static int ks_pcie_config_legacy_irq(struct keystone_pcie *ks_pcie) + struct device *dev = ks_pcie->pci->dev; + struct irq_domain *legacy_irq_domain; + struct device_node *np = ks_pcie->np; ++ struct irq_domain *parent_domain; ++ struct device_node *parent_node; + struct device_node *intc_np; +- int irq_count, irq, ret = 0, i; ++ int irq_count, ret = 0; + +- intc_np = of_get_child_by_name(np, "legacy-interrupt-controller"); ++ intc_np = of_get_child_by_name(np, "interrupt-controller"); + if (!intc_np) { +- /* +- * Since legacy interrupts are modeled as edge-interrupts in +- * AM6, keep it disabled for now. +- */ +- if (ks_pcie->is_am6) +- return 0; + dev_warn(dev, "legacy-interrupt-controller node is absent\n"); + return -EINVAL; + } ++ ks_pcie->legacy_intc_np = intc_np; ++ ++ parent_node = of_irq_find_parent(intc_np); ++ if (!parent_node) { ++ dev_err(dev, "unable to obtain parent node\n"); ++ ret = -ENXIO; ++ goto err; ++ } ++ ++ parent_domain = irq_find_host(parent_node); ++ if (!parent_domain) { ++ dev_err(dev, "unable to obtain parent domain\n"); ++ ret = -ENXIO; ++ goto err; ++ } ++ ++ of_node_put(parent_node); + + irq_count = of_irq_count(intc_np); + if (!irq_count) { +@@ -714,31 +761,13 @@ static int ks_pcie_config_legacy_irq(struct keystone_pcie *ks_pcie) + goto err; + } + +- for (i = 0; i < irq_count; i++) { +- irq = irq_of_parse_and_map(intc_np, i); +- if (!irq) { +- ret = -EINVAL; +- goto err; +- } +- ks_pcie->legacy_host_irqs[i] = irq; +- +- irq_set_chained_handler_and_data(irq, +- ks_pcie_legacy_irq_handler, +- ks_pcie); +- } +- +- legacy_irq_domain = +- irq_domain_add_linear(intc_np, PCI_NUM_INTX, +- &ks_pcie_legacy_irq_domain_ops, NULL); ++ legacy_irq_domain = irq_domain_add_hierarchy(parent_domain, 0, PCI_NUM_INTX, intc_np, ++ &ks_pcie_legacy_irq_domain_ops, ks_pcie); + if (!legacy_irq_domain) { + dev_err(dev, "Failed to add irq domain for legacy irqs\n"); + ret = -EINVAL; + goto err; + } +- ks_pcie->legacy_irq_domain = legacy_irq_domain; +- +- for (i = 0; i < PCI_NUM_INTX; i++) +- ks_pcie_app_writel(ks_pcie, IRQ_ENABLE_SET(i), INTx_EN); + + err: + of_node_put(intc_np); +-- +2.42.0 + diff --git a/recipes-kernel/linux/files/patches-6.1/0059-PCI-keystone-Add-PCI-legacy-interrupt-support-for-AM.patch b/recipes-kernel/linux/files/patches-6.1/0059-PCI-keystone-Add-PCI-legacy-interrupt-support-for-AM.patch new file mode 100644 index 000000000..48edae63e --- /dev/null +++ b/recipes-kernel/linux/files/patches-6.1/0059-PCI-keystone-Add-PCI-legacy-interrupt-support-for-AM.patch @@ -0,0 +1,148 @@ +From 60708bfefc62f2fc06cfd9ae3ee2b2ca2075ade8 Mon Sep 17 00:00:00 2001 +From: Kishon Vijay Abraham I +Date: Tue, 11 Jul 2023 18:02:23 +0530 +Subject: [PATCH 59/69] PCI: keystone: Add PCI legacy interrupt support for + AM654 + +Add PCI legacy interrupt support for AM654. AM654 has a single HW +interrupt line for all the four legacy interrupts INTA/INTB/INTC/INTD. +The HW interrupt line connected to GIC is a pulse interrupt whereas +the legacy interrupts by definition is level interrupt. In order to +provide level interrupt functionality to edge interrupt line, PCIe +in AM654 has provided IRQ_EOI register. When the SW writes to IRQ_EOI +register after handling the interrupt, the IP checks the state of +legacy interrupt and re-triggers pulse interrupt invoking the handler +again. + +Signed-off-by: Kishon Vijay Abraham I +Signed-off-by: Achal Verma +Link: https://lore.kernel.org/linux-pci/20210325090026.8843-6-kishon@ti.com/ +Signed-off-by: Vignesh Raghavendra +[Taken from TI 6.1 SDK] +--- + drivers/pci/controller/dwc/pci-keystone.c | 87 +++++++++++++++++++++-- + 1 file changed, 82 insertions(+), 5 deletions(-) + +diff --git a/drivers/pci/controller/dwc/pci-keystone.c b/drivers/pci/controller/dwc/pci-keystone.c +index 44545536641d..5797818860e5 100644 +--- a/drivers/pci/controller/dwc/pci-keystone.c ++++ b/drivers/pci/controller/dwc/pci-keystone.c +@@ -118,6 +118,7 @@ struct keystone_pcie { + /* PCI Device ID */ + u32 device_id; + struct device_node *legacy_intc_np; ++ struct irq_domain *legacy_irq_domain; + + int msi_host_irq; + int num_lanes; +@@ -289,6 +290,29 @@ static irqreturn_t ks_pcie_handle_error_irq(struct keystone_pcie *ks_pcie) + return IRQ_HANDLED; + } + ++static void ks_pcie_am654_legacy_irq_handler(struct irq_desc *desc) ++{ ++ struct keystone_pcie *ks_pcie = irq_desc_get_handler_data(desc); ++ struct irq_chip *chip = irq_desc_get_chip(desc); ++ int virq, i; ++ u32 reg; ++ ++ chained_irq_enter(chip, desc); ++ ++ for (i = 0; i < PCI_NUM_INTX; i++) { ++ reg = ks_pcie_app_readl(ks_pcie, IRQ_STATUS(i)); ++ if (!(reg & INTx_EN)) ++ continue; ++ ++ virq = irq_linear_revmap(ks_pcie->legacy_irq_domain, i); ++ generic_handle_irq(virq); ++ ks_pcie_app_writel(ks_pcie, IRQ_STATUS(i), INTx_EN); ++ ks_pcie_app_writel(ks_pcie, IRQ_EOI, i); ++ } ++ ++ chained_irq_exit(chip, desc); ++} ++ + void ks_pcie_irq_eoi(struct irq_data *data) + { + struct keystone_pcie *ks_pcie = irq_data_get_irq_chip_data(data); +@@ -721,6 +745,54 @@ static int ks_pcie_config_msi_irq(struct keystone_pcie *ks_pcie) + return ret; + } + ++static int ks_pcie_am654_intx_map(struct irq_domain *domain, unsigned int irq, ++ irq_hw_number_t hwirq) ++{ ++ irq_set_chip_and_handler(irq, &dummy_irq_chip, handle_simple_irq); ++ irq_set_chip_data(irq, domain->host_data); ++ ++ return 0; ++} ++ ++static const struct irq_domain_ops ks_pcie_am654_irq_domain_ops = { ++ .map = ks_pcie_am654_intx_map, ++}; ++ ++static int ks_pcie_am654_config_legacy_irq(struct keystone_pcie *ks_pcie) ++{ ++ struct device *dev = ks_pcie->pci->dev; ++ struct irq_domain *legacy_irq_domain; ++ struct device_node *np = ks_pcie->np; ++ struct device_node *intc_np; ++ int ret = 0; ++ int irq; ++ int i; ++ ++ intc_np = of_get_child_by_name(np, "interrupt-controller"); ++ if (!intc_np) { ++ dev_warn(dev, "legacy interrupt-controller node is absent\n"); ++ return -EINVAL; ++ } ++ ++ irq = irq_of_parse_and_map(intc_np, 0); ++ if (!irq) ++ return -EINVAL; ++ ++ irq_set_chained_handler_and_data(irq, ks_pcie_am654_legacy_irq_handler, ks_pcie); ++ legacy_irq_domain = irq_domain_add_linear(intc_np, PCI_NUM_INTX, ++ &ks_pcie_am654_irq_domain_ops, ks_pcie); ++ if (!legacy_irq_domain) { ++ dev_err(dev, "Failed to add irq domain for legacy irqs\n"); ++ return -EINVAL; ++ } ++ ks_pcie->legacy_irq_domain = legacy_irq_domain; ++ ++ for (i = 0; i < PCI_NUM_INTX; i++) ++ ks_pcie_app_writel(ks_pcie, IRQ_ENABLE_SET(i), INTx_EN); ++ ++ return ret; ++} ++ + static int ks_pcie_config_legacy_irq(struct keystone_pcie *ks_pcie) + { + struct device *dev = ks_pcie->pci->dev; +@@ -835,12 +907,17 @@ static int __init ks_pcie_host_init(struct dw_pcie_rp *pp) + int ret; + + pp->bridge->ops = &ks_pcie_ops; +- if (!ks_pcie->is_am6) +- pp->bridge->child_ops = &ks_child_pcie_ops; + +- ret = ks_pcie_config_legacy_irq(ks_pcie); +- if (ret) +- return ret; ++ if (!ks_pcie->is_am6) { ++ pp->bridge->child_ops = &ks_child_pcie_ops; ++ ret = ks_pcie_config_legacy_irq(ks_pcie); ++ if (ret) ++ return ret; ++ } else { ++ ret = ks_pcie_am654_config_legacy_irq(ks_pcie); ++ if (ret) ++ return ret; ++ } + + ret = ks_pcie_config_msi_irq(ks_pcie); + if (ret) +-- +2.42.0 + diff --git a/recipes-kernel/linux/files/patches-6.1/0060-PCI-keystone-Add-workaround-for-Errata-i2037-AM65x-S.patch b/recipes-kernel/linux/files/patches-6.1/0060-PCI-keystone-Add-workaround-for-Errata-i2037-AM65x-S.patch new file mode 100644 index 000000000..858524503 --- /dev/null +++ b/recipes-kernel/linux/files/patches-6.1/0060-PCI-keystone-Add-workaround-for-Errata-i2037-AM65x-S.patch @@ -0,0 +1,114 @@ +From 49f17d96f2027d04f661ecedfabda39806dd2979 Mon Sep 17 00:00:00 2001 +From: Kishon Vijay Abraham I +Date: Tue, 11 Jul 2023 18:02:26 +0530 +Subject: [PATCH 60/69] PCI: keystone: Add workaround for Errata #i2037 (AM65x + SR 1.0) + +Errata #i2037 in AM65x/DRA80xM Processors Silicon Revision 1.0 +(SPRZ452D_July 2018_Revised December 2019 [1]) mentions when an +inbound PCIe TLP spans more than two internal AXI 128-byte bursts, +the bus may corrupt the packet payload and the corrupt data may +cause associated applications or the processor to hang. + +The workaround for Errata #i2037 is to limit the maximum read +request size and maximum payload size to 128 Bytes. Add workaround +for Errata #i2037 here. The errata and workaround is applicable +only to AM65x SR 1.0 and later versions of the silicon will have +this fixed. + +[1] -> http://www.ti.com/lit/er/sprz452d/sprz452d.pdf + +Signed-off-by: Kishon Vijay Abraham I +Signed-off-by: Achal Verma +Link: https://lore.kernel.org/linux-pci/20210325090026.8843-7-kishon@ti.com/ +Signed-off-by: Vignesh Raghavendra +[Taken from TI 6.1 SDK] +--- + drivers/pci/controller/dwc/pci-keystone.c | 42 +++++++++++++++++++++++ + 1 file changed, 42 insertions(+) + +diff --git a/drivers/pci/controller/dwc/pci-keystone.c b/drivers/pci/controller/dwc/pci-keystone.c +index 5797818860e5..fefb375a777a 100644 +--- a/drivers/pci/controller/dwc/pci-keystone.c ++++ b/drivers/pci/controller/dwc/pci-keystone.c +@@ -35,6 +35,11 @@ + #define PCIE_DEVICEID_SHIFT 16 + + /* Application registers */ ++#define PID 0x000 ++#define RTL GENMASK(15, 11) ++#define RTL_SHIFT 11 ++#define AM6_PCI_PG1_RTL_VER 0x15 ++ + #define CMD_STATUS 0x004 + #define LTSSM_EN_VAL BIT(0) + #define OB_XLAT_EN_VAL BIT(1) +@@ -106,6 +111,8 @@ + + #define to_keystone_pcie(x) dev_get_drvdata((x)->dev) + ++#define PCI_DEVICE_ID_TI_AM654X 0xb00c ++ + struct ks_pcie_of_data { + enum dw_pcie_device_mode mode; + const struct dw_pcie_host_ops *host_ops; +@@ -614,7 +621,11 @@ static int ks_pcie_start_link(struct dw_pcie *pci) + static void ks_pcie_quirk(struct pci_dev *dev) + { + struct pci_bus *bus = dev->bus; ++ struct keystone_pcie *ks_pcie; ++ struct device *bridge_dev; + struct pci_dev *bridge; ++ u32 val; ++ + static const struct pci_device_id rc_pci_devids[] = { + { PCI_DEVICE(PCI_VENDOR_ID_TI, PCIE_RC_K2HK), + .class = PCI_CLASS_BRIDGE_PCI_NORMAL, .class_mask = ~0, }, +@@ -626,6 +637,11 @@ static void ks_pcie_quirk(struct pci_dev *dev) + .class = PCI_CLASS_BRIDGE_PCI_NORMAL, .class_mask = ~0, }, + { 0, }, + }; ++ static const struct pci_device_id am6_pci_devids[] = { ++ { PCI_DEVICE(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_AM654X), ++ .class = PCI_CLASS_BRIDGE_PCI << 8, .class_mask = ~0, }, ++ { 0, }, ++ }; + + if (pci_is_root_bus(bus)) + bridge = dev; +@@ -651,6 +667,32 @@ static void ks_pcie_quirk(struct pci_dev *dev) + pcie_set_readrq(dev, 256); + } + } ++ ++ /* ++ * Memory transactions fail with PCI controller in AM654 PG1.0 ++ * when MRRS is set to more than 128 Bytes. Force the MRRS to ++ * 128 Bytes in all downstream devices. ++ */ ++ if (pci_match_id(am6_pci_devids, bridge)) { ++ bridge_dev = pci_get_host_bridge_device(dev); ++ if (!bridge_dev && !bridge_dev->parent) ++ return; ++ ++ ks_pcie = dev_get_drvdata(bridge_dev->parent); ++ if (!ks_pcie) ++ return; ++ ++ val = ks_pcie_app_readl(ks_pcie, PID); ++ val &= RTL; ++ val >>= RTL_SHIFT; ++ if (val != AM6_PCI_PG1_RTL_VER) ++ return; ++ ++ if (pcie_get_readrq(dev) > 128) { ++ dev_info(&dev->dev, "limiting MRRS to 128\n"); ++ pcie_set_readrq(dev, 128); ++ } ++ } + } + DECLARE_PCI_FIXUP_ENABLE(PCI_ANY_ID, PCI_ANY_ID, ks_pcie_quirk); + +-- +2.42.0 + diff --git a/recipes-kernel/linux/files/patches-6.1/0061-arm64-dts-ti-k3-am65-main-Add-properties-to-support-.patch b/recipes-kernel/linux/files/patches-6.1/0061-arm64-dts-ti-k3-am65-main-Add-properties-to-support-.patch new file mode 100644 index 000000000..07f5b7dcc --- /dev/null +++ b/recipes-kernel/linux/files/patches-6.1/0061-arm64-dts-ti-k3-am65-main-Add-properties-to-support-.patch @@ -0,0 +1,65 @@ +From 17eff093e6c3ee88e278c523a39d59a0089c7280 Mon Sep 17 00:00:00 2001 +From: Kishon Vijay Abraham I +Date: Tue, 11 Jul 2023 18:02:25 +0530 +Subject: [PATCH 61/69] arm64: dts: ti: k3-am65-main: Add properties to support + legacy interrupts + +Add DT properties in PCIe DT node to support legacy interrupts. + +Signed-off-by: Kishon Vijay Abraham I +Signed-off-by: Sekhar Nori +Signed-off-by: Achal Verma +Link: https://serenity.dal.design.ti.com/patchwork/project/linux-patch-review/patch/20210330120812.23944-10-kishon@ti.com/ +Signed-off-by: Vignesh Raghavendra +[Taken from TI 6.1 SDK] +--- + arch/arm64/boot/dts/ti/k3-am65-main.dtsi | 26 ++++++++++++++++++++++++ + 1 file changed, 26 insertions(+) + +diff --git a/arch/arm64/boot/dts/ti/k3-am65-main.dtsi b/arch/arm64/boot/dts/ti/k3-am65-main.dtsi +index 231634fdc469..b781aea9979c 100644 +--- a/arch/arm64/boot/dts/ti/k3-am65-main.dtsi ++++ b/arch/arm64/boot/dts/ti/k3-am65-main.dtsi +@@ -706,6 +706,19 @@ pcie0_rc: pcie@5500000 { + interrupts = ; + msi-map = <0x0 &gic_its 0x0 0x10000>; + device_type = "pci"; ++ #interrupt-cells = <1>; ++ interrupt-map-mask = <0 0 0 7>; ++ interrupt-map = <0 0 0 1 &pcie0_intc 0>, /* INT A */ ++ <0 0 0 2 &pcie0_intc 0>, /* INT B */ ++ <0 0 0 3 &pcie0_intc 0>, /* INT C */ ++ <0 0 0 4 &pcie0_intc 0>; /* INT D */ ++ ++ pcie0_intc: interrupt-controller { ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ interrupt-parent = <&gic500>; ++ interrupts = ; ++ }; + }; + + pcie0_ep: pcie-ep@5500000 { +@@ -739,6 +752,19 @@ pcie1_rc: pcie@5600000 { + interrupts = ; + msi-map = <0x0 &gic_its 0x10000 0x10000>; + device_type = "pci"; ++ #interrupt-cells = <1>; ++ interrupt-map-mask = <0 0 0 7>; ++ interrupt-map = <0 0 0 1 &pcie1_intc 0>, /* INT A */ ++ <0 0 0 2 &pcie1_intc 0>, /* INT B */ ++ <0 0 0 3 &pcie1_intc 0>, /* INT C */ ++ <0 0 0 4 &pcie1_intc 0>; /* INT D */ ++ ++ pcie1_intc: interrupt-controller { ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ interrupt-parent = <&gic500>; ++ interrupts = ; ++ }; + }; + + pcie1_ep: pcie-ep@5600000 { +-- +2.42.0 + diff --git a/recipes-kernel/linux/files/patches-6.1/0062-firmware-ti_sci-Update-ti_sci_msg_req_reboot-to-incl.patch b/recipes-kernel/linux/files/patches-6.1/0062-firmware-ti_sci-Update-ti_sci_msg_req_reboot-to-incl.patch new file mode 100644 index 000000000..77e3a6248 --- /dev/null +++ b/recipes-kernel/linux/files/patches-6.1/0062-firmware-ti_sci-Update-ti_sci_msg_req_reboot-to-incl.patch @@ -0,0 +1,57 @@ +From 14a90606e33d1aad24272ce7e6a98e345814a1f1 Mon Sep 17 00:00:00 2001 +From: Suman Anna +Date: Fri, 23 Oct 2020 14:36:43 -0500 +Subject: [PATCH 62/69] firmware: ti_sci: Update ti_sci_msg_req_reboot to + include domain + +The ti_sci_msg_req_reboot message payload has been extended to include +a domain field, and this should be zero to reset the entire SoC with +System Firmwares newer than v2020.04. Add the domain field to the +ti_sci_msg_req_reboot message structure for completeness. Set it up +to zero to fix the reboot issues with newer firmwares. + +The ideal long-term fix should be to ensure that the transfer buffer +is zero-initialized. + +Signed-off-by: Suman Anna +Signed-off-by: Dave Gerlach +[Taken from TI 5.10 SDK] +--- + drivers/firmware/ti_sci.c | 1 + + drivers/firmware/ti_sci.h | 2 ++ + 2 files changed, 3 insertions(+) + +diff --git a/drivers/firmware/ti_sci.c b/drivers/firmware/ti_sci.c +index 4c550cfbc086..b7a52e5855e3 100644 +--- a/drivers/firmware/ti_sci.c ++++ b/drivers/firmware/ti_sci.c +@@ -1690,6 +1690,7 @@ static int ti_sci_cmd_core_reboot(const struct ti_sci_handle *handle) + return ret; + } + req = (struct ti_sci_msg_req_reboot *)xfer->xfer_buf; ++ req->domain = 0; + + ret = ti_sci_do_xfer(info, xfer); + if (ret) { +diff --git a/drivers/firmware/ti_sci.h b/drivers/firmware/ti_sci.h +index ef3a8214d002..c0766dfcd7a1 100644 +--- a/drivers/firmware/ti_sci.h ++++ b/drivers/firmware/ti_sci.h +@@ -124,12 +124,14 @@ struct ti_sci_msg_resp_version { + /** + * struct ti_sci_msg_req_reboot - Reboot the SoC + * @hdr: Generic Header ++ * @domain: Domain to be reset, 0 for full SoC reboot + * + * Request type is TI_SCI_MSG_SYS_RESET, responded with a generic + * ACK/NACK message. + */ + struct ti_sci_msg_req_reboot { + struct ti_sci_msg_hdr hdr; ++ u8 domain; + } __packed; + + /** +-- +2.42.0 + diff --git a/recipes-kernel/linux/files/patches-6.1/0063-WIP-arm64-dts-ti-iot2050-Add-node-for-generic-spidev.patch b/recipes-kernel/linux/files/patches-6.1/0063-WIP-arm64-dts-ti-iot2050-Add-node-for-generic-spidev.patch new file mode 100644 index 000000000..b8a9470d1 --- /dev/null +++ b/recipes-kernel/linux/files/patches-6.1/0063-WIP-arm64-dts-ti-iot2050-Add-node-for-generic-spidev.patch @@ -0,0 +1,38 @@ +From daebb16ed102e1778c2130a125a0beb7f443dae7 Mon Sep 17 00:00:00 2001 +From: Jan Kiszka +Date: Thu, 11 Mar 2021 15:28:21 +0100 +Subject: [PATCH 63/69] WIP: arm64: dts: ti: iot2050: Add node for generic + spidev + +This allows to use mcu_spi0 via userspace spidev. + +TODO: Clarify official binding for rohm,dh2228fv. So far it is only a +de-facto binding, done by some in-tree DTs and the driver. Maybe model +as overlay instead? + +Signed-off-by: Jan Kiszka +[Siemens patch from 5.10] +--- + arch/arm64/boot/dts/ti/k3-am65-iot2050-common.dtsi | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/arch/arm64/boot/dts/ti/k3-am65-iot2050-common.dtsi b/arch/arm64/boot/dts/ti/k3-am65-iot2050-common.dtsi +index 46e7cc73b972..5644bc0a8dda 100644 +--- a/arch/arm64/boot/dts/ti/k3-am65-iot2050-common.dtsi ++++ b/arch/arm64/boot/dts/ti/k3-am65-iot2050-common.dtsi +@@ -582,6 +582,12 @@ &mcu_spi0 { + #address-cells = <1>; + #size-cells = <0>; + ti,pindir-d0-out-d1-in; ++ ++ spidev@0 { ++ compatible = "rohm,dh2228fv"; ++ spi-max-frequency = <20000000>; ++ reg = <0>; ++ }; + }; + + &tscadc0 { +-- +2.42.0 + diff --git a/recipes-kernel/linux/files/patches-6.1/0064-arm64-dts-ti-iot2050-Add-icssg-prueth-nodes-for-PG1-.patch b/recipes-kernel/linux/files/patches-6.1/0064-arm64-dts-ti-iot2050-Add-icssg-prueth-nodes-for-PG1-.patch new file mode 100644 index 000000000..d18213340 --- /dev/null +++ b/recipes-kernel/linux/files/patches-6.1/0064-arm64-dts-ti-iot2050-Add-icssg-prueth-nodes-for-PG1-.patch @@ -0,0 +1,185 @@ +From 8bbe1a3809aaaee66e88f3a51abe5afc22495f64 Mon Sep 17 00:00:00 2001 +From: Jan Kiszka +Date: Sat, 27 Jun 2020 10:53:13 +0200 +Subject: [PATCH 64/69] arm64: dts: ti: iot2050: Add icssg-prueth nodes for PG1 + and PG2 devices + +Add the required nodes to enable ICSSG SR1.0 and SR2.0 based prueth +networking. + +Signed-off-by: Jan Kiszka +[Siemens patch from 5.10] +--- + .../boot/dts/ti/k3-am65-iot2050-common.dtsi | 129 +++++++++++++++++- + 1 file changed, 128 insertions(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/ti/k3-am65-iot2050-common.dtsi b/arch/arm64/boot/dts/ti/k3-am65-iot2050-common.dtsi +index 5644bc0a8dda..81cc6eb11797 100644 +--- a/arch/arm64/boot/dts/ti/k3-am65-iot2050-common.dtsi ++++ b/arch/arm64/boot/dts/ti/k3-am65-iot2050-common.dtsi +@@ -11,12 +11,15 @@ + + #include "k3-am654.dtsi" + #include ++#include + + / { + aliases { + spi0 = &mcu_spi0; + mmc0 = &sdhci1; + mmc1 = &sdhci0; ++ ethernet1 = &icssg0_emac0; ++ ethernet2 = &icssg0_emac1; + }; + + chosen { +@@ -108,6 +111,80 @@ dp_refclk: clock { + #clock-cells = <0>; + clock-frequency = <19200000>; + }; ++ ++ /* Dual Ethernet application node on PRU-ICSSG0 */ ++ icssg0_eth: icssg0-eth { ++ compatible = "ti,am654-icssg-prueth"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&icssg0_rgmii_pins_default>; ++ sram = <&msmc_ram>; ++ ++ ti,prus = <&pru0_0>, <&rtu0_0>, <&tx_pru0_0>, ++ <&pru0_1>, <&rtu0_1>, <&tx_pru0_1>; ++ firmware-name = "ti-pruss/am65x-sr2-pru0-prueth-fw.elf", ++ "ti-pruss/am65x-sr2-rtu0-prueth-fw.elf", ++ "ti-pruss/am65x-sr2-txpru0-prueth-fw.elf", ++ "ti-pruss/am65x-sr2-pru1-prueth-fw.elf", ++ "ti-pruss/am65x-sr2-rtu1-prueth-fw.elf", ++ "ti-pruss/am65x-sr2-txpru1-prueth-fw.elf"; ++ ++ ti,pruss-gp-mux-sel = <2>, /* MII mode */ ++ <2>, ++ <2>, ++ <2>, /* MII mode */ ++ <2>, ++ <2>; ++ ++ ti,mii-g-rt = <&icssg0_mii_g_rt>; ++ ti,mii-rt = <&icssg0_mii_rt>; ++ ti,iep = <&icssg0_iep0>, <&icssg0_iep1>; ++ ++ interrupt-parent = <&icssg0_intc>; ++ interrupts = <24 0 2>, <25 1 3>; ++ interrupt-names = "tx_ts0", "tx_ts1"; ++ ++ dmas = <&main_udmap 0xc100>, /* egress slice 0 */ ++ <&main_udmap 0xc101>, /* egress slice 0 */ ++ <&main_udmap 0xc102>, /* egress slice 0 */ ++ <&main_udmap 0xc103>, /* egress slice 0 */ ++ <&main_udmap 0xc104>, /* egress slice 1 */ ++ <&main_udmap 0xc105>, /* egress slice 1 */ ++ <&main_udmap 0xc106>, /* egress slice 1 */ ++ <&main_udmap 0xc107>, /* egress slice 1 */ ++ ++ <&main_udmap 0x4100>, /* ingress slice 0 */ ++ <&main_udmap 0x4101>, /* ingress slice 1 */ ++ <&main_udmap 0x4102>, /* mgmnt rsp slice 0 */ ++ <&main_udmap 0x4103>; /* mgmnt rsp slice 1 */ ++ dma-names = "tx0-0", "tx0-1", "tx0-2", "tx0-3", ++ "tx1-0", "tx1-1", "tx1-2", "tx1-3", ++ "rx0", "rx1", ++ "rxmgm0", "rxmgm1"; ++ ++ ethernet-ports { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ icssg0_emac0: port@0 { ++ reg = <0>; ++ phy-handle = <&icssg0_eth0_phy>; ++ phy-mode = "rgmii-id"; ++ ti,syscon-rgmii-delay = <&scm_conf 0x4100>; ++ ti,half-duplex-capable; ++ /* Filled in by bootloader */ ++ local-mac-address = [00 00 00 00 00 00]; ++ }; ++ ++ icssg0_emac1: port@1 { ++ reg = <1>; ++ phy-handle = <&icssg0_eth1_phy>; ++ phy-mode = "rgmii-id"; ++ ti,syscon-rgmii-delay = <&scm_conf 0x4104>; ++ ti,half-duplex-capable; ++ /* Filled in by bootloader */ ++ local-mac-address = [00 00 00 00 00 00]; ++ }; ++ }; ++ }; + }; + + &wkup_pmx0 { +@@ -336,6 +413,43 @@ AM65X_IOPAD(0x0074, PIN_INPUT, 5) /* (T27) I2C2_SCL */ + AM65X_IOPAD(0x0070, PIN_INPUT, 5) /* (R25) I2C2_SDA */ + >; + }; ++ ++ icssg0_mdio_pins_default: icssg0-mdio-pins-default { ++ pinctrl-single,pins = < ++ AM65X_IOPAD(0x0294, PIN_INPUT, 0) /* (AE26) PRG0_MDIO0_MDIO */ ++ AM65X_IOPAD(0x0298, PIN_OUTPUT, 0) /* (AE28) PRG0_MDIO0_MDC */ ++ >; ++ }; ++ ++ icssg0_rgmii_pins_default: icssg0-rgmii-pins-default { ++ pinctrl-single,pins = < ++ AM65X_IOPAD(0x0244, PIN_INPUT, 2) /* (AB28) PRG0_PRU1_GPO0.PRG0_RGMII2_RD0 */ ++ AM65X_IOPAD(0x0248, PIN_INPUT, 2) /* (AC28) PRG0_PRU1_GPO1.PRG0_RGMII2_RD1 */ ++ AM65X_IOPAD(0x024c, PIN_INPUT, 2) /* (AC27) PRG0_PRU1_GPO2.PRG0_RGMII2_RD2 */ ++ AM65X_IOPAD(0x0250, PIN_INPUT, 2) /* (AB26) PRG0_PRU1_GPO3.PRG0_RGMII2_RD3 */ ++ AM65X_IOPAD(0x0274, PIN_OUTPUT, 2) /* (AC25) PRG0_PRU1_GPO12.PRG0_RGMII2_TD0 */ ++ AM65X_IOPAD(0x0278, PIN_OUTPUT, 2) /* (AD25) PRG0_PRU1_GPO13.PRG0_RGMII2_TD1 */ ++ AM65X_IOPAD(0x027c, PIN_OUTPUT, 2) /* (AD24) PRG0_PRU1_GPO14.PRG0_RGMII2_TD2 */ ++ AM65X_IOPAD(0x0280, PIN_OUTPUT, 2) /* (AE27) PRG0_PRU1_GPO15.PRG0_RGMII2_TD3 */ ++ AM65X_IOPAD(0x0284, PIN_INPUT, 2) /* (AC24) PRG0_PRU1_GPO16.PRG0_RGMII2_TXC */ ++ AM65X_IOPAD(0x0270, PIN_OUTPUT, 2) /* (AB24) PRG0_PRU1_GPO11.PRG0_RGMII2_TX_CTL */ ++ AM65X_IOPAD(0x025c, PIN_INPUT, 2) /* (AB27) PRG0_PRU1_GPO6.PRG0_RGMII2_RXC */ ++ AM65X_IOPAD(0x0254, PIN_INPUT, 2) /* (AA25) PRG0_PRU1_GPO4.PRG0_RGMII2_RX_CTL */ ++ ++ AM65X_IOPAD(0x01f4, PIN_INPUT, 2) /* (V24) PRG0_PRU0_GPO0.PRG0_RGMII1_RD0 */ ++ AM65X_IOPAD(0x01f8, PIN_INPUT, 2) /* (W25) PRG0_PRU0_GPO1.PRG0_RGMII1_RD1 */ ++ AM65X_IOPAD(0x01fc, PIN_INPUT, 2) /* (W24) PRG0_PRU0_GPO2.PRG0_RGMII1_RD2 */ ++ AM65X_IOPAD(0x0200, PIN_INPUT, 2) /* (AA27) PRG0_PRU0_GPO3.PRG0_RGMII1_RD3 */ ++ AM65X_IOPAD(0x0224, PIN_OUTPUT, 2) /* (AD27) PRG0_PRU0_GPO12.PRG0_RGMII1_TD0 */ ++ AM65X_IOPAD(0x0228, PIN_OUTPUT, 2) /* (AC26) PRG0_PRU0_GPO13.PRG0_RGMII1_TD1 */ ++ AM65X_IOPAD(0x022c, PIN_OUTPUT, 2) /* (AD26) PRG0_PRU0_GPO14.PRG0_RGMII1_TD2 */ ++ AM65X_IOPAD(0x0230, PIN_OUTPUT, 2) /* (AA24) PRG0_PRU0_GPO15.PRG0_RGMII1_TD3 */ ++ AM65X_IOPAD(0x0234, PIN_INPUT, 2) /* (AD28) PRG0_PRU0_GPO16.PRG0_RGMII1_TXC */ ++ AM65X_IOPAD(0x0220, PIN_OUTPUT, 2) /* (AB25) PRG0_PRU0_GPO11.PRG0_RGMII1_TX_CTL */ ++ AM65X_IOPAD(0x020c, PIN_INPUT, 2) /* (Y25) PRG0_PRU0_GPO6.PRG0_RGMII1_RXC */ ++ AM65X_IOPAD(0x0204, PIN_INPUT, 2) /* (Y24) PRG0_PRU0_GPO4.PRG0_RGMII1_RX_CTL */ ++ >; ++ }; + }; + + &main_pmx1 { +@@ -789,7 +903,20 @@ &mcu_rti1 { + }; + + &icssg0_mdio { +- status = "disabled"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&icssg0_mdio_pins_default>; ++ ++ icssg0_eth0_phy: ethernet-phy@0 { ++ reg = <0>; ++ ti,rx-internal-delay = ; ++ ti,fifo-depth = ; ++ }; ++ ++ icssg0_eth1_phy: ethernet-phy@1 { ++ reg = <1>; ++ ti,rx-internal-delay = ; ++ ti,fifo-depth = ; ++ }; + }; + + &icssg1_mdio { +-- +2.42.0 + diff --git a/recipes-kernel/linux/files/patches-6.1/0065-arm64-dts-ti-iot2050-Definitions-for-runtime-pinmuxi.patch b/recipes-kernel/linux/files/patches-6.1/0065-arm64-dts-ti-iot2050-Definitions-for-runtime-pinmuxi.patch new file mode 100644 index 000000000..ec96afa03 --- /dev/null +++ b/recipes-kernel/linux/files/patches-6.1/0065-arm64-dts-ti-iot2050-Definitions-for-runtime-pinmuxi.patch @@ -0,0 +1,777 @@ +From ea91427516bff22a0252214d39a74fce347fdebb Mon Sep 17 00:00:00 2001 +From: Benedikt Niedermayr +Date: Tue, 21 Feb 2023 11:03:42 +0100 +Subject: [PATCH 65/69] arm64: dts: ti: iot2050: Definitions for runtime + pinmuxing + +Add multiple device tree nodes in order to support +runtime pinmuxing via debugfs. + +All nodes are added to the pinctrl device node, +since they are now belonging to multiple interfaces now. + +Note: Pinconf is also handled by debugfs-pinmux. This is possible since +pinconf and pinmux accessing the same 32-Bit register and setting the +function mask to 32-Bit allows writes to the whole register. + +Signed-off-by: Benedikt Niedermayr +[Siemens patch from 5.10] +--- + .../boot/dts/ti/k3-am65-iot2050-common.dtsi | 669 +++++++++++++++++- + .../dts/ti/k3-am6548-iot2050-advanced-m2.dts | 5 +- + 2 files changed, 631 insertions(+), 43 deletions(-) + +diff --git a/arch/arm64/boot/dts/ti/k3-am65-iot2050-common.dtsi b/arch/arm64/boot/dts/ti/k3-am65-iot2050-common.dtsi +index 81cc6eb11797..e26a164e6a08 100644 +--- a/arch/arm64/boot/dts/ti/k3-am65-iot2050-common.dtsi ++++ b/arch/arm64/boot/dts/ti/k3-am65-iot2050-common.dtsi +@@ -188,6 +188,425 @@ icssg0_emac1: port@1 { + }; + + &wkup_pmx0 { ++ pinctrl-names = ++ "default", ++ "d0-uart0-rxd", "d0-gpio", "d0-gpio-pullup", "d0-gpio-pulldown", ++ "d1-uart0-txd", "d1-gpio", "d1-gpio-pullup", "d1-gpio-pulldown", ++ "d2-uart0-ctsn", "d2-gpio", "d2-gpio-pullup", "d2-gpio-pulldown", ++ "d3-uart0-rtsn", "d3-gpio", "d3-gpio-pullup", "d3-gpio-pulldown", ++ "d10-spi0-cs0", "d10-gpio", "d10-gpio-pullup", "d10-gpio-pulldown", ++ "d11-spi0-d0", "d11-gpio", "d11-gpio-pullup", "d11-gpio-pulldown", ++ "d12-spi0-d1", "d12-gpio", "d12-gpio-pullup", "d12-gpio-pulldown", ++ "d13-spi0-clk", "d13-gpio", "d13-gpio-pullup", "d13-gpio-pulldown", ++ "a0-gpio", "a0-gpio-pullup", "a0-gpio-pulldown", ++ "a1-gpio", "a1-gpio-pullup", "a1-gpio-pulldown", ++ "a2-gpio", "a2-gpio-pullup", "a2-gpio-pulldown", ++ "a3-gpio", "a3-gpio-pullup", "a3-gpio-pulldown", ++ "a4-gpio", "a4-gpio-pullup", "a4-gpio-pulldown", ++ "a5-gpio", "a5-gpio-pullup", "a5-gpio-pulldown"; ++ ++ pinctrl-0 = <&d0_uart0_rxd>; ++ pinctrl-1 = <&d0_uart0_rxd>; ++ pinctrl-2 = <&d0_gpio>; ++ pinctrl-3 = <&d0_gpio_pullup>; ++ pinctrl-4 = <&d0_gpio_pulldown>; ++ pinctrl-5 = <&d1_uart0_txd>; ++ pinctrl-6 = <&d1_gpio>; ++ pinctrl-7 = <&d1_gpio_pullup>; ++ pinctrl-8 = <&d1_gpio_pulldown>; ++ pinctrl-9 = <&d2_uart0_ctsn>; ++ pinctrl-10 = <&d2_gpio>; ++ pinctrl-11 = <&d2_gpio_pullup>; ++ pinctrl-12 = <&d2_gpio_pulldown>; ++ pinctrl-13 = <&d3_uart0_rtsn>; ++ pinctrl-14 = <&d3_gpio>; ++ pinctrl-15 = <&d3_gpio_pullup>; ++ pinctrl-16 = <&d3_gpio_pulldown>; ++ pinctrl-17 = <&d10_spi0_cs0>; ++ pinctrl-18 = <&d10_gpio>; ++ pinctrl-19 = <&d10_gpio_pullup>; ++ pinctrl-20 = <&d10_gpio_pulldown>; ++ pinctrl-21 = <&d11_spi0_d0>; ++ pinctrl-22 = <&d11_gpio>; ++ pinctrl-23 = <&d11_gpio_pullup>; ++ pinctrl-24 = <&d11_gpio_pulldown>; ++ pinctrl-25 = <&d12_spi0_d1>; ++ pinctrl-26 = <&d12_gpio>; ++ pinctrl-27 = <&d12_gpio_pullup>; ++ pinctrl-28 = <&d12_gpio_pulldown>; ++ pinctrl-29 = <&d13_spi0_clk>; ++ pinctrl-30 = <&d13_gpio>; ++ pinctrl-31 = <&d13_gpio_pullup>; ++ pinctrl-32 = <&d13_gpio_pulldown>; ++ pinctrl-33 = <&a0_gpio>; ++ pinctrl-34 = <&a0_gpio_pullup>; ++ pinctrl-35 = <&a0_gpio_pulldown>; ++ pinctrl-36 = <&a1_gpio>; ++ pinctrl-37 = <&a1_gpio_pullup>; ++ pinctrl-38 = <&a1_gpio_pulldown>; ++ pinctrl-39 = <&a2_gpio>; ++ pinctrl-40 = <&a2_gpio_pullup>; ++ pinctrl-41 = <&a2_gpio_pulldown>; ++ pinctrl-42 = <&a3_gpio>; ++ pinctrl-43 = <&a3_gpio_pullup>; ++ pinctrl-44 = <&a3_gpio_pulldown>; ++ pinctrl-45 = <&a4_gpio>; ++ pinctrl-46 = <&a4_gpio_pullup>; ++ pinctrl-47 = <&a4_gpio_pulldown>; ++ pinctrl-48 = <&a5_gpio>; ++ pinctrl-49 = <&a5_gpio_pullup>; ++ pinctrl-50 = <&a5_gpio_pulldown>; ++ ++ d0_uart0_rxd: d0-uart0-rxd { ++ pinctrl-single,pins = < ++ /* (P4) MCU_UART0_RXD */ ++ AM65X_WKUP_IOPAD(0x0044, PIN_INPUT, 4) ++ >; ++ }; ++ ++ d0_gpio: d0-gpio { ++ pinctrl-single,pins = < ++ /* (P4) WKUP_GPIO0_29 */ ++ AM65X_WKUP_IOPAD(0x0044, PIN_INPUT, 7) ++ >; ++ }; ++ ++ d0_gpio_pullup: d0-gpio-pullup { ++ pinctrl-single,pins = < ++ /* (P4) WKUP_GPIO0_29 */ ++ AM65X_WKUP_IOPAD(0x0044, PIN_INPUT_PULLUP, 7) ++ >; ++ }; ++ ++ d0_gpio_pulldown: d0-gpio-pulldown { ++ pinctrl-single,pins = < ++ /* (P4) WKUP_GPIO0_29 */ ++ AM65X_WKUP_IOPAD(0x0044, PIN_INPUT_PULLDOWN, 7) ++ >; ++ }; ++ ++ d1_uart0_txd: d1-uart0-txd { ++ pinctrl-single,pins = < ++ /* (P5) MCU_UART0_TXD */ ++ AM65X_WKUP_IOPAD(0x0048, PIN_OUTPUT, 4) ++ >; ++ }; ++ ++ d1_gpio: d1-gpio { ++ pinctrl-single,pins = < ++ /* (P5) WKUP_GPIO0_30 */ ++ AM65X_WKUP_IOPAD(0x0048, PIN_INPUT, 7) ++ >; ++ }; ++ ++ d1_gpio_pullup: d1-gpio-pullup { ++ pinctrl-single,pins = < ++ /* (P5) WKUP_GPIO0_30 */ ++ AM65X_WKUP_IOPAD(0x0048, PIN_INPUT, 7) ++ >; ++ }; ++ ++ d1_gpio_pulldown: d1-gpio-pulldown { ++ pinctrl-single,pins = < ++ /* (P5) WKUP_GPIO0_30 */ ++ AM65X_WKUP_IOPAD(0x0048, PIN_INPUT_PULLDOWN, 7) ++ >; ++ }; ++ ++ d2_uart0_ctsn: d2-uart0-ctsn { ++ pinctrl-single,pins = < ++ /* (P1) MCU_UART0_CTSn */ ++ AM65X_WKUP_IOPAD(0x004C, PIN_INPUT, 4) ++ >; ++ }; ++ ++ d2_gpio: d2-gpio { ++ pinctrl-single,pins = < ++ /* (P5) WKUP_GPIO0_31 */ ++ AM65X_WKUP_IOPAD(0x004C, PIN_INPUT, 7) ++ >; ++ }; ++ ++ d2_gpio_pullup: d2-gpio-pullup { ++ pinctrl-single,pins = < ++ /* (P5) WKUP_GPIO0_31 */ ++ AM65X_WKUP_IOPAD(0x004C, PIN_INPUT, 7) ++ >; ++ }; ++ ++ d2_gpio_pulldown: d2-gpio-pulldown { ++ pinctrl-single,pins = < ++ /* (P5) WKUP_GPIO0_31 */ ++ AM65X_WKUP_IOPAD(0x004C, PIN_INPUT_PULLDOWN, 7) ++ >; ++ }; ++ ++ d3_uart0_rtsn: d3-uart0-rtsn { ++ pinctrl-single,pins = < ++ /* (N3) MCU_UART0_RTSn */ ++ AM65X_WKUP_IOPAD(0x0054, PIN_OUTPUT, 4) ++ >; ++ }; ++ ++ d3_gpio: d3-gpio { ++ pinctrl-single,pins = < ++ /* (N3) WKUP_GPIO0_33 */ ++ AM65X_WKUP_IOPAD(0x0054, PIN_INPUT, 7) ++ >; ++ }; ++ ++ d3_gpio_pullup: d3-gpio-pullup { ++ pinctrl-single,pins = < ++ /* (N3) WKUP_GPIO0_33 */ ++ AM65X_WKUP_IOPAD(0x0054, PIN_INPUT, 7) ++ >; ++ }; ++ ++ d3_gpio_pulldown: d3-gpio-pulldown { ++ pinctrl-single,pins = < ++ /* (N3) WKUP_GPIO0_33 */ ++ AM65X_WKUP_IOPAD(0x0054, PIN_INPUT_PULLDOWN, 7) ++ >; ++ }; ++ ++ d10_spi0_cs0: d10-spi0-cs0 { ++ pinctrl-single,pins = < ++ /* (Y4) MCU_SPI0_CS0 */ ++ AM65X_WKUP_IOPAD(0x009c, PIN_OUTPUT, 0) ++ >; ++ }; ++ ++ d10_gpio: d10-gpio { ++ pinctrl-single,pins = < ++ /* (Y4) WKUP_GPIO0_51 */ ++ AM65X_WKUP_IOPAD(0x009c, PIN_INPUT, 7) ++ >; ++ }; ++ ++ d10_gpio_pullup: d10-gpio-pullup { ++ pinctrl-single,pins = < ++ /* (Y4) WKUP_GPIO0_51 */ ++ AM65X_WKUP_IOPAD(0x009c, PIN_INPUT, 7) ++ >; ++ }; ++ ++ d10_gpio_pulldown: d10-gpio-pulldown { ++ pinctrl-single,pins = < ++ /* (Y4) WKUP_GPIO0_51 */ ++ AM65X_WKUP_IOPAD(0x009c, PIN_INPUT_PULLDOWN, 7) ++ >; ++ }; ++ ++ d11_spi0_d0: d11-spi0-d0 { ++ pinctrl-single,pins = < ++ /* (Y3) MCU_SPI0_D0 */ ++ AM65X_WKUP_IOPAD(0x0094, PIN_INPUT, 0) ++ >; ++ }; ++ ++ d11_gpio: d11-gpio { ++ pinctrl-single,pins = < ++ /* (Y3) WKUP_GPIO0_49 */ ++ AM65X_WKUP_IOPAD(0x0094, PIN_INPUT, 7) ++ >; ++ }; ++ ++ d11_gpio_pullup: d11-gpio-pullup { ++ pinctrl-single,pins = < ++ /* (Y3) WKUP_GPIO0_49 */ ++ AM65X_WKUP_IOPAD(0x0094, PIN_INPUT, 7) ++ >; ++ }; ++ ++ d11_gpio_pulldown: d11-gpio-pulldown { ++ pinctrl-single,pins = < ++ /* (Y3) WKUP_GPIO0_49 */ ++ AM65X_WKUP_IOPAD(0x0094, PIN_INPUT_PULLDOWN, 7) ++ >; ++ }; ++ ++ d12_spi0_d1: d12-spi0-d1 { ++ pinctrl-single,pins = < ++ /* (Y2) MCU_SPI0_D1 */ ++ AM65X_WKUP_IOPAD(0x0098, PIN_INPUT, 0) ++ >; ++ }; ++ ++ d12_gpio: d12-gpio { ++ pinctrl-single,pins = < ++ /* (Y2) WKUP_GPIO0_50 */ ++ AM65X_WKUP_IOPAD(0x0098, PIN_INPUT, 7) ++ >; ++ }; ++ ++ d12_gpio_pullup: d12-gpio-pullup { ++ pinctrl-single,pins = < ++ /* (Y2) WKUP_GPIO0_50 */ ++ AM65X_WKUP_IOPAD(0x0098, PIN_INPUT, 7) ++ >; ++ }; ++ ++ d12_gpio_pulldown: d12-gpio-pulldown { ++ pinctrl-single,pins = < ++ /* (Y2) WKUP_GPIO0_50 */ ++ AM65X_WKUP_IOPAD(0x0098, PIN_INPUT_PULLDOWN, 7) ++ >; ++ }; ++ ++ d13_spi0_clk: d13-spi0-clk { ++ pinctrl-single,pins = < ++ /* (Y1) MCU_SPI0_CLK */ ++ AM65X_WKUP_IOPAD(0x0090, PIN_INPUT, 0) ++ >; ++ }; ++ ++ d13_gpio: d13-gpio { ++ pinctrl-single,pins = < ++ /* (Y1) WKUP_GPIO0_48 */ ++ AM65X_WKUP_IOPAD(0x0090, PIN_INPUT, 7) ++ >; ++ }; ++ ++ d13_gpio_pullup: d13-gpio-pullup { ++ pinctrl-single,pins = < ++ /* (Y1) WKUP_GPIO0_48 */ ++ AM65X_WKUP_IOPAD(0x0090, PIN_INPUT, 7) ++ >; ++ }; ++ ++ d13_gpio_pulldown: d13-gpio-pulldown { ++ pinctrl-single,pins = < ++ /* (Y1) WKUP_GPIO0_48 */ ++ AM65X_WKUP_IOPAD(0x0090, PIN_INPUT_PULLDOWN, 7) ++ >; ++ }; ++ ++ a0_gpio: a0-gpio { ++ pinctrl-single,pins = < ++ /* (L6) WKUP_GPIO0_45 */ ++ AM65X_WKUP_IOPAD(0x0084, PIN_INPUT, 7) ++ >; ++ }; ++ ++ a0_gpio_pullup: a0-gpio-pullup { ++ pinctrl-single,pins = < ++ /* (L6) WKUP_GPIO0_45 */ ++ AM65X_WKUP_IOPAD(0x0084, PIN_INPUT, 7) ++ >; ++ }; ++ ++ a0_gpio_pulldown: a0-gpio-pulldown { ++ pinctrl-single,pins = < ++ /* (L6) WKUP_GPIO0_45 */ ++ AM65X_WKUP_IOPAD(0x0084, PIN_INPUT_PULLDOWN, 7) ++ >; ++ }; ++ ++ a1_gpio: a1-gpio { ++ pinctrl-single,pins = < ++ /* (M6) WKUP_GPIO0_44 */ ++ AM65X_WKUP_IOPAD(0x0080, PIN_INPUT, 7) ++ >; ++ }; ++ ++ a1_gpio_pullup: a1-gpio-pullup { ++ pinctrl-single,pins = < ++ /* (M6) WKUP_GPIO0_44 */ ++ AM65X_WKUP_IOPAD(0x0080, PIN_INPUT, 7) ++ >; ++ }; ++ ++ a1_gpio_pulldown: a1-gpio-pulldown { ++ pinctrl-single,pins = < ++ /* (M6) WKUP_GPIO0_44 */ ++ AM65X_WKUP_IOPAD(0x0080, PIN_INPUT_PULLDOWN, 7) ++ >; ++ }; ++ ++ a2_gpio: a2-gpio { ++ pinctrl-single,pins = < ++ /* (L5) WKUP_GPIO0_43 */ ++ AM65X_WKUP_IOPAD(0x007C, PIN_INPUT, 7) ++ >; ++ }; ++ ++ a2_gpio_pullup: a2-gpio-pullup { ++ pinctrl-single,pins = < ++ /* (L5) WKUP_GPIO0_43 */ ++ AM65X_WKUP_IOPAD(0x007C, PIN_INPUT, 7) ++ >; ++ }; ++ ++ a2_gpio_pulldown: a2-gpio-pulldown { ++ pinctrl-single,pins = < ++ /* (L5) WKUP_GPIO0_43 */ ++ AM65X_WKUP_IOPAD(0x007C, PIN_INPUT_PULLDOWN, 7) ++ >; ++ }; ++ ++ a3_gpio: a3-gpio { ++ pinctrl-single,pins = < ++ /* (M5) WKUP_GPIO0_39 */ ++ AM65X_WKUP_IOPAD(0x006C, PIN_INPUT, 7) ++ >; ++ }; ++ ++ a3_gpio_pullup: a3-gpio-pullup { ++ pinctrl-single,pins = < ++ /* (M5) WKUP_GPIO0_39 */ ++ AM65X_WKUP_IOPAD(0x006C, PIN_INPUT, 7) ++ >; ++ }; ++ ++ a3_gpio_pulldown: a3-gpio-pulldown { ++ pinctrl-single,pins = < ++ /* (M5) WKUP_GPIO0_39 */ ++ AM65X_WKUP_IOPAD(0x006C, PIN_INPUT_PULLDOWN, 7) ++ >; ++ }; ++ ++ a4_gpio: a4-gpio { ++ pinctrl-single,pins = < ++ /* (L2) WKUP_GPIO0_42 */ ++ AM65X_WKUP_IOPAD(0x0078, PIN_INPUT, 7) ++ >; ++ }; ++ ++ a4_gpio_pullup: a4-gpio-pullup { ++ pinctrl-single,pins = < ++ /* (L2) WKUP_GPIO0_42 */ ++ AM65X_WKUP_IOPAD(0x0078, PIN_INPUT, 7) ++ >; ++ }; ++ ++ a4_gpio_pulldown: a4-gpio-pulldown { ++ pinctrl-single,pins = < ++ /* (L2) WKUP_GPIO0_42 */ ++ AM65X_WKUP_IOPAD(0x0078, PIN_INPUT_PULLDOWN, 7) ++ >; ++ }; ++ ++ a5_gpio: a5-gpio { ++ pinctrl-single,pins = < ++ /* (N5) WKUP_GPIO0_35 */ ++ AM65X_WKUP_IOPAD(0x005C, PIN_INPUT, 7) ++ >; ++ }; ++ ++ a5_gpio_pullup: a5-gpio-pullup { ++ pinctrl-single,pins = < ++ /* (N5) WKUP_GPIO0_35 */ ++ AM65X_WKUP_IOPAD(0x005C, PIN_INPUT_PULLUP, 7) ++ >; ++ }; ++ ++ a5_gpio_pulldown: a5-gpio-pulldown { ++ pinctrl-single,pins = < ++ /* (N5) WKUP_GPIO0_35 */ ++ AM65X_WKUP_IOPAD(0x005C, PIN_INPUT_PULLDOWN, 7) ++ >; ++ }; ++ + wkup_i2c0_pins_default: wkup-i2c0-pins-default { + pinctrl-single,pins = < + /* (AC7) WKUP_I2C0_SCL */ +@@ -220,23 +639,6 @@ AM65X_WKUP_IOPAD(0x0034, PIN_INPUT, 7) + >; + }; + +- arduino_uart_pins_default: arduino-uart-pins-default { +- pinctrl-single,pins = < +- /* (P4) MCU_UART0_RXD */ +- AM65X_WKUP_IOPAD(0x0044, PIN_INPUT, 4) +- /* (P5) MCU_UART0_TXD */ +- AM65X_WKUP_IOPAD(0x0048, PIN_OUTPUT, 4) +- >; +- }; +- +- arduino_io_d2_to_d3_pins_default: arduino-io-d2-to-d3-pins-default { +- pinctrl-single,pins = < +- /* (P1) WKUP_GPIO0_31 */ +- AM65X_WKUP_IOPAD(0x004C, PIN_OUTPUT, 7) +- /* (N3) WKUP_GPIO0_33 */ +- AM65X_WKUP_IOPAD(0x0054, PIN_OUTPUT, 7) +- >; +- }; + + arduino_io_oe_pins_default: arduino-io-oe-pins-default { + pinctrl-single,pins = < +@@ -251,6 +653,8 @@ AM65X_WKUP_IOPAD(0x0068, PIN_OUTPUT, 7) + /* (M1) WKUP_GPIO0_41 */ + AM65X_WKUP_IOPAD(0x0074, PIN_OUTPUT, 7) + >; ++ pinctrl-single,bias-pullup = <0x20000 0x20000 0x10000 0x30000>; ++ pinctrl-single,bias-pulldown = <0x00000 0x0 0x10000 0x30000>; + }; + + mcu_fss0_ospi0_pins_default: mcu-fss0-ospi0-pins-default { +@@ -316,6 +720,214 @@ AM65X_WKUP_IOPAD(0x003C, PIN_OUTPUT, 7) + }; + + &main_pmx0 { ++ pinctrl-names = ++ "default", ++ "d4-ehrpwm0-a", "d4-gpio", "d4-gpio-pullup", "d4-gpio-pulldown", ++ "d5-ehrpwm1-a", "d5-gpio", "d5-gpio-pullup", "d5-gpio-pulldown", ++ "d6-ehrpwm2-a", "d6-gpio", "d6-gpio-pullup", "d6-gpio-pulldown", ++ "d7-ehrpwm3-a", "d7-gpio", "d7-gpio-pullup", "d7-gpio-pulldown", ++ "d8-ehrpwm4-a", "d8-gpio", "d8-gpio-pullup", "d8-gpio-pulldown", ++ "d9-ehrpwm5-a", "d9-gpio", "d9-gpio-pullup", "d9-gpio-pulldown"; ++ ++ pinctrl-0 = <&d4_ehrpwm0_a>; ++ pinctrl-1 = <&d4_ehrpwm0_a>; ++ pinctrl-2 = <&d4_gpio>; ++ pinctrl-3 = <&d4_gpio_pullup>; ++ pinctrl-4 = <&d4_gpio_pulldown>; ++ ++ pinctrl-5 = <&d5_ehrpwm1_a>; ++ pinctrl-6 = <&d5_gpio>; ++ pinctrl-7 = <&d5_gpio_pullup>; ++ pinctrl-8 = <&d5_gpio_pulldown>; ++ ++ pinctrl-9 = <&d6_ehrpwm2_a>; ++ pinctrl-10 = <&d6_gpio>; ++ pinctrl-11 = <&d6_gpio_pullup>; ++ pinctrl-12 = <&d6_gpio_pulldown>; ++ ++ pinctrl-13 = <&d7_ehrpwm3_a>; ++ pinctrl-14 = <&d7_gpio>; ++ pinctrl-15 = <&d7_gpio_pullup>; ++ pinctrl-16 = <&d7_gpio_pulldown>; ++ ++ pinctrl-17 = <&d8_ehrpwm4_a>; ++ pinctrl-18 = <&d8_gpio>; ++ pinctrl-19 = <&d8_gpio_pullup>; ++ pinctrl-20 = <&d8_gpio_pulldown>; ++ ++ pinctrl-21 = <&d9_ehrpwm5_a>; ++ pinctrl-22 = <&d9_gpio>; ++ pinctrl-23 = <&d9_gpio_pullup>; ++ pinctrl-24 = <&d9_gpio_pulldown>; ++ ++ d4_ehrpwm0_a: d4-ehrpwm0-a { ++ pinctrl-single,pins = < ++ /* (AG18) EHRPWM0_A */ ++ AM65X_IOPAD(0x0084, PIN_OUTPUT, 5) ++ >; ++ }; ++ ++ d4_gpio: d4-gpio { ++ pinctrl-single,pins = < ++ /* (AG18) GPIO0_33 */ ++ AM65X_IOPAD(0x0084, PIN_INPUT, 7) ++ >; ++ }; ++ ++ d4_gpio_pullup: d4-gpio-pullup { ++ pinctrl-single,pins = < ++ /* (AG18) GPIO0_33 */ ++ AM65X_IOPAD(0x0084, PIN_INPUT_PULLUP, 7) ++ >; ++ }; ++ ++ d4_gpio_pulldown: d4-gpio-pulldown { ++ pinctrl-single,pins = < ++ /* (AG18) GPIO0_33 */ ++ AM65X_IOPAD(0x0084, PIN_INPUT_PULLDOWN, 7) ++ >; ++ }; ++ ++ d5_ehrpwm1_a: d5-ehrpwm1-a { ++ pinctrl-single,pins = < ++ /* (AF17) EHRPWM1_A */ ++ AM65X_IOPAD(0x008C, PIN_OUTPUT, 5) ++ >; ++ }; ++ ++ d5_gpio: d5-gpio { ++ pinctrl-single,pins = < ++ /* (AF17) GPIO0_35 */ ++ AM65X_IOPAD(0x008C, PIN_INPUT, 7) ++ >; ++ }; ++ ++ d5_gpio_pullup: d5-gpio-pullup { ++ pinctrl-single,pins = < ++ /* (AF17) GPIO0_35 */ ++ AM65X_IOPAD(0x008C, PIN_INPUT_PULLUP, 7) ++ >; ++ }; ++ ++ d5_gpio_pulldown: d5-gpio-pulldown { ++ pinctrl-single,pins = < ++ /* (AF17) GPIO0_35 */ ++ AM65X_IOPAD(0x008C, PIN_INPUT_PULLDOWN, 7) ++ >; ++ }; ++ ++ d6_ehrpwm2_a: d6-ehrpwm2-a { ++ pinctrl-single,pins = < ++ /* (AH16) EHRPWM2_A */ ++ AM65X_IOPAD(0x0098, PIN_OUTPUT, 5) ++ >; ++ }; ++ ++ d6_gpio: d6-gpio { ++ pinctrl-single,pins = < ++ /* (AH16) GPIO0_38 */ ++ AM65X_IOPAD(0x0098, PIN_INPUT, 7) ++ >; ++ }; ++ ++ d6_gpio_pullup: d6-gpio-pullup { ++ pinctrl-single,pins = < ++ /* (AH16) GPIO0_38 */ ++ AM65X_IOPAD(0x0098, PIN_INPUT_PULLUP, 7) ++ >; ++ }; ++ ++ d6_gpio_pulldown: d6-gpio-pulldown { ++ pinctrl-single,pins = < ++ /* (AH16) GPIO0_38 */ ++ AM65X_IOPAD(0x0098, PIN_INPUT_PULLDOWN, 7) ++ >; ++ }; ++ ++ d7_ehrpwm3_a: d7-ehrpwm3-a { ++ pinctrl-single,pins = < ++ /* (AH15) EHRPWM3_A */ ++ AM65X_IOPAD(0x00AC, PIN_OUTPUT, 5) ++ >; ++ }; ++ ++ d7_gpio: d7-gpio { ++ pinctrl-single,pins = < ++ /* (AH15) GPIO0_43 */ ++ AM65X_IOPAD(0x00AC, PIN_INPUT, 7) ++ >; ++ }; ++ ++ d7_gpio_pullup: d7-gpio-pullup { ++ pinctrl-single,pins = < ++ /* (AH15) GPIO0_43 */ ++ AM65X_IOPAD(0x00AC, PIN_INPUT_PULLUP, 7) ++ >; ++ }; ++ ++ d7_gpio_pulldown: d7-gpio-pulldown { ++ pinctrl-single,pins = < ++ /* (AH15) GPIO0_43 */ ++ AM65X_IOPAD(0x00AC, PIN_INPUT_PULLDOWN, 7) ++ >; ++ }; ++ ++ d8_ehrpwm4_a: d8-ehrpwm4-a { ++ pinctrl-single,pins = < ++ /* (AG15) EHRPWM4_A */ ++ AM65X_IOPAD(0x00C0, PIN_OUTPUT, 5) ++ >; ++ }; ++ ++ d8_gpio: d8-gpio { ++ pinctrl-single,pins = < ++ /* (AG15) GPIO0_48 */ ++ AM65X_IOPAD(0x00C0, PIN_INPUT, 7) ++ >; ++ }; ++ ++ d8_gpio_pullup: d8-gpio-pullup { ++ pinctrl-single,pins = < ++ /* (AG15) GPIO0_48 */ ++ AM65X_IOPAD(0x00C0, PIN_INPUT_PULLUP, 7) ++ >; ++ }; ++ ++ d8_gpio_pulldown: d8-gpio-pulldown { ++ pinctrl-single,pins = < ++ /* (AG15) GPIO0_48 */ ++ AM65X_IOPAD(0x00C0, PIN_INPUT_PULLDOWN, 7) ++ >; ++ }; ++ ++ d9_ehrpwm5_a: d9-ehrpwm5-a { ++ pinctrl-single,pins = < ++ /* (AD15) EHRPWM5_A */ ++ AM65X_IOPAD(0x00CC, PIN_OUTPUT, 5) ++ >; ++ }; ++ ++ d9_gpio: d9-gpio { ++ pinctrl-single,pins = < ++ /* (AD15) GPIO0_51 */ ++ AM65X_IOPAD(0x00CC, PIN_INPUT, 7) ++ >; ++ }; ++ ++ d9_gpio_pullup: d9-gpio-pullup { ++ pinctrl-single,pins = < ++ /* (AD15) GPIO0_51 */ ++ AM65X_IOPAD(0x00CC, PIN_INPUT_PULLUP, 7) ++ >; ++ }; ++ ++ d9_gpio_pulldown: d9-gpio-pulldown { ++ pinctrl-single,pins = < ++ /* (AD15) GPIO0_51 */ ++ AM65X_IOPAD(0x00CC, PIN_INPUT_PULLDOWN, 7) ++ >; ++ }; ++ + main_uart1_pins_default: main-uart1-pins-default { + pinctrl-single,pins = < + AM65X_IOPAD(0x0174, PIN_INPUT, 6) /* (AE23) UART1_RXD */ +@@ -357,17 +969,6 @@ AM65X_IOPAD(0x02c0, PIN_OUTPUT, 0) /* (AC8) USB1_DRVVBUS */ + >; + }; + +- arduino_io_d4_to_d9_pins_default: arduino-io-d4-to-d9-pins-default { +- pinctrl-single,pins = < +- AM65X_IOPAD(0x0084, PIN_OUTPUT, 7) /* (AG18) GPIO0_33 */ +- AM65X_IOPAD(0x008C, PIN_OUTPUT, 7) /* (AF17) GPIO0_35 */ +- AM65X_IOPAD(0x0098, PIN_OUTPUT, 7) /* (AH16) GPIO0_38 */ +- AM65X_IOPAD(0x00AC, PIN_OUTPUT, 7) /* (AH15) GPIO0_43 */ +- AM65X_IOPAD(0x00C0, PIN_OUTPUT, 7) /* (AG15) GPIO0_48 */ +- AM65X_IOPAD(0x00CC, PIN_OUTPUT, 7) /* (AD15) GPIO0_51 */ +- >; +- }; +- + dss_vout1_pins_default: dss-vout1-pins-default { + pinctrl-single,pins = < + AM65X_IOPAD(0x0000, PIN_OUTPUT, 1) /* VOUT1_DATA0 */ +@@ -488,14 +1089,7 @@ &main_uart2 { + status = "disabled"; + }; + +-&mcu_uart0 { +- pinctrl-names = "default"; +- pinctrl-0 = <&arduino_uart_pins_default>; +-}; +- + &main_gpio0 { +- pinctrl-names = "default"; +- pinctrl-0 = <&arduino_io_d4_to_d9_pins_default>; + gpio-line-names = + "main_gpio0-base", "", "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", "", "", +@@ -508,12 +1102,12 @@ &main_gpio0 { + &wkup_gpio0 { + pinctrl-names = "default"; + pinctrl-0 = < +- &arduino_io_d2_to_d3_pins_default + &arduino_i2c_aio_switch_pins_default + &arduino_io_oe_pins_default + &push_button_pins_default + &db9_com_mode_pins_default + >; ++ + gpio-line-names = + /* 0..9 */ + "wkup_gpio0-base", "", "", "", "UART0-mode1", "UART0-mode0", +@@ -690,9 +1284,6 @@ &usb1 { + }; + + &mcu_spi0 { +- pinctrl-names = "default"; +- pinctrl-0 = <&mcu_spi0_pins_default>; +- + #address-cells = <1>; + #size-cells = <0>; + ti,pindir-d0-out-d1-in; +diff --git a/arch/arm64/boot/dts/ti/k3-am6548-iot2050-advanced-m2.dts b/arch/arm64/boot/dts/ti/k3-am6548-iot2050-advanced-m2.dts +index 9400e35882a6..b3a21765c9ed 100644 +--- a/arch/arm64/boot/dts/ti/k3-am6548-iot2050-advanced-m2.dts ++++ b/arch/arm64/boot/dts/ti/k3-am6548-iot2050-advanced-m2.dts +@@ -66,10 +66,7 @@ AM65X_IOPAD(0x001c, PIN_INPUT_PULLUP, 7) /* (C23) GPIO1_89 */ + + &main_gpio0 { + pinctrl-names = "default"; +- pinctrl-0 = < +- &main_m2_pcie_mux_control +- &arduino_io_d4_to_d9_pins_default +- >; ++ pinctrl-0 = <&main_m2_pcie_mux_control>; + }; + + &main_gpio1 { +-- +2.42.0 + diff --git a/recipes-kernel/linux/files/patches-6.1/0066-arm64-dts-ti-iot2050-Refactor-the-m.2-and-minipcie-p.patch b/recipes-kernel/linux/files/patches-6.1/0066-arm64-dts-ti-iot2050-Refactor-the-m.2-and-minipcie-p.patch new file mode 100644 index 000000000..3f0f7266c --- /dev/null +++ b/recipes-kernel/linux/files/patches-6.1/0066-arm64-dts-ti-iot2050-Refactor-the-m.2-and-minipcie-p.patch @@ -0,0 +1,93 @@ +From 83916f56d193b50f478908236f63ae35ab4dee4d Mon Sep 17 00:00:00 2001 +From: Su Bao Cheng +Date: Fri, 19 May 2023 10:16:39 +0800 +Subject: [PATCH 66/69] arm64: dts: ti: iot2050: Refactor the m.2 and minipcie + power pin + +Make the m.2 power control pin also available on miniPCIE variants. + +This can fix some miniPCIE card hang issue, by forcing a power on reset +during boot. + +Signed-off-by: Baocheng Su +[Siemens patch from 5.10] +--- + .../arm64/boot/dts/ti/k3-am65-iot2050-common-pg2.dtsi | 5 ++++- + arch/arm64/boot/dts/ti/k3-am65-iot2050-common.dtsi | 11 +++++++++++ + .../boot/dts/ti/k3-am6548-iot2050-advanced-m2.dts | 8 +------- + 3 files changed, 16 insertions(+), 8 deletions(-) + +diff --git a/arch/arm64/boot/dts/ti/k3-am65-iot2050-common-pg2.dtsi b/arch/arm64/boot/dts/ti/k3-am65-iot2050-common-pg2.dtsi +index e73458ca6900..0dada0b39e36 100644 +--- a/arch/arm64/boot/dts/ti/k3-am65-iot2050-common-pg2.dtsi ++++ b/arch/arm64/boot/dts/ti/k3-am65-iot2050-common-pg2.dtsi +@@ -20,7 +20,10 @@ AM65X_IOPAD(0x01e0, PIN_OUTPUT, 7) + + &main_gpio1 { + pinctrl-names = "default"; +- pinctrl-0 = <&cp2102n_reset_pin_default>; ++ pinctrl-0 = < ++ &main_pcie_enable_pins_default ++ &cp2102n_reset_pin_default ++ >; + gpio-line-names = + "", "", "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", "", "", +diff --git a/arch/arm64/boot/dts/ti/k3-am65-iot2050-common.dtsi b/arch/arm64/boot/dts/ti/k3-am65-iot2050-common.dtsi +index e26a164e6a08..f142e2b8753b 100644 +--- a/arch/arm64/boot/dts/ti/k3-am65-iot2050-common.dtsi ++++ b/arch/arm64/boot/dts/ti/k3-am65-iot2050-common.dtsi +@@ -928,6 +928,12 @@ AM65X_IOPAD(0x00CC, PIN_INPUT_PULLDOWN, 7) + >; + }; + ++ main_pcie_enable_pins_default: main-pcie-enable-pins-default { ++ pinctrl-single,pins = < ++ AM65X_IOPAD(0x01c4, PIN_INPUT_PULLUP, 7) /* (AH13) GPIO1_17 */ ++ >; ++ }; ++ + main_uart1_pins_default: main-uart1-pins-default { + pinctrl-single,pins = < + AM65X_IOPAD(0x0174, PIN_INPUT, 6) /* (AE23) UART1_RXD */ +@@ -1099,6 +1105,11 @@ &main_gpio0 { + "", "IO9"; + }; + ++&main_gpio1 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&main_pcie_enable_pins_default>; ++}; ++ + &wkup_gpio0 { + pinctrl-names = "default"; + pinctrl-0 = < +diff --git a/arch/arm64/boot/dts/ti/k3-am6548-iot2050-advanced-m2.dts b/arch/arm64/boot/dts/ti/k3-am6548-iot2050-advanced-m2.dts +index b3a21765c9ed..663ff4d501c2 100644 +--- a/arch/arm64/boot/dts/ti/k3-am6548-iot2050-advanced-m2.dts ++++ b/arch/arm64/boot/dts/ti/k3-am6548-iot2050-advanced-m2.dts +@@ -27,12 +27,6 @@ &mcu_r5fss0 { + }; + + &main_pmx0 { +- main_m2_enable_pins_default: main-m2-enable-pins-default { +- pinctrl-single,pins = < +- AM65X_IOPAD(0x01c4, PIN_INPUT_PULLUP, 7) /* (AH13) GPIO1_17 */ +- >; +- }; +- + main_bkey_pcie_reset: main-bkey-pcie-reset { + pinctrl-single,pins = < + AM65X_IOPAD(0x01bc, PIN_OUTPUT_PULLUP, 7) /* (AG13) GPIO1_15 */ +@@ -72,7 +66,7 @@ &main_gpio0 { + &main_gpio1 { + pinctrl-names = "default"; + pinctrl-0 = < +- &main_m2_enable_pins_default ++ &main_pcie_enable_pins_default + &main_pmx0_m2_config_pins_default + &main_pmx1_m2_config_pins_default + &cp2102n_reset_pin_default +-- +2.42.0 + diff --git a/recipes-kernel/linux/files/patches-6.1/0067-arm64-dts-ti-Indicate-the-green-light-is-off-when-pa.patch b/recipes-kernel/linux/files/patches-6.1/0067-arm64-dts-ti-Indicate-the-green-light-is-off-when-pa.patch new file mode 100644 index 000000000..6f8dacfac --- /dev/null +++ b/recipes-kernel/linux/files/patches-6.1/0067-arm64-dts-ti-Indicate-the-green-light-is-off-when-pa.patch @@ -0,0 +1,30 @@ +From 441ea0d3ca62578f2daae773f81f9e7274ccb099 Mon Sep 17 00:00:00 2001 +From: chao zeng +Date: Thu, 16 Dec 2021 15:09:25 +0800 +Subject: [PATCH 67/69] arm64: dts: ti: Indicate the green light is off when + panic + +The green light is out of control when panic occurs. +it should be off thhen + +Signed-off-by: chao zeng +[Siemens patch from 5.10] +--- + arch/arm64/boot/dts/ti/k3-am65-iot2050-common.dtsi | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/arch/arm64/boot/dts/ti/k3-am65-iot2050-common.dtsi b/arch/arm64/boot/dts/ti/k3-am65-iot2050-common.dtsi +index f142e2b8753b..debd5719f32d 100644 +--- a/arch/arm64/boot/dts/ti/k3-am65-iot2050-common.dtsi ++++ b/arch/arm64/boot/dts/ti/k3-am65-iot2050-common.dtsi +@@ -87,6 +87,7 @@ status-led-red { + + status-led-green { + gpios = <&wkup_gpio0 24 GPIO_ACTIVE_HIGH>; ++ panic-indicator-off; + }; + + user-led1-red { +-- +2.42.0 + diff --git a/recipes-kernel/linux/files/patches-6.1/0068-HACK-setting-the-RJ45-port-led-behavior.patch b/recipes-kernel/linux/files/patches-6.1/0068-HACK-setting-the-RJ45-port-led-behavior.patch new file mode 100644 index 000000000..9def94a66 --- /dev/null +++ b/recipes-kernel/linux/files/patches-6.1/0068-HACK-setting-the-RJ45-port-led-behavior.patch @@ -0,0 +1,42 @@ +From a9705e065ee3007b7ba09c63eef40b73a49fa2f8 Mon Sep 17 00:00:00 2001 +From: zengchao +Date: Wed, 6 Nov 2019 11:21:49 +0800 +Subject: [PATCH 68/69] HACK: setting the RJ45 port led behavior + +Temporary needed until we have a proper, likely LED-class based +solution upstream. + +Signed-off-by: zengchao +[Siemens patch from 5.10] +--- + drivers/net/phy/dp83867.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/drivers/net/phy/dp83867.c b/drivers/net/phy/dp83867.c +index f7436191fa80..e8950dcd6506 100644 +--- a/drivers/net/phy/dp83867.c ++++ b/drivers/net/phy/dp83867.c +@@ -55,6 +55,10 @@ + #define DP83867_10M_SGMII_CFG 0x016F + #define DP83867_10M_SGMII_RATE_ADAPT_MASK BIT(7) + ++/*RJ45 led configuration*/ ++#define DP83867_LEDCR_1 0x0018 ++#define RJ45_LED_SETTING 0x665b ++ + #define DP83867_SW_RESET BIT(15) + #define DP83867_SW_RESTART BIT(14) + +@@ -520,6 +524,9 @@ static int dp83867_verify_rgmii_cfg(struct phy_device *phydev) + return -EINVAL; + } + ++ /*Set the RJ45 led action*/ ++ phy_write_mmd(phydev, DP83867_DEVADDR, DP83867_LEDCR_1, RJ45_LED_SETTING); ++ + return 0; + } + +-- +2.42.0 + diff --git a/recipes-kernel/linux/files/patches-6.1/0069-WIP-feat-extend-led-panic-indicator-on-and-off.patch b/recipes-kernel/linux/files/patches-6.1/0069-WIP-feat-extend-led-panic-indicator-on-and-off.patch new file mode 100644 index 000000000..ec3623c70 --- /dev/null +++ b/recipes-kernel/linux/files/patches-6.1/0069-WIP-feat-extend-led-panic-indicator-on-and-off.patch @@ -0,0 +1,129 @@ +From 2238d998d851090e47e6c33478e8cf3bc133d4e9 Mon Sep 17 00:00:00 2001 +From: Su Baocheng +Date: Tue, 22 Dec 2020 15:05:56 +0800 +Subject: [PATCH 69/69] WIP: feat:extend led panic-indicator on and off + +WIP because upstream strategy is still under discussion. + +Signed-off-by: Gao Nian +[Jan: ported and fixed non-panic cases] +Signed-off-by: Jan Kiszka +[Siemens patch from 5.10] +--- + drivers/leds/led-triggers.c | 10 ++++++++-- + drivers/leds/leds-gpio.c | 12 ++++++++++-- + drivers/leds/trigger/ledtrig-panic.c | 5 ++++- + include/linux/leds.h | 8 +++++++- + 4 files changed, 29 insertions(+), 6 deletions(-) + +diff --git a/drivers/leds/led-triggers.c b/drivers/leds/led-triggers.c +index 072491d3e17b..d310690432d1 100644 +--- a/drivers/leds/led-triggers.c ++++ b/drivers/leds/led-triggers.c +@@ -386,8 +386,14 @@ void led_trigger_event(struct led_trigger *trig, + return; + + rcu_read_lock(); +- list_for_each_entry_rcu(led_cdev, &trig->led_cdevs, trig_list) +- led_set_brightness(led_cdev, brightness); ++ list_for_each_entry_rcu(led_cdev, &trig->led_cdevs, trig_list) { ++ if (led_cdev->flags & LED_PANIC_INDICATOR_OFF) ++ led_set_brightness(led_cdev, LED_OFF); ++ else if (led_cdev->flags & LED_PANIC_INDICATOR_ON) ++ led_set_brightness(led_cdev, LED_FULL); ++ else ++ led_set_brightness(led_cdev, brightness); ++ } + rcu_read_unlock(); + } + EXPORT_SYMBOL_GPL(led_trigger_event); +diff --git a/drivers/leds/leds-gpio.c b/drivers/leds/leds-gpio.c +index 092eb59a7d32..055272aa8289 100644 +--- a/drivers/leds/leds-gpio.c ++++ b/drivers/leds/leds-gpio.c +@@ -101,8 +101,12 @@ static int create_gpio_led(const struct gpio_led *template, + led_dat->cdev.max_brightness = 1; + if (!template->retain_state_suspended) + led_dat->cdev.flags |= LED_CORE_SUSPENDRESUME; +- if (template->panic_indicator) ++ if (template->panic_indicator == LEDS_PANICINDICATOR_BLINK) + led_dat->cdev.flags |= LED_PANIC_INDICATOR; ++ else if (template->panic_indicator == LEDS_PANICINDICATOR_OFF) ++ led_dat->cdev.flags |= LED_PANIC_INDICATOR_OFF; ++ else if (template->panic_indicator == LEDS_PANICINDICATOR_ON) ++ led_dat->cdev.flags |= LED_PANIC_INDICATOR_ON; + if (template->retain_state_shutdown) + led_dat->cdev.flags |= LED_RETAIN_AT_SHUTDOWN; + +@@ -168,7 +172,11 @@ static struct gpio_leds_priv *gpio_leds_create(struct platform_device *pdev) + if (fwnode_property_present(child, "retain-state-shutdown")) + led.retain_state_shutdown = 1; + if (fwnode_property_present(child, "panic-indicator")) +- led.panic_indicator = 1; ++ led.panic_indicator = LEDS_PANICINDICATOR_BLINK; ++ else if (fwnode_property_present(child, "panic-indicator-off")) ++ led.panic_indicator = LEDS_PANICINDICATOR_OFF; ++ else if (fwnode_property_present(child, "panic-indicator-on")) ++ led.panic_indicator = LEDS_PANICINDICATOR_ON; + + ret = create_gpio_led(&led, led_dat, dev, child, NULL); + if (ret < 0) { +diff --git a/drivers/leds/trigger/ledtrig-panic.c b/drivers/leds/trigger/ledtrig-panic.c +index 64abf2e91608..579c84bc4d79 100644 +--- a/drivers/leds/trigger/ledtrig-panic.c ++++ b/drivers/leds/trigger/ledtrig-panic.c +@@ -33,6 +33,7 @@ static void led_trigger_set_panic(struct led_classdev *led_cdev) + /* Avoid the delayed blink path */ + led_cdev->blink_delay_on = 0; + led_cdev->blink_delay_off = 0; ++ led_cdev->work_flags = 0; + + led_cdev->trigger = trig; + if (trig->activate) +@@ -47,7 +48,9 @@ static int led_trigger_panic_notifier(struct notifier_block *nb, + struct led_classdev *led_cdev; + + list_for_each_entry(led_cdev, &leds_list, node) +- if (led_cdev->flags & LED_PANIC_INDICATOR) ++ if (led_cdev->flags & (LED_PANIC_INDICATOR | ++ LED_PANIC_INDICATOR_OFF | ++ LED_PANIC_INDICATOR_ON)) + led_trigger_set_panic(led_cdev); + return NOTIFY_DONE; + } +diff --git a/include/linux/leds.h b/include/linux/leds.h +index ba4861ec73d3..09697564645b 100644 +--- a/include/linux/leds.h ++++ b/include/linux/leds.h +@@ -85,6 +85,8 @@ struct led_classdev { + #define LED_BRIGHT_HW_CHANGED BIT(21) + #define LED_RETAIN_AT_SHUTDOWN BIT(22) + #define LED_INIT_DEFAULT_TRIGGER BIT(23) ++#define LED_PANIC_INDICATOR_OFF BIT(24) ++#define LED_PANIC_INDICATOR_ON BIT(25) + + /* set_brightness_work / blink_timer flags, atomic, private. */ + unsigned long work_flags; +@@ -520,7 +522,7 @@ struct gpio_led { + unsigned gpio; + unsigned active_low : 1; + unsigned retain_state_suspended : 1; +- unsigned panic_indicator : 1; ++ unsigned panic_indicator : 2; + unsigned default_state : 2; + unsigned retain_state_shutdown : 1; + /* default_state should be one of LEDS_GPIO_DEFSTATE_(ON|OFF|KEEP) */ +@@ -530,6 +532,10 @@ struct gpio_led { + #define LEDS_GPIO_DEFSTATE_ON LEDS_DEFSTATE_ON + #define LEDS_GPIO_DEFSTATE_KEEP LEDS_DEFSTATE_KEEP + ++#define LEDS_PANICINDICATOR_BLINK 1 ++#define LEDS_PANICINDICATOR_OFF 2 ++#define LEDS_PANICINDICATOR_ON 3 ++ + struct gpio_led_platform_data { + int num_leds; + const struct gpio_led *leds; +-- +2.42.0 + diff --git a/recipes-kernel/linux/linux-iot2050-6.1.inc b/recipes-kernel/linux/linux-iot2050-6.1.inc new file mode 100644 index 000000000..28a21cf88 --- /dev/null +++ b/recipes-kernel/linux/linux-iot2050-6.1.inc @@ -0,0 +1,29 @@ +# +# Copyright (c) Siemens AG, 2018-2022 +# +# This file is subject to the terms and conditions of the MIT License. See +# COPYING.MIT file in the top-level directory. +# + +require recipes-kernel/linux/linux-custom.inc + +def get_patches(d, patchdir): + import glob + + files_dir = os.path.join(d.getVar('THISDIR'), 'files') + patch_glob = os.path.join(files_dir, patchdir, '*.patch') + patches = glob.glob(patch_glob) + patches.sort() + + return ' '.join(['file://' + patch[len(files_dir)+1:] for patch in patches]) + +SRC_URI += " \ + https://cdn.kernel.org/pub/linux/kernel/projects/cip/6.1/linux-cip-${PV}.tar.gz \ + ${@get_patches(d, 'patches-6.1')} \ + file://patches-6.1/ \ + file://${KERNEL_DEFCONFIG} \ + file://iot2050_defconfig_extra.cfg" + +S = "${WORKDIR}/linux-cip-${PV}" + +KERNEL_DEFCONFIG = "iot2050_defconfig_base" diff --git a/recipes-kernel/linux/linux-iot2050-rt_6.1.54-cip6-rt3.bb b/recipes-kernel/linux/linux-iot2050-rt_6.1.54-cip6-rt3.bb new file mode 100644 index 000000000..e9e2d497f --- /dev/null +++ b/recipes-kernel/linux/linux-iot2050-rt_6.1.54-cip6-rt3.bb @@ -0,0 +1,12 @@ +# +# Copyright (c) Siemens AG, 2018-2023 +# +# This file is subject to the terms and conditions of the MIT License. See +# COPYING.MIT file in the top-level directory. +# + +require linux-iot2050-6.1.inc + +SRC_URI[sha256sum] = "8c9cb5edc7318cdf8b50594003934bb1465ab8aabc76393f5f402690b2c1f071" + +SRC_URI += "file://iot2050-rt.cfg" diff --git a/recipes-kernel/linux/linux-iot2050_6.1.54-cip6.bb b/recipes-kernel/linux/linux-iot2050_6.1.54-cip6.bb new file mode 100644 index 000000000..a69f6395c --- /dev/null +++ b/recipes-kernel/linux/linux-iot2050_6.1.54-cip6.bb @@ -0,0 +1,10 @@ +# +# Copyright (c) Siemens AG, 2018-2023 +# +# This file is subject to the terms and conditions of the MIT License. See +# COPYING.MIT file in the top-level directory. +# + +require linux-iot2050-6.1.inc + +SRC_URI[sha256sum] = "431498a219a445a17b79c7a4467dda912e4a31e1add35684aa6e36483c898304"