From a2b9ec0231707378e7e9ccaa140c5ebe664abd70 Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Sat, 1 May 2021 20:21:54 +0100 Subject: [PATCH 01/62] base-files: upgrade: take down loop and LVM before upgrade Users of devices with large block storage may choose to have an LVM partition on the same device which is used for booting OpenWrt. The presents a problem during sysupgrade as the root device is then still busy and changing partitions will not work as desired, leading to data corruption in case the newly flashed image is larger than the currently installed one. Having loop devices setup causes similar havoc. Make sure all volume groups are offline and all loop devices have been released before sysupgrade. Signed-off-by: Daniel Golle --- package/base-files/files/lib/upgrade/stage2 | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/package/base-files/files/lib/upgrade/stage2 b/package/base-files/files/lib/upgrade/stage2 index 23d356a447..e2259e3472 100755 --- a/package/base-files/files/lib/upgrade/stage2 +++ b/package/base-files/files/lib/upgrade/stage2 @@ -33,6 +33,9 @@ supivot() { # } switch_to_ramfs() { + RAMFS_COPY_LOSETUP="$(command -v losetup)" + RAMFS_COPY_LVM="$(command -v lvm)" + for binary in \ /bin/busybox /bin/ash /bin/sh /bin/mount /bin/umount \ pivot_root mount_root reboot sync kill sleep \ @@ -43,6 +46,7 @@ switch_to_ramfs() { ubiupdatevol ubiattach ubiblock ubiformat \ ubidetach ubirsvol ubirmvol ubimkvol \ snapshot snapshot_tool date \ + $RAMFS_COPY_LOSETUP $RAMFS_COPY_LVM \ $RAMFS_COPY_BIN do local file="$(command -v "$binary" 2>/dev/null)" @@ -60,6 +64,12 @@ switch_to_ramfs() { /bin/mount -o remount,ro /mnt /bin/umount -l /mnt + [ "$RAMFS_COPY_LOSETUP" ] && losetup -D + [ "$RAMFS_COPY_LVM" ] && { + mkdir -p /tmp/lvm/cache + $RAMFS_COPY_LVM vgchange -aln --ignorelockingfailure + } + grep /overlay /proc/mounts > /dev/null && { /bin/mount -o noatime,remount,ro /overlay /bin/umount -l /overlay From b607e7df34031738b18582aaa1f4f93505d06734 Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Wed, 5 May 2021 13:17:30 +0100 Subject: [PATCH 02/62] procd: update to git HEAD 021ece8 procd: Use /dev/console for serial console if exists Signed-off-by: Daniel Golle --- package/system/procd/Makefile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package/system/procd/Makefile b/package/system/procd/Makefile index a2c1cf9798..4c34bab6f1 100644 --- a/package/system/procd/Makefile +++ b/package/system/procd/Makefile @@ -12,9 +12,9 @@ PKG_RELEASE:=$(AUTORELEASE) PKG_SOURCE_PROTO:=git PKG_SOURCE_URL=$(PROJECT_GIT)/project/procd.git -PKG_SOURCE_DATE:=2021-03-21 -PKG_SOURCE_VERSION:=7ee456346baca29af40a6d1a5071e57f32ebf762 -PKG_MIRROR_HASH:=aad23bc8f0548a46e60e4967b3f6645f03bad61c395269244c3509cc41f2c3d0 +PKG_SOURCE_DATE:=2021-05-05 +PKG_SOURCE_VERSION:=021ece84de430fca988acd6934f6046ea59d8c37 +PKG_MIRROR_HASH:=edbe464cadbae000f4a48a6f1e6a0f5d27ae3ad521e308205252ad89639b6f9d CMAKE_INSTALL:=1 PKG_LICENSE:=GPL-2.0 From dfef88b6cacceec151ca4ce4bb3dc50c1c5cf1d2 Mon Sep 17 00:00:00 2001 From: Alex Henrie Date: Mon, 3 May 2021 21:07:17 -0600 Subject: [PATCH 03/62] tplink-safeloader: fix product_name of TP-Link AD7200 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The stock firmware does not accept firmware with "Talon" in the name. Tested on firmware version 1.0.10 Build 20160902 rel. 57400 which came preinstalled, as well as latest firmware version 2.0.1 Build 20170103 rel.71053 flashed from AD7200v1-up-ver2-0-1-P1[20170103-rel71053]_2017-01-04_10.08.28.bin. Fixes: 1a775a4fd033 ("ipq806x: add support for TP-Link Talon AD7200") Signed-off-by: Alex Henrie [added details about vendor firmware] Signed-off-by: Petr Štetiar --- tools/firmware-utils/src/tplink-safeloader.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/firmware-utils/src/tplink-safeloader.c b/tools/firmware-utils/src/tplink-safeloader.c index b3d5c9151d..8a47e6a58f 100644 --- a/tools/firmware-utils/src/tplink-safeloader.c +++ b/tools/firmware-utils/src/tplink-safeloader.c @@ -676,7 +676,7 @@ static struct device_info boards[] = { .vendor = "", .support_list = "SupportList:\r\n" - "{product_name:Talon AD7200,product_ver:1.0.0,special_id:00000000}\r\n", + "{product_name:AD7200,product_ver:1.0.0,special_id:00000000}\r\n", .part_trail = 0x00, .soft_ver = NULL, From ed4641e9f1ad940cb60187dea09cf17c865efcaf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Thu, 6 May 2021 13:10:17 +0200 Subject: [PATCH 04/62] kernel: fix parsing fixed subpartitions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rafał Miłecki --- ...ers-ofpart-fix-parsing-subpartitions.patch | 76 +++++++++++++++++++ ...ers-ofpart-fix-parsing-subpartitions.patch | 76 +++++++++++++++++++ .../202-linksys-find-active-root.patch | 4 +- .../202-linksys-find-active-root.patch | 4 +- .../patches-5.10/0101-find_active_root.patch | 8 +- .../patches-5.4/0101-find_active_root.patch | 8 +- .../patches-5.10/400-find_active_root.patch | 4 +- .../patches-5.4/400-find_active_root.patch | 4 +- 8 files changed, 168 insertions(+), 16 deletions(-) create mode 100644 target/linux/generic/pending-5.10/410-mtd-parsers-ofpart-fix-parsing-subpartitions.patch create mode 100644 target/linux/generic/pending-5.4/410-mtd-parsers-ofpart-fix-parsing-subpartitions.patch diff --git a/target/linux/generic/pending-5.10/410-mtd-parsers-ofpart-fix-parsing-subpartitions.patch b/target/linux/generic/pending-5.10/410-mtd-parsers-ofpart-fix-parsing-subpartitions.patch new file mode 100644 index 0000000000..353fa96748 --- /dev/null +++ b/target/linux/generic/pending-5.10/410-mtd-parsers-ofpart-fix-parsing-subpartitions.patch @@ -0,0 +1,76 @@ +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= +Date: Thu, 6 May 2021 12:33:58 +0200 +Subject: [PATCH] mtd: parsers: ofpart: fix parsing subpartitions +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +ofpart was recently patched to not scan random partition nodes as +subpartitions. That change unfortunately broke scanning valid +subpartitions like: + +partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + compatible = "fixed-partitions"; + label = "bootloader"; + reg = <0x0 0x100000>; + + partition@0 { + label = "config"; + reg = <0x80000 0x80000>; + }; + }; +}; + +Fix that regression by adding 1 more code path. We actually need 3 +conditional blocks to support 3 possible cases. This change also makes +code easier to understand & follow. + +Reported-by: David Bauer +Fixes: 2d751203aacf ("mtd: parsers: ofpart: limit parsing of deprecated DT syntax +Signed-off-by: Rafał Miłecki +--- + drivers/mtd/parsers/ofpart_core.c | 26 ++++++++++++++------------ + 1 file changed, 14 insertions(+), 12 deletions(-) + +--- a/drivers/mtd/parsers/ofpart_core.c ++++ b/drivers/mtd/parsers/ofpart_core.c +@@ -57,20 +57,22 @@ static int parse_fixed_partitions(struct + if (!mtd_node) + return 0; + +- ofpart_node = of_get_child_by_name(mtd_node, "partitions"); +- if (!ofpart_node && !master->parent) { +- /* +- * We might get here even when ofpart isn't used at all (e.g., +- * when using another parser), so don't be louder than +- * KERN_DEBUG +- */ +- pr_debug("%s: 'partitions' subnode not found on %pOF. Trying to parse direct subnodes as partitions.\n", +- master->name, mtd_node); ++ if (!master->parent) { /* Master */ ++ ofpart_node = of_get_child_by_name(mtd_node, "partitions"); ++ if (!ofpart_node) { ++ /* ++ * We might get here even when ofpart isn't used at all (e.g., ++ * when using another parser), so don't be louder than ++ * KERN_DEBUG ++ */ ++ pr_debug("%s: 'partitions' subnode not found on %pOF. Trying to parse direct subnodes as partitions.\n", ++ master->name, mtd_node); ++ ofpart_node = mtd_node; ++ dedicated = false; ++ } ++ } else { /* Partition */ + ofpart_node = mtd_node; +- dedicated = false; + } +- if (!ofpart_node) +- return 0; + + of_id = of_match_node(parse_ofpart_match_table, ofpart_node); + if (dedicated && !of_id) { diff --git a/target/linux/generic/pending-5.4/410-mtd-parsers-ofpart-fix-parsing-subpartitions.patch b/target/linux/generic/pending-5.4/410-mtd-parsers-ofpart-fix-parsing-subpartitions.patch new file mode 100644 index 0000000000..d0fc1d50e2 --- /dev/null +++ b/target/linux/generic/pending-5.4/410-mtd-parsers-ofpart-fix-parsing-subpartitions.patch @@ -0,0 +1,76 @@ +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= +Date: Thu, 6 May 2021 12:33:58 +0200 +Subject: [PATCH] mtd: parsers: ofpart: fix parsing subpartitions +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +ofpart was recently patched to not scan random partition nodes as +subpartitions. That change unfortunately broke scanning valid +subpartitions like: + +partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + compatible = "fixed-partitions"; + label = "bootloader"; + reg = <0x0 0x100000>; + + partition@0 { + label = "config"; + reg = <0x80000 0x80000>; + }; + }; +}; + +Fix that regression by adding 1 more code path. We actually need 3 +conditional blocks to support 3 possible cases. This change also makes +code easier to understand & follow. + +Reported-by: David Bauer +Fixes: 2d751203aacf ("mtd: parsers: ofpart: limit parsing of deprecated DT syntax +Signed-off-by: Rafał Miłecki +--- + drivers/mtd/parsers/ofpart_core.c | 26 ++++++++++++++------------ + 1 file changed, 14 insertions(+), 12 deletions(-) + +--- a/drivers/mtd/parsers/ofpart_core.c ++++ b/drivers/mtd/parsers/ofpart_core.c +@@ -57,20 +57,22 @@ static int parse_fixed_partitions(struct + if (!mtd_node) + return 0; + +- ofpart_node = of_get_child_by_name(mtd_node, "partitions"); +- if (!ofpart_node && !mtd_is_partition(master)) { +- /* +- * We might get here even when ofpart isn't used at all (e.g., +- * when using another parser), so don't be louder than +- * KERN_DEBUG +- */ +- pr_debug("%s: 'partitions' subnode not found on %pOF. Trying to parse direct subnodes as partitions.\n", +- master->name, mtd_node); ++ if (!mtd_is_partition(master)) { /* Master */ ++ ofpart_node = of_get_child_by_name(mtd_node, "partitions"); ++ if (!ofpart_node) { ++ /* ++ * We might get here even when ofpart isn't used at all (e.g., ++ * when using another parser), so don't be louder than ++ * KERN_DEBUG ++ */ ++ pr_debug("%s: 'partitions' subnode not found on %pOF. Trying to parse direct subnodes as partitions.\n", ++ master->name, mtd_node); ++ ofpart_node = mtd_node; ++ dedicated = false; ++ } ++ } else { /* Partition */ + ofpart_node = mtd_node; +- dedicated = false; + } +- if (!ofpart_node) +- return 0; + + of_id = of_match_node(parse_ofpart_match_table, ofpart_node); + if (dedicated && !of_id) { diff --git a/target/linux/kirkwood/patches-5.10/202-linksys-find-active-root.patch b/target/linux/kirkwood/patches-5.10/202-linksys-find-active-root.patch index b50c0370bd..515bb21707 100644 --- a/target/linux/kirkwood/patches-5.10/202-linksys-find-active-root.patch +++ b/target/linux/kirkwood/patches-5.10/202-linksys-find-active-root.patch @@ -22,7 +22,7 @@ Signed-off-by: Imre Kaloz const char *partname; struct device_node *pp; int nr_parts, i, ret = 0; -@@ -131,9 +134,15 @@ static int parse_fixed_partitions(struct +@@ -133,9 +136,15 @@ static int parse_fixed_partitions(struct parts[i].size = of_read_number(reg + a_cells, s_cells); parts[i].of_node = pp; @@ -41,7 +41,7 @@ Signed-off-by: Imre Kaloz parts[i].name = partname; if (of_get_property(pp, "read-only", &len)) -@@ -250,6 +259,18 @@ static int __init ofpart_parser_init(voi +@@ -252,6 +261,18 @@ static int __init ofpart_parser_init(voi return 0; } diff --git a/target/linux/kirkwood/patches-5.4/202-linksys-find-active-root.patch b/target/linux/kirkwood/patches-5.4/202-linksys-find-active-root.patch index 016ec01112..fe5e1e2cd0 100644 --- a/target/linux/kirkwood/patches-5.4/202-linksys-find-active-root.patch +++ b/target/linux/kirkwood/patches-5.4/202-linksys-find-active-root.patch @@ -22,7 +22,7 @@ Signed-off-by: Imre Kaloz const char *partname; struct device_node *pp; int nr_parts, i, ret = 0; -@@ -131,9 +134,15 @@ static int parse_fixed_partitions(struct +@@ -133,9 +136,15 @@ static int parse_fixed_partitions(struct parts[i].size = of_read_number(reg + a_cells, s_cells); parts[i].of_node = pp; @@ -41,7 +41,7 @@ Signed-off-by: Imre Kaloz parts[i].name = partname; if (of_get_property(pp, "read-only", &len)) -@@ -247,6 +256,18 @@ static int __init ofpart_parser_init(voi +@@ -249,6 +258,18 @@ static int __init ofpart_parser_init(voi return 0; } diff --git a/target/linux/lantiq/patches-5.10/0101-find_active_root.patch b/target/linux/lantiq/patches-5.10/0101-find_active_root.patch index 14c33e31a6..925ac9dbba 100644 --- a/target/linux/lantiq/patches-5.10/0101-find_active_root.patch +++ b/target/linux/lantiq/patches-5.10/0101-find_active_root.patch @@ -48,7 +48,7 @@ /* Pull of_node from the master device node */ mtd_node = mtd_get_of_node(master); -@@ -93,7 +127,9 @@ static int parse_fixed_partitions(struct +@@ -95,7 +129,9 @@ static int parse_fixed_partitions(struct return 0; parts = kcalloc(nr_parts, sizeof(*parts), GFP_KERNEL); @@ -59,7 +59,7 @@ return -ENOMEM; i = 0; -@@ -145,6 +181,11 @@ static int parse_fixed_partitions(struct +@@ -147,6 +183,11 @@ static int parse_fixed_partitions(struct if (of_property_read_bool(pp, "slc-mode")) parts[i].add_flags |= MTD_SLC_ON_MLC_EMULATION; @@ -71,7 +71,7 @@ i++; } -@@ -154,6 +195,11 @@ static int parse_fixed_partitions(struct +@@ -156,6 +197,11 @@ static int parse_fixed_partitions(struct if (quirks && quirks->post_parse) quirks->post_parse(master, parts, nr_parts); @@ -83,7 +83,7 @@ *pparts = parts; return nr_parts; -@@ -164,6 +210,7 @@ ofpart_fail: +@@ -166,6 +212,7 @@ ofpart_fail: ofpart_none: of_node_put(pp); kfree(parts); diff --git a/target/linux/lantiq/patches-5.4/0101-find_active_root.patch b/target/linux/lantiq/patches-5.4/0101-find_active_root.patch index 6e55ef9d7a..3f76535964 100644 --- a/target/linux/lantiq/patches-5.4/0101-find_active_root.patch +++ b/target/linux/lantiq/patches-5.4/0101-find_active_root.patch @@ -48,7 +48,7 @@ /* Pull of_node from the master device node */ mtd_node = mtd_get_of_node(master); -@@ -93,7 +127,9 @@ static int parse_fixed_partitions(struct +@@ -95,7 +129,9 @@ static int parse_fixed_partitions(struct return 0; parts = kcalloc(nr_parts, sizeof(*parts), GFP_KERNEL); @@ -59,7 +59,7 @@ return -ENOMEM; i = 0; -@@ -142,6 +178,11 @@ static int parse_fixed_partitions(struct +@@ -144,6 +180,11 @@ static int parse_fixed_partitions(struct if (of_get_property(pp, "lock", &len)) parts[i].mask_flags |= MTD_POWERUP_LOCK; @@ -71,7 +71,7 @@ i++; } -@@ -151,6 +192,11 @@ static int parse_fixed_partitions(struct +@@ -153,6 +194,11 @@ static int parse_fixed_partitions(struct if (quirks && quirks->post_parse) quirks->post_parse(master, parts, nr_parts); @@ -83,7 +83,7 @@ *pparts = parts; return nr_parts; -@@ -161,6 +207,7 @@ ofpart_fail: +@@ -163,6 +209,7 @@ ofpart_fail: ofpart_none: of_node_put(pp); kfree(parts); diff --git a/target/linux/mvebu/patches-5.10/400-find_active_root.patch b/target/linux/mvebu/patches-5.10/400-find_active_root.patch index 63b4c48dcf..5582d20c68 100644 --- a/target/linux/mvebu/patches-5.10/400-find_active_root.patch +++ b/target/linux/mvebu/patches-5.10/400-find_active_root.patch @@ -22,7 +22,7 @@ Signed-off-by: Imre Kaloz struct device_node *pp; int nr_parts, i, ret = 0; bool dedicated = true; -@@ -131,9 +134,13 @@ static int parse_fixed_partitions(struct +@@ -133,9 +136,13 @@ static int parse_fixed_partitions(struct parts[i].size = of_read_number(reg + a_cells, s_cells); parts[i].of_node = pp; @@ -39,7 +39,7 @@ Signed-off-by: Imre Kaloz parts[i].name = partname; if (of_get_property(pp, "read-only", &len)) -@@ -250,6 +257,18 @@ static int __init ofpart_parser_init(voi +@@ -252,6 +259,18 @@ static int __init ofpart_parser_init(voi return 0; } diff --git a/target/linux/mvebu/patches-5.4/400-find_active_root.patch b/target/linux/mvebu/patches-5.4/400-find_active_root.patch index 3bdb1eab8f..65c43740fc 100644 --- a/target/linux/mvebu/patches-5.4/400-find_active_root.patch +++ b/target/linux/mvebu/patches-5.4/400-find_active_root.patch @@ -22,7 +22,7 @@ Signed-off-by: Imre Kaloz struct device_node *pp; int nr_parts, i, ret = 0; bool dedicated = true; -@@ -131,9 +134,13 @@ static int parse_fixed_partitions(struct +@@ -133,9 +136,13 @@ static int parse_fixed_partitions(struct parts[i].size = of_read_number(reg + a_cells, s_cells); parts[i].of_node = pp; @@ -39,7 +39,7 @@ Signed-off-by: Imre Kaloz parts[i].name = partname; if (of_get_property(pp, "read-only", &len)) -@@ -247,6 +254,18 @@ static int __init ofpart_parser_init(voi +@@ -249,6 +256,18 @@ static int __init ofpart_parser_init(voi return 0; } From fa731838c5247f29f68098d7c78fc444f068bda9 Mon Sep 17 00:00:00 2001 From: Mark Mentovai Date: Mon, 12 Apr 2021 11:59:18 -0400 Subject: [PATCH 05/62] ipq806x: dwmac: clear forced speed during probe On a Ubiquiti UniFi AC HD (ubnt,unifi-ac-hd, UAP-AC-HD, UAP301), a forced speed on gmac1 is set in the QSGMII PCS_ALL_CH_CTL register, presumably by the bootloader (4.3.28), preventing the interface from being usable. The QSDK NSS GMAC driver takes care to clear the forced speed in nss_gmac_qsgmii_dev_init (https://source.codeaurora.org/quic/qsdk/oss/lklm/nss-gmac/tree/ipq806x/nss_gmac_init.c?h=nss at d5bb14925861). gmac1 is connected to the port on the device labeled SECONDARY, and is currently eth0 but will be switched to eth1 by a subsequent patch. By clearing the QSGMII PCS forced speed during dwmac initialization when SGMII is in use, this port becomes usable. This patch is upstreamable, and will be sent upstream after successful testing in OpenWrt. Signed-off-by: Mark Mentovai Build-tested: ipq806x/ubnt,unifi-ac-hd Run-tested: ipq806x/ubnt,unifi-ac-hd --- ...-dwmac-ipq806x-qsgmii-pcs-all-ch-ctl.patch | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 target/linux/ipq806x/patches-5.4/100-dwmac-ipq806x-qsgmii-pcs-all-ch-ctl.patch diff --git a/target/linux/ipq806x/patches-5.4/100-dwmac-ipq806x-qsgmii-pcs-all-ch-ctl.patch b/target/linux/ipq806x/patches-5.4/100-dwmac-ipq806x-qsgmii-pcs-all-ch-ctl.patch new file mode 100644 index 0000000000..6cdbf4d3dc --- /dev/null +++ b/target/linux/ipq806x/patches-5.4/100-dwmac-ipq806x-qsgmii-pcs-all-ch-ctl.patch @@ -0,0 +1,33 @@ +--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c ++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c +@@ -64,6 +64,17 @@ + #define NSS_COMMON_CLK_DIV_SGMII_100 4 + #define NSS_COMMON_CLK_DIV_SGMII_10 49 + ++#define QSGMII_PCS_ALL_CH_CTL 0x80 ++#define QSGMII_PCS_CH_SPEED_FORCE 0x2 ++#define QSGMII_PCS_CH_SPEED_10 0x0 ++#define QSGMII_PCS_CH_SPEED_100 0x4 ++#define QSGMII_PCS_CH_SPEED_1000 0x8 ++#define QSGMII_PCS_CH_SPEED_MASK (QSGMII_PCS_CH_SPEED_FORCE | \ ++ QSGMII_PCS_CH_SPEED_10 | \ ++ QSGMII_PCS_CH_SPEED_100 | \ ++ QSGMII_PCS_CH_SPEED_1000) ++#define QSGMII_PCS_CH_SPEED_SHIFT(x) (x * 4) ++ + #define QSGMII_PCS_CAL_LCKDT_CTL 0x120 + #define QSGMII_PCS_CAL_LCKDT_CTL_RST BIT(19) + +@@ -345,6 +356,12 @@ static int ipq806x_gmac_probe(struct pla + 0x1ul << QSGMII_PHY_RX_INPUT_EQU_OFFSET | + 0x2ul << QSGMII_PHY_CDR_PI_SLEW_OFFSET | + 0xCul << QSGMII_PHY_TX_DRV_AMP_OFFSET); ++ ++ regmap_update_bits(gmac->qsgmii_csr, ++ QSGMII_PCS_ALL_CH_CTL, ++ QSGMII_PCS_CH_SPEED_MASK << ++ QSGMII_PCS_CH_SPEED_SHIFT(gmac->id), ++ 0); + } + + plat_dat->has_gmac = true; From 4f74966852433651164c9a2a3544f727a45f30b4 Mon Sep 17 00:00:00 2001 From: Mark Mentovai Date: Mon, 12 Apr 2021 11:59:19 -0400 Subject: [PATCH 06/62] ipq806x: ubnt,unifi-ac-hd: use on-board PHYs Unlike many ipq806x devices, Ubiquiti UniFi AC HD (UAP-AC-HD, UAP301) has no switch on board. Its two Ethernet ports are connected to Atheros AR8033 PHYs. It is not appropriate to use fixed-link in this configuration. Instead, configure the correct PHYs in the device tree configuration to allow the at803x driver to load. Signed-off-by: Mark Mentovai Build-tested: ipq806x/ubnt,unifi-ac-hd Run-tested: ipq806x/ubnt,unifi-ac-hd --- .../arm/boot/dts/qcom-ipq8064-unifi-ac-hd.dts | 38 +++++++++---------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-unifi-ac-hd.dts b/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-unifi-ac-hd.dts index 7c2d6c9d13..70c51b90f3 100644 --- a/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-unifi-ac-hd.dts +++ b/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-unifi-ac-hd.dts @@ -16,6 +16,8 @@ led-running = &led_dome_blue; led-upgrade = &led_dome_blue; mdio-gpio0 = &mdio0; + ethernet0 = &gmac1; + ethernet1 = &gmac2; }; leds { @@ -229,38 +231,36 @@ pinctrl-0 = <&mdio0_pins>; pinctrl-names = "default"; -}; -&gmac2 { - status = "okay"; + phy4: ethernet-phy@4 { + reg = <4>; + }; - phy-mode = "sgmii"; - qcom,id = <2>; - qcom,emulation = <0>; - mdiobus = <&mdio0>; - - mtd-mac-address = <&eeprom 0x0>; - - fixed-link { - speed = <1000>; - full-duplex; + phy5: ethernet-phy@5 { + reg = <5>; }; }; &gmac1 { status = "okay"; + mdiobus = <&mdio0>; + phy-handle = <&phy5>; phy-mode = "sgmii"; qcom,id = <1>; - qcom,emulation = <0>; - mdiobus = <&mdio0>; mtd-mac-address = <&eeprom 0x6>; +}; - fixed-link { - speed = <1000>; - full-duplex; - }; +&gmac2 { + status = "okay"; + + mdiobus = <&mdio0>; + phy-handle = <&phy4>; + phy-mode = "sgmii"; + qcom,id = <2>; + + mtd-mac-address = <&eeprom 0x0>; }; &pcie0 { From 565814a5eeb9252d0586c9c7a576f7d1cc9d4bc3 Mon Sep 17 00:00:00 2001 From: Mark Mentovai Date: Mon, 12 Apr 2021 11:59:20 -0400 Subject: [PATCH 07/62] ipq806x: ubnt,unifi-ac-hd: reorder eth0 and eth1 The Ubiquiti UniFi AC HD (UAP-AC-HD, UAP301) has two Ethernet ports, labeled MAIN and SECONDARY, connected to gmac2 and gmac1, respectively. The standard probe order results in gmac1/SECONDARY being eth0 and gmac2/MAIN being eth1. This does not match the stock firmware, is contrary to user expectation, causes the wrong (high) MAC address to be used in a bridged configuration (the default for this device), and makes the gmac2/MAIN port unusable in the preinit environment (such as for failsafe). Until a recent patch, gmac1/SECONDARY (eth0) was not even usable. This reorders the ports so that gmac2/MAIN is eth0, and the now-working gmac1/SECONDARY is eth1. eth0 has the low MAC address and eth1 has the high; when bridged, the bridge takes on the correct low MAC address. This matches the stock firmware. The MAIN port is usable for failsafe during preinit. This device does not have a switch on board, so there's no possibility to remap ports via switch configuration. "ip link set $interface name" is used instead, during preinit before networking is configured. Signed-off-by: Mark Mentovai Build-tested: ipq806x/ubnt,unifi-ac-hd Run-tested: ipq806x/ubnt,unifi-ac-hd --- .../ipq806x/base-files/lib/preinit/04_reorder_eth | 13 +++++++++++++ .../arch/arm/boot/dts/qcom-ipq8064-unifi-ac-hd.dts | 4 ++-- 2 files changed, 15 insertions(+), 2 deletions(-) create mode 100644 target/linux/ipq806x/base-files/lib/preinit/04_reorder_eth diff --git a/target/linux/ipq806x/base-files/lib/preinit/04_reorder_eth b/target/linux/ipq806x/base-files/lib/preinit/04_reorder_eth new file mode 100644 index 0000000000..9f58473617 --- /dev/null +++ b/target/linux/ipq806x/base-files/lib/preinit/04_reorder_eth @@ -0,0 +1,13 @@ +. /lib/functions.sh + +preinit_reorder_eth() { + case $(board_name) in + ubnt,unifi-ac-hd) + ip link set eth0 name ethtmp + ip link set eth1 name eth0 + ip link set ethtmp name eth1 + ;; + esac +} + +boot_hook_add preinit_main preinit_reorder_eth diff --git a/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-unifi-ac-hd.dts b/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-unifi-ac-hd.dts index 70c51b90f3..672be3ca2c 100644 --- a/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-unifi-ac-hd.dts +++ b/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-unifi-ac-hd.dts @@ -16,8 +16,8 @@ led-running = &led_dome_blue; led-upgrade = &led_dome_blue; mdio-gpio0 = &mdio0; - ethernet0 = &gmac1; - ethernet1 = &gmac2; + ethernet0 = &gmac2; + ethernet1 = &gmac1; }; leds { From 75ca641f1b84e15110146f16b643b0f5f1c41090 Mon Sep 17 00:00:00 2001 From: Mark Mentovai Date: Mon, 12 Apr 2021 11:59:50 -0400 Subject: [PATCH 08/62] ipq806x: Add "snps,dwmac" to all gmac compatible= This was introduced to gmac2 and gmac3 in 57ea767a53c1 without fanfare. There's no indication of why it was added to those devices, but not to gmac0 or gmac1. It was probably an unintentional omission. It should be present on all four gmac devices. This property is considered by drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c stmmac_probe_config_dt. Signed-off-by: Mark Mentovai Build-tested: ipq806x/ubnt,unifi-ac-hd Run-tested: ipq806x/ubnt,unifi-ac-hd --- .../ipq806x/patches-5.4/083-ipq8064-dtsi-additions.patch | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target/linux/ipq806x/patches-5.4/083-ipq8064-dtsi-additions.patch b/target/linux/ipq806x/patches-5.4/083-ipq8064-dtsi-additions.patch index 221ecd7396..cbb0231d43 100644 --- a/target/linux/ipq806x/patches-5.4/083-ipq8064-dtsi-additions.patch +++ b/target/linux/ipq806x/patches-5.4/083-ipq8064-dtsi-additions.patch @@ -879,7 +879,7 @@ + + gmac0: ethernet@37000000 { + device_type = "network"; -+ compatible = "qcom,ipq806x-gmac"; ++ compatible = "qcom,ipq806x-gmac", "snps,dwmac"; + reg = <0x37000000 0x200000>; + interrupts = ; + interrupt-names = "macirq"; @@ -902,7 +902,7 @@ + + gmac1: ethernet@37200000 { + device_type = "network"; -+ compatible = "qcom,ipq806x-gmac"; ++ compatible = "qcom,ipq806x-gmac", "snps,dwmac"; + reg = <0x37200000 0x200000>; + interrupts = ; + interrupt-names = "macirq"; From daa586082740842e86c72c5c0e58320897a7d277 Mon Sep 17 00:00:00 2001 From: John Audia Date: Sun, 2 May 2021 07:28:04 -0400 Subject: [PATCH 09/62] kernel: bump 5.4 to 5.4.116 All patches automatically rebased. Build system: x86_64 Build-tested: ipq806x/R7800 Run-tested: ipq806x/R7800 No dmesg regressions, everything functional Signed-off-by: John Audia --- include/kernel-version.mk | 4 ++-- .../realtek/patches-5.4/300-mips-add-rtl838x-platform.patch | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/kernel-version.mk b/include/kernel-version.mk index 65e31e81e3..5b003e31a0 100644 --- a/include/kernel-version.mk +++ b/include/kernel-version.mk @@ -6,10 +6,10 @@ ifdef CONFIG_TESTING_KERNEL KERNEL_PATCHVER:=$(KERNEL_TESTING_PATCHVER) endif -LINUX_VERSION-5.4 = .115 +LINUX_VERSION-5.4 = .116 LINUX_VERSION-5.10 = .33 -LINUX_KERNEL_HASH-5.4.115 = 5b4724748527a622a886232b5da1471619eb3aa3bb38a11851275eba09989dd2 +LINUX_KERNEL_HASH-5.4.116 = fa8bce778c23a2c5be36e5b5b5005bcfd4ac3df8a90999e9e64189634bbbc9aa LINUX_KERNEL_HASH-5.10.33 = 933fdbc36371c0f830b7a6a957a559fca2dad1cc0eaa852ef42fb168185b4315 remove_uri_prefix=$(subst git://,,$(subst http://,,$(subst https://,,$(1)))) diff --git a/target/linux/realtek/patches-5.4/300-mips-add-rtl838x-platform.patch b/target/linux/realtek/patches-5.4/300-mips-add-rtl838x-platform.patch index e946a5b1a0..ecc77b2a73 100644 --- a/target/linux/realtek/patches-5.4/300-mips-add-rtl838x-platform.patch +++ b/target/linux/realtek/patches-5.4/300-mips-add-rtl838x-platform.patch @@ -10,7 +10,7 @@ platforms += sgi-ip27 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig -@@ -630,6 +630,26 @@ config RALINK +@@ -631,6 +631,26 @@ config RALINK select ARCH_HAS_RESET_CONTROLLER select RESET_CONTROLLER From c829bc1f2c3c47e230905864f2f5f8c759f88ce6 Mon Sep 17 00:00:00 2001 From: Raylynn Knight Date: Wed, 5 May 2021 12:11:44 -0400 Subject: [PATCH 10/62] realtek: Add support for Netgear S350 series switches GS308T and GS310TP The Netgear GS308T v1 is an 8 port gigabit switch. The GS310TP v1 is an 8 port POE+ gigabit switch with 2 SFP Ports (currently untested). The GS308T v1 and GS310TP v1 are quite similar to the Netgear GS1xx devices already supported. Theses two devices use the same Netgear firmware and are very similar to there corresponding GS1xx devices. For this reason they share a large portion of the device tree with the GS108T and GS110TP with exception of the uimage magic and model and compatible values. All of the above feature a dual firmware layout, referred to as Image0 and Image1 in the Netgear firmware. In order to manipulate the PoE+ on the GS310TP v1 , one needs the rtl83xx-poe package Specifications (GS308T) ---------------------- * RTL8380M SoC, 1 MIPS 4KEc core @ 500MHz * 128MB DDR3-1600 DRAM (Winbond W631GG8MB-12) * 32MB 3v NOR SPI Flash (Winbond W25Q256JVFQ) * RTL8231 GPIO extender to control the LEDs and the reset button * 8 x 10/100/1000BASE-T ports, internal PHY (RTL8218B) * UART (115200 8N1) via unpopulated standard 0.1" pin header marked J1 * Power is supplied via a 12V 1A barrel connector Specifications (GS310TP) ---------------------- * RTL8380M SoC, 1 MIPS 4KEc core @ 500MHz * Nuvoton M0516LDN for controlling PoE * 128MB DDR3-1600 DRAM (Winbond W631GG8MB-12) * 32MB 3v NOR SPI Flash (Winbond W25Q256JVFQ) * RTL8231 GPIO extender to control the LEDs and the reset button * 8 x 10/100/1000BASE-T PoE+ ports, 2 x Gigabit SFP ports, internal PHY (RTL8218B) * UART (115200 8N1) via unpopulated standard 0.1" pin header marked J1 * Power is supplied via a 54V 1.25A barrel connector Both devices have UART pinout ----------- J1 | [o]ooo ^ ||`------ GND | |`------- RX [TX out of the serial adapter] | `-------- TX [RX into the serial adapter] `---------- Vcc (3V3) [the square pin] The through holes are filled with PB-free solder which melts at 375C. They can also be drilled using a 0.9mm bit. Installation ------------ Instructions are identical to those for the similar Negear devices and apply both to the GS308T v1 and GS310TP v1 as well. ------------------- Boot initramfs image from U-Boot -------------------------------- 1. Press the Escape key at the `Hit Esc key to stop autoboot` prompt 2. Init network with `rtk network on` command 3. Load image with `tftpboot 0x8f000000 openwrt-realtek-generic-netgear_gs308t-v1-initramfs-kernel.bin` command 4. Boot the image with `bootm` command The switch defaults to IP 192.168.1.1 and tries to fetch the image via TFTP from 192.168.1.111. Updating the installed firmware ------------------------------- The OpenWRT ramdisk image can be flashed directly from the Netgear UI. The Image0 slot should be used in order to enable sysupgrade. As with similar switches, changing the active boot partition can be accomplished in U-Boot as follows: 1. Press the Escape key at the `Hit Esc key to stop autoboot` prompt 2. Run `setsys bootpartition {0|1}` to select the boot partition 3. Run `savesys` followed by `boota` to proceed with the boot process Signed-off-by: Raylynn Knight --- .../realtek/base-files/etc/board.d/02_network | 3 + .../realtek/dts/rtl8380_netgear_gigabit.dtsi | 58 ------------------ .../dts/rtl8380_netgear_gigabit_1xx.dtsi | 61 +++++++++++++++++++ .../dts/rtl8380_netgear_gigabit_3xx.dtsi | 61 +++++++++++++++++++ .../realtek/dts/rtl8380_netgear_gs108t-v3.dts | 2 +- .../dts/rtl8380_netgear_gs110tpp-v1.dts | 2 +- .../realtek/dts/rtl8380_netgear_gs308t-v1.dts | 8 +++ .../dts/rtl8380_netgear_gs310tp-v1.dts | 21 +++++++ target/linux/realtek/image/Makefile | 17 ++++++ 9 files changed, 173 insertions(+), 60 deletions(-) create mode 100644 target/linux/realtek/dts/rtl8380_netgear_gigabit_1xx.dtsi create mode 100644 target/linux/realtek/dts/rtl8380_netgear_gigabit_3xx.dtsi create mode 100644 target/linux/realtek/dts/rtl8380_netgear_gs308t-v1.dts create mode 100644 target/linux/realtek/dts/rtl8380_netgear_gs310tp-v1.dts diff --git a/target/linux/realtek/base-files/etc/board.d/02_network b/target/linux/realtek/base-files/etc/board.d/02_network index 1e199db589..c1dd230bb8 100644 --- a/target/linux/realtek/base-files/etc/board.d/02_network +++ b/target/linux/realtek/base-files/etc/board.d/02_network @@ -51,6 +51,9 @@ case $board in netgear,gs110tpp-v1) ucidef_set_poe 130 "$lan_list" ;; +netgear,gs310tp-v1) + ucidef_set_poe 55 "$lan_list" + ;; zyxel,gs1900-10hp) ucidef_set_poe 77 "$lan_list" ;; diff --git a/target/linux/realtek/dts/rtl8380_netgear_gigabit.dtsi b/target/linux/realtek/dts/rtl8380_netgear_gigabit.dtsi index 0d34ca5dc2..8ba66d6023 100644 --- a/target/linux/realtek/dts/rtl8380_netgear_gigabit.dtsi +++ b/target/linux/realtek/dts/rtl8380_netgear_gigabit.dtsi @@ -33,64 +33,6 @@ indirect-access-bus-id = <0>; }; -&spi0 { - status = "okay"; - - flash@0 { - compatible = "jedec,spi-nor"; - reg = <0>; - spi-max-frequency = <50000000>; - - partitions { - compatible = "fixed-partitions"; - #address-cells = <1>; - #size-cells = <1>; - - partition@0 { - label = "u-boot"; - reg = <0x0000000 0x00e0000>; - read-only; - }; - - partition@e0000 { - label = "u-boot-env"; - reg = <0x00e0000 0x0010000>; - read-only; - }; - - partition@f0000 { - label = "u-boot-env2"; - reg = <0x00f0000 0x0010000>; - }; - - partition@100000 { - label = "jffs"; - reg = <0x0100000 0x0100000>; - read-only; - }; - - partition@200000 { - label = "jffs2"; - reg = <0x0200000 0x0100000>; - read-only; - }; - - partition@300000 { - label = "firmware"; - compatible = "openwrt,uimage", "denx,uimage"; - openwrt,ih-magic = <0x4e474520>; - reg = <0x0300000 0x0e80000>; - }; - - partition@1180000 { - label = "runtime2"; - reg = <0x1180000 0x0e80000>; - read-only; - }; - }; - }; -}; - ðernet0 { mdio: mdio-bus { compatible = "realtek,rtl838x-mdio"; diff --git a/target/linux/realtek/dts/rtl8380_netgear_gigabit_1xx.dtsi b/target/linux/realtek/dts/rtl8380_netgear_gigabit_1xx.dtsi new file mode 100644 index 0000000000..7eccfcb5a2 --- /dev/null +++ b/target/linux/realtek/dts/rtl8380_netgear_gigabit_1xx.dtsi @@ -0,0 +1,61 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "rtl8380_netgear_gigabit.dtsi" + +&spi0 { + status = "okay"; + + flash@0 { + compatible = "jedec,spi-nor"; + reg = <0>; + spi-max-frequency = <50000000>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "u-boot"; + reg = <0x0000000 0x00e0000>; + read-only; + }; + + partition@e0000 { + label = "u-boot-env"; + reg = <0x00e0000 0x0010000>; + read-only; + }; + + partition@f0000 { + label = "u-boot-env2"; + reg = <0x00f0000 0x0010000>; + }; + + partition@100000 { + label = "jffs"; + reg = <0x0100000 0x0100000>; + read-only; + }; + + partition@200000 { + label = "jffs2"; + reg = <0x0200000 0x0100000>; + read-only; + }; + + partition@300000 { + label = "firmware"; + compatible = "openwrt,uimage", "denx,uimage"; + openwrt,ih-magic = <0x4e474520>; + reg = <0x0300000 0x0e80000>; + }; + + partition@1180000 { + label = "runtime2"; + reg = <0x1180000 0x0e80000>; + read-only; + }; + }; + }; +}; diff --git a/target/linux/realtek/dts/rtl8380_netgear_gigabit_3xx.dtsi b/target/linux/realtek/dts/rtl8380_netgear_gigabit_3xx.dtsi new file mode 100644 index 0000000000..efb146a25a --- /dev/null +++ b/target/linux/realtek/dts/rtl8380_netgear_gigabit_3xx.dtsi @@ -0,0 +1,61 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "rtl8380_netgear_gigabit.dtsi" + +&spi0 { + status = "okay"; + + flash@0 { + compatible = "jedec,spi-nor"; + reg = <0>; + spi-max-frequency = <50000000>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "u-boot"; + reg = <0x0000000 0x00e0000>; + read-only; + }; + + partition@e0000 { + label = "u-boot-env"; + reg = <0x00e0000 0x0010000>; + read-only; + }; + + partition@f0000 { + label = "u-boot-env2"; + reg = <0x00f0000 0x0010000>; + }; + + partition@100000 { + label = "jffs"; + reg = <0x0100000 0x0100000>; + read-only; + }; + + partition@200000 { + label = "jffs2"; + reg = <0x0200000 0x0100000>; + read-only; + }; + + partition@300000 { + label = "firmware"; + compatible = "openwrt,uimage", "denx,uimage"; + openwrt,ih-magic = <0x4e474335>; + reg = <0x0300000 0x0e80000>; + }; + + partition@1180000 { + label = "runtime2"; + reg = <0x1180000 0x0e80000>; + read-only; + }; + }; + }; +}; diff --git a/target/linux/realtek/dts/rtl8380_netgear_gs108t-v3.dts b/target/linux/realtek/dts/rtl8380_netgear_gs108t-v3.dts index 080fee6107..b701e88d1a 100644 --- a/target/linux/realtek/dts/rtl8380_netgear_gs108t-v3.dts +++ b/target/linux/realtek/dts/rtl8380_netgear_gs108t-v3.dts @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-or-later -#include "rtl8380_netgear_gigabit.dtsi" +#include "rtl8380_netgear_gigabit_1xx.dtsi" / { compatible = "netgear,gs108t-v3", "realtek,rtl838x-soc"; diff --git a/target/linux/realtek/dts/rtl8380_netgear_gs110tpp-v1.dts b/target/linux/realtek/dts/rtl8380_netgear_gs110tpp-v1.dts index 265cc51c30..646f4ed516 100644 --- a/target/linux/realtek/dts/rtl8380_netgear_gs110tpp-v1.dts +++ b/target/linux/realtek/dts/rtl8380_netgear_gs110tpp-v1.dts @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-or-later -#include "rtl8380_netgear_gigabit.dtsi" +#include "rtl8380_netgear_gigabit_1xx.dtsi" / { compatible = "netgear,gs110tpp-v1", "realtek,rtl838x-soc"; diff --git a/target/linux/realtek/dts/rtl8380_netgear_gs308t-v1.dts b/target/linux/realtek/dts/rtl8380_netgear_gs308t-v1.dts new file mode 100644 index 0000000000..016ed8beb6 --- /dev/null +++ b/target/linux/realtek/dts/rtl8380_netgear_gs308t-v1.dts @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "rtl8380_netgear_gigabit_3xx.dtsi" + +/ { + compatible = "netgear,gs308t-v1", "realtek,rtl838x-soc"; + model = "Netgear GS308T v1"; +}; diff --git a/target/linux/realtek/dts/rtl8380_netgear_gs310tp-v1.dts b/target/linux/realtek/dts/rtl8380_netgear_gs310tp-v1.dts new file mode 100644 index 0000000000..e3f59bde69 --- /dev/null +++ b/target/linux/realtek/dts/rtl8380_netgear_gs310tp-v1.dts @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "rtl8380_netgear_gigabit_3xx.dtsi" + +/ { + compatible = "netgear,gs310tp-v1", "realtek,rtl838x-soc"; + model = "Netgear GS310TP v1"; + +}; + +&mdio { + INTERNAL_PHY(24) + INTERNAL_PHY(26) +}; + +&switch0 { + ports { + SWITCH_SFP_PORT(24, 9, rgmii-id) + SWITCH_SFP_PORT(26, 10, rgmii-id) + }; +}; diff --git a/target/linux/realtek/image/Makefile b/target/linux/realtek/image/Makefile index 18e5fedb9b..b889cf84d8 100644 --- a/target/linux/realtek/image/Makefile +++ b/target/linux/realtek/image/Makefile @@ -86,6 +86,23 @@ define Device/netgear_gs110tpp-v1 endef TARGET_DEVICES += netgear_gs110tpp-v1 +define Device/netgear_gs308t-v1 + $(Device/netgear_nge) + DEVICE_MODEL := GS308T + DEVICE_VARIANT := v1 + UIMAGE_MAGIC := 0x4e474335 +endef +TARGET_DEVICES += netgear_gs308t-v1 + +define Device/netgear_gs310tp-v1 + $(Device/netgear_nge) + DEVICE_MODEL := GS310TP + DEVICE_VARIANT := v1 + UIMAGE_MAGIC := 0x4e474335 + DEVICE_PACKAGES += lua-rs232 +endef +TARGET_DEVICES += netgear_gs310tp-v1 + define Device/zyxel_gs1900 SOC := rtl8380 IMAGE_SIZE := 6976k From 4c0c860846b1ad0ba586f847f38dd9bb43aef4b9 Mon Sep 17 00:00:00 2001 From: INAGAKI Hiroshi Date: Wed, 16 Sep 2020 14:11:05 +0900 Subject: [PATCH 11/62] realtek: add support for INABA Abaniact AML2-17GP MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit INABA Abaniact AML2-17GP is a 17 port gigabit switch, based on RTL8382. Specification: - SoC : Realtek RTL8382 - RAM : DDR3 128 MiB (SK hynix H5TQ1G63EFR) - Flash : SPI-NOR 32 MiB (Macronix MX25L25635FZ2I-10G) - Ethernet : 10/100/1000 Mbps x17 - port 1-8 : RTL8218B (SoC) - port 8-16 : RTL8218D - port wan : RTL8214FC - LEDs/Keys : 1x, 1x - UART : pin header on PCB (Molex 530470410 compatible) - J14: 3.3V, GND, RX, TX from rear side - 115200n8 - Power : 100-240 VAC, 50/60 Hz, 0.21 A - Plug : IEC 60320-C13 Flash instruction using initramfs image: 1. Boot AML2-17GP normally 2. Set the IP address of computer to the range of 192.168.1.0/24, other than 192.168.1.248 and connect computer to "WAN/CONSOLE" port of AML2-17GP 3. Access to "http://192.168.1.248" and open firmware setting page -- UI Language: 日本語 -- "メンテナンス" -> "デュアルイメージ" -- UI Language: ENGLISH -- "Maintenance" -> "Dual Image" 4. Check "イメージ情報 (en: "Images Information")" and set the first image to active by choosing "アクティブイメージ" (en: "Active Image") in the partition "0" 5. open firmware upgrade page -- UI Language: 日本語 -- "メンテナンス" -> "アップグレードマネージャー" -- UI Language: ENGLISH -- "Maintenance" -> "Upgrade Manager" 6. Set the properties as follows -- UI Language: 日本語 -- "アップグレード方式" : "HTTP" "アップグレードタイプ" : "イメージ" "イメージ" : "アクティブ" "ブラウズファイル" : (select the OpenWrt initramfs image) -- UI Language: ENGLISH -- "Upgrade Method" : "HTTP" "Upgrade Type" : "Image" "Image" : "(Active)" "Browse file" : (select the OpenWrt initramfs image) 7. Press "アップグレード" (en: "Upgrade") button and perform upgrade 8. Wait ~150 seconds to complete flashing 9. After the flashing, the following message is showed and press "OK" button to reboot -- UI Language: 日本語 -- "成功!! 今すぐリブートしますか?" -- UI Language: ENGLISH -- "Success!! Do you want to reboot now?" 10. After the rebooting, reconnect the cable to other port (1-16) and open the SSH connection, download the sysupgrade image to the device and perform sysupgrade with it 11. Wait ~120 seconds to complete sysupgrade Note: - The uploaded image via WebUI will only be written with the length embedded in the uImage header. If the sysupgrade image is specified, only the kernel is flashed and lacks the rootfs, this causes a kernel panic while booting and bootloops. To avoid this issue, initramfs image is required for flashing on WebUI of stock firmware. - This device has 1x LED named as "POWER", but it's not connected to the GPIO of SoC and cannot be controlled. - port 17 is named as "WAN/CONSOLE". This port is for the upstream connection and console access (telnet/WebUI) on stock firmware. Back to stock firmware: 1. Set "bootpartition" variable in u-boot-env2 partition to "1" by fw_setsys fw_setsys bootpartition 1 2. Reboot AML2-17GP Signed-off-by: INAGAKI Hiroshi --- .../realtek/dts/rtl8382_inaba_aml2-17gp.dts | 164 ++++++++++++++++++ target/linux/realtek/image/Makefile | 9 + 2 files changed, 173 insertions(+) create mode 100644 target/linux/realtek/dts/rtl8382_inaba_aml2-17gp.dts diff --git a/target/linux/realtek/dts/rtl8382_inaba_aml2-17gp.dts b/target/linux/realtek/dts/rtl8382_inaba_aml2-17gp.dts new file mode 100644 index 0000000000..87761ac462 --- /dev/null +++ b/target/linux/realtek/dts/rtl8382_inaba_aml2-17gp.dts @@ -0,0 +1,164 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT + +#include "rtl838x.dtsi" + +#include +#include + +/ { + compatible = "inaba,aml2-17gp", "realtek,rtl838x-soc"; + model = "INABA Abaniact AML2-17GP"; + + chosen { + bootargs = "console=ttyS0,115200"; + }; + + memory@0 { + device_type = "memory"; + reg = <0x0 0x8000000>; + }; + + keys { + compatible = "gpio-keys-polled"; + poll-interval = <20>; + + reset { + label = "reset"; + gpios = <&gpio0 24 GPIO_ACTIVE_LOW>; + linux,code = ; + }; + }; +}; + +&gpio0 { + indirect-access-bus-id = <0>; +}; + +&spi0 { + status = "okay"; + + flash@0 { + compatible = "jedec,spi-nor"; + reg = <0>; + spi-max-frequency = <10000000>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "u-boot"; + reg = <0x0 0x80000>; + read-only; + }; + + partition@80000 { + label = "u-boot-env"; + reg = <0x80000 0x10000>; + read-only; + }; + + partition@90000 { + label = "u-boot-env2"; + reg = <0x90000 0x10000>; + }; + + partition@a0000 { + label = "jffs2_cfg"; + reg = <0xa0000 0x400000>; + read-only; + }; + + partition@4a0000 { + label = "jffs2_log"; + reg = <0x4a0000 0x100000>; + read-only; + }; + + partition@5a0000 { + compatible = "openwrt,uimage", "denx,uimage"; + label = "firmware"; + reg = <0x5a0000 0xd30000>; + openwrt,ih-magic = <0x83800000>; + }; + + partition@12d0000 { + label = "runtime2"; + reg = <0x12d0000 0xd30000>; + }; + }; + }; +}; + +ðernet0 { + mdio-bus { + compatible = "realtek,rtl838x-mdio"; + regmap = <ðernet0>; + #address-cells = <1>; + #size-cells = <0>; + + INTERNAL_PHY(8) + INTERNAL_PHY(9) + INTERNAL_PHY(10) + INTERNAL_PHY(11) + INTERNAL_PHY(12) + INTERNAL_PHY(13) + INTERNAL_PHY(14) + INTERNAL_PHY(15) + + EXTERNAL_PHY(16) + EXTERNAL_PHY(17) + EXTERNAL_PHY(18) + EXTERNAL_PHY(19) + EXTERNAL_PHY(20) + EXTERNAL_PHY(21) + EXTERNAL_PHY(22) + EXTERNAL_PHY(23) + + EXTERNAL_PHY(24) + }; +}; + +&switch0 { + ports { + #address-cells = <1>; + #size-cells = <0>; + + SWITCH_PORT(8, 1, internal) + SWITCH_PORT(9, 2, internal) + SWITCH_PORT(10, 3, internal) + SWITCH_PORT(11, 4, internal) + SWITCH_PORT(12, 5, internal) + SWITCH_PORT(13, 6, internal) + SWITCH_PORT(14, 7, internal) + SWITCH_PORT(15, 8, internal) + + SWITCH_PORT(16, 9, qsgmii) + SWITCH_PORT(17, 10, qsgmii) + SWITCH_PORT(18, 11, qsgmii) + SWITCH_PORT(19, 12, qsgmii) + SWITCH_PORT(20, 13, qsgmii) + SWITCH_PORT(21, 14, qsgmii) + SWITCH_PORT(22, 15, qsgmii) + SWITCH_PORT(23, 16, qsgmii) + + port@24 { + reg = <24>; + label = "wan"; + phy-handle = <&phy24>; + phy-mode = "qsgmii"; + }; + + port@28 { + ethernet = <ðernet0>; + reg = <28>; + phy-mode = "internal"; + + fixed-link { + speed = <1000>; + full-duplex; + }; + }; + }; +}; diff --git a/target/linux/realtek/image/Makefile b/target/linux/realtek/image/Makefile index b889cf84d8..ebc0c0a784 100644 --- a/target/linux/realtek/image/Makefile +++ b/target/linux/realtek/image/Makefile @@ -72,6 +72,15 @@ define Device/d-link_dgs-1210-28 endef TARGET_DEVICES += d-link_dgs-1210-28 +define Device/inaba_aml2-17gp + SOC := rtl8382 + IMAGE_SIZE := 13504k + DEVICE_VENDOR := INABA + DEVICE_MODEL := Abaniact AML2-17GP + UIMAGE_MAGIC := 0x83800000 +endef +TARGET_DEVICES += inaba_aml2-17gp + define Device/netgear_gs108t-v3 $(Device/netgear_nge) DEVICE_MODEL := GS108T From 861b82d36ae43efec8d16e61b82482e38996af92 Mon Sep 17 00:00:00 2001 From: Ansuel Smith Date: Sun, 28 Mar 2021 03:29:59 +0200 Subject: [PATCH 12/62] ipq806x: improve system latency Various report and data show that the freq 384000 is too low and cause some extra latency to the entire system. OEM qsdk code also set the min frequency for this target to 800 mhz. Also some user notice some instability with this idle frequency, solved by setting the min frequency to 600mhz. Fix all these kind of problem by introducing a boot init.d script that set the min frequency to 600mhz and set the ondemand governor to be more aggressive. The script set these value only if the ondemand governor is detected. 384 mhz freq is still available and user can decide to restore the old behavior by disabling this script. Signed-off-by: Ansuel Smith --- .../linux/ipq806x/base-files/etc/init.d/cpufreq | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100755 target/linux/ipq806x/base-files/etc/init.d/cpufreq diff --git a/target/linux/ipq806x/base-files/etc/init.d/cpufreq b/target/linux/ipq806x/base-files/etc/init.d/cpufreq new file mode 100755 index 0000000000..19278902ed --- /dev/null +++ b/target/linux/ipq806x/base-files/etc/init.d/cpufreq @@ -0,0 +1,17 @@ +#!/bin/sh /etc/rc.common + +START=15 + +boot() { + local governor + + governor=$(cat /sys/devices/system/cpu/cpufreq/policy0/scaling_governor) + + if [ "$governor" = "ondemand" ]; then + # Effective only with ondemand + echo 600000 > /sys/devices/system/cpu/cpufreq/policy0/scaling_min_freq + echo 600000 > /sys/devices/system/cpu/cpufreq/policy1/scaling_min_freq + echo 10 > /sys/devices/system/cpu/cpufreq/ondemand/sampling_down_factor + echo 50 > /sys/devices/system/cpu/cpufreq/ondemand/up_threshold + fi +} From d53be2a2e98129ecf32009893ec46b1ce644721a Mon Sep 17 00:00:00 2001 From: Ansuel Smith Date: Mon, 1 Mar 2021 00:58:57 +0100 Subject: [PATCH 13/62] ipq806x: copy kernel 5.4 patches to 5.10 Copy kernel 5.4 patches and config to 5.10 Signed-off-by: Ansuel Smith --- target/linux/ipq806x/config-5.10 | 526 ++++++++++ ...ings-qcom_adm-Fix-channel-specifiers.patch | 71 ++ .../0002-dmaengine-Add-ADM-driver.patch | 966 +++++++++++++++++ ...0030-clk-Disable-i2c-device-on-gsbi4.patch | 40 + ...d-add-SMEM-parser-for-QCOM-platforms.patch | 282 +++++ ...ically-select-PCI_DOMAINS-if-PCI-is-.patch | 29 + ...rt-adjusting-OPP-voltages-at-runtime.patch | 153 +++ ...per-to-get-an-opp-regulator-for-devi.patch | 52 + ...e-voltage-tolerance-when-adjusting-t.patch | 47 + ...-dt-Handle-OPP-voltage-adjust-events.patch | 118 +++ ...-dt-Add-L2-frequency-scaling-support.patch | 199 ++++ ...056-cpufreq-dt-Add-missing-rcu-locks.patch | 23 + ...add-fab-scaling-support-with-cpufreq.patch | 243 +++++ ...le-Add-cpuidle-support-for-QCOM-cpus.patch | 29 + ...arch-arm-force-ZRELADDR-on-arch-qcom.patch | 62 ++ ...conflicts-with-OpenWrt-auto-mounting.patch | 23 + .../0063-1-ipq806x-tsens-driver.patch | 616 +++++++++++ ...sens-support-configurable-interrupts.patch | 437 ++++++++ .../0063-3-tsens-fix-kernel-5_4.patch | 68 ++ .../0063-4-ip806x-tsense-rework-driver.patch | 107 ++ .../0065-arm-override-compiler-flags.patch | 21 + ...Mangle-bootloader-s-kernel-arguments.patch | 210 ++++ .../0069-arm-boot-add-dts-files.patch | 37 + .../0072-add-ipq806x-with-no-clocks.patch | 10 + ...RM-dts-qcom-add-gpio-ranges-property.patch | 70 ++ ...s-qcom-add-scm-definition-to-ipq806x.patch | 29 + .../082-ipq8064-dtsi-tweaks.patch | 130 +++ .../083-ipq8064-dtsi-additions.patch | 992 ++++++++++++++++++ .../084-ipq8064-v1.0-dtsi-cleanup.patch | 89 ++ .../085-ipq8064-v1.0-dtsi-additions.patch | 14 + ...e-scm_call-to-route-GPIO-irq-to-Apps.patch | 104 ++ ...Fixed-missing-RGMII-pincontrol-defin.patch | 56 + ...t-disable-pretimeout-on-timer-platfo.patch | 98 ++ ...ed-the-enable-regs-and-mask-for-PRNG.patch | 28 + .../090-v5.8-clk-clk-rpm-fixes.patch | 90 ++ ...91-v5.8-regulator-add-smb208-support.patch | 63 ++ ...mem-Add-support-for-krait-based-socs.patch | 361 +++++++ ...eq-qcom-fix-wrong-compatible-binding.patch | 26 + ...Use-bulk-clk-api-and-assert-on-error.patch | 228 ++++ ...6x-PCI-qcom-Add-ipq8064-rev2-variant.patch | 36 + ...om-Support-pci-speed-set-for-ipq806x.patch | 74 ++ ...06x-net-mdio-add-ipq8064-mdio-driver.patch | 216 ++++ ...-add-qcom-ipq806x-dwc-usb-phy-driver.patch | 621 +++++++++++ ..._5db-when-device-property-read-fails.patch | 31 + .../850-soc-add-qualcomm-syscon.patch | 121 +++ .../patches-5.10/851-add-gsbi1-dts.patch | 44 + .../900-arm-add-cmdline-override.patch | 37 + .../997-device_tree_cmdline.patch | 12 + 48 files changed, 7939 insertions(+) create mode 100644 target/linux/ipq806x/config-5.10 create mode 100644 target/linux/ipq806x/patches-5.10/0001-dtbindings-qcom_adm-Fix-channel-specifiers.patch create mode 100644 target/linux/ipq806x/patches-5.10/0002-dmaengine-Add-ADM-driver.patch create mode 100644 target/linux/ipq806x/patches-5.10/0030-clk-Disable-i2c-device-on-gsbi4.patch create mode 100644 target/linux/ipq806x/patches-5.10/0031-mtd-add-SMEM-parser-for-QCOM-platforms.patch create mode 100644 target/linux/ipq806x/patches-5.10/0033-ARM-qcom-automatically-select-PCI_DOMAINS-if-PCI-is-.patch create mode 100644 target/linux/ipq806x/patches-5.10/0049-PM-OPP-Support-adjusting-OPP-voltages-at-runtime.patch create mode 100644 target/linux/ipq806x/patches-5.10/0051-PM-OPP-Add-a-helper-to-get-an-opp-regulator-for-devi.patch create mode 100644 target/linux/ipq806x/patches-5.10/0052-PM-OPP-Update-the-voltage-tolerance-when-adjusting-t.patch create mode 100644 target/linux/ipq806x/patches-5.10/0054-cpufreq-dt-Handle-OPP-voltage-adjust-events.patch create mode 100644 target/linux/ipq806x/patches-5.10/0055-cpufreq-dt-Add-L2-frequency-scaling-support.patch create mode 100644 target/linux/ipq806x/patches-5.10/0056-cpufreq-dt-Add-missing-rcu-locks.patch create mode 100644 target/linux/ipq806x/patches-5.10/0057-add-fab-scaling-support-with-cpufreq.patch create mode 100644 target/linux/ipq806x/patches-5.10/0059-ARM-cpuidle-Add-cpuidle-support-for-QCOM-cpus.patch create mode 100644 target/linux/ipq806x/patches-5.10/0060-HACK-arch-arm-force-ZRELADDR-on-arch-qcom.patch create mode 100644 target/linux/ipq806x/patches-5.10/0061-mtd-rootfs-conflicts-with-OpenWrt-auto-mounting.patch create mode 100644 target/linux/ipq806x/patches-5.10/0063-1-ipq806x-tsens-driver.patch create mode 100644 target/linux/ipq806x/patches-5.10/0063-2-tsens-support-configurable-interrupts.patch create mode 100644 target/linux/ipq806x/patches-5.10/0063-3-tsens-fix-kernel-5_4.patch create mode 100644 target/linux/ipq806x/patches-5.10/0063-4-ip806x-tsense-rework-driver.patch create mode 100644 target/linux/ipq806x/patches-5.10/0065-arm-override-compiler-flags.patch create mode 100644 target/linux/ipq806x/patches-5.10/0067-generic-Mangle-bootloader-s-kernel-arguments.patch create mode 100644 target/linux/ipq806x/patches-5.10/0069-arm-boot-add-dts-files.patch create mode 100644 target/linux/ipq806x/patches-5.10/0072-add-ipq806x-with-no-clocks.patch create mode 100644 target/linux/ipq806x/patches-5.10/080-v5.7-ARM-dts-qcom-add-gpio-ranges-property.patch create mode 100644 target/linux/ipq806x/patches-5.10/081-v5.8-ARM-dts-qcom-add-scm-definition-to-ipq806x.patch create mode 100644 target/linux/ipq806x/patches-5.10/082-ipq8064-dtsi-tweaks.patch create mode 100644 target/linux/ipq806x/patches-5.10/083-ipq8064-dtsi-additions.patch create mode 100644 target/linux/ipq806x/patches-5.10/084-ipq8064-v1.0-dtsi-cleanup.patch create mode 100644 target/linux/ipq806x/patches-5.10/085-ipq8064-v1.0-dtsi-additions.patch create mode 100644 target/linux/ipq806x/patches-5.10/086-v5.8-pinctrl-qom-use-scm_call-to-route-GPIO-irq-to-Apps.patch create mode 100644 target/linux/ipq806x/patches-5.10/087-v5.8-ipq8064-pinctrl-Fixed-missing-RGMII-pincontrol-defin.patch create mode 100644 target/linux/ipq806x/patches-5.10/088-v5.8-watchdog-qcom-wdt-disable-pretimeout-on-timer-platfo.patch create mode 100644 target/linux/ipq806x/patches-5.10/089-v5.8-ipq806x-gcc-Added-the-enable-regs-and-mask-for-PRNG.patch create mode 100644 target/linux/ipq806x/patches-5.10/090-v5.8-clk-clk-rpm-fixes.patch create mode 100644 target/linux/ipq806x/patches-5.10/091-v5.8-regulator-add-smb208-support.patch create mode 100644 target/linux/ipq806x/patches-5.10/092-1-v5.7-qcom-cpufreq-nvmem-Add-support-for-krait-based-socs.patch create mode 100644 target/linux/ipq806x/patches-5.10/092-2-v5.7-cpufreq-qcom-fix-wrong-compatible-binding.patch create mode 100644 target/linux/ipq806x/patches-5.10/093-4-v5.8-ipq806x-PCI-qcom-Use-bulk-clk-api-and-assert-on-error.patch create mode 100644 target/linux/ipq806x/patches-5.10/093-7-v5.8-ipq806x-PCI-qcom-Add-ipq8064-rev2-variant.patch create mode 100644 target/linux/ipq806x/patches-5.10/093-8-v5.8-ipq806x-PCI-qcom-Support-pci-speed-set-for-ipq806x.patch create mode 100644 target/linux/ipq806x/patches-5.10/094-v5.7-ipq806x-net-mdio-add-ipq8064-mdio-driver.patch create mode 100644 target/linux/ipq806x/patches-5.10/095-1-v5.9-phy-qualcomm-add-qcom-ipq806x-dwc-usb-phy-driver.patch create mode 100644 target/linux/ipq806x/patches-5.10/095-2-v5.9-phy-qualcomm-fix-setting-of-tx_deamp_3_5db-when-device-property-read-fails.patch create mode 100644 target/linux/ipq806x/patches-5.10/850-soc-add-qualcomm-syscon.patch create mode 100644 target/linux/ipq806x/patches-5.10/851-add-gsbi1-dts.patch create mode 100644 target/linux/ipq806x/patches-5.10/900-arm-add-cmdline-override.patch create mode 100644 target/linux/ipq806x/patches-5.10/997-device_tree_cmdline.patch diff --git a/target/linux/ipq806x/config-5.10 b/target/linux/ipq806x/config-5.10 new file mode 100644 index 0000000000..e6160bd455 --- /dev/null +++ b/target/linux/ipq806x/config-5.10 @@ -0,0 +1,526 @@ +CONFIG_ALIGNMENT_TRAP=y +# CONFIG_APQ_GCC_8084 is not set +# CONFIG_APQ_MMCC_8084 is not set +CONFIG_AR8216_PHY=y +CONFIG_ARCH_32BIT_OFF_T=y +CONFIG_ARCH_CLOCKSOURCE_DATA=y +CONFIG_ARCH_HAS_BINFMT_FLAT=y +CONFIG_ARCH_HAS_DEBUG_VIRTUAL=y +CONFIG_ARCH_HAS_ELF_RANDOMIZE=y +CONFIG_ARCH_HAS_FORTIFY_SOURCE=y +CONFIG_ARCH_HAS_GCOV_PROFILE_ALL=y +CONFIG_ARCH_HAS_KCOV=y +CONFIG_ARCH_HAS_KEEPINITRD=y +CONFIG_ARCH_HAS_MEMBARRIER_SYNC_CORE=y +CONFIG_ARCH_HAS_PHYS_TO_DMA=y +CONFIG_ARCH_HAS_SETUP_DMA_OPS=y +CONFIG_ARCH_HAS_SET_MEMORY=y +CONFIG_ARCH_HAS_STRICT_KERNEL_RWX=y +CONFIG_ARCH_HAS_STRICT_MODULE_RWX=y +CONFIG_ARCH_HAS_TEARDOWN_DMA_OPS=y +CONFIG_ARCH_HAS_TICK_BROADCAST=y +CONFIG_ARCH_HAVE_CUSTOM_GPIO_H=y +CONFIG_ARCH_HIBERNATION_POSSIBLE=y +CONFIG_ARCH_KEEP_MEMBLOCK=y +# CONFIG_ARCH_MDM9615 is not set +CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y +CONFIG_ARCH_MSM8960=y +CONFIG_ARCH_MSM8974=y +CONFIG_ARCH_MSM8X60=y +CONFIG_ARCH_MULTIPLATFORM=y +CONFIG_ARCH_MULTI_V6_V7=y +CONFIG_ARCH_MULTI_V7=y +CONFIG_ARCH_NR_GPIO=0 +CONFIG_ARCH_OPTIONAL_KERNEL_RWX=y +CONFIG_ARCH_OPTIONAL_KERNEL_RWX_DEFAULT=y +CONFIG_ARCH_QCOM=y +CONFIG_ARCH_SUPPORTS_ATOMIC_RMW=y +CONFIG_ARCH_SUPPORTS_BIG_ENDIAN=y +CONFIG_ARCH_SUPPORTS_UPROBES=y +CONFIG_ARCH_SUSPEND_POSSIBLE=y +CONFIG_ARCH_USE_BUILTIN_BSWAP=y +CONFIG_ARCH_USE_CMPXCHG_LOCKREF=y +CONFIG_ARCH_WANT_DEFAULT_TOPDOWN_MMAP_LAYOUT=y +CONFIG_ARCH_WANT_GENERAL_HUGETLB=y +CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y +CONFIG_ARM=y +CONFIG_ARM_AMBA=y +CONFIG_ARM_APPENDED_DTB=y +CONFIG_ARM_ARCH_TIMER=y +CONFIG_ARM_ARCH_TIMER_EVTSTREAM=y +CONFIG_ARM_ATAG_DTB_COMPAT=y +# CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_FROM_BOOTLOADER is not set +CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_MANGLE=y +CONFIG_ARM_CPUIDLE=y +CONFIG_ARM_CPU_SUSPEND=y +# CONFIG_ARM_CPU_TOPOLOGY is not set +CONFIG_ARM_GIC=y +CONFIG_ARM_HAS_SG_CHAIN=y +CONFIG_ARM_L1_CACHE_SHIFT=6 +CONFIG_ARM_L1_CACHE_SHIFT_6=y +CONFIG_ARM_MODULE_PLTS=y +CONFIG_ARM_PATCH_IDIV=y +CONFIG_ARM_PATCH_PHYS_VIRT=y +# CONFIG_ARM_QCOM_CPUFREQ_HW is not set +CONFIG_ARM_QCOM_CPUFREQ_NVMEM=y +CONFIG_ARM_QCOM_CPUIDLE=y +# CONFIG_ARM_SMMU is not set +CONFIG_ARM_THUMB=y +CONFIG_ARM_UNWIND=y +CONFIG_ARM_VIRT_EXT=y +CONFIG_AT803X_PHY=y +CONFIG_BINFMT_FLAT_ARGVP_ENVP_ON_STACK=y +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_MQ_PCI=y +CONFIG_BOUNCE=y +# CONFIG_CACHE_L2X0 is not set +CONFIG_CC_HAS_KASAN_GENERIC=y +CONFIG_CLKDEV_LOOKUP=y +CONFIG_CLKSRC_QCOM=y +CONFIG_CLONE_BACKWARDS=y +CONFIG_CMDLINE_OVERRIDE=y +CONFIG_COMMON_CLK=y +CONFIG_COMMON_CLK_QCOM=y +CONFIG_COMPAT_32BIT_TIME=y +CONFIG_CPUFREQ_DT=y +CONFIG_CPUFREQ_DT_PLATDEV=y +CONFIG_CPU_32v6K=y +CONFIG_CPU_32v7=y +CONFIG_CPU_ABRT_EV7=y +CONFIG_CPU_CACHE_V7=y +CONFIG_CPU_CACHE_VIPT=y +CONFIG_CPU_COPY_V6=y +CONFIG_CPU_CP15=y +CONFIG_CPU_CP15_MMU=y +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y +# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set +CONFIG_CPU_FREQ_GOV_ATTR_SET=y +CONFIG_CPU_FREQ_GOV_COMMON=y +# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set +CONFIG_CPU_FREQ_GOV_ONDEMAND=y +CONFIG_CPU_FREQ_GOV_PERFORMANCE=y +# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set +CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y +# CONFIG_CPU_FREQ_GOV_USERSPACE is not set +CONFIG_CPU_FREQ_STAT=y +CONFIG_CPU_HAS_ASID=y +CONFIG_CPU_IDLE=y +CONFIG_CPU_IDLE_GOV_LADDER=y +CONFIG_CPU_IDLE_GOV_MENU=y +CONFIG_CPU_IDLE_MULTIPLE_DRIVERS=y +CONFIG_CPU_PABRT_V7=y +CONFIG_CPU_PM=y +CONFIG_CPU_RMAP=y +CONFIG_CPU_SPECTRE=y +CONFIG_CPU_THERMAL=y +CONFIG_CPU_THUMB_CAPABLE=y +CONFIG_CPU_TLB_V7=y +CONFIG_CPU_V7=y +CONFIG_CRC16=y +# CONFIG_CRC32_SARWATE is not set +CONFIG_CRC32_SLICEBY8=y +CONFIG_CRYPTO_ACOMP2=y +CONFIG_CRYPTO_AEAD=y +CONFIG_CRYPTO_AEAD2=y +CONFIG_CRYPTO_DEFLATE=y +CONFIG_CRYPTO_DEV_QCOM_RNG=y +CONFIG_CRYPTO_DRBG=y +CONFIG_CRYPTO_DRBG_HMAC=y +CONFIG_CRYPTO_DRBG_MENU=y +CONFIG_CRYPTO_HASH=y +CONFIG_CRYPTO_HASH2=y +CONFIG_CRYPTO_HASH_INFO=y +CONFIG_CRYPTO_HMAC=y +CONFIG_CRYPTO_HW=y +CONFIG_CRYPTO_JITTERENTROPY=y +CONFIG_CRYPTO_LIB_SHA256=y +CONFIG_CRYPTO_LZO=y +CONFIG_CRYPTO_MANAGER=y +CONFIG_CRYPTO_MANAGER2=y +CONFIG_CRYPTO_NULL2=y +CONFIG_CRYPTO_RNG=y +CONFIG_CRYPTO_RNG2=y +CONFIG_CRYPTO_SHA256=y +CONFIG_CRYPTO_ZSTD=y +CONFIG_DCACHE_WORD_ACCESS=y +CONFIG_DEBUG_GPIO=y +CONFIG_DEBUG_LL_INCLUDE="mach/debug-macro.S" +CONFIG_DMADEVICES=y +CONFIG_DMA_ENGINE=y +CONFIG_DMA_OF=y +CONFIG_DMA_REMAP=y +CONFIG_DMA_VIRTUAL_CHANNELS=y +CONFIG_DTC=y +CONFIG_DT_IDLE_STATES=y +# CONFIG_DWMAC_GENERIC is not set +CONFIG_DWMAC_IPQ806X=y +# CONFIG_DWMAC_QCOM_ETHQOS is not set +CONFIG_DYNAMIC_DEBUG=y +CONFIG_EDAC_ATOMIC_SCRUB=y +CONFIG_EDAC_SUPPORT=y +CONFIG_ETHERNET_PACKET_MANGLE=y +CONFIG_FIXED_PHY=y +CONFIG_FIX_EARLYCON_MEM=y +CONFIG_FW_LOADER_PAGED_BUF=y +CONFIG_GENERIC_ALLOCATOR=y +CONFIG_GENERIC_BUG=y +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y +CONFIG_GENERIC_CPU_AUTOPROBE=y +CONFIG_GENERIC_EARLY_IOREMAP=y +CONFIG_GENERIC_IDLE_POLL_SETUP=y +CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK=y +CONFIG_GENERIC_IRQ_MULTI_HANDLER=y +CONFIG_GENERIC_IRQ_SHOW=y +CONFIG_GENERIC_IRQ_SHOW_LEVEL=y +CONFIG_GENERIC_MSI_IRQ=y +CONFIG_GENERIC_MSI_IRQ_DOMAIN=y +CONFIG_GENERIC_PCI_IOMAP=y +CONFIG_GENERIC_PHY=y +CONFIG_GENERIC_PINCONF=y +CONFIG_GENERIC_PINCTRL_GROUPS=y +CONFIG_GENERIC_PINMUX_FUNCTIONS=y +CONFIG_GENERIC_SCHED_CLOCK=y +CONFIG_GENERIC_SMP_IDLE_THREAD=y +CONFIG_GENERIC_STRNCPY_FROM_USER=y +CONFIG_GENERIC_STRNLEN_USER=y +CONFIG_GENERIC_TIME_VSYSCALL=y +CONFIG_GPIOLIB=y +CONFIG_GPIOLIB_IRQCHIP=y +CONFIG_GRO_CELLS=y +CONFIG_HANDLE_DOMAIN_IRQ=y +CONFIG_HARDEN_BRANCH_PREDICTOR=y +CONFIG_HARDIRQS_SW_RESEND=y +CONFIG_HAS_DMA=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT_MAP=y +CONFIG_HAVE_ARCH_AUDITSYSCALL=y +CONFIG_HAVE_ARCH_BITREVERSE=y +CONFIG_HAVE_ARCH_JUMP_LABEL=y +CONFIG_HAVE_ARCH_KGDB=y +CONFIG_HAVE_ARCH_PFN_VALID=y +CONFIG_HAVE_ARCH_SECCOMP_FILTER=y +CONFIG_HAVE_ARCH_THREAD_STRUCT_WHITELIST=y +CONFIG_HAVE_ARCH_TRACEHOOK=y +CONFIG_HAVE_ARM_ARCH_TIMER=y +CONFIG_HAVE_ARM_SMCCC=y +CONFIG_HAVE_CLK=y +CONFIG_HAVE_CLK_PREPARE=y +CONFIG_HAVE_CONTEXT_TRACKING=y +CONFIG_HAVE_COPY_THREAD_TLS=y +CONFIG_HAVE_C_RECORDMCOUNT=y +CONFIG_HAVE_DEBUG_KMEMLEAK=y +CONFIG_HAVE_DMA_CONTIGUOUS=y +CONFIG_HAVE_DYNAMIC_FTRACE=y +CONFIG_HAVE_DYNAMIC_FTRACE_WITH_REGS=y +CONFIG_HAVE_EBPF_JIT=y +CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y +CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y +CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y +CONFIG_HAVE_FUNCTION_TRACER=y +CONFIG_HAVE_IDE=y +CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y +CONFIG_HAVE_LD_DEAD_CODE_DATA_ELIMINATION=y +CONFIG_HAVE_MOD_ARCH_SPECIFIC=y +CONFIG_HAVE_NET_DSA=y +CONFIG_HAVE_OPROFILE=y +CONFIG_HAVE_OPTPROBES=y +CONFIG_HAVE_PCI=y +CONFIG_HAVE_PERF_EVENTS=y +CONFIG_HAVE_PERF_REGS=y +CONFIG_HAVE_PERF_USER_STACK_DUMP=y +CONFIG_HAVE_PROC_CPU=y +CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y +CONFIG_HAVE_RSEQ=y +CONFIG_HAVE_SMP=y +CONFIG_HAVE_SYSCALL_TRACEPOINTS=y +CONFIG_HAVE_UID16=y +CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y +CONFIG_HIGHMEM=y +# CONFIG_HIGHPTE is not set +CONFIG_HWMON=y +CONFIG_HWSPINLOCK=y +CONFIG_HWSPINLOCK_QCOM=y +CONFIG_HW_RANDOM=y +CONFIG_HZ=100 +CONFIG_HZ_100=y +CONFIG_HZ_FIXED=0 +CONFIG_I2C=y +CONFIG_I2C_BOARDINFO=y +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_HELPER_AUTO=y +CONFIG_I2C_QUP=y +CONFIG_INITRAMFS_SOURCE="" +# CONFIG_IOMMU_DEBUGFS is not set +# CONFIG_IOMMU_IO_PGTABLE_ARMV7S is not set +# CONFIG_IOMMU_IO_PGTABLE_LPAE is not set +CONFIG_IOMMU_SUPPORT=y +# CONFIG_IPQ_GCC_4019 is not set +CONFIG_IPQ_GCC_806X=y +# CONFIG_IPQ_GCC_8074 is not set +# CONFIG_IPQ_LCC_806X is not set +CONFIG_IRQCHIP=y +CONFIG_IRQ_DOMAIN=y +CONFIG_IRQ_DOMAIN_HIERARCHY=y +CONFIG_IRQ_FORCED_THREADING=y +CONFIG_IRQ_WORK=y +CONFIG_KPSS_XCC=y +CONFIG_KRAITCC=y +CONFIG_KRAIT_CLOCKS=y +CONFIG_KRAIT_L2_ACCESSORS=y +CONFIG_LEDS_TRIGGER_DISK=y +CONFIG_LIBFDT=y +CONFIG_LOCK_DEBUGGING_SUPPORT=y +CONFIG_LOCK_SPIN_ON_OWNER=y +CONFIG_LZO_COMPRESS=y +CONFIG_LZO_DECOMPRESS=y +CONFIG_MDIO_BITBANG=y +CONFIG_MDIO_BUS=y +CONFIG_MDIO_DEVICE=y +CONFIG_MDIO_GPIO=y +CONFIG_MDIO_IPQ8064=y +# CONFIG_MDM_GCC_9615 is not set +# CONFIG_MDM_LCC_9615 is not set +CONFIG_MEMFD_CREATE=y +CONFIG_MFD_QCOM_RPM=y +# CONFIG_MFD_SPMI_PMIC is not set +CONFIG_MFD_SYSCON=y +CONFIG_MIGHT_HAVE_CACHE_L2X0=y +CONFIG_MIGRATION=y +CONFIG_MMC=y +CONFIG_MMC_ARMMMCI=y +CONFIG_MMC_BLOCK=y +CONFIG_MMC_BLOCK_MINORS=16 +CONFIG_MMC_QCOM_DML=y +CONFIG_MMC_SDHCI=y +CONFIG_MMC_SDHCI_IO_ACCESSORS=y +CONFIG_MMC_SDHCI_MSM=y +# CONFIG_MMC_SDHCI_PCI is not set +CONFIG_MMC_SDHCI_PLTFM=y +# CONFIG_MMC_TIFM_SD is not set +CONFIG_MODULES_USE_ELF_REL=y +CONFIG_MSM_GCC_8660=y +# CONFIG_MSM_GCC_8916 is not set +# CONFIG_MSM_GCC_8960 is not set +# CONFIG_MSM_GCC_8974 is not set +# CONFIG_MSM_GCC_8994 is not set +# CONFIG_MSM_GCC_8996 is not set +# CONFIG_MSM_GCC_8998 is not set +# CONFIG_MSM_IOMMU is not set +# CONFIG_MSM_LCC_8960 is not set +# CONFIG_MSM_MMCC_8960 is not set +# CONFIG_MSM_MMCC_8974 is not set +# CONFIG_MSM_MMCC_8996 is not set +CONFIG_MTD_CMDLINE_PARTS=y +CONFIG_MTD_NAND_CORE=y +CONFIG_MTD_NAND_ECC_SW_HAMMING=y +CONFIG_MTD_NAND_QCOM=y +CONFIG_MTD_QCOM_SMEM_PARTS=y +CONFIG_MTD_RAW_NAND=y +CONFIG_MTD_SPI_NOR=y +CONFIG_MTD_SPLIT_FIRMWARE=y +CONFIG_MTD_SPLIT_FIT_FW=y +CONFIG_MTD_SPLIT_UIMAGE_FW=y +CONFIG_MTD_UBI=y +CONFIG_MTD_UBI_BEB_LIMIT=20 +CONFIG_MTD_UBI_BLOCK=y +CONFIG_MTD_UBI_WL_THRESHOLD=4096 +CONFIG_MUTEX_SPIN_ON_OWNER=y +CONFIG_NEED_DMA_MAP_STATE=y +CONFIG_NEON=y +CONFIG_NET_DEVLINK=y +CONFIG_NET_DSA=y +CONFIG_NET_DSA_QCA8K=y +CONFIG_NET_DSA_TAG_QCA=y +CONFIG_NET_FLOW_LIMIT=y +CONFIG_NET_PTP_CLASSIFY=y +CONFIG_NET_SWITCHDEV=y +CONFIG_NLS=y +CONFIG_NO_HZ=y +CONFIG_NO_HZ_COMMON=y +CONFIG_NO_HZ_IDLE=y +CONFIG_NR_CPUS=2 +CONFIG_NVMEM=y +CONFIG_OF=y +CONFIG_OF_ADDRESS=y +CONFIG_OF_EARLY_FLATTREE=y +CONFIG_OF_FLATTREE=y +CONFIG_OF_GPIO=y +CONFIG_OF_IRQ=y +CONFIG_OF_KOBJ=y +CONFIG_OF_MDIO=y +CONFIG_OF_NET=y +CONFIG_OLD_SIGACTION=y +CONFIG_OLD_SIGSUSPEND3=y +CONFIG_PADATA=y +CONFIG_PAGE_OFFSET=0xC0000000 +CONFIG_PAGE_POOL=y +CONFIG_PCI=y +CONFIG_PCIEAER=y +CONFIG_PCIEPORTBUS=y +CONFIG_PCIE_DW=y +CONFIG_PCIE_DW_HOST=y +CONFIG_PCIE_QCOM=y +CONFIG_PCI_DEBUG=y +CONFIG_PCI_DISABLE_COMMON_QUIRKS=y +CONFIG_PCI_DOMAINS=y +CONFIG_PCI_DOMAINS_GENERIC=y +CONFIG_PCI_MSI=y +CONFIG_PCI_MSI_IRQ_DOMAIN=y +CONFIG_PERF_USE_VMALLOC=y +CONFIG_PGTABLE_LEVELS=2 +CONFIG_PHYLIB=y +CONFIG_PHYLINK=y +# CONFIG_PHY_QCOM_APQ8064_SATA is not set +CONFIG_PHY_QCOM_IPQ806X_SATA=y +# CONFIG_PHY_QCOM_PCIE2 is not set +# CONFIG_PHY_QCOM_QMP is not set +# CONFIG_PHY_QCOM_QUSB2 is not set +# CONFIG_PHY_QCOM_UFS is not set +CONFIG_PINCTRL=y +# CONFIG_PINCTRL_APQ8064 is not set +# CONFIG_PINCTRL_APQ8084 is not set +# CONFIG_PINCTRL_IPQ4019 is not set +CONFIG_PINCTRL_IPQ8064=y +# CONFIG_PINCTRL_IPQ8074 is not set +# CONFIG_PINCTRL_MDM9615 is not set +CONFIG_PINCTRL_MSM=y +# CONFIG_PINCTRL_MSM8660 is not set +# CONFIG_PINCTRL_MSM8916 is not set +# CONFIG_PINCTRL_MSM8960 is not set +# CONFIG_PINCTRL_MSM8994 is not set +# CONFIG_PINCTRL_MSM8996 is not set +# CONFIG_PINCTRL_MSM8998 is not set +# CONFIG_PINCTRL_QCOM_SPMI_PMIC is not set +# CONFIG_PINCTRL_QCOM_SSBI_PMIC is not set +# CONFIG_PINCTRL_QCS404 is not set +# CONFIG_PINCTRL_SC7180 is not set +# CONFIG_PINCTRL_SDM660 is not set +# CONFIG_PINCTRL_SDM845 is not set +# CONFIG_PINCTRL_SM8150 is not set +CONFIG_PM_OPP=y +CONFIG_POWER_RESET=y +CONFIG_POWER_RESET_MSM=y +CONFIG_POWER_SUPPLY=y +CONFIG_PPS=y +CONFIG_PRINTK_TIME=y +CONFIG_PTP_1588_CLOCK=y +# CONFIG_QCOM_A53PLL is not set +CONFIG_QCOM_ADM=y +CONFIG_QCOM_BAM_DMA=y +CONFIG_QCOM_CLK_RPM=y +# CONFIG_QCOM_COMMAND_DB is not set +# CONFIG_QCOM_EBI2 is not set +# CONFIG_QCOM_GENI_SE is not set +CONFIG_QCOM_GSBI=y +CONFIG_QCOM_HFPLL=y +# CONFIG_QCOM_IOMMU is not set +# CONFIG_QCOM_LLCC is not set +# CONFIG_QCOM_PDC is not set +CONFIG_QCOM_PM=y +CONFIG_QCOM_QFPROM=y +# CONFIG_QCOM_RMTFS_MEM is not set +CONFIG_QCOM_RPMCC=y +CONFIG_QCOM_SCM=y +CONFIG_QCOM_SCM_32=y +# CONFIG_QCOM_SCM_DOWNLOAD_MODE_DEFAULT is not set +CONFIG_QCOM_SMEM=y +# CONFIG_QCOM_SMSM is not set +# CONFIG_QCOM_SOCINFO is not set +CONFIG_QCOM_TCSR=y +CONFIG_QCOM_TSENS=y +CONFIG_QCOM_WDT=y +# CONFIG_QCS_GCC_404 is not set +# CONFIG_QCS_TURING_404 is not set +# CONFIG_QRTR is not set +CONFIG_RAS=y +CONFIG_RATIONAL=y +CONFIG_RCU_CPU_STALL_TIMEOUT=21 +CONFIG_RCU_NEED_SEGCBLIST=y +CONFIG_RCU_STALL_COMMON=y +CONFIG_REFCOUNT_FULL=y +CONFIG_REGMAP=y +CONFIG_REGMAP_MMIO=y +CONFIG_REGULATOR=y +CONFIG_REGULATOR_FIXED_VOLTAGE=y +CONFIG_REGULATOR_QCOM_RPM=y +# CONFIG_REGULATOR_QCOM_SPMI is not set +CONFIG_RESET_CONTROLLER=y +# CONFIG_RESET_QCOM_AOSS is not set +# CONFIG_RESET_QCOM_PDC is not set +CONFIG_RFS_ACCEL=y +CONFIG_RPS=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_I2C_AND_SPI=y +CONFIG_RTC_MC146818_LIB=y +CONFIG_RWSEM_SPIN_ON_OWNER=y +# CONFIG_SDM_CAMCC_845 is not set +# CONFIG_SDM_DISPCC_845 is not set +# CONFIG_SDM_GCC_660 is not set +# CONFIG_SDM_GCC_845 is not set +# CONFIG_SDM_GPUCC_845 is not set +# CONFIG_SDM_LPASSCC_845 is not set +# CONFIG_SDM_VIDEOCC_845 is not set +CONFIG_SERIAL_8250_FSL=y +CONFIG_SERIAL_MCTRL_GPIO=y +CONFIG_SERIAL_MSM=y +CONFIG_SERIAL_MSM_CONSOLE=y +CONFIG_SGL_ALLOC=y +CONFIG_SMP=y +CONFIG_SMP_ON_UP=y +# CONFIG_SM_GCC_8150 is not set +CONFIG_SPARSE_IRQ=y +CONFIG_SPI=y +CONFIG_SPI_MASTER=y +CONFIG_SPI_MEM=y +CONFIG_SPI_QUP=y +CONFIG_SPMI=y +CONFIG_SPMI_MSM_PMIC_ARB=y +# CONFIG_SPMI_PMIC_CLKDIV is not set +CONFIG_SRCU=y +CONFIG_STMMAC_ETH=y +CONFIG_STMMAC_PLATFORM=y +# CONFIG_STMMAC_SELFTESTS is not set +CONFIG_SWCONFIG=y +CONFIG_SWCONFIG_LEDS=y +CONFIG_SWPHY=y +CONFIG_SWP_EMULATE=y +CONFIG_SYS_SUPPORTS_APM_EMULATION=y +CONFIG_THERMAL=y +CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y +CONFIG_THERMAL_EMERGENCY_POWEROFF_DELAY_MS=0 +CONFIG_THERMAL_GOV_STEP_WISE=y +CONFIG_THERMAL_HWMON=y +CONFIG_THERMAL_OF=y +CONFIG_TICK_CPU_ACCOUNTING=y +CONFIG_TIMER_OF=y +CONFIG_TIMER_PROBE=y +CONFIG_TREE_RCU=y +CONFIG_TREE_SRCU=y +CONFIG_UBIFS_FS=y +CONFIG_UBIFS_FS_ADVANCED_COMPR=y +CONFIG_UBIFS_FS_LZO=y +CONFIG_UBIFS_FS_ZLIB=y +CONFIG_UBIFS_FS_ZSTD=y +# CONFIG_UCLAMP_TASK is not set +CONFIG_UEVENT_HELPER_PATH="" +CONFIG_UNCOMPRESS_INCLUDE="debug/uncompress.h" +CONFIG_UNWINDER_ARM=y +CONFIG_USB=y +CONFIG_USB_COMMON=y +CONFIG_USB_SUPPORT=y +CONFIG_USE_OF=y +CONFIG_VFP=y +CONFIG_VFPv3=y +CONFIG_WATCHDOG_CORE=y +CONFIG_XPS=y +CONFIG_XXHASH=y +CONFIG_XZ_DEC_ARM=y +CONFIG_XZ_DEC_BCJ=y +CONFIG_ZBOOT_ROM_BSS=0 +CONFIG_ZBOOT_ROM_TEXT=0 +CONFIG_ZLIB_DEFLATE=y +CONFIG_ZLIB_INFLATE=y +CONFIG_ZSTD_COMPRESS=y +CONFIG_ZSTD_DECOMPRESS=y diff --git a/target/linux/ipq806x/patches-5.10/0001-dtbindings-qcom_adm-Fix-channel-specifiers.patch b/target/linux/ipq806x/patches-5.10/0001-dtbindings-qcom_adm-Fix-channel-specifiers.patch new file mode 100644 index 0000000000..83d7bbc6f4 --- /dev/null +++ b/target/linux/ipq806x/patches-5.10/0001-dtbindings-qcom_adm-Fix-channel-specifiers.patch @@ -0,0 +1,71 @@ +From 28d0ed88f536dd639adf1b0c7c08e04be3c8f294 Mon Sep 17 00:00:00 2001 +From: Thomas Pedersen +Date: Mon, 16 May 2016 17:58:50 -0700 +Subject: [PATCH 01/69] dtbindings: qcom_adm: Fix channel specifiers + +Original patch from Andy Gross. + +This patch removes the crci information from the dma +channel property. At least one client device requires +using more than one CRCI value for a channel. This does +not match the current binding and the crci information +needs to be removed. + +Instead, the client device will provide this information +via other means. + +Signed-off-by: Andy Gross +Signed-off-by: Thomas Pedersen +--- + Documentation/devicetree/bindings/dma/qcom_adm.txt | 16 ++++++---------- + 1 file changed, 6 insertions(+), 10 deletions(-) + +--- a/Documentation/devicetree/bindings/dma/qcom_adm.txt ++++ b/Documentation/devicetree/bindings/dma/qcom_adm.txt +@@ -4,8 +4,7 @@ Required properties: + - compatible: must contain "qcom,adm" for IPQ/APQ8064 and MSM8960 + - reg: Address range for DMA registers + - interrupts: Should contain one interrupt shared by all channels +-- #dma-cells: must be <2>. First cell denotes the channel number. Second cell +- denotes CRCI (client rate control interface) flow control assignment. ++- #dma-cells: must be <1>. First cell denotes the channel number. + - clocks: Should contain the core clock and interface clock. + - clock-names: Must contain "core" for the core clock and "iface" for the + interface clock. +@@ -22,7 +21,7 @@ Example: + compatible = "qcom,adm"; + reg = <0x18300000 0x100000>; + interrupts = <0 170 0>; +- #dma-cells = <2>; ++ #dma-cells = <1>; + + clocks = <&gcc ADM0_CLK>, <&gcc ADM0_PBUS_CLK>; + clock-names = "core", "iface"; +@@ -35,15 +34,12 @@ Example: + qcom,ee = <0>; + }; + +-DMA clients must use the format descripted in the dma.txt file, using a three ++DMA clients must use the format descripted in the dma.txt file, using a two + cell specifier for each channel. + +-Each dmas request consists of 3 cells: ++Each dmas request consists of two cells: + 1. phandle pointing to the DMA controller + 2. channel number +- 3. CRCI assignment, if applicable. If no CRCI flow control is required, use 0. +- The CRCI is used for flow control. It identifies the peripheral device that +- is the source/destination for the transferred data. + + Example: + +@@ -55,7 +51,7 @@ Example: + + cs-gpios = <&qcom_pinmux 20 0>; + +- dmas = <&adm_dma 6 9>, +- <&adm_dma 5 10>; ++ dmas = <&adm_dma 6>, ++ <&adm_dma 5>; + dma-names = "rx", "tx"; + }; diff --git a/target/linux/ipq806x/patches-5.10/0002-dmaengine-Add-ADM-driver.patch b/target/linux/ipq806x/patches-5.10/0002-dmaengine-Add-ADM-driver.patch new file mode 100644 index 0000000000..aa7d2e791e --- /dev/null +++ b/target/linux/ipq806x/patches-5.10/0002-dmaengine-Add-ADM-driver.patch @@ -0,0 +1,966 @@ +From 563fa24db4e529c5a3311928d73a8a90531ee527 Mon Sep 17 00:00:00 2001 +From: Thomas Pedersen +Date: Mon, 16 May 2016 17:58:51 -0700 +Subject: [PATCH 02/69] dmaengine: Add ADM driver + +Original patch by Andy Gross. + +Add the DMA engine driver for the QCOM Application Data Mover (ADM) DMA +controller found in the MSM8x60 and IPQ/APQ8064 platforms. + +The ADM supports both memory to memory transactions and memory +to/from peripheral device transactions. The controller also provides flow +control capabilities for transactions to/from peripheral devices. + +The initial release of this driver supports slave transfers to/from peripherals +and also incorporates CRCI (client rate control interface) flow control. + +Signed-off-by: Andy Gross +Signed-off-by: Thomas Pedersen +--- + drivers/dma/qcom/Kconfig | 10 + + drivers/dma/qcom/Makefile | 1 + + drivers/dma/qcom/qcom_adm.c | 900 ++++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 911 insertions(+) + create mode 100644 drivers/dma/qcom/qcom_adm.c + +--- a/drivers/dma/qcom/Kconfig ++++ b/drivers/dma/qcom/Kconfig +@@ -28,3 +28,13 @@ config QCOM_HIDMA + (user to kernel, kernel to kernel, etc.). It only supports + memcpy interface. The core is not intended for general + purpose slave DMA. ++ ++config QCOM_ADM ++ tristate "Qualcomm ADM support" ++ depends on ARCH_QCOM || (COMPILE_TEST && OF && ARM) ++ select DMA_ENGINE ++ select DMA_VIRTUAL_CHANNELS ++ ---help--- ++ Enable support for the Qualcomm ADM DMA controller. This controller ++ provides DMA capabilities for both general purpose and on-chip ++ peripheral devices. +--- a/drivers/dma/qcom/Makefile ++++ b/drivers/dma/qcom/Makefile +@@ -4,3 +4,4 @@ obj-$(CONFIG_QCOM_HIDMA_MGMT) += hdma_mg + hdma_mgmt-objs := hidma_mgmt.o hidma_mgmt_sys.o + obj-$(CONFIG_QCOM_HIDMA) += hdma.o + hdma-objs := hidma_ll.o hidma.o hidma_dbg.o ++obj-$(CONFIG_QCOM_ADM) += qcom_adm.o +--- /dev/null ++++ b/drivers/dma/qcom/qcom_adm.c +@@ -0,0 +1,914 @@ ++/* ++ * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 and ++ * only version 2 as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "../dmaengine.h" ++#include "../virt-dma.h" ++ ++/* ADM registers - calculated from channel number and security domain */ ++#define ADM_CHAN_MULTI 0x4 ++#define ADM_CI_MULTI 0x4 ++#define ADM_CRCI_MULTI 0x4 ++#define ADM_EE_MULTI 0x800 ++#define ADM_CHAN_OFFS(chan) (ADM_CHAN_MULTI * chan) ++#define ADM_EE_OFFS(ee) (ADM_EE_MULTI * ee) ++#define ADM_CHAN_EE_OFFS(chan, ee) (ADM_CHAN_OFFS(chan) + ADM_EE_OFFS(ee)) ++#define ADM_CHAN_OFFS(chan) (ADM_CHAN_MULTI * chan) ++#define ADM_CI_OFFS(ci) (ADM_CHAN_OFF(ci)) ++#define ADM_CH_CMD_PTR(chan, ee) (ADM_CHAN_EE_OFFS(chan, ee)) ++#define ADM_CH_RSLT(chan, ee) (0x40 + ADM_CHAN_EE_OFFS(chan, ee)) ++#define ADM_CH_FLUSH_STATE0(chan, ee) (0x80 + ADM_CHAN_EE_OFFS(chan, ee)) ++#define ADM_CH_STATUS_SD(chan, ee) (0x200 + ADM_CHAN_EE_OFFS(chan, ee)) ++#define ADM_CH_CONF(chan) (0x240 + ADM_CHAN_OFFS(chan)) ++#define ADM_CH_RSLT_CONF(chan, ee) (0x300 + ADM_CHAN_EE_OFFS(chan, ee)) ++#define ADM_SEC_DOMAIN_IRQ_STATUS(ee) (0x380 + ADM_EE_OFFS(ee)) ++#define ADM_CI_CONF(ci) (0x390 + ci * ADM_CI_MULTI) ++#define ADM_GP_CTL 0x3d8 ++#define ADM_CRCI_CTL(crci, ee) (0x400 + crci * ADM_CRCI_MULTI + \ ++ ADM_EE_OFFS(ee)) ++ ++/* channel status */ ++#define ADM_CH_STATUS_VALID BIT(1) ++ ++/* channel result */ ++#define ADM_CH_RSLT_VALID BIT(31) ++#define ADM_CH_RSLT_ERR BIT(3) ++#define ADM_CH_RSLT_FLUSH BIT(2) ++#define ADM_CH_RSLT_TPD BIT(1) ++ ++/* channel conf */ ++#define ADM_CH_CONF_SHADOW_EN BIT(12) ++#define ADM_CH_CONF_MPU_DISABLE BIT(11) ++#define ADM_CH_CONF_PERM_MPU_CONF BIT(9) ++#define ADM_CH_CONF_FORCE_RSLT_EN BIT(7) ++#define ADM_CH_CONF_SEC_DOMAIN(ee) (((ee & 0x3) << 4) | ((ee & 0x4) << 11)) ++ ++/* channel result conf */ ++#define ADM_CH_RSLT_CONF_FLUSH_EN BIT(1) ++#define ADM_CH_RSLT_CONF_IRQ_EN BIT(0) ++ ++/* CRCI CTL */ ++#define ADM_CRCI_CTL_MUX_SEL BIT(18) ++#define ADM_CRCI_CTL_RST BIT(17) ++ ++/* CI configuration */ ++#define ADM_CI_RANGE_END(x) (x << 24) ++#define ADM_CI_RANGE_START(x) (x << 16) ++#define ADM_CI_BURST_4_WORDS BIT(2) ++#define ADM_CI_BURST_8_WORDS BIT(3) ++ ++/* GP CTL */ ++#define ADM_GP_CTL_LP_EN BIT(12) ++#define ADM_GP_CTL_LP_CNT(x) (x << 8) ++ ++/* Command pointer list entry */ ++#define ADM_CPLE_LP BIT(31) ++#define ADM_CPLE_CMD_PTR_LIST BIT(29) ++ ++/* Command list entry */ ++#define ADM_CMD_LC BIT(31) ++#define ADM_CMD_DST_CRCI(n) (((n) & 0xf) << 7) ++#define ADM_CMD_SRC_CRCI(n) (((n) & 0xf) << 3) ++ ++#define ADM_CMD_TYPE_SINGLE 0x0 ++#define ADM_CMD_TYPE_BOX 0x3 ++ ++#define ADM_CRCI_MUX_SEL BIT(4) ++#define ADM_DESC_ALIGN 8 ++#define ADM_MAX_XFER (SZ_64K-1) ++#define ADM_MAX_ROWS (SZ_64K-1) ++#define ADM_MAX_CHANNELS 16 ++ ++struct adm_desc_hw_box { ++ u32 cmd; ++ u32 src_addr; ++ u32 dst_addr; ++ u32 row_len; ++ u32 num_rows; ++ u32 row_offset; ++}; ++ ++struct adm_desc_hw_single { ++ u32 cmd; ++ u32 src_addr; ++ u32 dst_addr; ++ u32 len; ++}; ++ ++struct adm_async_desc { ++ struct virt_dma_desc vd; ++ struct adm_device *adev; ++ ++ size_t length; ++ enum dma_transfer_direction dir; ++ dma_addr_t dma_addr; ++ size_t dma_len; ++ ++ void *cpl; ++ dma_addr_t cp_addr; ++ u32 crci; ++ u32 mux; ++ u32 blk_size; ++}; ++ ++struct adm_chan { ++ struct virt_dma_chan vc; ++ struct adm_device *adev; ++ ++ /* parsed from DT */ ++ u32 id; /* channel id */ ++ ++ struct adm_async_desc *curr_txd; ++ struct dma_slave_config slave; ++ struct list_head node; ++ ++ int error; ++ int initialized; ++}; ++ ++static inline struct adm_chan *to_adm_chan(struct dma_chan *common) ++{ ++ return container_of(common, struct adm_chan, vc.chan); ++} ++ ++struct adm_device { ++ void __iomem *regs; ++ struct device *dev; ++ struct dma_device common; ++ struct device_dma_parameters dma_parms; ++ struct adm_chan *channels; ++ ++ u32 ee; ++ ++ struct clk *core_clk; ++ struct clk *iface_clk; ++ ++ struct reset_control *clk_reset; ++ struct reset_control *c0_reset; ++ struct reset_control *c1_reset; ++ struct reset_control *c2_reset; ++ int irq; ++}; ++ ++/** ++ * adm_free_chan - Frees dma resources associated with the specific channel ++ * ++ * Free all allocated descriptors associated with this channel ++ * ++ */ ++static void adm_free_chan(struct dma_chan *chan) ++{ ++ /* free all queued descriptors */ ++ vchan_free_chan_resources(to_virt_chan(chan)); ++} ++ ++/** ++ * adm_get_blksize - Get block size from burst value ++ * ++ */ ++static int adm_get_blksize(unsigned int burst) ++{ ++ int ret; ++ ++ switch (burst) { ++ case 16: ++ case 32: ++ case 64: ++ case 128: ++ ret = ffs(burst>>4) - 1; ++ break; ++ case 192: ++ ret = 4; ++ break; ++ case 256: ++ ret = 5; ++ break; ++ default: ++ ret = -EINVAL; ++ break; ++ } ++ ++ return ret; ++} ++ ++/** ++ * adm_process_fc_descriptors - Process descriptors for flow controlled xfers ++ * ++ * @achan: ADM channel ++ * @desc: Descriptor memory pointer ++ * @sg: Scatterlist entry ++ * @crci: CRCI value ++ * @burst: Burst size of transaction ++ * @direction: DMA transfer direction ++ */ ++static void *adm_process_fc_descriptors(struct adm_chan *achan, ++ void *desc, struct scatterlist *sg, u32 crci, u32 burst, ++ enum dma_transfer_direction direction) ++{ ++ struct adm_desc_hw_box *box_desc = NULL; ++ struct adm_desc_hw_single *single_desc; ++ u32 remainder = sg_dma_len(sg); ++ u32 rows, row_offset, crci_cmd; ++ u32 mem_addr = sg_dma_address(sg); ++ u32 *incr_addr = &mem_addr; ++ u32 *src, *dst; ++ ++ if (direction == DMA_DEV_TO_MEM) { ++ crci_cmd = ADM_CMD_SRC_CRCI(crci); ++ row_offset = burst; ++ src = &achan->slave.src_addr; ++ dst = &mem_addr; ++ } else { ++ crci_cmd = ADM_CMD_DST_CRCI(crci); ++ row_offset = burst << 16; ++ src = &mem_addr; ++ dst = &achan->slave.dst_addr; ++ } ++ ++ while (remainder >= burst) { ++ box_desc = desc; ++ box_desc->cmd = ADM_CMD_TYPE_BOX | crci_cmd; ++ box_desc->row_offset = row_offset; ++ box_desc->src_addr = *src; ++ box_desc->dst_addr = *dst; ++ ++ rows = remainder / burst; ++ rows = min_t(u32, rows, ADM_MAX_ROWS); ++ box_desc->num_rows = rows << 16 | rows; ++ box_desc->row_len = burst << 16 | burst; ++ ++ *incr_addr += burst * rows; ++ remainder -= burst * rows; ++ desc += sizeof(*box_desc); ++ } ++ ++ /* if leftover bytes, do one single descriptor */ ++ if (remainder) { ++ single_desc = desc; ++ single_desc->cmd = ADM_CMD_TYPE_SINGLE | crci_cmd; ++ single_desc->len = remainder; ++ single_desc->src_addr = *src; ++ single_desc->dst_addr = *dst; ++ desc += sizeof(*single_desc); ++ ++ if (sg_is_last(sg)) ++ single_desc->cmd |= ADM_CMD_LC; ++ } else { ++ if (box_desc && sg_is_last(sg)) ++ box_desc->cmd |= ADM_CMD_LC; ++ } ++ ++ return desc; ++} ++ ++/** ++ * adm_process_non_fc_descriptors - Process descriptors for non-fc xfers ++ * ++ * @achan: ADM channel ++ * @desc: Descriptor memory pointer ++ * @sg: Scatterlist entry ++ * @direction: DMA transfer direction ++ */ ++static void *adm_process_non_fc_descriptors(struct adm_chan *achan, ++ void *desc, struct scatterlist *sg, ++ enum dma_transfer_direction direction) ++{ ++ struct adm_desc_hw_single *single_desc; ++ u32 remainder = sg_dma_len(sg); ++ u32 mem_addr = sg_dma_address(sg); ++ u32 *incr_addr = &mem_addr; ++ u32 *src, *dst; ++ ++ if (direction == DMA_DEV_TO_MEM) { ++ src = &achan->slave.src_addr; ++ dst = &mem_addr; ++ } else { ++ src = &mem_addr; ++ dst = &achan->slave.dst_addr; ++ } ++ ++ do { ++ single_desc = desc; ++ single_desc->cmd = ADM_CMD_TYPE_SINGLE; ++ single_desc->src_addr = *src; ++ single_desc->dst_addr = *dst; ++ single_desc->len = (remainder > ADM_MAX_XFER) ? ++ ADM_MAX_XFER : remainder; ++ ++ remainder -= single_desc->len; ++ *incr_addr += single_desc->len; ++ desc += sizeof(*single_desc); ++ } while (remainder); ++ ++ /* set last command if this is the end of the whole transaction */ ++ if (sg_is_last(sg)) ++ single_desc->cmd |= ADM_CMD_LC; ++ ++ return desc; ++} ++ ++/** ++ * adm_prep_slave_sg - Prep slave sg transaction ++ * ++ * @chan: dma channel ++ * @sgl: scatter gather list ++ * @sg_len: length of sg ++ * @direction: DMA transfer direction ++ * @flags: DMA flags ++ * @context: transfer context (unused) ++ */ ++static struct dma_async_tx_descriptor *adm_prep_slave_sg(struct dma_chan *chan, ++ struct scatterlist *sgl, unsigned int sg_len, ++ enum dma_transfer_direction direction, unsigned long flags, ++ void *context) ++{ ++ struct adm_chan *achan = to_adm_chan(chan); ++ struct adm_device *adev = achan->adev; ++ struct adm_async_desc *async_desc; ++ struct scatterlist *sg; ++ dma_addr_t cple_addr; ++ u32 i, burst; ++ u32 single_count = 0, box_count = 0, crci = 0; ++ void *desc; ++ u32 *cple; ++ int blk_size = 0; ++ ++ if (!is_slave_direction(direction)) { ++ dev_err(adev->dev, "invalid dma direction\n"); ++ return NULL; ++ } ++ ++ /* ++ * get burst value from slave configuration ++ */ ++ burst = (direction == DMA_MEM_TO_DEV) ? ++ achan->slave.dst_maxburst : ++ achan->slave.src_maxburst; ++ ++ /* if using flow control, validate burst and crci values */ ++ if (achan->slave.device_fc) { ++ ++ blk_size = adm_get_blksize(burst); ++ if (blk_size < 0) { ++ dev_err(adev->dev, "invalid burst value: %d\n", ++ burst); ++ return ERR_PTR(-EINVAL); ++ } ++ ++ crci = achan->slave.slave_id & 0xf; ++ if (!crci || achan->slave.slave_id > 0x1f) { ++ dev_err(adev->dev, "invalid crci value\n"); ++ return ERR_PTR(-EINVAL); ++ } ++ } ++ ++ /* iterate through sgs and compute allocation size of structures */ ++ for_each_sg(sgl, sg, sg_len, i) { ++ if (achan->slave.device_fc) { ++ box_count += DIV_ROUND_UP(sg_dma_len(sg) / burst, ++ ADM_MAX_ROWS); ++ if (sg_dma_len(sg) % burst) ++ single_count++; ++ } else { ++ single_count += DIV_ROUND_UP(sg_dma_len(sg), ++ ADM_MAX_XFER); ++ } ++ } ++ ++ async_desc = kzalloc(sizeof(*async_desc), GFP_ATOMIC); ++ if (!async_desc) ++ return ERR_PTR(-ENOMEM); ++ ++ if (crci) ++ async_desc->mux = achan->slave.slave_id & ADM_CRCI_MUX_SEL ? ++ ADM_CRCI_CTL_MUX_SEL : 0; ++ async_desc->crci = crci; ++ async_desc->blk_size = blk_size; ++ async_desc->dma_len = single_count * sizeof(struct adm_desc_hw_single) + ++ box_count * sizeof(struct adm_desc_hw_box) + ++ sizeof(*cple) + 2 * ADM_DESC_ALIGN; ++ ++ async_desc->cpl = kzalloc(async_desc->dma_len, GFP_ATOMIC); ++ if (!async_desc->cpl) ++ goto free; ++ ++ async_desc->adev = adev; ++ ++ /* both command list entry and descriptors must be 8 byte aligned */ ++ cple = PTR_ALIGN(async_desc->cpl, ADM_DESC_ALIGN); ++ desc = PTR_ALIGN(cple + 1, ADM_DESC_ALIGN); ++ ++ for_each_sg(sgl, sg, sg_len, i) { ++ async_desc->length += sg_dma_len(sg); ++ ++ if (achan->slave.device_fc) ++ desc = adm_process_fc_descriptors(achan, desc, sg, crci, ++ burst, direction); ++ else ++ desc = adm_process_non_fc_descriptors(achan, desc, sg, ++ direction); ++ } ++ ++ async_desc->dma_addr = dma_map_single(adev->dev, async_desc->cpl, ++ async_desc->dma_len, ++ DMA_TO_DEVICE); ++ if (dma_mapping_error(adev->dev, async_desc->dma_addr)) ++ goto free; ++ ++ cple_addr = async_desc->dma_addr + ((void *)cple - async_desc->cpl); ++ ++ /* init cmd list */ ++ dma_sync_single_for_cpu(adev->dev, cple_addr, sizeof(*cple), ++ DMA_TO_DEVICE); ++ *cple = ADM_CPLE_LP; ++ *cple |= (async_desc->dma_addr + ADM_DESC_ALIGN) >> 3; ++ dma_sync_single_for_device(adev->dev, cple_addr, sizeof(*cple), ++ DMA_TO_DEVICE); ++ ++ return vchan_tx_prep(&achan->vc, &async_desc->vd, flags); ++ ++free: ++ kfree(async_desc); ++ return ERR_PTR(-ENOMEM); ++} ++ ++/** ++ * adm_terminate_all - terminate all transactions on a channel ++ * @achan: adm dma channel ++ * ++ * Dequeues and frees all transactions, aborts current transaction ++ * No callbacks are done ++ * ++ */ ++static int adm_terminate_all(struct dma_chan *chan) ++{ ++ struct adm_chan *achan = to_adm_chan(chan); ++ struct adm_device *adev = achan->adev; ++ unsigned long flags; ++ LIST_HEAD(head); ++ ++ spin_lock_irqsave(&achan->vc.lock, flags); ++ vchan_get_all_descriptors(&achan->vc, &head); ++ ++ /* send flush command to terminate current transaction */ ++ writel_relaxed(0x0, ++ adev->regs + ADM_CH_FLUSH_STATE0(achan->id, adev->ee)); ++ ++ spin_unlock_irqrestore(&achan->vc.lock, flags); ++ ++ vchan_dma_desc_free_list(&achan->vc, &head); ++ ++ return 0; ++} ++ ++static int adm_slave_config(struct dma_chan *chan, struct dma_slave_config *cfg) ++{ ++ struct adm_chan *achan = to_adm_chan(chan); ++ unsigned long flag; ++ ++ spin_lock_irqsave(&achan->vc.lock, flag); ++ memcpy(&achan->slave, cfg, sizeof(struct dma_slave_config)); ++ spin_unlock_irqrestore(&achan->vc.lock, flag); ++ ++ return 0; ++} ++ ++/** ++ * adm_start_dma - start next transaction ++ * @achan - ADM dma channel ++ */ ++static void adm_start_dma(struct adm_chan *achan) ++{ ++ struct virt_dma_desc *vd = vchan_next_desc(&achan->vc); ++ struct adm_device *adev = achan->adev; ++ struct adm_async_desc *async_desc; ++ ++ lockdep_assert_held(&achan->vc.lock); ++ ++ if (!vd) ++ return; ++ ++ list_del(&vd->node); ++ ++ /* write next command list out to the CMD FIFO */ ++ async_desc = container_of(vd, struct adm_async_desc, vd); ++ achan->curr_txd = async_desc; ++ ++ /* reset channel error */ ++ achan->error = 0; ++ ++ if (!achan->initialized) { ++ /* enable interrupts */ ++ writel(ADM_CH_CONF_SHADOW_EN | ++ ADM_CH_CONF_PERM_MPU_CONF | ++ ADM_CH_CONF_MPU_DISABLE | ++ ADM_CH_CONF_SEC_DOMAIN(adev->ee), ++ adev->regs + ADM_CH_CONF(achan->id)); ++ ++ writel(ADM_CH_RSLT_CONF_IRQ_EN | ADM_CH_RSLT_CONF_FLUSH_EN, ++ adev->regs + ADM_CH_RSLT_CONF(achan->id, adev->ee)); ++ ++ achan->initialized = 1; ++ } ++ ++ /* set the crci block size if this transaction requires CRCI */ ++ if (async_desc->crci) { ++ writel(async_desc->mux | async_desc->blk_size, ++ adev->regs + ADM_CRCI_CTL(async_desc->crci, adev->ee)); ++ } ++ ++ /* make sure IRQ enable doesn't get reordered */ ++ wmb(); ++ ++ /* write next command list out to the CMD FIFO */ ++ writel(ALIGN(async_desc->dma_addr, ADM_DESC_ALIGN) >> 3, ++ adev->regs + ADM_CH_CMD_PTR(achan->id, adev->ee)); ++} ++ ++/** ++ * adm_dma_irq - irq handler for ADM controller ++ * @irq: IRQ of interrupt ++ * @data: callback data ++ * ++ * IRQ handler for the bam controller ++ */ ++static irqreturn_t adm_dma_irq(int irq, void *data) ++{ ++ struct adm_device *adev = data; ++ u32 srcs, i; ++ struct adm_async_desc *async_desc; ++ unsigned long flags; ++ ++ srcs = readl_relaxed(adev->regs + ++ ADM_SEC_DOMAIN_IRQ_STATUS(adev->ee)); ++ ++ for (i = 0; i < ADM_MAX_CHANNELS; i++) { ++ struct adm_chan *achan = &adev->channels[i]; ++ u32 status, result; ++ ++ if (srcs & BIT(i)) { ++ status = readl_relaxed(adev->regs + ++ ADM_CH_STATUS_SD(i, adev->ee)); ++ ++ /* if no result present, skip */ ++ if (!(status & ADM_CH_STATUS_VALID)) ++ continue; ++ ++ result = readl_relaxed(adev->regs + ++ ADM_CH_RSLT(i, adev->ee)); ++ ++ /* no valid results, skip */ ++ if (!(result & ADM_CH_RSLT_VALID)) ++ continue; ++ ++ /* flag error if transaction was flushed or failed */ ++ if (result & (ADM_CH_RSLT_ERR | ADM_CH_RSLT_FLUSH)) ++ achan->error = 1; ++ ++ spin_lock_irqsave(&achan->vc.lock, flags); ++ async_desc = achan->curr_txd; ++ ++ achan->curr_txd = NULL; ++ ++ if (async_desc) { ++ vchan_cookie_complete(&async_desc->vd); ++ ++ /* kick off next DMA */ ++ adm_start_dma(achan); ++ } ++ ++ spin_unlock_irqrestore(&achan->vc.lock, flags); ++ } ++ } ++ ++ return IRQ_HANDLED; ++} ++ ++/** ++ * adm_tx_status - returns status of transaction ++ * @chan: dma channel ++ * @cookie: transaction cookie ++ * @txstate: DMA transaction state ++ * ++ * Return status of dma transaction ++ */ ++static enum dma_status adm_tx_status(struct dma_chan *chan, dma_cookie_t cookie, ++ struct dma_tx_state *txstate) ++{ ++ struct adm_chan *achan = to_adm_chan(chan); ++ struct virt_dma_desc *vd; ++ enum dma_status ret; ++ unsigned long flags; ++ size_t residue = 0; ++ ++ ret = dma_cookie_status(chan, cookie, txstate); ++ if (ret == DMA_COMPLETE || !txstate) ++ return ret; ++ ++ spin_lock_irqsave(&achan->vc.lock, flags); ++ ++ vd = vchan_find_desc(&achan->vc, cookie); ++ if (vd) ++ residue = container_of(vd, struct adm_async_desc, vd)->length; ++ ++ spin_unlock_irqrestore(&achan->vc.lock, flags); ++ ++ /* ++ * residue is either the full length if it is in the issued list, or 0 ++ * if it is in progress. We have no reliable way of determining ++ * anything inbetween ++ */ ++ dma_set_residue(txstate, residue); ++ ++ if (achan->error) ++ return DMA_ERROR; ++ ++ return ret; ++} ++ ++/** ++ * adm_issue_pending - starts pending transactions ++ * @chan: dma channel ++ * ++ * Issues all pending transactions and starts DMA ++ */ ++static void adm_issue_pending(struct dma_chan *chan) ++{ ++ struct adm_chan *achan = to_adm_chan(chan); ++ unsigned long flags; ++ ++ spin_lock_irqsave(&achan->vc.lock, flags); ++ ++ if (vchan_issue_pending(&achan->vc) && !achan->curr_txd) ++ adm_start_dma(achan); ++ spin_unlock_irqrestore(&achan->vc.lock, flags); ++} ++ ++/** ++ * adm_dma_free_desc - free descriptor memory ++ * @vd: virtual descriptor ++ * ++ */ ++static void adm_dma_free_desc(struct virt_dma_desc *vd) ++{ ++ struct adm_async_desc *async_desc = container_of(vd, ++ struct adm_async_desc, vd); ++ ++ dma_unmap_single(async_desc->adev->dev, async_desc->dma_addr, ++ async_desc->dma_len, DMA_TO_DEVICE); ++ kfree(async_desc->cpl); ++ kfree(async_desc); ++} ++ ++static void adm_channel_init(struct adm_device *adev, struct adm_chan *achan, ++ u32 index) ++{ ++ achan->id = index; ++ achan->adev = adev; ++ ++ vchan_init(&achan->vc, &adev->common); ++ achan->vc.desc_free = adm_dma_free_desc; ++} ++ ++static int adm_dma_probe(struct platform_device *pdev) ++{ ++ struct adm_device *adev; ++ struct resource *iores; ++ int ret; ++ u32 i; ++ ++ adev = devm_kzalloc(&pdev->dev, sizeof(*adev), GFP_KERNEL); ++ if (!adev) ++ return -ENOMEM; ++ ++ adev->dev = &pdev->dev; ++ ++ iores = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ adev->regs = devm_ioremap_resource(&pdev->dev, iores); ++ if (IS_ERR(adev->regs)) ++ return PTR_ERR(adev->regs); ++ ++ adev->irq = platform_get_irq(pdev, 0); ++ if (adev->irq < 0) ++ return adev->irq; ++ ++ ret = of_property_read_u32(pdev->dev.of_node, "qcom,ee", &adev->ee); ++ if (ret) { ++ dev_err(adev->dev, "Execution environment unspecified\n"); ++ return ret; ++ } ++ ++ adev->core_clk = devm_clk_get(adev->dev, "core"); ++ if (IS_ERR(adev->core_clk)) ++ return PTR_ERR(adev->core_clk); ++ ++ ret = clk_prepare_enable(adev->core_clk); ++ if (ret) { ++ dev_err(adev->dev, "failed to prepare/enable core clock\n"); ++ return ret; ++ } ++ ++ adev->iface_clk = devm_clk_get(adev->dev, "iface"); ++ if (IS_ERR(adev->iface_clk)) { ++ ret = PTR_ERR(adev->iface_clk); ++ goto err_disable_core_clk; ++ } ++ ++ ret = clk_prepare_enable(adev->iface_clk); ++ if (ret) { ++ dev_err(adev->dev, "failed to prepare/enable iface clock\n"); ++ goto err_disable_core_clk; ++ } ++ ++ adev->clk_reset = devm_reset_control_get(&pdev->dev, "clk"); ++ if (IS_ERR(adev->clk_reset)) { ++ dev_err(adev->dev, "failed to get ADM0 reset\n"); ++ ret = PTR_ERR(adev->clk_reset); ++ goto err_disable_clks; ++ } ++ ++ adev->c0_reset = devm_reset_control_get(&pdev->dev, "c0"); ++ if (IS_ERR(adev->c0_reset)) { ++ dev_err(adev->dev, "failed to get ADM0 C0 reset\n"); ++ ret = PTR_ERR(adev->c0_reset); ++ goto err_disable_clks; ++ } ++ ++ adev->c1_reset = devm_reset_control_get(&pdev->dev, "c1"); ++ if (IS_ERR(adev->c1_reset)) { ++ dev_err(adev->dev, "failed to get ADM0 C1 reset\n"); ++ ret = PTR_ERR(adev->c1_reset); ++ goto err_disable_clks; ++ } ++ ++ adev->c2_reset = devm_reset_control_get(&pdev->dev, "c2"); ++ if (IS_ERR(adev->c2_reset)) { ++ dev_err(adev->dev, "failed to get ADM0 C2 reset\n"); ++ ret = PTR_ERR(adev->c2_reset); ++ goto err_disable_clks; ++ } ++ ++ reset_control_assert(adev->clk_reset); ++ reset_control_assert(adev->c0_reset); ++ reset_control_assert(adev->c1_reset); ++ reset_control_assert(adev->c2_reset); ++ ++ reset_control_deassert(adev->clk_reset); ++ reset_control_deassert(adev->c0_reset); ++ reset_control_deassert(adev->c1_reset); ++ reset_control_deassert(adev->c2_reset); ++ ++ adev->channels = devm_kcalloc(adev->dev, ADM_MAX_CHANNELS, ++ sizeof(*adev->channels), GFP_KERNEL); ++ ++ if (!adev->channels) { ++ ret = -ENOMEM; ++ goto err_disable_clks; ++ } ++ ++ /* allocate and initialize channels */ ++ INIT_LIST_HEAD(&adev->common.channels); ++ ++ for (i = 0; i < ADM_MAX_CHANNELS; i++) ++ adm_channel_init(adev, &adev->channels[i], i); ++ ++ /* reset CRCIs */ ++ for (i = 0; i < 16; i++) ++ writel(ADM_CRCI_CTL_RST, adev->regs + ++ ADM_CRCI_CTL(i, adev->ee)); ++ ++ /* configure client interfaces */ ++ writel(ADM_CI_RANGE_START(0x40) | ADM_CI_RANGE_END(0xb0) | ++ ADM_CI_BURST_8_WORDS, adev->regs + ADM_CI_CONF(0)); ++ writel(ADM_CI_RANGE_START(0x2a) | ADM_CI_RANGE_END(0x2c) | ++ ADM_CI_BURST_8_WORDS, adev->regs + ADM_CI_CONF(1)); ++ writel(ADM_CI_RANGE_START(0x12) | ADM_CI_RANGE_END(0x28) | ++ ADM_CI_BURST_8_WORDS, adev->regs + ADM_CI_CONF(2)); ++ writel(ADM_GP_CTL_LP_EN | ADM_GP_CTL_LP_CNT(0xf), ++ adev->regs + ADM_GP_CTL); ++ ++ ret = devm_request_irq(adev->dev, adev->irq, adm_dma_irq, ++ 0, "adm_dma", adev); ++ if (ret) ++ goto err_disable_clks; ++ ++ platform_set_drvdata(pdev, adev); ++ ++ adev->common.dev = adev->dev; ++ adev->common.dev->dma_parms = &adev->dma_parms; ++ ++ /* set capabilities */ ++ dma_cap_zero(adev->common.cap_mask); ++ dma_cap_set(DMA_SLAVE, adev->common.cap_mask); ++ dma_cap_set(DMA_PRIVATE, adev->common.cap_mask); ++ ++ /* initialize dmaengine apis */ ++ adev->common.directions = BIT(DMA_DEV_TO_MEM | DMA_MEM_TO_DEV); ++ adev->common.residue_granularity = DMA_RESIDUE_GRANULARITY_DESCRIPTOR; ++ adev->common.src_addr_widths = DMA_SLAVE_BUSWIDTH_4_BYTES; ++ adev->common.dst_addr_widths = DMA_SLAVE_BUSWIDTH_4_BYTES; ++ adev->common.device_free_chan_resources = adm_free_chan; ++ adev->common.device_prep_slave_sg = adm_prep_slave_sg; ++ adev->common.device_issue_pending = adm_issue_pending; ++ adev->common.device_tx_status = adm_tx_status; ++ adev->common.device_terminate_all = adm_terminate_all; ++ adev->common.device_config = adm_slave_config; ++ ++ ret = dma_async_device_register(&adev->common); ++ if (ret) { ++ dev_err(adev->dev, "failed to register dma async device\n"); ++ goto err_disable_clks; ++ } ++ ++ ret = of_dma_controller_register(pdev->dev.of_node, ++ of_dma_xlate_by_chan_id, ++ &adev->common); ++ if (ret) ++ goto err_unregister_dma; ++ ++ return 0; ++ ++err_unregister_dma: ++ dma_async_device_unregister(&adev->common); ++err_disable_clks: ++ clk_disable_unprepare(adev->iface_clk); ++err_disable_core_clk: ++ clk_disable_unprepare(adev->core_clk); ++ ++ return ret; ++} ++ ++static int adm_dma_remove(struct platform_device *pdev) ++{ ++ struct adm_device *adev = platform_get_drvdata(pdev); ++ struct adm_chan *achan; ++ u32 i; ++ ++ of_dma_controller_free(pdev->dev.of_node); ++ dma_async_device_unregister(&adev->common); ++ ++ for (i = 0; i < ADM_MAX_CHANNELS; i++) { ++ achan = &adev->channels[i]; ++ ++ /* mask IRQs for this channel/EE pair */ ++ writel(0, adev->regs + ADM_CH_RSLT_CONF(achan->id, adev->ee)); ++ ++ adm_terminate_all(&adev->channels[i].vc.chan); ++ } ++ ++ devm_free_irq(adev->dev, adev->irq, adev); ++ ++ clk_disable_unprepare(adev->core_clk); ++ clk_disable_unprepare(adev->iface_clk); ++ ++ return 0; ++} ++ ++static const struct of_device_id adm_of_match[] = { ++ { .compatible = "qcom,adm", }, ++ {} ++}; ++MODULE_DEVICE_TABLE(of, adm_of_match); ++ ++static struct platform_driver adm_dma_driver = { ++ .probe = adm_dma_probe, ++ .remove = adm_dma_remove, ++ .driver = { ++ .name = "adm-dma-engine", ++ .of_match_table = adm_of_match, ++ }, ++}; ++ ++module_platform_driver(adm_dma_driver); ++ ++MODULE_AUTHOR("Andy Gross "); ++MODULE_DESCRIPTION("QCOM ADM DMA engine driver"); ++MODULE_LICENSE("GPL v2"); diff --git a/target/linux/ipq806x/patches-5.10/0030-clk-Disable-i2c-device-on-gsbi4.patch b/target/linux/ipq806x/patches-5.10/0030-clk-Disable-i2c-device-on-gsbi4.patch new file mode 100644 index 0000000000..a5fb714e6c --- /dev/null +++ b/target/linux/ipq806x/patches-5.10/0030-clk-Disable-i2c-device-on-gsbi4.patch @@ -0,0 +1,40 @@ +From 0c974b87829e007dc4fae94e20d488204e20e662 Mon Sep 17 00:00:00 2001 +From: John Crispin +Date: Thu, 9 Mar 2017 08:16:10 +0100 +Subject: [PATCH 30/69] clk: Disable i2c device on gsbi4 + +This patch was not annotated and comes from the v4.4 tree. + +Signed-off-by: John Crispin +--- + drivers/clk/qcom/gcc-ipq806x.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +--- a/drivers/clk/qcom/gcc-ipq806x.c ++++ b/drivers/clk/qcom/gcc-ipq806x.c +@@ -365,7 +365,7 @@ static struct clk_rcg gsbi1_uart_src = { + .parent_names = gcc_pxo_pll8, + .num_parents = 2, + .ops = &clk_rcg_ops, +- .flags = CLK_SET_PARENT_GATE, ++ .flags = CLK_SET_PARENT_GATE | CLK_IGNORE_UNUSED, + }, + }, + }; +@@ -383,7 +383,7 @@ static struct clk_branch gsbi1_uart_clk + }, + .num_parents = 1, + .ops = &clk_branch_ops, +- .flags = CLK_SET_RATE_PARENT, ++ .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, + }, + }; +@@ -961,6 +961,7 @@ static struct clk_branch gsbi1_h_clk = { + .hw.init = &(struct clk_init_data){ + .name = "gsbi1_h_clk", + .ops = &clk_branch_ops, ++ .flags = CLK_IGNORE_UNUSED, + }, + }, + }; diff --git a/target/linux/ipq806x/patches-5.10/0031-mtd-add-SMEM-parser-for-QCOM-platforms.patch b/target/linux/ipq806x/patches-5.10/0031-mtd-add-SMEM-parser-for-QCOM-platforms.patch new file mode 100644 index 0000000000..6aa404c8c5 --- /dev/null +++ b/target/linux/ipq806x/patches-5.10/0031-mtd-add-SMEM-parser-for-QCOM-platforms.patch @@ -0,0 +1,282 @@ +From d8eeb4de90e968ba32d956728c866f20752cf2c3 Mon Sep 17 00:00:00 2001 +From: Mathieu Olivari +Date: Thu, 9 Mar 2017 08:18:08 +0100 +Subject: [PATCH 31/69] mtd: add SMEM parser for QCOM platforms + +On QCOM platforms using MTD devices storage (such as IPQ806x), SMEM is +used to store partition layout. This new parser can now be used to read +SMEM and use it to register an MTD layout according to its content. + +Signed-off-by: Mathieu Olivari +Signed-off-by: Ram Chandra Jangir +--- + drivers/mtd/parsers/Kconfig | 7 ++ + drivers/mtd/parsers/Makefile | 1 + + drivers/mtd/parsers/qcom_smem_part.c | 228 +++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 236 insertions(+) + create mode 100644 drivers/mtd/parsers/qcom_smem_part.c + +--- a/drivers/mtd/parsers/Kconfig ++++ b/drivers/mtd/parsers/Kconfig +@@ -119,6 +119,13 @@ config MTD_PARSER_TRX + This driver will parse TRX header and report at least two partitions: + kernel and rootfs. + ++config MTD_QCOM_SMEM_PARTS ++ tristate "QCOM SMEM partitioning support" ++ depends on QCOM_SMEM ++ help ++ This provides partitions parser for QCOM devices using SMEM ++ such as IPQ806x. ++ + config MTD_SHARPSL_PARTS + tristate "Sharp SL Series NAND flash partition parser" + depends on MTD_NAND_SHARPSL || MTD_NAND_TMIO || COMPILE_TEST +--- a/drivers/mtd/parsers/Makefile ++++ b/drivers/mtd/parsers/Makefile +@@ -8,6 +8,7 @@ obj-$(CONFIG_MTD_OF_PARTS) += ofpart.o + obj-$(CONFIG_MTD_PARSER_IMAGETAG) += parser_imagetag.o + obj-$(CONFIG_MTD_AFS_PARTS) += afs.o + obj-$(CONFIG_MTD_PARSER_TRX) += parser_trx.o ++obj-$(CONFIG_MTD_QCOM_SMEM_PARTS) += qcom_smem_part.o + obj-$(CONFIG_MTD_SHARPSL_PARTS) += sharpslpart.o + obj-$(CONFIG_MTD_REDBOOT_PARTS) += redboot.o + obj-$(CONFIG_MTD_ROUTERBOOT_PARTS) += routerbootpart.o +--- /dev/null ++++ b/drivers/mtd/parsers/qcom_smem_part.c +@@ -0,0 +1,235 @@ ++/* ++ * Copyright (c) 2015, The Linux Foundation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 and ++ * only version 2 as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ */ ++ ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#include ++ ++/* Processor/host identifier for the application processor */ ++#define SMEM_HOST_APPS 0 ++ ++/* SMEM items index */ ++#define SMEM_AARM_PARTITION_TABLE 9 ++#define SMEM_BOOT_FLASH_TYPE 421 ++#define SMEM_BOOT_FLASH_BLOCK_SIZE 424 ++ ++/* SMEM Flash types */ ++#define SMEM_FLASH_NAND 2 ++#define SMEM_FLASH_SPI 6 ++ ++#define SMEM_PART_NAME_SZ 16 ++#define SMEM_PARTS_MAX 32 ++ ++struct smem_partition { ++ char name[SMEM_PART_NAME_SZ]; ++ __le32 start; ++ __le32 size; ++ __le32 attr; ++}; ++ ++struct smem_partition_table { ++ u8 magic[8]; ++ __le32 version; ++ __le32 len; ++ struct smem_partition parts[SMEM_PARTS_MAX]; ++}; ++ ++/* SMEM Magic values in partition table */ ++static const u8 SMEM_PTABLE_MAGIC[] = { ++ 0xaa, 0x73, 0xee, 0x55, ++ 0xdb, 0xbd, 0x5e, 0xe3, ++}; ++ ++static int qcom_smem_get_flash_blksz(u64 **smem_blksz) ++{ ++ size_t size; ++ ++ *smem_blksz = qcom_smem_get(SMEM_HOST_APPS, SMEM_BOOT_FLASH_BLOCK_SIZE, ++ &size); ++ ++ if (IS_ERR(*smem_blksz)) { ++ pr_err("Unable to read flash blksz from SMEM\n"); ++ return -ENOENT; ++ } ++ ++ if (size != sizeof(**smem_blksz)) { ++ pr_err("Invalid flash blksz size in SMEM\n"); ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static int qcom_smem_get_flash_type(u64 **smem_flash_type) ++{ ++ size_t size; ++ ++ *smem_flash_type = qcom_smem_get(SMEM_HOST_APPS, SMEM_BOOT_FLASH_TYPE, ++ &size); ++ ++ if (IS_ERR(*smem_flash_type)) { ++ pr_err("Unable to read flash type from SMEM\n"); ++ return -ENOENT; ++ } ++ ++ if (size != sizeof(**smem_flash_type)) { ++ pr_err("Invalid flash type size in SMEM\n"); ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static int qcom_smem_get_flash_partitions(struct smem_partition_table **pparts) ++{ ++ size_t size; ++ ++ *pparts = qcom_smem_get(SMEM_HOST_APPS, SMEM_AARM_PARTITION_TABLE, ++ &size); ++ ++ if (IS_ERR(*pparts)) { ++ pr_err("Unable to read partition table from SMEM\n"); ++ return -ENOENT; ++ } ++ ++ return 0; ++} ++ ++static int of_dev_node_match(struct device *dev, const void *data) ++{ ++ return dev->of_node == data; ++} ++ ++static bool is_spi_device(struct device_node *np) ++{ ++ struct device *dev; ++ ++ dev = bus_find_device(&spi_bus_type, NULL, np, of_dev_node_match); ++ if (!dev) ++ return false; ++ ++ put_device(dev); ++ return true; ++} ++ ++static int parse_qcom_smem_partitions(struct mtd_info *master, ++ const struct mtd_partition **pparts, ++ struct mtd_part_parser_data *data) ++{ ++ struct smem_partition_table *smem_parts; ++ u64 *smem_flash_type, *smem_blksz; ++ struct mtd_partition *mtd_parts; ++ struct device_node *of_node = master->dev.of_node; ++ int i, ret; ++ ++ /* ++ * SMEM will only store the partition table of the boot device. ++ * If this is not the boot device, do not return any partition. ++ */ ++ ret = qcom_smem_get_flash_type(&smem_flash_type); ++ if (ret < 0) ++ return ret; ++ ++ if ((*smem_flash_type == SMEM_FLASH_NAND && !mtd_type_is_nand(master)) ++ || (*smem_flash_type == SMEM_FLASH_SPI && !is_spi_device(of_node))) ++ return 0; ++ ++ /* ++ * Just for sanity purpose, make sure the block size in SMEM matches the ++ * block size of the MTD device ++ */ ++ ret = qcom_smem_get_flash_blksz(&smem_blksz); ++ if (ret < 0) ++ return ret; ++ ++ if (*smem_blksz != master->erasesize) { ++ pr_err("SMEM block size differs from MTD block size\n"); ++ return -EINVAL; ++ } ++ ++ /* Get partition pointer from SMEM */ ++ ret = qcom_smem_get_flash_partitions(&smem_parts); ++ if (ret < 0) ++ return ret; ++ ++ if (memcmp(SMEM_PTABLE_MAGIC, smem_parts->magic, ++ sizeof(SMEM_PTABLE_MAGIC))) { ++ pr_err("SMEM partition magic invalid\n"); ++ return -EINVAL; ++ } ++ ++ /* Allocate and populate the mtd structures */ ++ mtd_parts = kcalloc(le32_to_cpu(smem_parts->len), sizeof(*mtd_parts), ++ GFP_KERNEL); ++ if (!mtd_parts) ++ return -ENOMEM; ++ ++ for (i = 0; i < smem_parts->len; i++) { ++ struct smem_partition *s_part = &smem_parts->parts[i]; ++ struct mtd_partition *m_part = &mtd_parts[i]; ++ ++ m_part->name = s_part->name; ++ m_part->size = le32_to_cpu(s_part->size) * (*smem_blksz); ++ m_part->offset = le32_to_cpu(s_part->start) * (*smem_blksz); ++ ++ /* ++ * The last SMEM partition may have its size marked as ++ * something like 0xffffffff, which means "until the end of the ++ * flash device". In this case, truncate it. ++ */ ++ if (m_part->offset + m_part->size > master->size) ++ m_part->size = master->size - m_part->offset; ++ } ++ ++ *pparts = mtd_parts; ++ ++ return smem_parts->len; ++} ++ ++static const struct of_device_id qcom_smem_of_match_table[] = { ++ { .compatible = "qcom,smem" }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, qcom_smem_of_match_table); ++ ++static struct mtd_part_parser qcom_smem_parser = { ++ .owner = THIS_MODULE, ++ .parse_fn = parse_qcom_smem_partitions, ++ .name = "qcom-smem", ++ .of_match_table = qcom_smem_of_match_table, ++}; ++ ++static int __init qcom_smem_parser_init(void) ++{ ++ register_mtd_parser(&qcom_smem_parser); ++ return 0; ++} ++ ++static void __exit qcom_smem_parser_exit(void) ++{ ++ deregister_mtd_parser(&qcom_smem_parser); ++} ++ ++module_init(qcom_smem_parser_init); ++module_exit(qcom_smem_parser_exit); ++ ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("Mathieu Olivari "); ++MODULE_DESCRIPTION("Parsing code for SMEM based partition tables"); diff --git a/target/linux/ipq806x/patches-5.10/0033-ARM-qcom-automatically-select-PCI_DOMAINS-if-PCI-is-.patch b/target/linux/ipq806x/patches-5.10/0033-ARM-qcom-automatically-select-PCI_DOMAINS-if-PCI-is-.patch new file mode 100644 index 0000000000..a12aa721e2 --- /dev/null +++ b/target/linux/ipq806x/patches-5.10/0033-ARM-qcom-automatically-select-PCI_DOMAINS-if-PCI-is-.patch @@ -0,0 +1,29 @@ +From 48051ece78136e4235a2415a52797db56f8a4478 Mon Sep 17 00:00:00 2001 +From: Mathieu Olivari +Date: Tue, 21 Apr 2015 19:09:07 -0700 +Subject: [PATCH 33/69] ARM: qcom: automatically select PCI_DOMAINS if PCI is + enabled + +If multiple PCIe devices are present in the system, the kernel will +panic at boot time when trying to scan the PCI buses. This happens on +IPQ806x based platforms, which has 3 PCIe ports. + +Enabling this option allows the kernel to assign the pci-domains +according to the device-tree content. This allows multiple PCIe +controllers to coexist in the system. + +Signed-off-by: Mathieu Olivari +--- + arch/arm/mach-qcom/Kconfig | 1 + + 1 file changed, 1 insertion(+) + +--- a/arch/arm/mach-qcom/Kconfig ++++ b/arch/arm/mach-qcom/Kconfig +@@ -7,6 +7,7 @@ menuconfig ARCH_QCOM + select ARM_AMBA + select PINCTRL + select QCOM_SCM if SMP ++ select PCI_DOMAINS if PCI + help + Support for Qualcomm's devicetree based systems. + diff --git a/target/linux/ipq806x/patches-5.10/0049-PM-OPP-Support-adjusting-OPP-voltages-at-runtime.patch b/target/linux/ipq806x/patches-5.10/0049-PM-OPP-Support-adjusting-OPP-voltages-at-runtime.patch new file mode 100644 index 0000000000..9efbd583b4 --- /dev/null +++ b/target/linux/ipq806x/patches-5.10/0049-PM-OPP-Support-adjusting-OPP-voltages-at-runtime.patch @@ -0,0 +1,153 @@ +From: Sylwester Nawrocki +To: krzk@kernel.org, vireshk@kernel.org, robh+dt@kernel.org +Cc: sboyd@kernel.org, roger.lu@mediatek.com, + linux-pm@vger.kernel.org, linux-arm-kernel@lists.infradead.org, + linux-samsung-soc@vger.kernel.org, devicetree@vger.kernel.org, + b.zolnierkie@samsung.com, m.szyprowski@samsung.com, + Stephen Boyd , + Sylwester Nawrocki +Subject: [PATCH v5 1/4] PM / OPP: Support adjusting OPP voltages at runtime +Date: Wed, 16 Oct 2019 16:57:53 +0200 +Message-ID: <20191016145756.16004-2-s.nawrocki@samsung.com> (raw) +In-Reply-To: <20191016145756.16004-1-s.nawrocki@samsung.com> + +From: Stephen Boyd + +On some SoCs the Adaptive Voltage Scaling (AVS) technique is +employed to optimize the operating voltage of a device. At a +given frequency, the hardware monitors dynamic factors and either +makes a suggestion for how much to adjust a voltage for the +current frequency, or it automatically adjusts the voltage +without software intervention. Add an API to the OPP library for +the former case, so that AVS type devices can update the voltages +for an OPP when the hardware determines the voltage should +change. The assumption is that drivers like CPUfreq or devfreq +will register for the OPP notifiers and adjust the voltage +according to suggestions that AVS makes. + +This patch is derived from [1] submitted by Stephen. +[1] https://lore.kernel.org/patchwork/patch/599279/ + +Signed-off-by: Stephen Boyd +Signed-off-by: Roger Lu +[s.nawrocki@samsung.com: added handling of OPP min/max voltage] +Signed-off-by: Sylwester Nawrocki +--- + drivers/opp/core.c | 69 ++++++++++++++++++++++++++++++++++++++++++ + include/linux/pm_opp.h | 13 ++++++++ + 2 files changed, 82 insertions(+) + +--- a/drivers/opp/core.c ++++ b/drivers/opp/core.c +@@ -2102,6 +2102,75 @@ put_table: + } + + /** ++ * dev_pm_opp_adjust_voltage() - helper to change the voltage of an OPP ++ * @dev: device for which we do this operation ++ * @freq: OPP frequency to adjust voltage of ++ * @u_volt: new OPP target voltage ++ * @u_volt_min: new OPP min voltage ++ * @u_volt_max: new OPP max voltage ++ * ++ * Return: -EINVAL for bad pointers, -ENOMEM if no memory available for the ++ * copy operation, returns 0 if no modifcation was done OR modification was ++ * successful. ++ */ ++int dev_pm_opp_adjust_voltage(struct device *dev, unsigned long freq, ++ unsigned long u_volt, unsigned long u_volt_min, ++ unsigned long u_volt_max) ++ ++{ ++ struct opp_table *opp_table; ++ struct dev_pm_opp *tmp_opp, *opp = ERR_PTR(-ENODEV); ++ int r = 0; ++ ++ /* Find the opp_table */ ++ opp_table = _find_opp_table(dev); ++ if (IS_ERR(opp_table)) { ++ r = PTR_ERR(opp_table); ++ dev_warn(dev, "%s: Device OPP not found (%d)\n", __func__, r); ++ return r; ++ } ++ ++ mutex_lock(&opp_table->lock); ++ ++ /* Do we have the frequency? */ ++ list_for_each_entry(tmp_opp, &opp_table->opp_list, node) { ++ if (tmp_opp->rate == freq) { ++ opp = tmp_opp; ++ break; ++ } ++ } ++ ++ if (IS_ERR(opp)) { ++ r = PTR_ERR(opp); ++ goto adjust_unlock; ++ } ++ ++ /* Is update really needed? */ ++ if (opp->supplies->u_volt == u_volt) ++ goto adjust_unlock; ++ ++ opp->supplies->u_volt = u_volt; ++ opp->supplies->u_volt_min = u_volt_min; ++ opp->supplies->u_volt_max = u_volt_max; ++ ++ dev_pm_opp_get(opp); ++ mutex_unlock(&opp_table->lock); ++ ++ /* Notify the voltage change of the OPP */ ++ blocking_notifier_call_chain(&opp_table->head, OPP_EVENT_ADJUST_VOLTAGE, ++ opp); ++ ++ dev_pm_opp_put(opp); ++ goto adjust_put_table; ++ ++adjust_unlock: ++ mutex_unlock(&opp_table->lock); ++adjust_put_table: ++ dev_pm_opp_put_opp_table(opp_table); ++ return r; ++} ++ ++/** + * dev_pm_opp_enable() - Enable a specific OPP + * @dev: device for which we do this operation + * @freq: OPP frequency to enable +--- a/include/linux/pm_opp.h ++++ b/include/linux/pm_opp.h +@@ -22,6 +22,7 @@ struct opp_table; + + enum dev_pm_opp_event { + OPP_EVENT_ADD, OPP_EVENT_REMOVE, OPP_EVENT_ENABLE, OPP_EVENT_DISABLE, ++ OPP_EVENT_ADJUST_VOLTAGE, + }; + + /** +@@ -113,6 +114,10 @@ int dev_pm_opp_add(struct device *dev, u + void dev_pm_opp_remove(struct device *dev, unsigned long freq); + void dev_pm_opp_remove_all_dynamic(struct device *dev); + ++int dev_pm_opp_adjust_voltage(struct device *dev, unsigned long freq, ++ unsigned long u_volt, unsigned long u_volt_min, ++ unsigned long u_volt_max); ++ + int dev_pm_opp_enable(struct device *dev, unsigned long freq); + + int dev_pm_opp_disable(struct device *dev, unsigned long freq); +@@ -242,6 +247,14 @@ static inline void dev_pm_opp_remove_all + { + } + ++static inline int ++dev_pm_opp_adjust_voltage(struct device *dev, unsigned long freq, ++ unsigned long u_volt, unsigned long u_volt_min, ++ unsigned long u_volt_max) ++{ ++ return 0; ++} ++ + static inline int dev_pm_opp_enable(struct device *dev, unsigned long freq) + { + return 0; diff --git a/target/linux/ipq806x/patches-5.10/0051-PM-OPP-Add-a-helper-to-get-an-opp-regulator-for-devi.patch b/target/linux/ipq806x/patches-5.10/0051-PM-OPP-Add-a-helper-to-get-an-opp-regulator-for-devi.patch new file mode 100644 index 0000000000..35fe45fca7 --- /dev/null +++ b/target/linux/ipq806x/patches-5.10/0051-PM-OPP-Add-a-helper-to-get-an-opp-regulator-for-devi.patch @@ -0,0 +1,52 @@ +From d06ca5e7a3cf726f5be5ffd96e93ccd798b8c09a Mon Sep 17 00:00:00 2001 +From: Georgi Djakov +Date: Thu, 12 May 2016 14:41:33 +0300 +Subject: [PATCH 51/69] PM / OPP: Add a helper to get an opp regulator for + device + +Signed-off-by: Georgi Djakov +--- + drivers/opp/core.c | 21 +++++++++++++++++++++ + include/linux/pm_opp.h | 1 + + 2 files changed, 22 insertions(+) + +--- a/drivers/opp/core.c ++++ b/drivers/opp/core.c +@@ -127,6 +127,27 @@ unsigned long dev_pm_opp_get_freq(struct + } + EXPORT_SYMBOL_GPL(dev_pm_opp_get_freq); + ++struct regulator *dev_pm_opp_get_regulator(struct device *dev) ++{ ++ struct opp_table *opp_table; ++ struct regulator *reg; ++ ++ rcu_read_lock(); ++ ++ opp_table = _find_opp_table(dev); ++ if (IS_ERR(opp_table)) { ++ rcu_read_unlock(); ++ return ERR_CAST(opp_table); ++ } ++ ++ reg = opp_table->regulators[0]; ++ ++ rcu_read_unlock(); ++ ++ return reg; ++} ++EXPORT_SYMBOL_GPL(dev_pm_opp_get_regulator); ++ + /** + * dev_pm_opp_get_level() - Gets the level corresponding to an available opp + * @opp: opp for which level value has to be returned for +--- a/include/linux/pm_opp.h ++++ b/include/linux/pm_opp.h +@@ -83,6 +83,7 @@ void dev_pm_opp_put_opp_table(struct opp + unsigned long dev_pm_opp_get_voltage(struct dev_pm_opp *opp); + + unsigned long dev_pm_opp_get_freq(struct dev_pm_opp *opp); ++struct regulator *dev_pm_opp_get_regulator(struct device *dev); + + unsigned int dev_pm_opp_get_level(struct dev_pm_opp *opp); + diff --git a/target/linux/ipq806x/patches-5.10/0052-PM-OPP-Update-the-voltage-tolerance-when-adjusting-t.patch b/target/linux/ipq806x/patches-5.10/0052-PM-OPP-Update-the-voltage-tolerance-when-adjusting-t.patch new file mode 100644 index 0000000000..8498a0b6df --- /dev/null +++ b/target/linux/ipq806x/patches-5.10/0052-PM-OPP-Update-the-voltage-tolerance-when-adjusting-t.patch @@ -0,0 +1,47 @@ +From 4533c285c2aedce6d4434d7b877066de3b1ecb33 Mon Sep 17 00:00:00 2001 +From: Georgi Djakov +Date: Thu, 25 Aug 2016 18:43:35 +0300 +Subject: [PATCH 52/69] PM / OPP: Update the voltage tolerance when adjusting + the OPP + +When the voltage is adjusted, the voltage tolerance is not updated. +This can lead to situations where the voltage min value is greater +than the voltage max value. The final result is triggering a BUG() +in the regulator core. +Fix this by updating the voltage tolerance values too. + +Signed-off-by: Georgi Djakov +--- + drivers/opp/core.c | 5 +++++ + 1 file changed, 5 insertions(+) + +--- a/drivers/opp/core.c ++++ b/drivers/opp/core.c +@@ -2142,6 +2142,7 @@ int dev_pm_opp_adjust_voltage(struct dev + struct opp_table *opp_table; + struct dev_pm_opp *tmp_opp, *opp = ERR_PTR(-ENODEV); + int r = 0; ++ unsigned long tol; + + /* Find the opp_table */ + opp_table = _find_opp_table(dev); +@@ -2171,8 +2172,17 @@ int dev_pm_opp_adjust_voltage(struct dev + goto adjust_unlock; + + opp->supplies->u_volt = u_volt; +- opp->supplies->u_volt_min = u_volt_min; +- opp->supplies->u_volt_max = u_volt_max; ++ ++ tol = u_volt * opp_table->voltage_tolerance_v1 / 100; ++ if ( u_volt_min == u_volt ) ++ opp->supplies->u_volt_min = u_volt - tol; ++ else ++ opp->supplies->u_volt_min = u_volt_min; ++ ++ if ( u_volt_max == u_volt ) ++ opp->supplies->u_volt_max = u_volt + tol; ++ else ++ opp->supplies->u_volt_max = u_volt_max; + + dev_pm_opp_get(opp); + mutex_unlock(&opp_table->lock); diff --git a/target/linux/ipq806x/patches-5.10/0054-cpufreq-dt-Handle-OPP-voltage-adjust-events.patch b/target/linux/ipq806x/patches-5.10/0054-cpufreq-dt-Handle-OPP-voltage-adjust-events.patch new file mode 100644 index 0000000000..2e9c101d94 --- /dev/null +++ b/target/linux/ipq806x/patches-5.10/0054-cpufreq-dt-Handle-OPP-voltage-adjust-events.patch @@ -0,0 +1,118 @@ +From 10577f74c35bd395951d1b2382c8d821089b5745 Mon Sep 17 00:00:00 2001 +From: Stephen Boyd +Date: Fri, 18 Sep 2015 17:52:08 -0700 +Subject: [PATCH 54/69] cpufreq-dt: Handle OPP voltage adjust events + +On some SoCs the Adaptive Voltage Scaling (AVS) technique is +employed to optimize the operating voltage of a device. At a +given frequency, the hardware monitors dynamic factors and either +makes a suggestion for how much to adjust a voltage for the +current frequency, or it automatically adjusts the voltage +without software intervention. + +In the former case, an AVS driver will call +dev_pm_opp_modify_voltage() and update the voltage for the +particular OPP the CPUs are using. Add an OPP notifier to +cpufreq-dt so that we can adjust the voltage of the CPU when AVS +updates the OPP. + +Signed-off-by: Stephen Boyd +Acked-by: Viresh Kumar +Signed-off-by: Georgi Djakov +--- + drivers/cpufreq/cpufreq-dt.c | 68 ++++++++++++++++++++++++++++++++++++++++++-- + 1 file changed, 65 insertions(+), 3 deletions(-) + +--- a/drivers/cpufreq/cpufreq-dt.c ++++ b/drivers/cpufreq/cpufreq-dt.c +@@ -27,6 +27,9 @@ struct private_data { + struct opp_table *opp_table; + struct device *cpu_dev; + const char *reg_name; ++ struct notifier_block opp_nb; ++ struct mutex lock; ++ unsigned long opp_freq; + bool have_static_opps; + }; + +@@ -42,12 +45,15 @@ static int set_target(struct cpufreq_pol + unsigned long freq = policy->freq_table[index].frequency; + int ret; + ++ mutex_lock(&priv->lock); + ret = dev_pm_opp_set_rate(priv->cpu_dev, freq * 1000); + + if (!ret) { ++ priv->opp_freq = freq * 1000; + arch_set_freq_scale(policy->related_cpus, freq, + policy->cpuinfo.max_freq); + } ++ mutex_unlock(&priv->lock); + + return ret; + } +@@ -90,6 +96,39 @@ node_put: + return name; + } + ++static int opp_notifier(struct notifier_block *nb, unsigned long event, ++ void *data) ++{ ++ struct dev_pm_opp *opp = data; ++ struct private_data *priv = container_of(nb, struct private_data, ++ opp_nb); ++ struct device *cpu_dev = priv->cpu_dev; ++ struct regulator *cpu_reg; ++ unsigned long volt, freq; ++ int ret = 0; ++ ++ if (event == OPP_EVENT_ADJUST_VOLTAGE) { ++ cpu_reg = dev_pm_opp_get_regulator(cpu_dev); ++ if (IS_ERR(cpu_reg)) { ++ ret = PTR_ERR(cpu_reg); ++ goto out; ++ } ++ volt = dev_pm_opp_get_voltage(opp); ++ freq = dev_pm_opp_get_freq(opp); ++ ++ mutex_lock(&priv->lock); ++ if (freq == priv->opp_freq) { ++ ret = regulator_set_voltage_triplet(cpu_reg, volt, volt, volt); ++ } ++ mutex_unlock(&priv->lock); ++ if (ret) ++ dev_err(cpu_dev, "failed to scale voltage: %d\n", ret); ++ } ++ ++out: ++ return notifier_from_errno(ret); ++} ++ + static int resources_available(void) + { + struct device *cpu_dev; +@@ -246,10 +285,14 @@ static int cpufreq_init(struct cpufreq_p + __func__, ret); + } + ++ mutex_init(&priv->lock); ++ priv->opp_nb.notifier_call = opp_notifier; ++ dev_pm_opp_register_notifier(cpu_dev, &priv->opp_nb); ++ + ret = dev_pm_opp_init_cpufreq_table(cpu_dev, &freq_table); + if (ret) { + dev_err(cpu_dev, "failed to init cpufreq table: %d\n", ret); +- goto out_free_opp; ++ goto out_unregister_nb; + } + + priv->cpu_dev = cpu_dev; +@@ -281,6 +324,8 @@ static int cpufreq_init(struct cpufreq_p + + out_free_cpufreq_table: + dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table); ++out_unregister_nb: ++ dev_pm_opp_unregister_notifier(cpu_dev, &priv->opp_nb); + out_free_opp: + if (priv->have_static_opps) + dev_pm_opp_of_cpumask_remove_table(policy->cpus); diff --git a/target/linux/ipq806x/patches-5.10/0055-cpufreq-dt-Add-L2-frequency-scaling-support.patch b/target/linux/ipq806x/patches-5.10/0055-cpufreq-dt-Add-L2-frequency-scaling-support.patch new file mode 100644 index 0000000000..910c2b1722 --- /dev/null +++ b/target/linux/ipq806x/patches-5.10/0055-cpufreq-dt-Add-L2-frequency-scaling-support.patch @@ -0,0 +1,199 @@ +--- a/drivers/cpufreq/cpufreq-dt.c ++++ b/drivers/cpufreq/cpufreq-dt.c +@@ -39,20 +39,85 @@ static struct freq_attr *cpufreq_dt_attr + NULL, + }; + ++struct shared_data { ++ unsigned long *curr_freq_table; ++ unsigned long curr_l2_freq; ++ unsigned long curr_l2_volt; ++}; ++ ++static struct shared_data *cpus_shared_data; ++ + static int set_target(struct cpufreq_policy *policy, unsigned int index) + { + struct private_data *priv = policy->driver_data; + unsigned long freq = policy->freq_table[index].frequency; ++ struct clk *l2_clk = policy->l2_clk; ++ struct regulator *l2_regulator = policy->l2_regulator; ++ unsigned long l2_freq, target_l2_freq; ++ unsigned long l2_vol, target_l2_volt; ++ unsigned long target_freq; + int ret; + + mutex_lock(&priv->lock); + ret = dev_pm_opp_set_rate(priv->cpu_dev, freq * 1000); + + if (!ret) { ++ if (policy->l2_rate_set) { ++ int cpu, l2_index, tol = 0; ++ target_freq = freq * 1000; ++ ++ cpus_shared_data->curr_freq_table[policy->cpu] = target_freq; ++ for_each_present_cpu(cpu) ++ if (cpu != policy->cpu) ++ target_freq = max(target_freq, cpus_shared_data->curr_freq_table[cpu]); ++ ++ for (l2_index = 2; l2_index > 0; l2_index--) ++ if (target_freq >= policy->l2_cpufreq[l2_index]) ++ break; ++ ++ l2_freq = cpus_shared_data->curr_l2_freq; ++ target_l2_freq = policy->l2_rate[l2_index]; ++ ++ if (l2_freq != target_l2_freq) { ++ ++ /* ++ * Set to idle bin if switching from normal to high bin ++ * or vice versa ++ */ ++ if ( (l2_index == 2 && l2_freq == policy->l2_rate[1]) || ++ (l2_index == 1 && l2_freq == policy->l2_rate[2]) ) { ++ ret = clk_set_rate(l2_clk, policy->l2_rate[0]); ++ if (ret) ++ goto exit; ++ } ++ ++ /* scale l2 with the core */ ++ ret = clk_set_rate(l2_clk, target_l2_freq); ++ if (ret) ++ goto exit; ++ cpus_shared_data->curr_l2_freq = target_l2_freq; ++ ++ if (policy->l2_volt_set) { ++ ++ l2_vol = cpus_shared_data->curr_l2_volt; ++ target_l2_volt = policy->l2_volt[l2_index]; ++ ++ if (l2_vol != target_l2_volt) { ++ tol = target_l2_volt * policy->l2_volt_tol / 100; ++ ret = regulator_set_voltage_tol(l2_regulator,target_l2_volt,tol); ++ if (ret) ++ goto exit; ++ cpus_shared_data->curr_l2_volt = target_l2_volt; ++ } ++ } ++ } ++ } + priv->opp_freq = freq * 1000; + arch_set_freq_scale(policy->related_cpus, freq, + policy->cpuinfo.max_freq); + } ++ ++exit: + mutex_unlock(&priv->lock); + + return ret; +@@ -195,6 +260,9 @@ static int cpufreq_init(struct cpufreq_p + bool fallback = false; + const char *name; + int ret; ++ struct device_node *np, *l2_np; ++ struct clk *l2_clk = NULL; ++ struct regulator *l2_regulator = NULL; + + cpu_dev = get_cpu_device(policy->cpu); + if (!cpu_dev) { +@@ -302,6 +370,57 @@ static int cpufreq_init(struct cpufreq_p + + policy->suspend_freq = dev_pm_opp_get_suspend_opp_freq(cpu_dev) / 1000; + ++ policy->l2_rate_set = false; ++ policy->l2_volt_set = false; ++ ++ l2_clk = clk_get(cpu_dev, "l2"); ++ if (!IS_ERR(l2_clk)) ++ policy->l2_clk = l2_clk; ++ ++ l2_np = of_find_node_by_name(NULL, "qcom,l2"); ++ if (l2_np) { ++ struct device_node *vdd; ++ np = of_node_get(priv->cpu_dev->of_node); ++ ++ if (np) ++ of_property_read_u32(np, "voltage-tolerance", &policy->l2_volt_tol); ++ ++ of_property_read_u32_array(l2_np, "qcom,l2-rates", policy->l2_rate, 3); ++ if (policy->l2_rate[0] && policy->l2_rate[1] && policy->l2_rate[2]) { ++ policy->l2_rate_set = true; ++ of_property_read_u32_array(l2_np, "qcom,l2-cpufreq", policy->l2_cpufreq, 3); ++ of_property_read_u32_array(l2_np, "qcom,l2-volt", policy->l2_volt, 3); ++ } else ++ pr_warn("L2: failed to parse L2 rates\n"); ++ ++ if (!policy->l2_cpufreq[0] && !policy->l2_cpufreq[1] && ++ !policy->l2_cpufreq[2] && policy->l2_rate_set) { ++ int i; ++ ++ pr_warn("L2: failed to parse target cpu freq, using defaults\n"); ++ for (i = 0; i < 3; i++) ++ policy->l2_cpufreq[i] = policy->l2_rate[i]; ++ } ++ ++ if (policy->l2_volt[0] && policy->l2_volt[1] && policy->l2_volt[2] && ++ policy->l2_volt_tol && policy->l2_rate_set) { ++ vdd = of_parse_phandle(l2_np, "qcom,l2-supply", 0); ++ ++ if (vdd) { ++ l2_regulator = devm_regulator_get(cpu_dev, vdd->name); ++ if (!IS_ERR(l2_regulator)) { ++ policy->l2_regulator = l2_regulator; ++ policy->l2_volt_set = true; ++ } else { ++ pr_warn("failed to get l2 supply\n"); ++ l2_regulator = NULL; ++ } ++ ++ of_node_put(vdd); ++ } ++ } ++ } ++ + /* Support turbo/boost mode */ + if (policy_has_boost_freq(policy)) { + /* This gets disabled by core on driver unregister */ +@@ -401,6 +520,14 @@ static int dt_cpufreq_probe(struct platf + if (ret) + return ret; + ++ cpus_shared_data = kzalloc(sizeof(struct shared_data), GFP_KERNEL); ++ if (!cpus_shared_data) ++ return -ENOMEM; ++ ++ cpus_shared_data->curr_freq_table = kzalloc(sizeof(int) * CONFIG_NR_CPUS, GFP_KERNEL); ++ if (!cpus_shared_data->curr_freq_table) ++ return -ENOMEM; ++ + if (data) { + if (data->have_governor_per_policy) + dt_cpufreq_driver.flags |= CPUFREQ_HAVE_GOVERNOR_PER_POLICY; +@@ -419,6 +546,8 @@ static int dt_cpufreq_probe(struct platf + + static int dt_cpufreq_remove(struct platform_device *pdev) + { ++ kfree(cpus_shared_data->curr_freq_table); ++ kfree(cpus_shared_data); + cpufreq_unregister_driver(&dt_cpufreq_driver); + return 0; + } +--- a/include/linux/cpufreq.h ++++ b/include/linux/cpufreq.h +@@ -58,7 +58,15 @@ struct cpufreq_policy { + should set cpufreq */ + unsigned int cpu; /* cpu managing this policy, must be online */ + +- struct clk *clk; ++ struct clk *clk; ++ struct clk *l2_clk; /* L2 clock */ ++ struct regulator *l2_regulator; /* L2 supply */ ++ unsigned int l2_rate[3]; /* L2 bus clock rate */ ++ bool l2_rate_set; ++ unsigned int l2_cpufreq[3]; /* L2 target CPU frequency */ ++ unsigned int l2_volt[3]; /* L2 voltage array */ ++ bool l2_volt_set; ++ unsigned int l2_volt_tol; /* L2 voltage tolerance */ + struct cpufreq_cpuinfo cpuinfo;/* see above */ + + unsigned int min; /* in kHz */ diff --git a/target/linux/ipq806x/patches-5.10/0056-cpufreq-dt-Add-missing-rcu-locks.patch b/target/linux/ipq806x/patches-5.10/0056-cpufreq-dt-Add-missing-rcu-locks.patch new file mode 100644 index 0000000000..9b85839e19 --- /dev/null +++ b/target/linux/ipq806x/patches-5.10/0056-cpufreq-dt-Add-missing-rcu-locks.patch @@ -0,0 +1,23 @@ +From 001a8dcb56ced58c518aaa10a4f0ba5e878705b6 Mon Sep 17 00:00:00 2001 +From: Georgi Djakov +Date: Tue, 17 May 2016 16:15:43 +0300 +Subject: [PATCH 56/69] cpufreq-dt: Add missing rcu locks + +Signed-off-by: Georgi Djakov +--- + drivers/cpufreq/cpufreq-dt.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/drivers/cpufreq/cpufreq-dt.c ++++ b/drivers/cpufreq/cpufreq-dt.c +@@ -178,8 +178,10 @@ static int opp_notifier(struct notifier_ + ret = PTR_ERR(cpu_reg); + goto out; + } ++ rcu_read_lock(); + volt = dev_pm_opp_get_voltage(opp); + freq = dev_pm_opp_get_freq(opp); ++ rcu_read_unlock(); + + mutex_lock(&priv->lock); + if (freq == priv->opp_freq) { diff --git a/target/linux/ipq806x/patches-5.10/0057-add-fab-scaling-support-with-cpufreq.patch b/target/linux/ipq806x/patches-5.10/0057-add-fab-scaling-support-with-cpufreq.patch new file mode 100644 index 0000000000..441500df79 --- /dev/null +++ b/target/linux/ipq806x/patches-5.10/0057-add-fab-scaling-support-with-cpufreq.patch @@ -0,0 +1,243 @@ +--- a/drivers/clk/qcom/Makefile ++++ b/drivers/clk/qcom/Makefile +@@ -15,6 +15,7 @@ clk-qcom-$(CONFIG_KRAIT_CLOCKS) += clk-k + clk-qcom-y += clk-hfpll.o + clk-qcom-y += reset.o + clk-qcom-$(CONFIG_QCOM_GDSC) += gdsc.o ++clk-qcom-y += fab_scaling.o + + # Keep alphabetically sorted by config + obj-$(CONFIG_APQ_GCC_8084) += gcc-apq8084.o +--- /dev/null ++++ b/drivers/clk/qcom/fab_scaling.c +@@ -0,0 +1,172 @@ ++/* ++ * Copyright (c) 2015, The Linux Foundation. All rights reserved. ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++struct qcom_fab_scaling_data { ++ u32 fab_freq_high; ++ u32 fab_freq_nominal; ++ u32 cpu_freq_threshold; ++ struct clk *apps_fab_clk; ++ struct clk *ddr_fab_clk; ++}; ++ ++static struct qcom_fab_scaling_data *drv_data; ++ ++int scale_fabrics(unsigned long max_cpu_freq) ++{ ++ struct clk *apps_fab_clk = drv_data->apps_fab_clk, ++ *ddr_fab_clk = drv_data->ddr_fab_clk; ++ unsigned long target_freq, cur_freq; ++ int ret; ++ ++ /* Skip fab scaling if the driver is not ready */ ++ if (!apps_fab_clk || !ddr_fab_clk) ++ return 0; ++ ++ if (max_cpu_freq > drv_data->cpu_freq_threshold) ++ target_freq = drv_data->fab_freq_high; ++ else ++ target_freq = drv_data->fab_freq_nominal; ++ ++ cur_freq = clk_get_rate(ddr_fab_clk); ++ ++ if (target_freq != cur_freq) { ++ ret = clk_set_rate(apps_fab_clk, target_freq); ++ if (ret) ++ return ret; ++ ret = clk_set_rate(ddr_fab_clk, target_freq); ++ if (ret) ++ return ret; ++ } ++ ++ return 0; ++} ++EXPORT_SYMBOL(scale_fabrics); ++ ++static int ipq806x_fab_scaling_probe(struct platform_device *pdev) ++{ ++ struct device_node *np = pdev->dev.of_node; ++ struct clk *apps_fab_clk, *ddr_fab_clk; ++ int ret; ++ ++ if (!np) ++ return -ENODEV; ++ ++ drv_data = kzalloc(sizeof(*drv_data), GFP_KERNEL); ++ if (!drv_data) ++ return -ENOMEM; ++ ++ if (of_property_read_u32(np, "fab_freq_high", &drv_data->fab_freq_high)) { ++ pr_err("FABRICS turbo freq not found. Using defaults...\n"); ++ drv_data->fab_freq_high = 533000000; ++ } ++ ++ if (of_property_read_u32(np, "fab_freq_nominal", &drv_data->fab_freq_nominal)) { ++ pr_err("FABRICS nominal freq not found. Using defaults...\n"); ++ drv_data->fab_freq_nominal = 400000000; ++ } ++ ++ if (of_property_read_u32(np, "cpu_freq_threshold", &drv_data->cpu_freq_threshold)) { ++ pr_err("FABRICS cpu freq threshold not found. Using defaults...\n"); ++ drv_data->cpu_freq_threshold = 1000000000; ++ } ++ ++ apps_fab_clk = devm_clk_get(&pdev->dev, "apps-fab-clk"); ++ ret = PTR_ERR_OR_ZERO(apps_fab_clk); ++ if (ret) { ++ /* ++ * If apps fab clk node is present, but clock is not yet ++ * registered, we should try defering probe. ++ */ ++ if (ret != -EPROBE_DEFER) { ++ pr_err("Failed to get APPS FABRIC clock: %d\n", ret); ++ ret = -ENODEV; ++ } ++ goto err; ++ } ++ ++ clk_prepare_enable(apps_fab_clk); ++ clk_set_rate(apps_fab_clk, drv_data->fab_freq_high); ++ drv_data->apps_fab_clk = apps_fab_clk; ++ ++ ddr_fab_clk = devm_clk_get(&pdev->dev, "ddr-fab-clk"); ++ ret = PTR_ERR_OR_ZERO(ddr_fab_clk); ++ if (ret) { ++ /* ++ * If ddr fab clk node is present, but clock is not yet ++ * registered, we should try defering probe. ++ */ ++ if (ret != -EPROBE_DEFER) { ++ pr_err("Failed to get DDR FABRIC clock: %d\n", ret); ++ ddr_fab_clk = NULL; ++ ret = -ENODEV; ++ } ++ goto err; ++ } ++ ++ clk_prepare_enable(ddr_fab_clk); ++ clk_set_rate(ddr_fab_clk, drv_data->fab_freq_high); ++ drv_data->ddr_fab_clk = ddr_fab_clk; ++ ++ return 0; ++err: ++ kfree(drv_data); ++ return ret; ++} ++ ++static int ipq806x_fab_scaling_remove(struct platform_device *pdev) ++{ ++ kfree(drv_data); ++ return 0; ++} ++ ++static const struct of_device_id fab_scaling_ipq806x_match_table[] = { ++ { .compatible = "qcom,fab-scaling" }, ++ { } ++}; ++ ++static struct platform_driver fab_scaling_ipq806x_driver = { ++ .probe = ipq806x_fab_scaling_probe, ++ .remove = ipq806x_fab_scaling_remove, ++ .driver = { ++ .name = "fab-scaling", ++ .of_match_table = fab_scaling_ipq806x_match_table, ++ }, ++}; ++ ++static int __init fab_scaling_ipq806x_init(void) ++{ ++ return platform_driver_register(&fab_scaling_ipq806x_driver); ++} ++late_initcall(fab_scaling_ipq806x_init); ++ ++static void __exit fab_scaling_ipq806x_exit(void) ++{ ++ platform_driver_unregister(&fab_scaling_ipq806x_driver); ++} ++module_exit(fab_scaling_ipq806x_exit); +--- /dev/null ++++ b/include/linux/fab_scaling.h +@@ -0,0 +1,31 @@ ++/* ++ * Copyright (c) 2015, The Linux Foundation. All rights reserved. ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++ ++#ifndef __FAB_SCALING_H ++#define __FAB_SCALING_H ++ ++/** ++ * scale_fabrics - Scale DDR and APPS FABRICS ++ * ++ * This function monitors all the registered clocks and does APPS ++ * and DDR FABRIC scaling based on the idle frequencies with which ++ * it was registered. ++ * ++ */ ++int scale_fabrics(unsigned long max_cpu_freq); ++ ++#endif +--- a/drivers/cpufreq/cpufreq-dt.c ++++ b/drivers/cpufreq/cpufreq-dt.c +@@ -20,6 +20,7 @@ + #include + #include + #include ++#include + + #include "cpufreq-dt.h" + +@@ -111,6 +112,13 @@ static int set_target(struct cpufreq_pol + } + } + } ++ ++ /* ++ * Scale fabrics with max freq across all cores ++ */ ++ ret = scale_fabrics(target_freq); ++ if (ret) ++ goto exit; + } + priv->opp_freq = freq * 1000; + arch_set_freq_scale(policy->related_cpus, freq, diff --git a/target/linux/ipq806x/patches-5.10/0059-ARM-cpuidle-Add-cpuidle-support-for-QCOM-cpus.patch b/target/linux/ipq806x/patches-5.10/0059-ARM-cpuidle-Add-cpuidle-support-for-QCOM-cpus.patch new file mode 100644 index 0000000000..7d6e3f1605 --- /dev/null +++ b/target/linux/ipq806x/patches-5.10/0059-ARM-cpuidle-Add-cpuidle-support-for-QCOM-cpus.patch @@ -0,0 +1,29 @@ +From 04ca10340f1b4d92e849724d322a7ca225d11539 Mon Sep 17 00:00:00 2001 +From: Lina Iyer +Date: Wed, 25 Mar 2015 14:25:29 -0600 +Subject: [PATCH 59/69] ARM: cpuidle: Add cpuidle support for QCOM cpus + +Define ARM_QCOM_CPUIDLE config item to enable cpuidle support. + +Cc: Stephen Boyd +Cc: Arnd Bergmann +Cc: Kevin Hilman +Cc: Daniel Lezcano +Signed-off-by: Lina Iyer +--- + drivers/cpuidle/Kconfig.arm | 7 +++++++ + 1 file changed, 7 insertions(+) + +--- a/drivers/cpuidle/Kconfig.arm ++++ b/drivers/cpuidle/Kconfig.arm +@@ -86,3 +86,10 @@ config ARM_MVEBU_V7_CPUIDLE + depends on ARCH_MVEBU && !ARM64 + help + Select this to enable cpuidle on Armada 370, 38x and XP processors. ++ ++config ARM_QCOM_CPUIDLE ++ bool "CPU Idle Driver for QCOM processors" ++ depends on ARCH_QCOM ++ select ARM_CPUIDLE ++ help ++ Select this to enable cpuidle on QCOM processors. diff --git a/target/linux/ipq806x/patches-5.10/0060-HACK-arch-arm-force-ZRELADDR-on-arch-qcom.patch b/target/linux/ipq806x/patches-5.10/0060-HACK-arch-arm-force-ZRELADDR-on-arch-qcom.patch new file mode 100644 index 0000000000..d3b39ac3e3 --- /dev/null +++ b/target/linux/ipq806x/patches-5.10/0060-HACK-arch-arm-force-ZRELADDR-on-arch-qcom.patch @@ -0,0 +1,62 @@ +From fa71139b55e114aa8c3c4823ff8ee7d49ee810d4 Mon Sep 17 00:00:00 2001 +From: Mathieu Olivari +Date: Wed, 29 Apr 2015 15:21:46 -0700 +Subject: [PATCH 60/69] HACK: arch: arm: force ZRELADDR on arch-qcom + +ARCH_QCOM is using the ARCH_MULTIPLATFORM option, as now recommended +on most ARM architectures. This automatically calculate ZRELADDR by +masking PHYS_OFFSET with 0xf8000000. + +However, on IPQ806x, the first ~20MB of RAM is reserved for the hardware +network accelerators, and the bootloader removes this section from the +layout passed from the ATAGS (when used). + +For newer bootloader, when DT is used, this is not a problem, we just +reserve this memory in the device tree. But if the bootloader doesn't +have DT support, then ATAGS have to be used. In this case, the ARM +decompressor will position the kernel in this low mem, which will not be +in the RAM section mapped by the bootloader, which means the kernel will +freeze in the middle of the boot process trying to map the memory. + +As a work around, this patch allows disabling AUTO_ZRELADDR when +ARCH_QCOM is selected. It makes the zImage usage possible on bootloaders +which don't support device-tree, which is the case on certain early +IPQ806x based designs. + +Signed-off-by: Mathieu Olivari +--- + arch/arm/Kconfig | 2 +- + arch/arm/Makefile | 2 ++ + arch/arm/mach-qcom/Makefile.boot | 1 + + 3 files changed, 4 insertions(+), 1 deletion(-) + create mode 100644 arch/arm/mach-qcom/Makefile.boot + +--- a/arch/arm/Kconfig ++++ b/arch/arm/Kconfig +@@ -318,7 +318,7 @@ config ARCH_MULTIPLATFORM + depends on MMU + select ARM_HAS_SG_CHAIN + select ARM_PATCH_PHYS_VIRT +- select AUTO_ZRELADDR ++ select AUTO_ZRELADDR if !ARCH_QCOM + select TIMER_OF + select COMMON_CLK + select GENERIC_CLOCKEVENTS +--- a/arch/arm/Makefile ++++ b/arch/arm/Makefile +@@ -258,9 +258,11 @@ MACHINE := arch/arm/mach-$(word 1,$(mac + else + MACHINE := + endif ++ifeq ($(CONFIG_ARCH_QCOM),) + ifeq ($(CONFIG_ARCH_MULTIPLATFORM),y) + MACHINE := + endif ++endif + + machdirs := $(patsubst %,arch/arm/mach-%/,$(machine-y)) + platdirs := $(patsubst %,arch/arm/plat-%/,$(sort $(plat-y))) +--- /dev/null ++++ b/arch/arm/mach-qcom/Makefile.boot +@@ -0,0 +1 @@ ++zreladdr-y+= 0x42208000 diff --git a/target/linux/ipq806x/patches-5.10/0061-mtd-rootfs-conflicts-with-OpenWrt-auto-mounting.patch b/target/linux/ipq806x/patches-5.10/0061-mtd-rootfs-conflicts-with-OpenWrt-auto-mounting.patch new file mode 100644 index 0000000000..ff6f6edf49 --- /dev/null +++ b/target/linux/ipq806x/patches-5.10/0061-mtd-rootfs-conflicts-with-OpenWrt-auto-mounting.patch @@ -0,0 +1,23 @@ +From 5001f2e1a325b68dbf225bd17f69a4d3d975cca5 Mon Sep 17 00:00:00 2001 +From: John Crispin +Date: Thu, 9 Mar 2017 09:31:44 +0100 +Subject: [PATCH 61/69] mtd: "rootfs" conflicts with OpenWrt auto mounting + +Signed-off-by: John Crispin +--- + drivers/mtd/parsers/qcom_smem_part.c | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/drivers/mtd/parsers/qcom_smem_part.c ++++ b/drivers/mtd/parsers/qcom_smem_part.c +@@ -189,6 +189,10 @@ static int parse_qcom_smem_partitions(st + m_part->size = le32_to_cpu(s_part->size) * (*smem_blksz); + m_part->offset = le32_to_cpu(s_part->start) * (*smem_blksz); + ++ /* "rootfs" conflicts with OpenWrt auto mounting */ ++ if (mtd_type_is_nand(master) && !strcmp(m_part->name, "rootfs")) ++ m_part->name = "ubi"; ++ + /* + * The last SMEM partition may have its size marked as + * something like 0xffffffff, which means "until the end of the diff --git a/target/linux/ipq806x/patches-5.10/0063-1-ipq806x-tsens-driver.patch b/target/linux/ipq806x/patches-5.10/0063-1-ipq806x-tsens-driver.patch new file mode 100644 index 0000000000..80954c17fd --- /dev/null +++ b/target/linux/ipq806x/patches-5.10/0063-1-ipq806x-tsens-driver.patch @@ -0,0 +1,616 @@ +From 3302e1e1a3cfa4e67fda2a61d6f0c42205d40932 Mon Sep 17 00:00:00 2001 +From: Rajith Cherian +Date: Tue, 14 Feb 2017 18:30:43 +0530 +Subject: [PATCH] ipq8064: tsens: Base tsens driver for IPQ8064 + +Add TSENS driver template to support IPQ8064. +This is a base file copied from tsens-8960.c + +Change-Id: I47c573fdfa2d898243c6a6ba952d1632f91391f7 +Signed-off-by: Rajith Cherian + +ipq8064: tsens: TSENS driver support for IPQ8064 + +Support for IPQ8064 tsens driver. The driver works +with the thermal framework. The driver overrides the +following fucntionalities: + +1. Get current temperature. +2. Get/Set trip temperatures. +3. Enabled/Disable trip points. +4. ISR for threshold generated interrupt. +5. Notify userspace when trip points are hit. + +Change-Id: I8bc7204fd627d10875ab13fc1de8cb6c2ed7a918 +Signed-off-by: Rajith Cherian +--- + +--- a/drivers/thermal/qcom/Makefile ++++ b/drivers/thermal/qcom/Makefile +@@ -2,5 +2,5 @@ + obj-$(CONFIG_QCOM_TSENS) += qcom_tsens.o + + qcom_tsens-y += tsens.o tsens-common.o tsens-v0_1.o \ +- tsens-8960.o tsens-v2.o tsens-v1.o ++ tsens-8960.o tsens-v2.o tsens-v1.o tsens-ipq8064.o + obj-$(CONFIG_QCOM_SPMI_TEMP_ALARM) += qcom-spmi-temp-alarm.o +--- /dev/null ++++ b/drivers/thermal/qcom/tsens-ipq8064.c +@@ -0,0 +1,551 @@ ++/* ++ * Copyright (c) 2015, The Linux Foundation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 and ++ * only version 2 as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "tsens.h" ++ ++#define CAL_MDEGC 30000 ++ ++#define CONFIG_ADDR 0x3640 ++/* CONFIG_ADDR bitmasks */ ++#define CONFIG 0x9b ++#define CONFIG_MASK 0xf ++#define CONFIG_SHIFT 0 ++ ++#define STATUS_CNTL_8064 0x3660 ++#define CNTL_ADDR 0x3620 ++/* CNTL_ADDR bitmasks */ ++#define EN BIT(0) ++#define SW_RST BIT(1) ++#define SENSOR0_EN BIT(3) ++#define SLP_CLK_ENA BIT(26) ++#define MEASURE_PERIOD 1 ++#define SENSOR0_SHIFT 3 ++ ++/* INT_STATUS_ADDR bitmasks */ ++#define MIN_STATUS_MASK BIT(0) ++#define LOWER_STATUS_CLR BIT(1) ++#define UPPER_STATUS_CLR BIT(2) ++#define MAX_STATUS_MASK BIT(3) ++ ++#define THRESHOLD_ADDR 0x3624 ++/* THRESHOLD_ADDR bitmasks */ ++#define THRESHOLD_MAX_CODE 0x20000 ++#define THRESHOLD_MIN_CODE 0 ++#define THRESHOLD_MAX_LIMIT_SHIFT 24 ++#define THRESHOLD_MIN_LIMIT_SHIFT 16 ++#define THRESHOLD_UPPER_LIMIT_SHIFT 8 ++#define THRESHOLD_LOWER_LIMIT_SHIFT 0 ++#define THRESHOLD_MAX_LIMIT_MASK (THRESHOLD_MAX_CODE << \ ++ THRESHOLD_MAX_LIMIT_SHIFT) ++#define THRESHOLD_MIN_LIMIT_MASK (THRESHOLD_MAX_CODE << \ ++ THRESHOLD_MIN_LIMIT_SHIFT) ++#define THRESHOLD_UPPER_LIMIT_MASK (THRESHOLD_MAX_CODE << \ ++ THRESHOLD_UPPER_LIMIT_SHIFT) ++#define THRESHOLD_LOWER_LIMIT_MASK (THRESHOLD_MAX_CODE << \ ++ THRESHOLD_LOWER_LIMIT_SHIFT) ++ ++/* Initial temperature threshold values */ ++#define LOWER_LIMIT_TH 0x9d /* 95C */ ++#define UPPER_LIMIT_TH 0xa6 /* 105C */ ++#define MIN_LIMIT_TH 0x0 ++#define MAX_LIMIT_TH 0xff ++ ++#define S0_STATUS_ADDR 0x3628 ++#define STATUS_ADDR_OFFSET 2 ++#define SENSOR_STATUS_SIZE 4 ++#define INT_STATUS_ADDR 0x363c ++#define TRDY_MASK BIT(7) ++#define TIMEOUT_US 100 ++ ++#define TSENS_EN BIT(0) ++#define TSENS_SW_RST BIT(1) ++#define TSENS_ADC_CLK_SEL BIT(2) ++#define SENSOR0_EN BIT(3) ++#define SENSOR1_EN BIT(4) ++#define SENSOR2_EN BIT(5) ++#define SENSOR3_EN BIT(6) ++#define SENSOR4_EN BIT(7) ++#define SENSORS_EN (SENSOR0_EN | SENSOR1_EN | \ ++ SENSOR2_EN | SENSOR3_EN | SENSOR4_EN) ++#define TSENS_8064_SENSOR5_EN BIT(8) ++#define TSENS_8064_SENSOR6_EN BIT(9) ++#define TSENS_8064_SENSOR7_EN BIT(10) ++#define TSENS_8064_SENSOR8_EN BIT(11) ++#define TSENS_8064_SENSOR9_EN BIT(12) ++#define TSENS_8064_SENSOR10_EN BIT(13) ++#define TSENS_8064_SENSORS_EN (SENSORS_EN | \ ++ TSENS_8064_SENSOR5_EN | \ ++ TSENS_8064_SENSOR6_EN | \ ++ TSENS_8064_SENSOR7_EN | \ ++ TSENS_8064_SENSOR8_EN | \ ++ TSENS_8064_SENSOR9_EN | \ ++ TSENS_8064_SENSOR10_EN) ++ ++#define TSENS_8064_SEQ_SENSORS 5 ++#define TSENS_8064_S4_S5_OFFSET 40 ++#define TSENS_FACTOR 1 ++ ++/* Trips: from very hot to very cold */ ++enum tsens_trip_type { ++ TSENS_TRIP_STAGE3 = 0, ++ TSENS_TRIP_STAGE2, ++ TSENS_TRIP_STAGE1, ++ TSENS_TRIP_STAGE0, ++ TSENS_TRIP_NUM, ++}; ++ ++u32 tsens_8064_slope[] = { ++ 1176, 1176, 1154, 1176, ++ 1111, 1132, 1132, 1199, ++ 1132, 1199, 1132 ++ }; ++ ++/* Temperature on y axis and ADC-code on x-axis */ ++static inline int code_to_degC(u32 adc_code, const struct tsens_sensor *s) ++{ ++ int degcbeforefactor, degc; ++ ++ degcbeforefactor = (adc_code * s->slope) + s->offset; ++ ++ if (degcbeforefactor == 0) ++ degc = degcbeforefactor; ++ else if (degcbeforefactor > 0) ++ degc = (degcbeforefactor + TSENS_FACTOR/2) ++ / TSENS_FACTOR; ++ else ++ degc = (degcbeforefactor - TSENS_FACTOR/2) ++ / TSENS_FACTOR; ++ ++ return degc; ++} ++ ++static int degC_to_code(int degC, const struct tsens_sensor *s) ++{ ++ int code = ((degC * TSENS_FACTOR - s->offset) + (s->slope/2)) ++ / s->slope; ++ ++ if (code > THRESHOLD_MAX_CODE) ++ code = THRESHOLD_MAX_CODE; ++ else if (code < THRESHOLD_MIN_CODE) ++ code = THRESHOLD_MIN_CODE; ++ return code; ++} ++ ++static int suspend_ipq8064(struct tsens_priv *priv) ++{ ++ int ret; ++ unsigned int mask; ++ struct regmap *map = priv->tm_map; ++ ++ ret = regmap_read(map, THRESHOLD_ADDR, &priv->ctx.threshold); ++ if (ret) ++ return ret; ++ ++ ret = regmap_read(map, CNTL_ADDR, &priv->ctx.control); ++ if (ret) ++ return ret; ++ ++ mask = SLP_CLK_ENA | EN; ++ ++ ret = regmap_update_bits(map, CNTL_ADDR, mask, 0); ++ if (ret) ++ return ret; ++ ++ return 0; ++} ++ ++static int resume_ipq8064(struct tsens_priv *priv) ++{ ++ int ret; ++ struct regmap *map = priv->tm_map; ++ ++ ret = regmap_update_bits(map, CNTL_ADDR, SW_RST, SW_RST); ++ if (ret) ++ return ret; ++ ++ ret = regmap_update_bits(map, CONFIG_ADDR, CONFIG_MASK, CONFIG); ++ if (ret) ++ return ret; ++ ++ ret = regmap_write(map, THRESHOLD_ADDR, priv->ctx.threshold); ++ if (ret) ++ return ret; ++ ++ ret = regmap_write(map, CNTL_ADDR, priv->ctx.control); ++ if (ret) ++ return ret; ++ ++ return 0; ++} ++ ++static void notify_uspace_tsens_fn(struct work_struct *work) ++{ ++ struct tsens_sensor *s = container_of(work, struct tsens_sensor, ++ notify_work); ++ ++ sysfs_notify(&s->tzd->device.kobj, NULL, "type"); ++} ++ ++static void tsens_scheduler_fn(struct work_struct *work) ++{ ++ struct tsens_priv *priv = container_of(work, struct tsens_priv, ++ tsens_work); ++ unsigned int threshold, threshold_low, code, reg, sensor, mask; ++ unsigned int sensor_addr; ++ bool upper_th_x, lower_th_x; ++ int adc_code, ret; ++ ++ ret = regmap_read(priv->tm_map, STATUS_CNTL_8064, ®); ++ if (ret) ++ return; ++ reg = reg | LOWER_STATUS_CLR | UPPER_STATUS_CLR; ++ ret = regmap_write(priv->tm_map, STATUS_CNTL_8064, reg); ++ if (ret) ++ return; ++ ++ mask = ~(LOWER_STATUS_CLR | UPPER_STATUS_CLR); ++ ret = regmap_read(priv->tm_map, THRESHOLD_ADDR, &threshold); ++ if (ret) ++ return; ++ threshold_low = (threshold & THRESHOLD_LOWER_LIMIT_MASK) ++ >> THRESHOLD_LOWER_LIMIT_SHIFT; ++ threshold = (threshold & THRESHOLD_UPPER_LIMIT_MASK) ++ >> THRESHOLD_UPPER_LIMIT_SHIFT; ++ ++ ret = regmap_read(priv->tm_map, STATUS_CNTL_8064, ®); ++ if (ret) ++ return; ++ ++ ret = regmap_read(priv->tm_map, CNTL_ADDR, &sensor); ++ if (ret) ++ return; ++ sensor &= (uint32_t) TSENS_8064_SENSORS_EN; ++ sensor >>= SENSOR0_SHIFT; ++ ++ /* Constraint: There is only 1 interrupt control register for all ++ * 11 temperature sensor. So monitoring more than 1 sensor based ++ * on interrupts will yield inconsistent result. To overcome this ++ * issue we will monitor only sensor 0 which is the master sensor. ++ */ ++ ++ /* Skip if the sensor is disabled */ ++ if (sensor & 1) { ++ ret = regmap_read(priv->tm_map, priv->sensor[0].status, &code); ++ if (ret) ++ return; ++ upper_th_x = code >= threshold; ++ lower_th_x = code <= threshold_low; ++ if (upper_th_x) ++ mask |= UPPER_STATUS_CLR; ++ if (lower_th_x) ++ mask |= LOWER_STATUS_CLR; ++ if (upper_th_x || lower_th_x) { ++ /* Notify user space */ ++ schedule_work(&priv->sensor[0].notify_work); ++ regmap_read(priv->tm_map, sensor_addr, &adc_code); ++ pr_debug("Trigger (%d degrees) for sensor %d\n", ++ code_to_degC(adc_code, &priv->sensor[0]), 0); ++ } ++ } ++ regmap_write(priv->tm_map, STATUS_CNTL_8064, reg & mask); ++ ++ /* force memory to sync */ ++ mb(); ++} ++ ++static irqreturn_t tsens_isr(int irq, void *data) ++{ ++ struct tsens_priv *priv = data; ++ ++ schedule_work(&priv->tsens_work); ++ return IRQ_HANDLED; ++} ++ ++static void hw_init(struct tsens_priv *priv) ++{ ++ int ret; ++ unsigned int reg_cntl = 0, reg_cfg = 0, reg_thr = 0; ++ unsigned int reg_status_cntl = 0; ++ ++ regmap_read(priv->tm_map, CNTL_ADDR, ®_cntl); ++ regmap_write(priv->tm_map, CNTL_ADDR, reg_cntl | TSENS_SW_RST); ++ ++ reg_cntl |= SLP_CLK_ENA | (MEASURE_PERIOD << 18) ++ | (((1 << priv->num_sensors) - 1) << SENSOR0_SHIFT); ++ regmap_write(priv->tm_map, CNTL_ADDR, reg_cntl); ++ regmap_read(priv->tm_map, STATUS_CNTL_8064, ®_status_cntl); ++ reg_status_cntl |= LOWER_STATUS_CLR | UPPER_STATUS_CLR ++ | MIN_STATUS_MASK | MAX_STATUS_MASK; ++ regmap_write(priv->tm_map, STATUS_CNTL_8064, reg_status_cntl); ++ reg_cntl |= TSENS_EN; ++ regmap_write(priv->tm_map, CNTL_ADDR, reg_cntl); ++ ++ regmap_read(priv->tm_map, CONFIG_ADDR, ®_cfg); ++ reg_cfg = (reg_cfg & ~CONFIG_MASK) | (CONFIG << CONFIG_SHIFT); ++ regmap_write(priv->tm_map, CONFIG_ADDR, reg_cfg); ++ ++ reg_thr |= (LOWER_LIMIT_TH << THRESHOLD_LOWER_LIMIT_SHIFT) ++ | (UPPER_LIMIT_TH << THRESHOLD_UPPER_LIMIT_SHIFT) ++ | (MIN_LIMIT_TH << THRESHOLD_MIN_LIMIT_SHIFT) ++ | (MAX_LIMIT_TH << THRESHOLD_MAX_LIMIT_SHIFT); ++ ++ regmap_write(priv->tm_map, THRESHOLD_ADDR, reg_thr); ++ ++ ret = devm_request_irq(priv->dev, priv->tsens_irq, tsens_isr, ++ IRQF_TRIGGER_RISING, "tsens_interrupt", priv); ++ if (ret < 0) { ++ pr_err("%s: request_irq FAIL: %d\n", __func__, ret); ++ return; ++ } ++ ++ INIT_WORK(&priv->tsens_work, tsens_scheduler_fn); ++} ++ ++static int init_ipq8064(struct tsens_priv *priv) ++{ ++ int ret, i; ++ u32 reg_cntl, offset = 0; ++ ++ init_common(priv); ++ if (!priv->tm_map) ++ return -ENODEV; ++ ++ /* ++ * The status registers for each sensor are discontiguous ++ * because some SoCs have 5 sensors while others have more ++ * but the control registers stay in the same place, i.e ++ * directly after the first 5 status registers. ++ */ ++ for (i = 0; i < priv->num_sensors; i++) { ++ if (i >= TSENS_8064_SEQ_SENSORS) ++ offset = TSENS_8064_S4_S5_OFFSET; ++ ++ priv->sensor[i].status = S0_STATUS_ADDR + offset ++ + (i << STATUS_ADDR_OFFSET); ++ priv->sensor[i].slope = tsens_8064_slope[i]; ++ INIT_WORK(&priv->sensor[i].notify_work, ++ notify_uspace_tsens_fn); ++ } ++ ++ reg_cntl = SW_RST; ++ ret = regmap_update_bits(priv->tm_map, CNTL_ADDR, SW_RST, reg_cntl); ++ if (ret) ++ return ret; ++ ++ reg_cntl |= SLP_CLK_ENA | (MEASURE_PERIOD << 18); ++ reg_cntl &= ~SW_RST; ++ ret = regmap_update_bits(priv->tm_map, CONFIG_ADDR, ++ CONFIG_MASK, CONFIG); ++ ++ reg_cntl |= GENMASK(priv->num_sensors - 1, 0) << SENSOR0_SHIFT; ++ ret = regmap_write(priv->tm_map, CNTL_ADDR, reg_cntl); ++ if (ret) ++ return ret; ++ ++ reg_cntl |= EN; ++ ret = regmap_write(priv->tm_map, CNTL_ADDR, reg_cntl); ++ if (ret) ++ return ret; ++ ++ return 0; ++} ++ ++static int calibrate_ipq8064(struct tsens_priv *priv) ++{ ++ int i; ++ char *data, *data_backup; ++ ++ ssize_t num_read = priv->num_sensors; ++ struct tsens_sensor *s = priv->sensor; ++ ++ data = qfprom_read(priv->dev, "calib"); ++ if (IS_ERR(data)) { ++ pr_err("Calibration not found.\n"); ++ return PTR_ERR(data); ++ } ++ ++ data_backup = qfprom_read(priv->dev, "calib_backup"); ++ if (IS_ERR(data_backup)) { ++ pr_err("Backup calibration not found.\n"); ++ return PTR_ERR(data_backup); ++ } ++ ++ for (i = 0; i < num_read; i++) { ++ s[i].calib_data = readb_relaxed(data + i); ++ s[i].calib_data_backup = readb_relaxed(data_backup + i); ++ ++ if (s[i].calib_data_backup) ++ s[i].calib_data = s[i].calib_data_backup; ++ if (!s[i].calib_data) { ++ pr_err("QFPROM TSENS calibration data not present\n"); ++ return -ENODEV; ++ } ++ s[i].slope = tsens_8064_slope[i]; ++ s[i].offset = CAL_MDEGC - (s[i].calib_data * s[i].slope); ++ } ++ ++ hw_init(priv); ++ ++ return 0; ++} ++ ++static int get_temp_ipq8064(struct tsens_priv *priv, int id, int *temp) ++{ ++ int ret; ++ u32 code, trdy; ++ const struct tsens_sensor *s = &priv->sensor[id]; ++ unsigned long timeout; ++ ++ timeout = jiffies + usecs_to_jiffies(TIMEOUT_US); ++ do { ++ ret = regmap_read(priv->tm_map, INT_STATUS_ADDR, &trdy); ++ if (ret) ++ return ret; ++ if (!(trdy & TRDY_MASK)) ++ continue; ++ ret = regmap_read(priv->tm_map, s->status, &code); ++ if (ret) ++ return ret; ++ *temp = code_to_degC(code, s); ++ return 0; ++ } while (time_before(jiffies, timeout)); ++ ++ return -ETIMEDOUT; ++} ++ ++static int set_trip_temp_ipq8064(void *data, int trip, int temp) ++{ ++ unsigned int reg_th, reg_cntl; ++ int ret, code, code_chk, hi_code, lo_code; ++ const struct tsens_sensor *s = data; ++ struct tsens_priv *priv = s->priv; ++ ++ code_chk = code = degC_to_code(temp, s); ++ ++ if (code < THRESHOLD_MIN_CODE || code > THRESHOLD_MAX_CODE) ++ return -EINVAL; ++ ++ ret = regmap_read(priv->tm_map, STATUS_CNTL_8064, ®_cntl); ++ if (ret) ++ return ret; ++ ++ ret = regmap_read(priv->tm_map, THRESHOLD_ADDR, ®_th); ++ if (ret) ++ return ret; ++ ++ hi_code = (reg_th & THRESHOLD_UPPER_LIMIT_MASK) ++ >> THRESHOLD_UPPER_LIMIT_SHIFT; ++ lo_code = (reg_th & THRESHOLD_LOWER_LIMIT_MASK) ++ >> THRESHOLD_LOWER_LIMIT_SHIFT; ++ ++ switch (trip) { ++ case TSENS_TRIP_STAGE3: ++ code <<= THRESHOLD_MAX_LIMIT_SHIFT; ++ reg_th &= ~THRESHOLD_MAX_LIMIT_MASK; ++ break; ++ case TSENS_TRIP_STAGE2: ++ if (code_chk <= lo_code) ++ return -EINVAL; ++ code <<= THRESHOLD_UPPER_LIMIT_SHIFT; ++ reg_th &= ~THRESHOLD_UPPER_LIMIT_MASK; ++ break; ++ case TSENS_TRIP_STAGE1: ++ if (code_chk >= hi_code) ++ return -EINVAL; ++ code <<= THRESHOLD_LOWER_LIMIT_SHIFT; ++ reg_th &= ~THRESHOLD_LOWER_LIMIT_MASK; ++ break; ++ case TSENS_TRIP_STAGE0: ++ code <<= THRESHOLD_MIN_LIMIT_SHIFT; ++ reg_th &= ~THRESHOLD_MIN_LIMIT_MASK; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ ret = regmap_write(priv->tm_map, THRESHOLD_ADDR, reg_th | code); ++ if (ret) ++ return ret; ++ ++ return 0; ++} ++ ++static int set_trip_activate_ipq8064(void *data, int trip, ++ enum thermal_trip_activation_mode mode) ++{ ++ unsigned int reg_cntl, mask, val; ++ const struct tsens_sensor *s = data; ++ struct tsens_priv *priv = s->priv; ++ int ret; ++ ++ if (!priv || trip < 0) ++ return -EINVAL; ++ ++ ret = regmap_read(priv->tm_map, STATUS_CNTL_8064, ®_cntl); ++ if (ret) ++ return ret; ++ ++ switch (trip) { ++ case TSENS_TRIP_STAGE3: ++ mask = MAX_STATUS_MASK; ++ break; ++ case TSENS_TRIP_STAGE2: ++ mask = UPPER_STATUS_CLR; ++ break; ++ case TSENS_TRIP_STAGE1: ++ mask = LOWER_STATUS_CLR; ++ break; ++ case TSENS_TRIP_STAGE0: ++ mask = MIN_STATUS_MASK; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ if (mode == THERMAL_TRIP_ACTIVATION_DISABLED) ++ val = reg_cntl | mask; ++ else ++ val = reg_cntl & ~mask; ++ ++ ret = regmap_write(priv->tm_map, STATUS_CNTL_8064, val); ++ if (ret) ++ return ret; ++ ++ /* force memory to sync */ ++ mb(); ++ return 0; ++} ++ ++const struct tsens_ops ops_ipq8064 = { ++ .init = init_ipq8064, ++ .calibrate = calibrate_ipq8064, ++ .get_temp = get_temp_ipq8064, ++ .suspend = suspend_ipq8064, ++ .resume = resume_ipq8064, ++ .set_trip_temp = set_trip_temp_ipq8064, ++ .set_trip_activate = set_trip_activate_ipq8064, ++}; ++ ++const struct tsens_plat_data data_ipq8064 = { ++ .num_sensors = 11, ++ .ops = &ops_ipq8064, ++}; +--- a/drivers/thermal/qcom/tsens.c ++++ b/drivers/thermal/qcom/tsens.c +@@ -69,8 +69,11 @@ static const struct of_device_id tsens_t + }, { + .compatible = "qcom,tsens-v2", + .data = &data_tsens_v2, ++ }, { ++ .compatible = "qcom,ipq8064-tsens", ++ .data = &data_ipq8064, + }, +- {} ++ {} + }; + MODULE_DEVICE_TABLE(of, tsens_table); + +--- a/drivers/thermal/qcom/tsens.h ++++ b/drivers/thermal/qcom/tsens.h +@@ -324,7 +324,7 @@ extern const struct tsens_plat_data data + extern const struct tsens_plat_data data_8916, data_8974; + + /* TSENS v1 targets */ +-extern const struct tsens_plat_data data_tsens_v1; ++extern const struct tsens_plat_data data_tsens_v1, data_ipq8064; + + /* TSENS v2 targets */ + extern const struct tsens_plat_data data_8996, data_tsens_v2; diff --git a/target/linux/ipq806x/patches-5.10/0063-2-tsens-support-configurable-interrupts.patch b/target/linux/ipq806x/patches-5.10/0063-2-tsens-support-configurable-interrupts.patch new file mode 100644 index 0000000000..585bd62a58 --- /dev/null +++ b/target/linux/ipq806x/patches-5.10/0063-2-tsens-support-configurable-interrupts.patch @@ -0,0 +1,437 @@ +From 4e87400732c77765afae2ea89ed43837457aa604 Mon Sep 17 00:00:00 2001 +From: Rajith Cherian +Date: Wed, 1 Feb 2017 19:00:26 +0530 +Subject: [PATCH] ipq8064: tsens: Support for configurable interrupts + +Provide support for adding configurable high and +configurable low trip temperatures. An interrupts is +also triggerred when these trip points are hit. The +interrupts can be activated or deactivated from sysfs. +This functionality is made available only if +CONFIG_THERMAL_WRITABLE_TRIPS is defined. + +Change-Id: Ib73f3f9459de4fffce7bb985a0312a88291f4934 +Signed-off-by: Rajith Cherian +--- + .../devicetree/bindings/thermal/qcom-tsens.txt | 4 ++ + drivers/thermal/of-thermal.c | 63 ++++++++++++++++++---- + drivers/thermal/qcom/tsens.c | 43 ++++++++++++--- + drivers/thermal/qcom/tsens.h | 11 ++++ + drivers/thermal/thermal_core.c | 44 ++++++++++++++- + include/linux/thermal.h | 14 +++++ + 6 files changed, 162 insertions(+), 17 deletions(-) + +--- a/drivers/thermal/of-thermal.c ++++ b/drivers/thermal/of-thermal.c +@@ -91,7 +91,7 @@ static int of_thermal_get_temp(struct th + { + struct __thermal_zone *data = tz->devdata; + +- if (!data->ops->get_temp) ++ if (!data->ops->get_temp || (data->mode == THERMAL_DEVICE_DISABLED)) + return -EINVAL; + + return data->ops->get_temp(data->sensor_data, temp); +@@ -102,7 +102,8 @@ static int of_thermal_set_trips(struct t + { + struct __thermal_zone *data = tz->devdata; + +- if (!data->ops || !data->ops->set_trips) ++ if (!data->ops || !data->ops->set_trips ++ || (data->mode == THERMAL_DEVICE_DISABLED)) + return -EINVAL; + + return data->ops->set_trips(data->sensor_data, low, high); +@@ -188,6 +189,9 @@ static int of_thermal_set_emul_temp(stru + { + struct __thermal_zone *data = tz->devdata; + ++ if (data->mode == THERMAL_DEVICE_DISABLED) ++ return -EINVAL; ++ + return data->ops->set_emul_temp(data->sensor_data, temp); + } + +@@ -196,7 +200,7 @@ static int of_thermal_get_trend(struct t + { + struct __thermal_zone *data = tz->devdata; + +- if (!data->ops->get_trend) ++ if (!data->ops->get_trend || (data->mode == THERMAL_DEVICE_DISABLED)) + return -EINVAL; + + return data->ops->get_trend(data->sensor_data, trip, trend); +@@ -297,7 +301,9 @@ static int of_thermal_set_mode(struct th + mutex_unlock(&tz->lock); + + data->mode = mode; +- thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED); ++ ++ if (mode == THERMAL_DEVICE_ENABLED) ++ thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED); + + return 0; + } +@@ -307,7 +313,8 @@ static int of_thermal_get_trip_type(stru + { + struct __thermal_zone *data = tz->devdata; + +- if (trip >= data->ntrips || trip < 0) ++ if (trip >= data->ntrips || trip < 0 ++ || (data->mode == THERMAL_DEVICE_DISABLED)) + return -EDOM; + + *type = data->trips[trip].type; +@@ -315,12 +322,39 @@ static int of_thermal_get_trip_type(stru + return 0; + } + ++static int of_thermal_activate_trip_type(struct thermal_zone_device *tz, ++ int trip, enum thermal_trip_activation_mode mode) ++{ ++ struct __thermal_zone *data = tz->devdata; ++ ++ if (trip >= data->ntrips || trip < 0 ++ || (data->mode == THERMAL_DEVICE_DISABLED)) ++ return -EDOM; ++ ++ /* ++ * The configurable_hi and configurable_lo trip points can be ++ * activated and deactivated. ++ */ ++ ++ if (data->ops->set_trip_activate) { ++ int ret; ++ ++ ret = data->ops->set_trip_activate(data->sensor_data, ++ trip, mode); ++ if (ret) ++ return ret; ++ } ++ ++ return 0; ++} ++ + static int of_thermal_get_trip_temp(struct thermal_zone_device *tz, int trip, + int *temp) + { + struct __thermal_zone *data = tz->devdata; + +- if (trip >= data->ntrips || trip < 0) ++ if (trip >= data->ntrips || trip < 0 ++ || (data->mode == THERMAL_DEVICE_DISABLED)) + return -EDOM; + + *temp = data->trips[trip].temperature; +@@ -333,7 +367,8 @@ static int of_thermal_set_trip_temp(stru + { + struct __thermal_zone *data = tz->devdata; + +- if (trip >= data->ntrips || trip < 0) ++ if (trip >= data->ntrips || trip < 0 ++ || (data->mode == THERMAL_DEVICE_DISABLED)) + return -EDOM; + + if (data->ops->set_trip_temp) { +@@ -355,7 +390,8 @@ static int of_thermal_get_trip_hyst(stru + { + struct __thermal_zone *data = tz->devdata; + +- if (trip >= data->ntrips || trip < 0) ++ if (trip >= data->ntrips || trip < 0 ++ || (data->mode == THERMAL_DEVICE_DISABLED)) + return -EDOM; + + *hyst = data->trips[trip].hysteresis; +@@ -368,7 +404,8 @@ static int of_thermal_set_trip_hyst(stru + { + struct __thermal_zone *data = tz->devdata; + +- if (trip >= data->ntrips || trip < 0) ++ if (trip >= data->ntrips || trip < 0 ++ || (data->mode == THERMAL_DEVICE_DISABLED)) + return -EDOM; + + /* thermal framework should take care of data->mask & (1 << trip) */ +@@ -443,6 +480,9 @@ thermal_zone_of_add_sensor(struct device + if (ops->set_emul_temp) + tzd->ops->set_emul_temp = of_thermal_set_emul_temp; + ++ if (ops->set_trip_activate) ++ tzd->ops->set_trip_activate = of_thermal_activate_trip_type; ++ + mutex_unlock(&tzd->lock); + + return tzd; +@@ -762,7 +802,10 @@ static const char * const trip_types[] = + [THERMAL_TRIP_ACTIVE] = "active", + [THERMAL_TRIP_PASSIVE] = "passive", + [THERMAL_TRIP_HOT] = "hot", +- [THERMAL_TRIP_CRITICAL] = "critical", ++ [THERMAL_TRIP_CRITICAL] = "critical_high", ++ [THERMAL_TRIP_CONFIGURABLE_HI] = "configurable_hi", ++ [THERMAL_TRIP_CONFIGURABLE_LOW] = "configurable_lo", ++ [THERMAL_TRIP_CRITICAL_LOW] = "critical_low", + }; + + /** +--- a/drivers/thermal/qcom/tsens.c ++++ b/drivers/thermal/qcom/tsens.c +@@ -22,7 +22,7 @@ static int tsens_get_temp(void *data, in + + static int tsens_get_trend(void *data, int trip, enum thermal_trend *trend) + { +- const struct tsens_sensor *s = data; ++ struct tsens_sensor *s = data; + struct tsens_priv *priv = s->priv; + + if (priv->ops->get_trend) +@@ -31,9 +31,10 @@ static int tsens_get_trend(void *data, i + return -ENOTSUPP; + } + +-static int __maybe_unused tsens_suspend(struct device *dev) ++static int __maybe_unused tsens_suspend(void *data) + { +- struct tsens_priv *priv = dev_get_drvdata(dev); ++ struct tsens_sensor *s = data; ++ struct tsens_priv *priv = s->priv; + + if (priv->ops && priv->ops->suspend) + return priv->ops->suspend(priv); +@@ -41,9 +42,10 @@ static int __maybe_unused tsens_suspend + return 0; + } + +-static int __maybe_unused tsens_resume(struct device *dev) ++static int __maybe_unused tsens_resume(void *data) + { +- struct tsens_priv *priv = dev_get_drvdata(dev); ++ struct tsens_sensor *s = data; ++ struct tsens_priv *priv = s->priv; + + if (priv->ops && priv->ops->resume) + return priv->ops->resume(priv); +@@ -51,6 +53,30 @@ static int __maybe_unused tsens_resume(s + return 0; + } + ++static int __maybe_unused tsens_set_trip_temp(void *data, int trip, int temp) ++{ ++ struct tsens_sensor *s = data; ++ struct tsens_priv *priv = s->priv; ++ ++ if (priv->ops && priv->ops->set_trip_temp) ++ return priv->ops->set_trip_temp(s, trip, temp); ++ ++ return 0; ++} ++ ++static int __maybe_unused tsens_activate_trip_type(void *data, int trip, ++ enum thermal_trip_activation_mode mode) ++{ ++ struct tsens_sensor *s = data; ++ struct tsens_priv *priv = s->priv; ++ ++ if (priv->ops && priv->ops->set_trip_activate) ++ return priv->ops->set_trip_activate(s, trip, mode); ++ ++ return 0; ++} ++ ++ + static SIMPLE_DEV_PM_OPS(tsens_pm_ops, tsens_suspend, tsens_resume); + + static const struct of_device_id tsens_table[] = { +@@ -80,6 +106,8 @@ MODULE_DEVICE_TABLE(of, tsens_table); + static const struct thermal_zone_of_device_ops tsens_of_ops = { + .get_temp = tsens_get_temp, + .get_trend = tsens_get_trend, ++ .set_trip_temp = tsens_set_trip_temp, ++ .set_trip_activate = tsens_activate_trip_type, + }; + + static int tsens_register(struct tsens_priv *priv) +@@ -123,7 +151,7 @@ static int tsens_probe(struct platform_d + if (id) + data = id->data; + else +- data = &data_8960; ++ return -EINVAL; + + num_sensors = data->num_sensors; + +@@ -144,6 +172,9 @@ static int tsens_probe(struct platform_d + priv->dev = dev; + priv->num_sensors = num_sensors; + priv->ops = data->ops; ++ ++ priv->tsens_irq = platform_get_irq(pdev, 0); ++ + for (i = 0; i < priv->num_sensors; i++) { + if (data->hw_ids) + priv->sensor[i].hw_id = data->hw_ids[i]; +--- a/drivers/thermal/qcom/tsens.h ++++ b/drivers/thermal/qcom/tsens.h +@@ -40,9 +40,12 @@ enum tsens_ver { + struct tsens_sensor { + struct tsens_priv *priv; + struct thermal_zone_device *tzd; ++ struct work_struct notify_work; + int offset; + unsigned int id; + unsigned int hw_id; ++ int calib_data; ++ int calib_data_backup; + int slope; + u32 status; + }; +@@ -57,6 +60,9 @@ struct tsens_sensor { + * @suspend: Function to suspend the tsens device + * @resume: Function to resume the tsens device + * @get_trend: Function to get the thermal/temp trend ++ * @set_trip_temp: Function to set trip temp ++ * @get_trip_temp: Function to get trip temp ++ * @set_trip_activate: Function to activate trip points + */ + struct tsens_ops { + /* mandatory callbacks */ +@@ -69,6 +75,9 @@ struct tsens_ops { + int (*suspend)(struct tsens_priv *priv); + int (*resume)(struct tsens_priv *priv); + int (*get_trend)(struct tsens_priv *priv, int i, enum thermal_trend *trend); ++ int (*set_trip_temp)(void *data, int trip, int temp); ++ int (*set_trip_activate)(void *data, int trip, ++ enum thermal_trip_activation_mode mode); + }; + + #define REG_FIELD_FOR_EACH_SENSOR11(_name, _offset, _startbit, _stopbit) \ +@@ -300,6 +309,7 @@ struct tsens_context { + struct tsens_priv { + struct device *dev; + u32 num_sensors; ++ u32 tsens_irq; + struct regmap *tm_map; + struct regmap *srot_map; + u32 tm_offset; +@@ -308,6 +318,7 @@ struct tsens_priv { + const struct tsens_features *feat; + const struct reg_field *fields; + const struct tsens_ops *ops; ++ struct work_struct tsens_work; + struct tsens_sensor sensor[0]; + }; + +--- a/drivers/thermal/thermal_sysfs.c ++++ b/drivers/thermal/thermal_sysfs.c +@@ -113,12 +113,48 @@ trip_point_type_show(struct device *dev, + return sprintf(buf, "passive\n"); + case THERMAL_TRIP_ACTIVE: + return sprintf(buf, "active\n"); ++ case THERMAL_TRIP_CONFIGURABLE_HI: ++ return sprintf(buf, "configurable_hi\n"); ++ case THERMAL_TRIP_CONFIGURABLE_LOW: ++ return sprintf(buf, "configurable_low\n"); ++ case THERMAL_TRIP_CRITICAL_LOW: ++ return sprintf(buf, "critical_low\n"); + default: + return sprintf(buf, "unknown\n"); + } + } + + static ssize_t ++trip_point_type_activate(struct device *dev, struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ struct thermal_zone_device *tz = to_thermal_zone(dev); ++ int trip, ret; ++ char *enabled = "enabled"; ++ char *disabled = "disabled"; ++ ++ if (!tz->ops->set_trip_activate) ++ return -EPERM; ++ ++ if (!sscanf(attr->attr.name, "trip_point_%d_type", &trip)) ++ return -EINVAL; ++ ++ if (!strncmp(buf, enabled, strlen(enabled))) ++ ret = tz->ops->set_trip_activate(tz, trip, ++ THERMAL_TRIP_ACTIVATION_ENABLED); ++ else if (!strncmp(buf, disabled, strlen(disabled))) ++ ret = tz->ops->set_trip_activate(tz, trip, ++ THERMAL_TRIP_ACTIVATION_DISABLED); ++ else ++ ret = -EINVAL; ++ ++ if (ret) ++ return ret; ++ ++ return count; ++} ++ ++static ssize_t + trip_point_temp_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) + { +@@ -559,6 +595,12 @@ static int create_trip_attrs(struct ther + tz->trip_type_attrs[indx].attr.show = trip_point_type_show; + attrs[indx] = &tz->trip_type_attrs[indx].attr.attr; + ++ if (IS_ENABLED(CONFIG_THERMAL_WRITABLE_TRIPS)) { ++ tz->trip_type_attrs[indx].attr.store ++ = trip_point_type_activate; ++ tz->trip_type_attrs[indx].attr.attr.mode |= S_IWUSR; ++ } ++ + /* create trip temp attribute */ + snprintf(tz->trip_temp_attrs[indx].name, THERMAL_NAME_LENGTH, + "trip_point_%d_temp", indx); +--- a/include/linux/thermal.h ++++ b/include/linux/thermal.h +@@ -63,11 +63,19 @@ enum thermal_device_mode { + THERMAL_DEVICE_ENABLED, + }; + ++enum thermal_trip_activation_mode { ++ THERMAL_TRIP_ACTIVATION_DISABLED = 0, ++ THERMAL_TRIP_ACTIVATION_ENABLED, ++}; ++ + enum thermal_trip_type { + THERMAL_TRIP_ACTIVE = 0, + THERMAL_TRIP_PASSIVE, + THERMAL_TRIP_HOT, + THERMAL_TRIP_CRITICAL, ++ THERMAL_TRIP_CONFIGURABLE_HI, ++ THERMAL_TRIP_CONFIGURABLE_LOW, ++ THERMAL_TRIP_CRITICAL_LOW, + }; + + enum thermal_trend { +@@ -105,6 +113,8 @@ struct thermal_zone_device_ops { + enum thermal_trip_type *); + int (*get_trip_temp) (struct thermal_zone_device *, int, int *); + int (*set_trip_temp) (struct thermal_zone_device *, int, int); ++ int (*set_trip_activate) (struct thermal_zone_device *, int, ++ enum thermal_trip_activation_mode); + int (*get_trip_hyst) (struct thermal_zone_device *, int, int *); + int (*set_trip_hyst) (struct thermal_zone_device *, int, int); + int (*get_crit_temp) (struct thermal_zone_device *, int *); +@@ -349,6 +359,8 @@ struct thermal_genl_event { + * temperature. + * @set_trip_temp: a pointer to a function that sets the trip temperature on + * hardware. ++ * @activate_trip_type: a pointer to a function to enable/disable trip ++ * temperature interrupts + */ + struct thermal_zone_of_device_ops { + int (*get_temp)(void *, int *); +@@ -356,6 +368,8 @@ struct thermal_zone_of_device_ops { + int (*set_trips)(void *, int, int); + int (*set_emul_temp)(void *, int); + int (*set_trip_temp)(void *, int, int); ++ int (*set_trip_activate)(void *, int, ++ enum thermal_trip_activation_mode); + }; + + /** diff --git a/target/linux/ipq806x/patches-5.10/0063-3-tsens-fix-kernel-5_4.patch b/target/linux/ipq806x/patches-5.10/0063-3-tsens-fix-kernel-5_4.patch new file mode 100644 index 0000000000..6c056db3b7 --- /dev/null +++ b/target/linux/ipq806x/patches-5.10/0063-3-tsens-fix-kernel-5_4.patch @@ -0,0 +1,68 @@ +--- a/drivers/thermal/qcom/tsens-ipq8064.c ++++ b/drivers/thermal/qcom/tsens-ipq8064.c +@@ -18,6 +18,7 @@ + #include + #include + #include ++#include + #include + #include + #include "tsens.h" +@@ -320,15 +321,42 @@ static void hw_init(struct tsens_priv *p + INIT_WORK(&priv->tsens_work, tsens_scheduler_fn); + } + ++static const struct regmap_config tsens_config = { ++ .name = "tm", ++ .reg_bits = 32, ++ .val_bits = 32, ++ .reg_stride = 4, ++}; ++ + static int init_ipq8064(struct tsens_priv *priv) + { +- int ret, i; ++ struct device *dev = priv->dev; + u32 reg_cntl, offset = 0; ++ struct resource *res; ++ resource_size_t size; ++ void __iomem *base; ++ int ret, i; ++ struct platform_device *op = of_find_device_by_node(priv->dev->of_node); ++ ++ if (!op) ++ return -EINVAL; + +- init_common(priv); +- if (!priv->tm_map) +- return -ENODEV; ++ /* old DTs where SROT and TM were in a contiguous 2K block */ ++ priv->tm_offset = 0x1000; + ++ res = platform_get_resource(op, IORESOURCE_MEM, 0); ++ size = resource_size(res); ++ base = devm_ioremap(&op->dev, res->start, size); ++ if (IS_ERR(base)) { ++ ret = PTR_ERR(base); ++ goto err_put_device; ++ } ++ ++ priv->tm_map = devm_regmap_init_mmio(dev, base, &tsens_config); ++ if (IS_ERR(priv->tm_map)) { ++ ret = PTR_ERR(priv->tm_map); ++ goto err_put_device; ++ } + /* + * The status registers for each sensor are discontiguous + * because some SoCs have 5 sensors while others have more +@@ -367,6 +395,10 @@ static int init_ipq8064(struct tsens_pri + return ret; + + return 0; ++ ++err_put_device: ++ put_device(&op->dev); ++ return ret; + } + + static int calibrate_ipq8064(struct tsens_priv *priv) diff --git a/target/linux/ipq806x/patches-5.10/0063-4-ip806x-tsense-rework-driver.patch b/target/linux/ipq806x/patches-5.10/0063-4-ip806x-tsense-rework-driver.patch new file mode 100644 index 0000000000..67fc8db7a3 --- /dev/null +++ b/target/linux/ipq806x/patches-5.10/0063-4-ip806x-tsense-rework-driver.patch @@ -0,0 +1,107 @@ +--- a/drivers/thermal/qcom/tsens-ipq8064.c ++++ b/drivers/thermal/qcom/tsens-ipq8064.c +@@ -13,10 +13,12 @@ + */ + + #include ++#include + #include + #include + #include + #include ++#include + #include + #include + #include +@@ -211,9 +213,8 @@ static void tsens_scheduler_fn(struct wo + struct tsens_priv *priv = container_of(work, struct tsens_priv, + tsens_work); + unsigned int threshold, threshold_low, code, reg, sensor, mask; +- unsigned int sensor_addr; + bool upper_th_x, lower_th_x; +- int adc_code, ret; ++ int ret; + + ret = regmap_read(priv->tm_map, STATUS_CNTL_8064, ®); + if (ret) +@@ -262,9 +263,8 @@ static void tsens_scheduler_fn(struct wo + if (upper_th_x || lower_th_x) { + /* Notify user space */ + schedule_work(&priv->sensor[0].notify_work); +- regmap_read(priv->tm_map, sensor_addr, &adc_code); + pr_debug("Trigger (%d degrees) for sensor %d\n", +- code_to_degC(adc_code, &priv->sensor[0]), 0); ++ code_to_degC(code, &priv->sensor[0]), 0); + } + } + regmap_write(priv->tm_map, STATUS_CNTL_8064, reg & mask); +@@ -404,40 +404,55 @@ err_put_device: + static int calibrate_ipq8064(struct tsens_priv *priv) + { + int i; +- char *data, *data_backup; +- ++ int ret = 0; ++ u8 *data, *data_backup; ++ struct device *dev = priv->dev; + ssize_t num_read = priv->num_sensors; + struct tsens_sensor *s = priv->sensor; + +- data = qfprom_read(priv->dev, "calib"); ++ data = qfprom_read(dev, "calib"); + if (IS_ERR(data)) { +- pr_err("Calibration not found.\n"); +- return PTR_ERR(data); ++ ret = PTR_ERR(data); ++ if (ret != -EPROBE_DEFER) ++ dev_err(dev, "Calibration not found."); ++ goto exit; + } + +- data_backup = qfprom_read(priv->dev, "calib_backup"); ++ data_backup = qfprom_read(dev, "calib_backup"); + if (IS_ERR(data_backup)) { +- pr_err("Backup calibration not found.\n"); +- return PTR_ERR(data_backup); ++ ret = PTR_ERR(data_backup); ++ if (ret != -EPROBE_DEFER) ++ dev_err(dev, "Backup Calibration not found."); ++ goto free_data; + } + + for (i = 0; i < num_read; i++) { + s[i].calib_data = readb_relaxed(data + i); +- s[i].calib_data_backup = readb_relaxed(data_backup + i); ++ ++ if (!s[i].calib_data) { ++ s[i].calib_data_backup = readb_relaxed(data_backup + i); ++ ++ if (!s[i].calib_data_backup) { ++ dev_err(dev, "QFPROM TSENS calibration data not present"); ++ ret = -ENODEV; ++ goto free_backup; ++ } + +- if (s[i].calib_data_backup) + s[i].calib_data = s[i].calib_data_backup; +- if (!s[i].calib_data) { +- pr_err("QFPROM TSENS calibration data not present\n"); +- return -ENODEV; + } ++ + s[i].slope = tsens_8064_slope[i]; + s[i].offset = CAL_MDEGC - (s[i].calib_data * s[i].slope); + } + + hw_init(priv); + +- return 0; ++free_backup: ++ kfree(data_backup); ++free_data: ++ kfree(data); ++exit: ++ return ret; + } + + static int get_temp_ipq8064(struct tsens_priv *priv, int id, int *temp) diff --git a/target/linux/ipq806x/patches-5.10/0065-arm-override-compiler-flags.patch b/target/linux/ipq806x/patches-5.10/0065-arm-override-compiler-flags.patch new file mode 100644 index 0000000000..0d2a4274c7 --- /dev/null +++ b/target/linux/ipq806x/patches-5.10/0065-arm-override-compiler-flags.patch @@ -0,0 +1,21 @@ +From 4d8e29642661397a339ac3485f212c6360445421 Mon Sep 17 00:00:00 2001 +From: John Crispin +Date: Thu, 9 Mar 2017 09:33:32 +0100 +Subject: [PATCH 65/69] arm: override compiler flags + +Signed-off-by: John Crispin +--- + arch/arm/Makefile | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/arch/arm/Makefile ++++ b/arch/arm/Makefile +@@ -67,7 +67,7 @@ KBUILD_CFLAGS += $(call cc-option,-fno-i + # macro, but instead defines a whole series of macros which makes + # testing for a specific architecture or later rather impossible. + arch-$(CONFIG_CPU_32v7M) =-D__LINUX_ARM_ARCH__=7 -march=armv7-m -Wa,-march=armv7-m +-arch-$(CONFIG_CPU_32v7) =-D__LINUX_ARM_ARCH__=7 $(call cc-option,-march=armv7-a,-march=armv5t -Wa$(comma)-march=armv7-a) ++arch-$(CONFIG_CPU_32v7) =-D__LINUX_ARM_ARCH__=7 -mcpu=cortex-a15 + arch-$(CONFIG_CPU_32v6) =-D__LINUX_ARM_ARCH__=6 $(call cc-option,-march=armv6,-march=armv5t -Wa$(comma)-march=armv6) + # Only override the compiler option if ARMv6. The ARMv6K extensions are + # always available in ARMv7 diff --git a/target/linux/ipq806x/patches-5.10/0067-generic-Mangle-bootloader-s-kernel-arguments.patch b/target/linux/ipq806x/patches-5.10/0067-generic-Mangle-bootloader-s-kernel-arguments.patch new file mode 100644 index 0000000000..751ac10a19 --- /dev/null +++ b/target/linux/ipq806x/patches-5.10/0067-generic-Mangle-bootloader-s-kernel-arguments.patch @@ -0,0 +1,210 @@ +From 71270226b14733a4b1f2cde58ea9265caa50b38d Mon Sep 17 00:00:00 2001 +From: Adrian Panella +Date: Thu, 9 Mar 2017 09:37:17 +0100 +Subject: [PATCH 67/69] generic: Mangle bootloader's kernel arguments + +The command-line arguments provided by the boot loader will be +appended to a new device tree property: bootloader-args. +If there is a property "append-rootblock" in DT under /chosen +and a root= option in bootloaders command line it will be parsed +and added to DT bootargs with the form: XX. +Only command line ATAG will be processed, the rest of the ATAGs +sent by bootloader will be ignored. +This is usefull in dual boot systems, to get the current root partition +without afecting the rest of the system. + +Signed-off-by: Adrian Panella +--- + arch/arm/Kconfig | 11 +++++ + arch/arm/boot/compressed/atags_to_fdt.c | 72 ++++++++++++++++++++++++++++++++- + init/main.c | 16 ++++++++ + 3 files changed, 98 insertions(+), 1 deletion(-) + +--- a/arch/arm/Kconfig ++++ b/arch/arm/Kconfig +@@ -1827,6 +1827,17 @@ config ARM_ATAG_DTB_COMPAT_CMDLINE_EXTEN + The command-line arguments provided by the boot loader will be + appended to the the device tree bootargs property. + ++config ARM_ATAG_DTB_COMPAT_CMDLINE_MANGLE ++ bool "Append rootblock parsing bootloader's kernel arguments" ++ help ++ The command-line arguments provided by the boot loader will be ++ appended to a new device tree property: bootloader-args. ++ If there is a property "append-rootblock" in DT under /chosen ++ and a root= option in bootloaders command line it will be parsed ++ and added to DT bootargs with the form: XX. ++ Only command line ATAG will be processed, the rest of the ATAGs ++ sent by bootloader will be ignored. ++ + endchoice + + config CMDLINE +--- a/arch/arm/boot/compressed/atags_to_fdt.c ++++ b/arch/arm/boot/compressed/atags_to_fdt.c +@@ -4,6 +4,8 @@ + + #if defined(CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_EXTEND) + #define do_extend_cmdline 1 ++#elif defined(CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_MANGLE) ++#define do_extend_cmdline 1 + #else + #define do_extend_cmdline 0 + #endif +@@ -67,6 +69,80 @@ static uint32_t get_cell_size(const void + return cell_size; + } + ++#if defined(CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_MANGLE) ++/** ++ * taken from arch/x86/boot/string.c ++ * local_strstr - Find the first substring in a %NUL terminated string ++ * @s1: The string to be searched ++ * @s2: The string to search for ++ */ ++static char *local_strstr(const char *s1, const char *s2) ++{ ++ size_t l1, l2; ++ ++ l2 = strlen(s2); ++ if (!l2) ++ return (char *)s1; ++ l1 = strlen(s1); ++ while (l1 >= l2) { ++ l1--; ++ if (!memcmp(s1, s2, l2)) ++ return (char *)s1; ++ s1++; ++ } ++ return NULL; ++} ++ ++static char *append_rootblock(char *dest, const char *str, int len, void *fdt) ++{ ++ char *ptr, *end, *tmp; ++ char *root="root="; ++ char *find_rootblock; ++ int i, l; ++ const char *rootblock; ++ ++ find_rootblock = getprop(fdt, "/chosen", "find-rootblock", &l); ++ if(!find_rootblock) ++ find_rootblock = root; ++ ++ //ARM doesn't have __HAVE_ARCH_STRSTR, so it was copied from x86 ++ ptr = local_strstr(str, find_rootblock); ++ ++ if(!ptr) ++ return dest; ++ ++ end = strchr(ptr, ' '); ++ end = end ? (end - 1) : (strchr(ptr, 0) - 1); ++ ++ // Some boards ubi.mtd=XX,ZZZZ, so let's check for '," too. ++ tmp = strchr(ptr, ','); ++ ++ if(tmp) ++ end = end < tmp ? end : tmp - 1; ++ ++ //find partition number (assumes format root=/dev/mtdXX | /dev/mtdblockXX | yy:XX | ubi.mtd=XX,ZZZZ ) ++ for( i = 0; end >= ptr && *end >= '0' && *end <= '9'; end--, i++); ++ ptr = end + 1; ++ ++ /* if append-rootblock property is set use it to append to command line */ ++ rootblock = getprop(fdt, "/chosen", "append-rootblock", &l); ++ if(rootblock != NULL) { ++ if(*dest != ' ') { ++ *dest = ' '; ++ dest++; ++ len++; ++ } ++ if (len + l + i <= COMMAND_LINE_SIZE) { ++ memcpy(dest, rootblock, l); ++ dest += l - 1; ++ memcpy(dest, ptr, i); ++ dest += i; ++ } ++ } ++ return dest; ++} ++#endif ++ + static void merge_fdt_bootargs(void *fdt, const char *fdt_cmdline) + { + char cmdline[COMMAND_LINE_SIZE]; +@@ -86,12 +162,21 @@ static void merge_fdt_bootargs(void *fdt + + /* and append the ATAG_CMDLINE */ + if (fdt_cmdline) { ++ ++#if defined(CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_MANGLE) ++ //save original bootloader args ++ //and append ubi.mtd with root partition number to current cmdline ++ setprop_string(fdt, "/chosen", "bootloader-args", fdt_cmdline); ++ ptr = append_rootblock(ptr, fdt_cmdline, len, fdt); ++ ++#else + len = strlen(fdt_cmdline); + if (ptr - cmdline + len + 2 < COMMAND_LINE_SIZE) { + *ptr++ = ' '; + memcpy(ptr, fdt_cmdline, len); + ptr += len; + } ++#endif + } + *ptr = '\0'; + +@@ -166,7 +251,9 @@ int atags_to_fdt(void *atag_list, void * + else + setprop_string(fdt, "/chosen", "bootargs", + atag->u.cmdline.cmdline); +- } else if (atag->hdr.tag == ATAG_MEM) { ++ } ++#ifndef CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_MANGLE ++ else if (atag->hdr.tag == ATAG_MEM) { + if (memcount >= sizeof(mem_reg_property)/4) + continue; + if (!atag->u.mem.size) +@@ -210,6 +297,10 @@ int atags_to_fdt(void *atag_list, void * + setprop(fdt, "/memory", "reg", mem_reg_property, + 4 * memcount * memsize); + } ++#else ++ ++ } ++#endif + + return fdt_pack(fdt); + } +--- a/init/main.c ++++ b/init/main.c +@@ -104,6 +104,10 @@ + #define CREATE_TRACE_POINTS + #include + ++#if defined(CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_MANGLE) ++#include ++#endif ++ + static int kernel_init(void *); + + extern void init_IRQ(void); +@@ -633,6 +637,18 @@ asmlinkage __visible void __init start_k + pr_notice("Kernel command line: %s\n", boot_command_line); + /* parameters may set static keys */ + jump_label_init(); ++ ++#if defined(CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_MANGLE) ++ //Show bootloader's original command line for reference ++ if(of_chosen) { ++ const char *prop = of_get_property(of_chosen, "bootloader-args", NULL); ++ if(prop) ++ pr_notice("Bootloader command line (ignored): %s\n", prop); ++ else ++ pr_notice("Bootloader command line not present\n"); ++ } ++#endif ++ + parse_early_param(); + after_dashes = parse_args("Booting kernel", + static_command_line, __start___param, diff --git a/target/linux/ipq806x/patches-5.10/0069-arm-boot-add-dts-files.patch b/target/linux/ipq806x/patches-5.10/0069-arm-boot-add-dts-files.patch new file mode 100644 index 0000000000..055a4cbc30 --- /dev/null +++ b/target/linux/ipq806x/patches-5.10/0069-arm-boot-add-dts-files.patch @@ -0,0 +1,37 @@ +From 8f68331e14dff9a101f2d0e1d6bec84a031f27ee Mon Sep 17 00:00:00 2001 +From: John Crispin +Date: Thu, 9 Mar 2017 11:03:18 +0100 +Subject: [PATCH 69/69] arm: boot: add dts files + +Signed-off-by: John Crispin +--- + arch/arm/boot/dts/Makefile | 8 ++++++++ + 1 file changed, 8 insertions(+) + +--- a/arch/arm/boot/dts/Makefile ++++ b/arch/arm/boot/dts/Makefile +@@ -842,7 +842,24 @@ dtb-$(CONFIG_ARCH_QCOM) += \ + qcom-ipq4019-ap.dk04.1-c3.dtb \ + qcom-ipq4019-ap.dk07.1-c1.dtb \ + qcom-ipq4019-ap.dk07.1-c2.dtb \ ++ qcom-ipq8062-wg2600hp3.dtb \ + qcom-ipq8064-ap148.dtb \ ++ qcom-ipq8064-c2600.dtb \ ++ qcom-ipq8064-d7800.dtb \ ++ qcom-ipq8064-db149.dtb \ ++ qcom-ipq8064-ap161.dtb \ ++ qcom-ipq8064-ea7500-v1.dtb \ ++ qcom-ipq8064-ea8500.dtb \ ++ qcom-ipq8064-g10.dtb \ ++ qcom-ipq8064-r7500.dtb \ ++ qcom-ipq8064-r7500v2.dtb \ ++ qcom-ipq8064-unifi-ac-hd.dtb \ ++ qcom-ipq8064-wg2600hp.dtb \ ++ qcom-ipq8064-wpq864.dtb \ ++ qcom-ipq8064-wxr-2533dhp.dtb \ ++ qcom-ipq8065-nbg6817.dtb \ ++ qcom-ipq8065-r7800.dtb \ ++ qcom-ipq8068-ecw5410.dtb \ + qcom-msm8660-surf.dtb \ + qcom-msm8960-cdp.dtb \ + qcom-msm8974-fairphone-fp2.dtb \ diff --git a/target/linux/ipq806x/patches-5.10/0072-add-ipq806x-with-no-clocks.patch b/target/linux/ipq806x/patches-5.10/0072-add-ipq806x-with-no-clocks.patch new file mode 100644 index 0000000000..b7cebd9d39 --- /dev/null +++ b/target/linux/ipq806x/patches-5.10/0072-add-ipq806x-with-no-clocks.patch @@ -0,0 +1,10 @@ +--- a/drivers/firmware/qcom_scm.c ++++ b/drivers/firmware/qcom_scm.c +@@ -598,6 +598,7 @@ static const struct of_device_id qcom_sc + SCM_HAS_BUS_CLK) + }, + { .compatible = "qcom,scm-ipq4019" }, ++ { .compatible = "qcom,scm-ipq806x" }, + { .compatible = "qcom,scm-msm8660", .data = (void *) SCM_HAS_CORE_CLK }, + { .compatible = "qcom,scm-msm8960", .data = (void *) SCM_HAS_CORE_CLK }, + { .compatible = "qcom,scm-msm8916", .data = (void *)(SCM_HAS_CORE_CLK | diff --git a/target/linux/ipq806x/patches-5.10/080-v5.7-ARM-dts-qcom-add-gpio-ranges-property.patch b/target/linux/ipq806x/patches-5.10/080-v5.7-ARM-dts-qcom-add-gpio-ranges-property.patch new file mode 100644 index 0000000000..0dc9debbfd --- /dev/null +++ b/target/linux/ipq806x/patches-5.10/080-v5.7-ARM-dts-qcom-add-gpio-ranges-property.patch @@ -0,0 +1,70 @@ +From patchwork Mon May 21 20:57:38 2018 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +Subject: [v5,3/4] ARM: dts: qcom: add gpio-ranges property +X-Patchwork-Submitter: Christian Lamparter +X-Patchwork-Id: 917856 +Message-Id: <0ae3376606a89bcdf3fe753a5c967f7103699e09.1526935804.git.chunkeey@gmail.com> +To: linux-gpio@vger.kernel.org, linux-arm-kernel@lists.infradead.org, + linux-arm-msm@vger.kernel.org, devicetree@vger.kernel.org +Cc: Bjorn Andersson , + Linus Walleij , + Stephen Boyd , David Brown , + Rob Herring , Mark Rutland , + Andy Gross , + Sven Eckelmann +Date: Mon, 21 May 2018 22:57:38 +0200 +From: Christian Lamparter +List-Id: + +This patch adds the gpio-ranges property to almost all of +the Qualcomm ARM platforms that utilize the pinctrl-msm +framework. + +The gpio-ranges property is part of the gpiolib subsystem. +As a result, the binding text is available in section +"2.1 gpio- and pin-controller interaction" of +Documentation/devicetree/bindings/gpio/gpio.txt + +For more information please see the patch titled: +"pinctrl: msm: fix gpio-hog related boot issues" from +this series. + +Reported-by: Sven Eckelmann +Tested-by: Sven Eckelmann [ipq4019] +Reviewed-by: Bjorn Andersson +Signed-off-by: Christian Lamparter +Reviewed-by: Linus Walleij +--- +To help with git bisect, the DT update patch has been intentionally +placed after the "pinctrl: msm: fix gpio-hog related boot issues". +Otherwise - if the order was reveresed - and bisect decides to split +between these two patches, the gpiochip_add_pin_ranges() function +will be executed twice with the same parameters for the same pinctrl. +--- + arch/arm/boot/dts/qcom-apq8064.dtsi | 1 + + arch/arm/boot/dts/qcom-apq8084.dtsi | 1 + + arch/arm/boot/dts/qcom-ipq4019.dtsi | 1 + + arch/arm/boot/dts/qcom-ipq8064.dtsi | 1 + + arch/arm/boot/dts/qcom-mdm9615.dtsi | 1 + + arch/arm/boot/dts/qcom-msm8660.dtsi | 1 + + arch/arm/boot/dts/qcom-msm8960.dtsi | 1 + + arch/arm/boot/dts/qcom-msm8974.dtsi | 1 + + arch/arm64/boot/dts/qcom/ipq8074.dtsi | 3 ++- + arch/arm64/boot/dts/qcom/msm8916.dtsi | 1 + + arch/arm64/boot/dts/qcom/msm8992.dtsi | 1 + + arch/arm64/boot/dts/qcom/msm8994.dtsi | 1 + + arch/arm64/boot/dts/qcom/msm8996.dtsi | 1 + + 13 files changed, 14 insertions(+), 1 deletion(-) + +--- a/arch/arm/boot/dts/qcom-ipq8064.dtsi ++++ b/arch/arm/boot/dts/qcom-ipq8064.dtsi +@@ -119,6 +119,7 @@ + reg = <0x800000 0x4000>; + + gpio-controller; ++ gpio-ranges = <&qcom_pinmux 0 0 69>; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; diff --git a/target/linux/ipq806x/patches-5.10/081-v5.8-ARM-dts-qcom-add-scm-definition-to-ipq806x.patch b/target/linux/ipq806x/patches-5.10/081-v5.8-ARM-dts-qcom-add-scm-definition-to-ipq806x.patch new file mode 100644 index 0000000000..f5483ac734 --- /dev/null +++ b/target/linux/ipq806x/patches-5.10/081-v5.8-ARM-dts-qcom-add-scm-definition-to-ipq806x.patch @@ -0,0 +1,29 @@ +From 51befb888f62b1a62434fb4b82328d698a30f9de Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Thu, 19 Mar 2020 23:44:24 +0100 +Subject: ARM: dts: qcom: add scm definition to ipq806x + +Add missing scm definition for ipq806x soc + +Signed-off-by: Ansuel Smith +Link: https://lore.kernel.org/r/20200319224424.18473-1-ansuelsmth@gmail.com +Signed-off-by: Bjorn Andersson +--- + arch/arm/boot/dts/qcom-ipq8064.dtsi | 6 ++++++ + 1 file changed, 6 insertions(+) + +--- a/arch/arm/boot/dts/qcom-ipq8064.dtsi ++++ b/arch/arm/boot/dts/qcom-ipq8064.dtsi +@@ -93,6 +93,12 @@ + }; + }; + ++ firmware { ++ scm { ++ compatible = "qcom,scm-ipq806x", "qcom,scm"; ++ }; ++ }; ++ + soc: soc { + #address-cells = <1>; + #size-cells = <1>; diff --git a/target/linux/ipq806x/patches-5.10/082-ipq8064-dtsi-tweaks.patch b/target/linux/ipq806x/patches-5.10/082-ipq8064-dtsi-tweaks.patch new file mode 100644 index 0000000000..568ca5bb88 --- /dev/null +++ b/target/linux/ipq806x/patches-5.10/082-ipq8064-dtsi-tweaks.patch @@ -0,0 +1,130 @@ +--- a/arch/arm/boot/dts/qcom-ipq8064.dtsi ++++ b/arch/arm/boot/dts/qcom-ipq8064.dtsi +@@ -20,7 +20,7 @@ + #address-cells = <1>; + #size-cells = <0>; + +- cpu@0 { ++ cpu0: cpu@0 { + compatible = "qcom,krait"; + enable-method = "qcom,kpss-acc-v1"; + device_type = "cpu"; +@@ -30,7 +30,7 @@ + qcom,saw = <&saw0>; + }; + +- cpu@1 { ++ cpu1: cpu@1 { + compatible = "qcom,krait"; + enable-method = "qcom,kpss-acc-v1"; + device_type = "cpu"; +@@ -67,7 +67,7 @@ + no-map; + }; + +- smem@41000000 { ++ smem: smem@41000000 { + reg = <0x41000000 0x200000>; + no-map; + }; +@@ -155,6 +155,7 @@ + function = "pcie3_rst"; + drive-strength = <12>; + bias-disable; ++ output-low; + }; + }; + +@@ -219,21 +220,23 @@ + acc0: clock-controller@2088000 { + compatible = "qcom,kpss-acc-v1"; + reg = <0x02088000 0x1000>, <0x02008000 0x1000>; ++ clock-output-names = "acpu0_aux"; + }; + + acc1: clock-controller@2098000 { + compatible = "qcom,kpss-acc-v1"; + reg = <0x02098000 0x1000>, <0x02008000 0x1000>; ++ clock-output-names = "acpu1_aux"; + }; + + saw0: regulator@2089000 { +- compatible = "qcom,saw2"; ++ compatible = "qcom,saw2", "qcom,apq8064-saw2-v1.1-cpu", "syscon"; + reg = <0x02089000 0x1000>, <0x02009000 0x1000>; + regulator; + }; + + saw1: regulator@2099000 { +- compatible = "qcom,saw2"; ++ compatible = "qcom,saw2", "qcom,apq8064-saw2-v1.1-cpu", "syscon"; + reg = <0x02099000 0x1000>, <0x02009000 0x1000>; + regulator; + }; +@@ -251,7 +254,7 @@ + + syscon-tcsr = <&tcsr>; + +- serial@12490000 { ++ gsbi2_serial: serial@12490000 { + compatible = "qcom,msm-uartdm-v1.3", "qcom,msm-uartdm"; + reg = <0x12490000 0x1000>, + <0x12480000 0x1000>; +@@ -326,7 +329,7 @@ + + syscon-tcsr = <&tcsr>; + +- serial@1a240000 { ++ gsbi5_serial: serial@1a240000 { + compatible = "qcom,msm-uartdm-v1.3", "qcom,msm-uartdm"; + reg = <0x1a240000 0x1000>, + <0x1a200000 0x1000>; +@@ -397,7 +400,7 @@ + status = "disabled"; + }; + +- sata@29000000 { ++ sata: sata@29000000 { + compatible = "qcom,ipq806x-ahci", "generic-ahci"; + reg = <0x29000000 0x180>; + +@@ -430,6 +433,7 @@ + reg = <0x00900000 0x4000>; + #clock-cells = <1>; + #reset-cells = <1>; ++ #power-domain-cells = <1>; + }; + + tcsr: syscon@1a400000 { +@@ -625,13 +629,13 @@ + qcom,ee = <0>; + }; + +- amba { +- compatible = "simple-bus"; ++ amba: amba { ++ compatible = "arm,amba-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges; + +- sdcc@12400000 { ++ sdcc1: sdcc@12400000 { + status = "disabled"; + compatible = "arm,pl18x", "arm,primecell"; + arm,primecell-periphid = <0x00051180>; +@@ -645,13 +649,12 @@ + non-removable; + cap-sd-highspeed; + cap-mmc-highspeed; +- mmc-ddr-1_8v; + vmmc-supply = <&vsdcc_fixed>; + dmas = <&sdcc1bam 2>, <&sdcc1bam 1>; + dma-names = "tx", "rx"; + }; + +- sdcc@12180000 { ++ sdcc3: sdcc@12180000 { + compatible = "arm,pl18x", "arm,primecell"; + arm,primecell-periphid = <0x00051180>; + status = "disabled"; diff --git a/target/linux/ipq806x/patches-5.10/083-ipq8064-dtsi-additions.patch b/target/linux/ipq806x/patches-5.10/083-ipq8064-dtsi-additions.patch new file mode 100644 index 0000000000..221ecd7396 --- /dev/null +++ b/target/linux/ipq806x/patches-5.10/083-ipq8064-dtsi-additions.patch @@ -0,0 +1,992 @@ +--- a/arch/arm/boot/dts/qcom-ipq8064.dtsi ++++ b/arch/arm/boot/dts/qcom-ipq8064.dtsi +@@ -8,6 +8,8 @@ + #include + #include + #include ++#include ++#include + + / { + #address-cells = <1>; +@@ -28,6 +30,16 @@ + next-level-cache = <&L2>; + qcom,acc = <&acc0>; + qcom,saw = <&saw0>; ++ clocks = <&kraitcc 0>, <&kraitcc 4>; ++ clock-names = "cpu", "l2"; ++ clock-latency = <100000>; ++ cpu-supply = <&smb208_s2a>; ++ operating-points-v2 = <&opp_table0>; ++ voltage-tolerance = <5>; ++ cooling-min-state = <0>; ++ cooling-max-state = <10>; ++ #cooling-cells = <2>; ++ cpu-idle-states = <&CPU_SPC>; + }; + + cpu1: cpu@1 { +@@ -38,11 +50,458 @@ + next-level-cache = <&L2>; + qcom,acc = <&acc1>; + qcom,saw = <&saw1>; ++ clocks = <&kraitcc 1>, <&kraitcc 4>; ++ clock-names = "cpu", "l2"; ++ clock-latency = <100000>; ++ cpu-supply = <&smb208_s2b>; ++ operating-points-v2 = <&opp_table0>; ++ voltage-tolerance = <5>; ++ cooling-min-state = <0>; ++ cooling-max-state = <10>; ++ #cooling-cells = <2>; ++ cpu-idle-states = <&CPU_SPC>; + }; + + L2: l2-cache { + compatible = "cache"; + cache-level = <2>; ++ qcom,saw = <&saw_l2>; ++ }; ++ ++ qcom,l2 { ++ qcom,l2-rates = <384000000 1000000000 1200000000>; ++ qcom,l2-cpufreq = <384000000 600000000 1200000000>; ++ qcom,l2-volt = <1100000 1100000 1150000>; ++ qcom,l2-supply = <&smb208_s1a>; ++ }; ++ ++ idle-states { ++ CPU_SPC: spc { ++ compatible = "qcom,idle-state-spc", "arm,idle-state"; ++ status = "disabled"; ++ entry-latency-us = <400>; ++ exit-latency-us = <900>; ++ min-residency-us = <3000>; ++ }; ++ }; ++ }; ++ ++ opp_table0: opp_table0 { ++ compatible = "operating-points-v2-kryo-cpu"; ++ nvmem-cells = <&speedbin_efuse>; ++ ++ opp-384000000 { ++ opp-hz = /bits/ 64 <384000000>; ++ opp-microvolt-speed0-pvs0-v0 = <1000000>; ++ opp-microvolt-speed0-pvs1-v0 = <925000>; ++ opp-microvolt-speed0-pvs2-v0 = <875000>; ++ opp-microvolt-speed0-pvs3-v0 = <800000>; ++ opp-supported-hw = <0x1>; ++ clock-latency-ns = <100000>; ++ }; ++ ++ opp-600000000 { ++ opp-hz = /bits/ 64 <600000000>; ++ opp-microvolt-speed0-pvs0-v0 = <1050000>; ++ opp-microvolt-speed0-pvs1-v0 = <975000>; ++ opp-microvolt-speed0-pvs2-v0 = <925000>; ++ opp-microvolt-speed0-pvs3-v0 = <850000>; ++ opp-supported-hw = <0x1>; ++ clock-latency-ns = <100000>; ++ }; ++ ++ opp-800000000 { ++ opp-hz = /bits/ 64 <800000000>; ++ opp-microvolt-speed0-pvs0-v0 = <1100000>; ++ opp-microvolt-speed0-pvs1-v0 = <1025000>; ++ opp-microvolt-speed0-pvs2-v0 = <995000>; ++ opp-microvolt-speed0-pvs3-v0 = <900000>; ++ opp-supported-hw = <0x1>; ++ clock-latency-ns = <100000>; ++ }; ++ ++ opp-1000000000 { ++ opp-hz = /bits/ 64 <1000000000>; ++ opp-microvolt-speed0-pvs0-v0 = <1150000>; ++ opp-microvolt-speed0-pvs1-v0 = <1075000>; ++ opp-microvolt-speed0-pvs2-v0 = <1025000>; ++ opp-microvolt-speed0-pvs3-v0 = <950000>; ++ opp-supported-hw = <0x1>; ++ clock-latency-ns = <100000>; ++ }; ++ ++ opp-1200000000 { ++ opp-hz = /bits/ 64 <1200000000>; ++ opp-microvolt-speed0-pvs0-v0 = <1200000>; ++ opp-microvolt-speed0-pvs1-v0 = <1125000>; ++ opp-microvolt-speed0-pvs2-v0 = <1075000>; ++ opp-microvolt-speed0-pvs3-v0 = <1000000>; ++ opp-supported-hw = <0x1>; ++ clock-latency-ns = <100000>; ++ }; ++ ++ opp-1400000000 { ++ opp-hz = /bits/ 64 <1400000000>; ++ opp-microvolt-speed0-pvs0-v0 = <1250000>; ++ opp-microvolt-speed0-pvs1-v0 = <1175000>; ++ opp-microvolt-speed0-pvs2-v0 = <1125000>; ++ opp-microvolt-speed0-pvs3-v0 = <1050000>; ++ opp-supported-hw = <0x1>; ++ clock-latency-ns = <100000>; ++ }; ++ }; ++ ++ thermal-zones { ++ tsens_tz_sensor0 { ++ polling-delay-passive = <0>; ++ polling-delay = <0>; ++ thermal-sensors = <&tsens 0>; ++ ++ trips { ++ cpu-critical-hi { ++ temperature = <125000>; ++ hysteresis = <2000>; ++ type = "critical_high"; ++ }; ++ ++ cpu-config-hi { ++ temperature = <105000>; ++ hysteresis = <2000>; ++ type = "configurable_hi"; ++ }; ++ ++ cpu-config-lo { ++ temperature = <95000>; ++ hysteresis = <2000>; ++ type = "configurable_lo"; ++ }; ++ ++ cpu-critical-low { ++ temperature = <0>; ++ hysteresis = <2000>; ++ type = "critical_low"; ++ }; ++ }; ++ }; ++ ++ tsens_tz_sensor1 { ++ polling-delay-passive = <0>; ++ polling-delay = <0>; ++ thermal-sensors = <&tsens 1>; ++ ++ trips { ++ cpu-critical-hi { ++ temperature = <125000>; ++ hysteresis = <2000>; ++ type = "critical_high"; ++ }; ++ ++ cpu-config-hi { ++ temperature = <105000>; ++ hysteresis = <2000>; ++ type = "configurable_hi"; ++ }; ++ ++ cpu-config-lo { ++ temperature = <95000>; ++ hysteresis = <2000>; ++ type = "configurable_lo"; ++ }; ++ ++ cpu-critical-low { ++ temperature = <0>; ++ hysteresis = <2000>; ++ type = "critical_low"; ++ }; ++ }; ++ }; ++ ++ tsens_tz_sensor2 { ++ polling-delay-passive = <0>; ++ polling-delay = <0>; ++ thermal-sensors = <&tsens 2>; ++ ++ trips { ++ cpu-critical-hi { ++ temperature = <125000>; ++ hysteresis = <2000>; ++ type = "critical_high"; ++ }; ++ ++ cpu-config-hi { ++ temperature = <105000>; ++ hysteresis = <2000>; ++ type = "configurable_hi"; ++ }; ++ ++ cpu-config-lo { ++ temperature = <95000>; ++ hysteresis = <2000>; ++ type = "configurable_lo"; ++ }; ++ ++ cpu-critical-low { ++ temperature = <0>; ++ hysteresis = <2000>; ++ type = "critical_low"; ++ }; ++ }; ++ }; ++ ++ tsens_tz_sensor3 { ++ polling-delay-passive = <0>; ++ polling-delay = <0>; ++ thermal-sensors = <&tsens 3>; ++ ++ trips { ++ cpu-critical-hi { ++ temperature = <125000>; ++ hysteresis = <2000>; ++ type = "critical_high"; ++ }; ++ ++ cpu-config-hi { ++ temperature = <105000>; ++ hysteresis = <2000>; ++ type = "configurable_hi"; ++ }; ++ ++ cpu-config-lo { ++ temperature = <95000>; ++ hysteresis = <2000>; ++ type = "configurable_lo"; ++ }; ++ ++ cpu-critical-low { ++ temperature = <0>; ++ hysteresis = <2000>; ++ type = "critical_low"; ++ }; ++ }; ++ }; ++ ++ tsens_tz_sensor4 { ++ polling-delay-passive = <0>; ++ polling-delay = <0>; ++ thermal-sensors = <&tsens 4>; ++ ++ trips { ++ cpu-critical-hi { ++ temperature = <125000>; ++ hysteresis = <2000>; ++ type = "critical_high"; ++ }; ++ ++ cpu-config-hi { ++ temperature = <105000>; ++ hysteresis = <2000>; ++ type = "configurable_hi"; ++ }; ++ ++ cpu-config-lo { ++ temperature = <95000>; ++ hysteresis = <2000>; ++ type = "configurable_lo"; ++ }; ++ ++ cpu-critical-low { ++ temperature = <0>; ++ hysteresis = <2000>; ++ type = "critical_low"; ++ }; ++ }; ++ }; ++ ++ tsens_tz_sensor5 { ++ polling-delay-passive = <0>; ++ polling-delay = <0>; ++ thermal-sensors = <&tsens 5>; ++ ++ trips { ++ cpu-critical-hi { ++ temperature = <125000>; ++ hysteresis = <2000>; ++ type = "critical_high"; ++ }; ++ ++ cpu-config-hi { ++ temperature = <105000>; ++ hysteresis = <2000>; ++ type = "configurable_hi"; ++ }; ++ ++ cpu-config-lo { ++ temperature = <95000>; ++ hysteresis = <2000>; ++ type = "configurable_lo"; ++ }; ++ ++ cpu-critical-low { ++ temperature = <0>; ++ hysteresis = <2000>; ++ type = "critical_low"; ++ }; ++ }; ++ }; ++ ++ tsens_tz_sensor6 { ++ polling-delay-passive = <0>; ++ polling-delay = <0>; ++ thermal-sensors = <&tsens 6>; ++ ++ trips { ++ cpu-critical-hi { ++ temperature = <125000>; ++ hysteresis = <2000>; ++ type = "critical_high"; ++ }; ++ ++ cpu-config-hi { ++ temperature = <105000>; ++ hysteresis = <2000>; ++ type = "configurable_hi"; ++ }; ++ ++ cpu-config-lo { ++ temperature = <95000>; ++ hysteresis = <2000>; ++ type = "configurable_lo"; ++ }; ++ ++ cpu-critical-low { ++ temperature = <0>; ++ hysteresis = <2000>; ++ type = "critical_low"; ++ }; ++ }; ++ }; ++ ++ tsens_tz_sensor7 { ++ polling-delay-passive = <0>; ++ polling-delay = <0>; ++ thermal-sensors = <&tsens 7>; ++ ++ trips { ++ cpu-critical-hi { ++ temperature = <125000>; ++ hysteresis = <2000>; ++ type = "critical_high"; ++ }; ++ ++ cpu-config-hi { ++ temperature = <105000>; ++ hysteresis = <2000>; ++ type = "configurable_hi"; ++ }; ++ ++ cpu-config-lo { ++ temperature = <95000>; ++ hysteresis = <2000>; ++ type = "configurable_lo"; ++ }; ++ ++ cpu-critical-low { ++ temperature = <0>; ++ hysteresis = <2000>; ++ type = "critical_low"; ++ }; ++ }; ++ }; ++ ++ tsens_tz_sensor8 { ++ polling-delay-passive = <0>; ++ polling-delay = <0>; ++ thermal-sensors = <&tsens 8>; ++ ++ trips { ++ cpu-critical-hi { ++ temperature = <125000>; ++ hysteresis = <2000>; ++ type = "critical_high"; ++ }; ++ ++ cpu-config-hi { ++ temperature = <105000>; ++ hysteresis = <2000>; ++ type = "configurable_hi"; ++ }; ++ ++ cpu-config-lo { ++ temperature = <95000>; ++ hysteresis = <2000>; ++ type = "configurable_lo"; ++ }; ++ ++ cpu-critical-low { ++ temperature = <0>; ++ hysteresis = <2000>; ++ type = "critical_low"; ++ }; ++ }; ++ }; ++ ++ tsens_tz_sensor9 { ++ polling-delay-passive = <0>; ++ polling-delay = <0>; ++ thermal-sensors = <&tsens 9>; ++ ++ trips { ++ cpu-critical-hi { ++ temperature = <125000>; ++ hysteresis = <2000>; ++ type = "critical_high"; ++ }; ++ ++ cpu-config-hi { ++ temperature = <105000>; ++ hysteresis = <2000>; ++ type = "configurable_hi"; ++ }; ++ ++ cpu-config-lo { ++ temperature = <95000>; ++ hysteresis = <2000>; ++ type = "configurable_lo"; ++ }; ++ ++ cpu-critical-low { ++ temperature = <0>; ++ hysteresis = <2000>; ++ type = "critical_low"; ++ }; ++ }; ++ }; ++ ++ tsens_tz_sensor10 { ++ polling-delay-passive = <0>; ++ polling-delay = <0>; ++ thermal-sensors = <&tsens 10>; ++ ++ trips { ++ cpu-critical-hi { ++ temperature = <125000>; ++ hysteresis = <2000>; ++ type = "critical_high"; ++ }; ++ ++ cpu-config-hi { ++ temperature = <105000>; ++ hysteresis = <2000>; ++ type = "configurable_hi"; ++ }; ++ ++ cpu-config-lo { ++ temperature = <95000>; ++ hysteresis = <2000>; ++ type = "configurable_lo"; ++ }; ++ ++ cpu-critical-low { ++ temperature = <0>; ++ hysteresis = <2000>; ++ type = "critical_low"; ++ }; ++ }; + }; + }; + +@@ -93,6 +552,15 @@ + }; + }; + ++ fab-scaling { ++ compatible = "qcom,fab-scaling"; ++ clocks = <&rpmcc RPM_APPS_FABRIC_A_CLK>, <&rpmcc RPM_EBI1_A_CLK>; ++ clock-names = "apps-fab-clk", "ddr-fab-clk"; ++ fab_freq_high = <533000000>; ++ fab_freq_nominal = <400000000>; ++ cpu_freq_threshold = <1000000000>; ++ }; ++ + firmware { + scm { + compatible = "qcom,scm-ipq806x", "qcom,scm"; +@@ -120,6 +588,84 @@ + reg-names = "lpass-lpaif"; + }; + ++ qfprom: qfprom@700000 { ++ compatible = "qcom,qfprom", "syscon"; ++ reg = <0x700000 0x1000>; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ status = "okay"; ++ tsens_calib: calib@400 { ++ reg = <0x400 0xb>; ++ }; ++ tsens_backup: backup@410 { ++ reg = <0x410 0xb>; ++ }; ++ speedbin_efuse: speedbin@0c0 { ++ reg = <0x0c0 0x4>; ++ }; ++ }; ++ ++ rpm: rpm@108000 { ++ compatible = "qcom,rpm-ipq8064"; ++ reg = <0x108000 0x1000>; ++ qcom,ipc = <&l2cc 0x8 2>; ++ ++ interrupts = , ++ , ++ ; ++ interrupt-names = "ack", "err", "wakeup"; ++ ++ clocks = <&gcc RPM_MSG_RAM_H_CLK>; ++ clock-names = "ram"; ++ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ rpmcc: clock-controller { ++ compatible = "qcom,rpmcc-ipq806x", "qcom,rpmcc"; ++ #clock-cells = <1>; ++ }; ++ ++ regulators { ++ compatible = "qcom,rpm-smb208-regulators"; ++ ++ smb208_s1a: s1a { ++ regulator-min-microvolt = <1050000>; ++ regulator-max-microvolt = <1150000>; ++ ++ qcom,switch-mode-frequency = <1200000>; ++ }; ++ ++ smb208_s1b: s1b { ++ regulator-min-microvolt = <1050000>; ++ regulator-max-microvolt = <1150000>; ++ ++ qcom,switch-mode-frequency = <1200000>; ++ }; ++ ++ smb208_s2a: s2a { ++ regulator-min-microvolt = < 800000>; ++ regulator-max-microvolt = <1250000>; ++ ++ qcom,switch-mode-frequency = <1200000>; ++ }; ++ ++ smb208_s2b: s2b { ++ regulator-min-microvolt = < 800000>; ++ regulator-max-microvolt = <1250000>; ++ ++ qcom,switch-mode-frequency = <1200000>; ++ }; ++ }; ++ }; ++ ++ rng@1a500000 { ++ compatible = "qcom,prng"; ++ reg = <0x1a500000 0x200>; ++ clocks = <&gcc PRNG_CLK>; ++ clock-names = "core"; ++ }; ++ + qcom_pinmux: pinmux@800000 { + compatible = "qcom,ipq8064-pinctrl"; + reg = <0x800000 0x4000>; +@@ -159,6 +705,15 @@ + }; + }; + ++ i2c4_pins: i2c4_pinmux { ++ mux { ++ pins = "gpio12", "gpio13"; ++ function = "gsbi4"; ++ drive-strength = <12>; ++ bias-disable; ++ }; ++ }; ++ + spi_pins: spi_pins { + mux { + pins = "gpio18", "gpio19", "gpio21"; +@@ -168,6 +723,53 @@ + }; + }; + ++ nand_pins: nand_pins { ++ disable { ++ pins = "gpio34", "gpio35", "gpio36", ++ "gpio37", "gpio38"; ++ function = "nand"; ++ drive-strength = <10>; ++ bias-disable; ++ }; ++ ++ pullups { ++ pins = "gpio39"; ++ function = "nand"; ++ drive-strength = <10>; ++ bias-pull-up; ++ }; ++ ++ hold { ++ pins = "gpio40", "gpio41", "gpio42", ++ "gpio43", "gpio44", "gpio45", ++ "gpio46", "gpio47"; ++ function = "nand"; ++ drive-strength = <10>; ++ bias-bus-hold; ++ }; ++ }; ++ ++ mdio0_pins: mdio0_pins { ++ mux { ++ pins = "gpio0", "gpio1"; ++ function = "mdio"; ++ drive-strength = <8>; ++ bias-disable; ++ }; ++ }; ++ ++ rgmii2_pins: rgmii2_pins { ++ mux { ++ pins = "gpio27", "gpio28", "gpio29", ++ "gpio30", "gpio31", "gpio32", ++ "gpio51", "gpio52", "gpio59", ++ "gpio60", "gpio61", "gpio62"; ++ function = "rgmii2"; ++ drive-strength = <8>; ++ bias-disable; ++ }; ++ }; ++ + leds_pins: leds_pins { + mux { + pins = "gpio7", "gpio8", "gpio9", +@@ -229,6 +831,17 @@ + clock-output-names = "acpu1_aux"; + }; + ++ l2cc: clock-controller@2011000 { ++ compatible = "qcom,kpss-gcc", "syscon"; ++ reg = <0x2011000 0x1000>; ++ clock-output-names = "acpu_l2_aux"; ++ }; ++ ++ kraitcc: clock-controller { ++ compatible = "qcom,krait-cc-v1"; ++ #clock-cells = <1>; ++ }; ++ + saw0: regulator@2089000 { + compatible = "qcom,saw2", "qcom,apq8064-saw2-v1.1-cpu", "syscon"; + reg = <0x02089000 0x1000>, <0x02009000 0x1000>; +@@ -241,6 +854,17 @@ + regulator; + }; + ++ saw_l2: regulator@02012000 { ++ compatible = "qcom,saw2", "syscon"; ++ reg = <0x02012000 0x1000>; ++ regulator; ++ }; ++ ++ sic_non_secure: sic-non-secure@12100000 { ++ compatible = "syscon"; ++ reg = <0x12100000 0x10000>; ++ }; ++ + gsbi2: gsbi@12480000 { + compatible = "qcom,gsbi-v1.0.0"; + cell-index = <2>; +@@ -436,6 +1060,15 @@ + #power-domain-cells = <1>; + }; + ++ tsens: thermal-sensor@900000 { ++ compatible = "qcom,ipq8064-tsens"; ++ reg = <0x900000 0x3680>; ++ nvmem-cells = <&tsens_calib>, <&tsens_backup>; ++ nvmem-cell-names = "calib", "calib_backup"; ++ interrupts = ; ++ #thermal-sensor-cells = <1>; ++ }; ++ + tcsr: syscon@1a400000 { + compatible = "qcom,tcsr-ipq8064", "syscon"; + reg = <0x1a400000 0x100>; +@@ -448,6 +1081,95 @@ + #reset-cells = <1>; + }; + ++ sfpb_mutex_block: syscon@1200600 { ++ compatible = "syscon"; ++ reg = <0x01200600 0x100>; ++ }; ++ ++ hs_phy_0: hs_phy_0 { ++ compatible = "qcom,ipq806x-usb-phy-hs"; ++ reg = <0x110f8800 0x30>; ++ clocks = <&gcc USB30_0_UTMI_CLK>; ++ clock-names = "ref"; ++ #phy-cells = <0>; ++ }; ++ ++ ss_phy_0: ss_phy_0 { ++ compatible = "qcom,ipq806x-usb-phy-ss"; ++ reg = <0x110f8830 0x30>; ++ clocks = <&gcc USB30_0_MASTER_CLK>; ++ clock-names = "ref"; ++ #phy-cells = <0>; ++ }; ++ ++ usb3_0: usb3@110f8800 { ++ compatible = "qcom,dwc3", "syscon"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ reg = <0x110f8800 0x8000>; ++ clocks = <&gcc USB30_0_MASTER_CLK>; ++ clock-names = "core"; ++ ++ ranges; ++ ++ resets = <&gcc USB30_0_MASTER_RESET>; ++ reset-names = "master"; ++ ++ status = "disabled"; ++ ++ dwc3_0: dwc3@11000000 { ++ compatible = "snps,dwc3"; ++ reg = <0x11000000 0xcd00>; ++ interrupts = ; ++ phys = <&hs_phy_0>, <&ss_phy_0>; ++ phy-names = "usb2-phy", "usb3-phy"; ++ dr_mode = "host"; ++ snps,dis_u3_susphy_quirk; ++ }; ++ }; ++ ++ hs_phy_1: hs_phy_1 { ++ compatible = "qcom,ipq806x-usb-phy-hs"; ++ reg = <0x100f8800 0x30>; ++ clocks = <&gcc USB30_1_UTMI_CLK>; ++ clock-names = "ref"; ++ #phy-cells = <0>; ++ }; ++ ++ ss_phy_1: ss_phy_1 { ++ compatible = "qcom,ipq806x-usb-phy-ss"; ++ reg = <0x100f8830 0x30>; ++ clocks = <&gcc USB30_1_MASTER_CLK>; ++ clock-names = "ref"; ++ #phy-cells = <0>; ++ }; ++ ++ usb3_1: usb3@100f8800 { ++ compatible = "qcom,dwc3", "syscon"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ reg = <0x100f8800 0x8000>; ++ clocks = <&gcc USB30_1_MASTER_CLK>; ++ clock-names = "core"; ++ ++ ranges; ++ ++ resets = <&gcc USB30_1_MASTER_RESET>; ++ reset-names = "master"; ++ ++ status = "disabled"; ++ ++ dwc3_1: dwc3@10000000 { ++ compatible = "snps,dwc3"; ++ reg = <0x10000000 0xcd00>; ++ interrupts = ; ++ phys = <&hs_phy_1>, <&ss_phy_1>; ++ phy-names = "usb2-phy", "usb3-phy"; ++ dr_mode = "host"; ++ snps,dis_u3_susphy_quirk; ++ }; ++ }; ++ + pcie0: pci@1b500000 { + compatible = "qcom,pcie-ipq8064"; + reg = <0x1b500000 0x1000 +@@ -601,6 +1323,167 @@ + perst-gpio = <&qcom_pinmux 63 GPIO_ACTIVE_LOW>; + }; + ++ adm_dma: dma@18300000 { ++ compatible = "qcom,adm"; ++ reg = <0x18300000 0x100000>; ++ interrupts = ; ++ #dma-cells = <1>; ++ ++ clocks = <&gcc ADM0_CLK>, <&gcc ADM0_PBUS_CLK>; ++ clock-names = "core", "iface"; ++ ++ resets = <&gcc ADM0_RESET>, ++ <&gcc ADM0_PBUS_RESET>, ++ <&gcc ADM0_C0_RESET>, ++ <&gcc ADM0_C1_RESET>, ++ <&gcc ADM0_C2_RESET>; ++ reset-names = "clk", "pbus", "c0", "c1", "c2"; ++ qcom,ee = <0>; ++ ++ status = "disabled"; ++ }; ++ ++ nand_controller: nand-controller@1ac00000 { ++ compatible = "qcom,ipq806x-nand"; ++ reg = <0x1ac00000 0x800>; ++ ++ clocks = <&gcc EBI2_CLK>, ++ <&gcc EBI2_AON_CLK>; ++ clock-names = "core", "aon"; ++ ++ dmas = <&adm_dma 3>; ++ dma-names = "rxtx"; ++ qcom,cmd-crci = <15>; ++ qcom,data-crci = <3>; ++ ++ status = "disabled"; ++ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ }; ++ ++ nss_common: syscon@03000000 { ++ compatible = "syscon"; ++ reg = <0x03000000 0x0000FFFF>; ++ }; ++ ++ qsgmii_csr: syscon@1bb00000 { ++ compatible = "syscon"; ++ reg = <0x1bb00000 0x000001FF>; ++ }; ++ ++ stmmac_axi_setup: stmmac-axi-config { ++ snps,wr_osr_lmt = <7>; ++ snps,rd_osr_lmt = <7>; ++ snps,blen = <16 0 0 0 0 0 0>; ++ }; ++ ++ mdio0: mdio@37000000 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ compatible = "qcom,ipq8064-mdio", "syscon"; ++ reg = <0x37000000 0x200000>; ++ resets = <&gcc GMAC_CORE1_RESET>; ++ reset-names = "stmmaceth"; ++ clocks = <&gcc GMAC_CORE1_CLK>; ++ clock-names = "stmmaceth"; ++ ++ status = "disabled"; ++ }; ++ ++ gmac0: ethernet@37000000 { ++ device_type = "network"; ++ compatible = "qcom,ipq806x-gmac"; ++ reg = <0x37000000 0x200000>; ++ interrupts = ; ++ interrupt-names = "macirq"; ++ ++ snps,axi-config = <&stmmac_axi_setup>; ++ snps,pbl = <32>; ++ snps,aal = <1>; ++ ++ qcom,nss-common = <&nss_common>; ++ qcom,qsgmii-csr = <&qsgmii_csr>; ++ ++ clocks = <&gcc GMAC_CORE1_CLK>; ++ clock-names = "stmmaceth"; ++ ++ resets = <&gcc GMAC_CORE1_RESET>; ++ reset-names = "stmmaceth"; ++ ++ status = "disabled"; ++ }; ++ ++ gmac1: ethernet@37200000 { ++ device_type = "network"; ++ compatible = "qcom,ipq806x-gmac"; ++ reg = <0x37200000 0x200000>; ++ interrupts = ; ++ interrupt-names = "macirq"; ++ ++ snps,axi-config = <&stmmac_axi_setup>; ++ snps,pbl = <32>; ++ snps,aal = <1>; ++ ++ qcom,nss-common = <&nss_common>; ++ qcom,qsgmii-csr = <&qsgmii_csr>; ++ ++ clocks = <&gcc GMAC_CORE2_CLK>; ++ clock-names = "stmmaceth"; ++ ++ resets = <&gcc GMAC_CORE2_RESET>; ++ reset-names = "stmmaceth"; ++ ++ status = "disabled"; ++ }; ++ ++ gmac2: ethernet@37400000 { ++ device_type = "network"; ++ compatible = "qcom,ipq806x-gmac", "snps,dwmac"; ++ reg = <0x37400000 0x200000>; ++ interrupts = ; ++ interrupt-names = "macirq"; ++ ++ snps,axi-config = <&stmmac_axi_setup>; ++ snps,pbl = <32>; ++ snps,aal = <1>; ++ ++ qcom,nss-common = <&nss_common>; ++ qcom,qsgmii-csr = <&qsgmii_csr>; ++ ++ clocks = <&gcc GMAC_CORE3_CLK>; ++ clock-names = "stmmaceth"; ++ ++ resets = <&gcc GMAC_CORE3_RESET>; ++ reset-names = "stmmaceth"; ++ ++ status = "disabled"; ++ }; ++ ++ gmac3: ethernet@37600000 { ++ device_type = "network"; ++ compatible = "qcom,ipq806x-gmac", "snps,dwmac"; ++ reg = <0x37600000 0x200000>; ++ interrupts = ; ++ interrupt-names = "macirq"; ++ ++ snps,axi-config = <&stmmac_axi_setup>; ++ snps,pbl = <32>; ++ snps,aal = <1>; ++ ++ qcom,nss-common = <&nss_common>; ++ qcom,qsgmii-csr = <&qsgmii_csr>; ++ ++ clocks = <&gcc GMAC_CORE4_CLK>; ++ clock-names = "stmmaceth"; ++ ++ resets = <&gcc GMAC_CORE4_RESET>; ++ reset-names = "stmmaceth"; ++ ++ status = "disabled"; ++ }; ++ + vsdcc_fixed: vsdcc-regulator { + compatible = "regulator-fixed"; + regulator-name = "SDCC Power"; +@@ -676,4 +1559,17 @@ + }; + }; + }; ++ ++ sfpb_mutex: sfpb-mutex { ++ compatible = "qcom,sfpb-mutex"; ++ syscon = <&sfpb_mutex_block 4 4>; ++ ++ #hwlock-cells = <1>; ++ }; ++ ++ smem { ++ compatible = "qcom,smem"; ++ memory-region = <&smem>; ++ hwlocks = <&sfpb_mutex 3>; ++ }; + }; diff --git a/target/linux/ipq806x/patches-5.10/084-ipq8064-v1.0-dtsi-cleanup.patch b/target/linux/ipq806x/patches-5.10/084-ipq8064-v1.0-dtsi-cleanup.patch new file mode 100644 index 0000000000..e5ea8e6393 --- /dev/null +++ b/target/linux/ipq806x/patches-5.10/084-ipq8064-v1.0-dtsi-cleanup.patch @@ -0,0 +1,89 @@ +This uses upstream qcom-ipq8064-v1.0.dtsi and modifies it by patches +instead of keeping a local version. +We drop partitions, LEDs and keys from the file as we will implement +them differently anyway. + +--- a/arch/arm/boot/dts/qcom-ipq8064-v1.0.dtsi ++++ b/arch/arm/boot/dts/qcom-ipq8064-v1.0.dtsi +@@ -42,16 +42,6 @@ + #size-cells = <1>; + spi-max-frequency = <50000000>; + reg = <0>; +- +- partition@0 { +- label = "rootfs"; +- reg = <0x0 0x1000000>; +- }; +- +- partition@1 { +- label = "scratch"; +- reg = <0x1000000 0x1000000>; +- }; + }; + }; + }; +@@ -64,64 +54,5 @@ + ports-implemented = <0x1>; + status = "ok"; + }; +- +- gpio_keys { +- compatible = "gpio-keys"; +- pinctrl-0 = <&buttons_pins>; +- pinctrl-names = "default"; +- +- button@1 { +- label = "reset"; +- linux,code = ; +- gpios = <&qcom_pinmux 54 GPIO_ACTIVE_LOW>; +- linux,input-type = <1>; +- debounce-interval = <60>; +- }; +- button@2 { +- label = "wps"; +- linux,code = ; +- gpios = <&qcom_pinmux 65 GPIO_ACTIVE_LOW>; +- linux,input-type = <1>; +- debounce-interval = <60>; +- }; +- }; +- +- leds { +- compatible = "gpio-leds"; +- pinctrl-0 = <&leds_pins>; +- pinctrl-names = "default"; +- +- led@7 { +- label = "led_usb1"; +- gpios = <&qcom_pinmux 7 GPIO_ACTIVE_HIGH>; +- linux,default-trigger = "usbdev"; +- default-state = "off"; +- }; +- +- led@8 { +- label = "led_usb3"; +- gpios = <&qcom_pinmux 8 GPIO_ACTIVE_HIGH>; +- linux,default-trigger = "usbdev"; +- default-state = "off"; +- }; +- +- led@9 { +- label = "status_led_fail"; +- gpios = <&qcom_pinmux 9 GPIO_ACTIVE_HIGH>; +- default-state = "off"; +- }; +- +- led@26 { +- label = "sata_led"; +- gpios = <&qcom_pinmux 26 GPIO_ACTIVE_HIGH>; +- default-state = "off"; +- }; +- +- led@53 { +- label = "status_led_pass"; +- gpios = <&qcom_pinmux 53 GPIO_ACTIVE_HIGH>; +- default-state = "off"; +- }; +- }; + }; + }; diff --git a/target/linux/ipq806x/patches-5.10/085-ipq8064-v1.0-dtsi-additions.patch b/target/linux/ipq806x/patches-5.10/085-ipq8064-v1.0-dtsi-additions.patch new file mode 100644 index 0000000000..58f6a46e4f --- /dev/null +++ b/target/linux/ipq806x/patches-5.10/085-ipq8064-v1.0-dtsi-additions.patch @@ -0,0 +1,14 @@ +This uses upstream qcom-ipq8064-v1.0.dtsi and modifies it by patches +instead of keeping a local version. This patch adds our local adjustments +for the (local) additional contents of qcom-ipq8064.dtsi + +--- a/arch/arm/boot/dts/qcom-ipq8064-v1.0.dtsi ++++ b/arch/arm/boot/dts/qcom-ipq8064-v1.0.dtsi +@@ -56,3 +56,7 @@ + }; + }; + }; ++ ++&CPU_SPC { ++ status = "okay"; ++}; diff --git a/target/linux/ipq806x/patches-5.10/086-v5.8-pinctrl-qom-use-scm_call-to-route-GPIO-irq-to-Apps.patch b/target/linux/ipq806x/patches-5.10/086-v5.8-pinctrl-qom-use-scm_call-to-route-GPIO-irq-to-Apps.patch new file mode 100644 index 0000000000..2b5171fc54 --- /dev/null +++ b/target/linux/ipq806x/patches-5.10/086-v5.8-pinctrl-qom-use-scm_call-to-route-GPIO-irq-to-Apps.patch @@ -0,0 +1,104 @@ +From 13bec8d49bdf10aab4e1570ef42417f6bfbb6126 Mon Sep 17 00:00:00 2001 +From: Ajay Kishore +Date: Fri, 27 Mar 2020 23:32:08 +0100 +Subject: pinctrl: qcom: use scm_call to route GPIO irq to Apps + +For IPQ806x targets, TZ protects the registers that are used to +configure the routing of interrupts to a target processor. +To resolve this, this patch uses scm call to route GPIO interrupts +to application processor. Also the scm call interface is changed. + +Signed-off-by: Ajay Kishore +Signed-off-by: Ansuel Smith +Link: https://lore.kernel.org/r/20200327223209.20409-1-ansuelsmth@gmail.com +Reviewed-by: Bjorn Andersson +Signed-off-by: Linus Walleij +--- + drivers/pinctrl/qcom/pinctrl-msm.c | 43 ++++++++++++++++++++++++++++++++------ + 1 file changed, 37 insertions(+), 6 deletions(-) + +(limited to 'drivers/pinctrl/qcom/pinctrl-msm.c') + +--- a/drivers/pinctrl/qcom/pinctrl-msm.c ++++ b/drivers/pinctrl/qcom/pinctrl-msm.c +@@ -22,6 +22,8 @@ + #include + #include + #include ++#include ++#include + + #include "../core.h" + #include "../pinconf.h" +@@ -57,6 +59,8 @@ struct msm_pinctrl { + struct irq_chip irq_chip; + int irq; + ++ bool intr_target_use_scm; ++ + raw_spinlock_t lock; + + DECLARE_BITMAP(dual_edge_irqs, MAX_NR_GPIO); +@@ -64,6 +68,7 @@ struct msm_pinctrl { + + const struct msm_pinctrl_soc_data *soc; + void __iomem *regs[MAX_NR_TILES]; ++ u32 phys_base[MAX_NR_TILES]; + }; + + #define MSM_ACCESSOR(name) \ +@@ -832,11 +837,30 @@ static int msm_gpio_irq_set_type(struct + else + clear_bit(d->hwirq, pctrl->dual_edge_irqs); + +- /* Route interrupts to application cpu */ +- val = msm_readl_intr_target(pctrl, g); +- val &= ~(7 << g->intr_target_bit); +- val |= g->intr_target_kpss_val << g->intr_target_bit; +- msm_writel_intr_target(val, pctrl, g); ++ /* Route interrupts to application cpu. ++ * With intr_target_use_scm interrupts are routed to ++ * application cpu using scm calls. ++ */ ++ if (pctrl->intr_target_use_scm) { ++ u32 addr = pctrl->phys_base[0] + g->intr_target_reg; ++ int ret; ++ ++ qcom_scm_io_readl(addr, &val); ++ ++ val &= ~(7 << g->intr_target_bit); ++ val |= g->intr_target_kpss_val << g->intr_target_bit; ++ ++ ret = qcom_scm_io_writel(addr, val); ++ if (ret) ++ dev_err(pctrl->dev, ++ "Failed routing %lu interrupt to Apps proc", ++ d->hwirq); ++ } else { ++ val = msm_readl_intr_target(pctrl, g); ++ val &= ~(7 << g->intr_target_bit); ++ val |= g->intr_target_kpss_val << g->intr_target_bit; ++ msm_writel_intr_target(val, pctrl, g); ++ } + + /* Update configuration for gpio. + * RAW_STATUS_EN is left on for all gpio irqs. Due to the +@@ -1138,6 +1162,9 @@ int msm_pinctrl_probe(struct platform_de + pctrl->dev = &pdev->dev; + pctrl->soc = soc_data; + pctrl->chip = msm_gpio_template; ++ pctrl->intr_target_use_scm = of_device_is_compatible( ++ pctrl->dev->of_node, ++ "qcom,ipq8064-pinctrl"); + + raw_spin_lock_init(&pctrl->lock); + +@@ -1154,6 +1181,8 @@ int msm_pinctrl_probe(struct platform_de + pctrl->regs[0] = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(pctrl->regs[0])) + return PTR_ERR(pctrl->regs[0]); ++ ++ pctrl->phys_base[0] = res->start; + } + + msm_pinctrl_setup_pm_reset(pctrl); diff --git a/target/linux/ipq806x/patches-5.10/087-v5.8-ipq8064-pinctrl-Fixed-missing-RGMII-pincontrol-defin.patch b/target/linux/ipq806x/patches-5.10/087-v5.8-ipq8064-pinctrl-Fixed-missing-RGMII-pincontrol-defin.patch new file mode 100644 index 0000000000..612c33cd0e --- /dev/null +++ b/target/linux/ipq806x/patches-5.10/087-v5.8-ipq8064-pinctrl-Fixed-missing-RGMII-pincontrol-defin.patch @@ -0,0 +1,56 @@ +From 8d8cec9bf6e9260397872785f249dfb59a417d08 Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Wed, 19 Feb 2020 18:59:39 +0100 +Subject: ipq8064: pinctrl: Fixed missing RGMII pincontrol definitions + +Add missing gpio definition for mdio and rgmii2. + +Signed-off-by: Ram Chandra Jangir +Signed-off-by: Ansuel Smith +Link: https://lore.kernel.org/r/20200219175940.744-1-ansuelsmth@gmail.com +Acked-by: Bjorn Andersson +Signed-off-by: Linus Walleij +--- + drivers/pinctrl/qcom/pinctrl-ipq8064.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +--- a/drivers/pinctrl/qcom/pinctrl-ipq8064.c ++++ b/drivers/pinctrl/qcom/pinctrl-ipq8064.c +@@ -299,7 +299,7 @@ static const char * const gpio_groups[] + }; + + static const char * const mdio_groups[] = { +- "gpio0", "gpio1", "gpio10", "gpio11", ++ "gpio0", "gpio1", "gpio2", "gpio10", "gpio11", "gpio66", + }; + + static const char * const mi2s_groups[] = { +@@ -403,8 +403,8 @@ static const char * const usb2_hsic_grou + }; + + static const char * const rgmii2_groups[] = { +- "gpio27", "gpio28", "gpio29", "gpio30", "gpio31", "gpio32", +- "gpio51", "gpio52", "gpio59", "gpio60", "gpio61", "gpio62", ++ "gpio2", "gpio27", "gpio28", "gpio29", "gpio30", "gpio31", "gpio32", ++ "gpio51", "gpio52", "gpio59", "gpio60", "gpio61", "gpio62", "gpio66", + }; + + static const char * const sata_groups[] = { +@@ -539,7 +539,7 @@ static const struct msm_function ipq8064 + static const struct msm_pingroup ipq8064_groups[] = { + PINGROUP(0, mdio, NA, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(1, mdio, NA, NA, NA, NA, NA, NA, NA, NA, NA), +- PINGROUP(2, gsbi5_spi_cs3, NA, NA, NA, NA, NA, NA, NA, NA, NA), ++ PINGROUP(2, gsbi5_spi_cs3, rgmii2, mdio, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(3, pcie1_rst, pcie1_prsnt, pdm, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(4, pcie1_pwren_n, pcie1_pwren, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(5, pcie1_clk_req, pcie1_pwrflt, NA, NA, NA, NA, NA, NA, NA, NA), +@@ -603,7 +603,7 @@ static const struct msm_pingroup ipq8064 + PINGROUP(63, pcie3_rst, NA, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(64, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(65, pcie3_clk_req, NA, NA, NA, NA, NA, NA, NA, NA, NA), +- PINGROUP(66, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA), ++ PINGROUP(66, rgmii2, mdio, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(67, usb2_hsic, NA, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(68, usb2_hsic, NA, NA, NA, NA, NA, NA, NA, NA, NA), + SDC_PINGROUP(sdc3_clk, 0x204a, 14, 6), diff --git a/target/linux/ipq806x/patches-5.10/088-v5.8-watchdog-qcom-wdt-disable-pretimeout-on-timer-platfo.patch b/target/linux/ipq806x/patches-5.10/088-v5.8-watchdog-qcom-wdt-disable-pretimeout-on-timer-platfo.patch new file mode 100644 index 0000000000..605eb7d07b --- /dev/null +++ b/target/linux/ipq806x/patches-5.10/088-v5.8-watchdog-qcom-wdt-disable-pretimeout-on-timer-platfo.patch @@ -0,0 +1,98 @@ +From 000de5417107623925a4cf0310579f744ff43c28 Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Tue, 4 Feb 2020 20:56:48 +0100 +Subject: watchdog: qcom-wdt: disable pretimeout on timer platform + +Some platform like ipq806x doesn't support pretimeout and define +some interrupts used by qcom,msm-timer. Change the driver to check +and use pretimeout only on qcom,kpss-wdt as it's the only platform +that actually supports it. + +Signed-off-by: Ansuel Smith +Reviewed-by: Guenter Roeck +Link: https://lore.kernel.org/r/20200204195648.23350-1-ansuelsmth@gmail.com +[groeck: Conflict resolution] +Signed-off-by: Guenter Roeck +Signed-off-by: Wim Van Sebroeck +--- + drivers/watchdog/qcom-wdt.c | 31 +++++++++++++++++++++++-------- + 1 file changed, 23 insertions(+), 8 deletions(-) + +--- a/drivers/watchdog/qcom-wdt.c ++++ b/drivers/watchdog/qcom-wdt.c +@@ -40,6 +40,11 @@ static const u32 reg_offset_data_kpss[] + [WDT_BITE_TIME] = 0x14, + }; + ++struct qcom_wdt_match_data { ++ const u32 *offset; ++ bool pretimeout; ++}; ++ + struct qcom_wdt { + struct watchdog_device wdd; + unsigned long rate; +@@ -179,19 +184,29 @@ static void qcom_clk_disable_unprepare(v + clk_disable_unprepare(data); + } + ++static const struct qcom_wdt_match_data match_data_apcs_tmr = { ++ .offset = reg_offset_data_apcs_tmr, ++ .pretimeout = false, ++}; ++ ++static const struct qcom_wdt_match_data match_data_kpss = { ++ .offset = reg_offset_data_kpss, ++ .pretimeout = true, ++}; ++ + static int qcom_wdt_probe(struct platform_device *pdev) + { + struct device *dev = &pdev->dev; + struct qcom_wdt *wdt; + struct resource *res; + struct device_node *np = dev->of_node; +- const u32 *regs; ++ const struct qcom_wdt_match_data *data; + u32 percpu_offset; + int irq, ret; + struct clk *clk; + +- regs = of_device_get_match_data(dev); +- if (!regs) { ++ data = of_device_get_match_data(dev); ++ if (!data) { + dev_err(dev, "Unsupported QCOM WDT module\n"); + return -ENODEV; + } +@@ -247,7 +262,7 @@ static int qcom_wdt_probe(struct platfor + + /* check if there is pretimeout support */ + irq = platform_get_irq_optional(pdev, 0); +- if (irq > 0) { ++ if (data->pretimeout && irq > 0) { + ret = devm_request_irq(dev, irq, qcom_wdt_isr, + IRQF_TRIGGER_RISING, + "wdt_bark", &wdt->wdd); +@@ -267,7 +282,7 @@ static int qcom_wdt_probe(struct platfor + wdt->wdd.min_timeout = 1; + wdt->wdd.max_timeout = 0x10000000U / wdt->rate; + wdt->wdd.parent = dev; +- wdt->layout = regs; ++ wdt->layout = data->offset; + + if (readl(wdt_addr(wdt, WDT_STS)) & 1) + wdt->wdd.bootstatus = WDIOF_CARDRESET; +@@ -311,9 +326,9 @@ static int __maybe_unused qcom_wdt_resum + static SIMPLE_DEV_PM_OPS(qcom_wdt_pm_ops, qcom_wdt_suspend, qcom_wdt_resume); + + static const struct of_device_id qcom_wdt_of_table[] = { +- { .compatible = "qcom,kpss-timer", .data = reg_offset_data_apcs_tmr }, +- { .compatible = "qcom,scss-timer", .data = reg_offset_data_apcs_tmr }, +- { .compatible = "qcom,kpss-wdt", .data = reg_offset_data_kpss }, ++ { .compatible = "qcom,kpss-timer", .data = &match_data_apcs_tmr }, ++ { .compatible = "qcom,scss-timer", .data = &match_data_apcs_tmr }, ++ { .compatible = "qcom,kpss-wdt", .data = &match_data_kpss }, + { }, + }; + MODULE_DEVICE_TABLE(of, qcom_wdt_of_table); diff --git a/target/linux/ipq806x/patches-5.10/089-v5.8-ipq806x-gcc-Added-the-enable-regs-and-mask-for-PRNG.patch b/target/linux/ipq806x/patches-5.10/089-v5.8-ipq806x-gcc-Added-the-enable-regs-and-mask-for-PRNG.patch new file mode 100644 index 0000000000..015a917e20 --- /dev/null +++ b/target/linux/ipq806x/patches-5.10/089-v5.8-ipq806x-gcc-Added-the-enable-regs-and-mask-for-PRNG.patch @@ -0,0 +1,28 @@ +From 1aec193ea41d672d11592714cdda8167eb3b38fc Mon Sep 17 00:00:00 2001 +From: Abhishek Sahu +Date: Wed, 18 Mar 2020 14:16:56 +0100 +Subject: ipq806x: gcc: Added the enable regs and mask for PRNG + +Kernel got hanged while reading from /dev/hwrng at the +time of PRNG clock enable + +Fixes: 24d8fba44af3 "clk: qcom: Add support for IPQ8064's global clock controller (GCC)" +Signed-off-by: Abhishek Sahu +Signed-off-by: Ansuel Smith +Link: https://lkml.kernel.org/r/20200318131657.345-1-ansuelsmth@gmail.com +Signed-off-by: Stephen Boyd +--- + drivers/clk/qcom/gcc-ipq806x.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/drivers/clk/qcom/gcc-ipq806x.c ++++ b/drivers/clk/qcom/gcc-ipq806x.c +@@ -1225,6 +1225,8 @@ static struct clk_rcg prng_src = { + .parent_map = gcc_pxo_pll8_map, + }, + .clkr = { ++ .enable_reg = 0x2e80, ++ .enable_mask = BIT(11), + .hw.init = &(struct clk_init_data){ + .name = "prng_src", + .parent_names = gcc_pxo_pll8, diff --git a/target/linux/ipq806x/patches-5.10/090-v5.8-clk-clk-rpm-fixes.patch b/target/linux/ipq806x/patches-5.10/090-v5.8-clk-clk-rpm-fixes.patch new file mode 100644 index 0000000000..a28570974e --- /dev/null +++ b/target/linux/ipq806x/patches-5.10/090-v5.8-clk-clk-rpm-fixes.patch @@ -0,0 +1,90 @@ +From eec152734be10c72d2d413a27ca9d282c28cdb61 Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Tue, 10 Mar 2020 15:37:56 +0100 +Subject: clk: qcom: clk-rpm: add missing rpm clk for ipq806x + +Add missing definition of rpm clk for ipq806x soc + +Signed-off-by: John Crispin +Signed-off-by: Ansuel Smith +Acked-by: John Crispin +Reviewed-by: Rob Herring +Link: https://lkml.kernel.org/r/20200310143756.244-1-ansuelsmth@gmail.com +Signed-off-by: Stephen Boyd +--- + .../devicetree/bindings/clock/qcom,rpmcc.txt | 1 + + drivers/clk/qcom/clk-rpm.c | 35 ++++++++++++++++++++++ + include/dt-bindings/clock/qcom,rpmcc.h | 4 +++ + 3 files changed, 40 insertions(+) + +--- a/Documentation/devicetree/bindings/clock/qcom,rpmcc.txt ++++ b/Documentation/devicetree/bindings/clock/qcom,rpmcc.txt +@@ -15,6 +15,7 @@ Required properties : + "qcom,rpmcc-msm8916", "qcom,rpmcc" + "qcom,rpmcc-msm8974", "qcom,rpmcc" + "qcom,rpmcc-apq8064", "qcom,rpmcc" ++ "qcom,rpmcc-ipq806x", "qcom,rpmcc" + "qcom,rpmcc-msm8996", "qcom,rpmcc" + "qcom,rpmcc-msm8998", "qcom,rpmcc" + "qcom,rpmcc-qcs404", "qcom,rpmcc" +--- a/drivers/clk/qcom/clk-rpm.c ++++ b/drivers/clk/qcom/clk-rpm.c +@@ -543,10 +543,45 @@ static const struct rpm_clk_desc rpm_clk + .num_clks = ARRAY_SIZE(apq8064_clks), + }; + ++/* ipq806x */ ++DEFINE_CLK_RPM(ipq806x, afab_clk, afab_a_clk, QCOM_RPM_APPS_FABRIC_CLK); ++DEFINE_CLK_RPM(ipq806x, cfpb_clk, cfpb_a_clk, QCOM_RPM_CFPB_CLK); ++DEFINE_CLK_RPM(ipq806x, daytona_clk, daytona_a_clk, QCOM_RPM_DAYTONA_FABRIC_CLK); ++DEFINE_CLK_RPM(ipq806x, ebi1_clk, ebi1_a_clk, QCOM_RPM_EBI1_CLK); ++DEFINE_CLK_RPM(ipq806x, sfab_clk, sfab_a_clk, QCOM_RPM_SYS_FABRIC_CLK); ++DEFINE_CLK_RPM(ipq806x, sfpb_clk, sfpb_a_clk, QCOM_RPM_SFPB_CLK); ++DEFINE_CLK_RPM(ipq806x, nss_fabric_0_clk, nss_fabric_0_a_clk, QCOM_RPM_NSS_FABRIC_0_CLK); ++DEFINE_CLK_RPM(ipq806x, nss_fabric_1_clk, nss_fabric_1_a_clk, QCOM_RPM_NSS_FABRIC_1_CLK); ++ ++static struct clk_rpm *ipq806x_clks[] = { ++ [RPM_APPS_FABRIC_CLK] = &ipq806x_afab_clk, ++ [RPM_APPS_FABRIC_A_CLK] = &ipq806x_afab_a_clk, ++ [RPM_CFPB_CLK] = &ipq806x_cfpb_clk, ++ [RPM_CFPB_A_CLK] = &ipq806x_cfpb_a_clk, ++ [RPM_DAYTONA_FABRIC_CLK] = &ipq806x_daytona_clk, ++ [RPM_DAYTONA_FABRIC_A_CLK] = &ipq806x_daytona_a_clk, ++ [RPM_EBI1_CLK] = &ipq806x_ebi1_clk, ++ [RPM_EBI1_A_CLK] = &ipq806x_ebi1_a_clk, ++ [RPM_SYS_FABRIC_CLK] = &ipq806x_sfab_clk, ++ [RPM_SYS_FABRIC_A_CLK] = &ipq806x_sfab_a_clk, ++ [RPM_SFPB_CLK] = &ipq806x_sfpb_clk, ++ [RPM_SFPB_A_CLK] = &ipq806x_sfpb_a_clk, ++ [RPM_NSS_FABRIC_0_CLK] = &ipq806x_nss_fabric_0_clk, ++ [RPM_NSS_FABRIC_0_A_CLK] = &ipq806x_nss_fabric_0_a_clk, ++ [RPM_NSS_FABRIC_1_CLK] = &ipq806x_nss_fabric_1_clk, ++ [RPM_NSS_FABRIC_1_A_CLK] = &ipq806x_nss_fabric_1_a_clk, ++}; ++ ++static const struct rpm_clk_desc rpm_clk_ipq806x = { ++ .clks = ipq806x_clks, ++ .num_clks = ARRAY_SIZE(ipq806x_clks), ++}; ++ + static const struct of_device_id rpm_clk_match_table[] = { + { .compatible = "qcom,rpmcc-msm8660", .data = &rpm_clk_msm8660 }, + { .compatible = "qcom,rpmcc-apq8060", .data = &rpm_clk_msm8660 }, + { .compatible = "qcom,rpmcc-apq8064", .data = &rpm_clk_apq8064 }, ++ { .compatible = "qcom,rpmcc-ipq806x", .data = &rpm_clk_ipq806x }, + { } + }; + MODULE_DEVICE_TABLE(of, rpm_clk_match_table); +--- a/include/dt-bindings/clock/qcom,rpmcc.h ++++ b/include/dt-bindings/clock/qcom,rpmcc.h +@@ -37,6 +37,10 @@ + #define RPM_XO_A0 27 + #define RPM_XO_A1 28 + #define RPM_XO_A2 29 ++#define RPM_NSS_FABRIC_0_CLK 30 ++#define RPM_NSS_FABRIC_0_A_CLK 31 ++#define RPM_NSS_FABRIC_1_CLK 32 ++#define RPM_NSS_FABRIC_1_A_CLK 33 + + /* SMD RPM clocks */ + #define RPM_SMD_XO_CLK_SRC 0 diff --git a/target/linux/ipq806x/patches-5.10/091-v5.8-regulator-add-smb208-support.patch b/target/linux/ipq806x/patches-5.10/091-v5.8-regulator-add-smb208-support.patch new file mode 100644 index 0000000000..42a02865a3 --- /dev/null +++ b/target/linux/ipq806x/patches-5.10/091-v5.8-regulator-add-smb208-support.patch @@ -0,0 +1,63 @@ +From b5f25304aece9f2e7eaab275bbb5461c666bf38c Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Wed, 19 Feb 2020 17:37:11 +0100 +Subject: regulator: add smb208 support + +Smb208 regulators are used on some ipq806x soc. +Add support for it to make it avaiable on some routers +that use it. + +Signed-off-by: Ansuel Smith +Signed-off-by: Adrian Panella +Acked-by: Lee Jones +Link: https://lore.kernel.org/r/20200219163711.479-1-ansuelsmth@gmail.com +Signed-off-by: Mark Brown +--- + Documentation/devicetree/bindings/mfd/qcom-rpm.txt | 4 ++++ + drivers/regulator/qcom_rpm-regulator.c | 9 +++++++++ + 2 files changed, 13 insertions(+) + +--- a/Documentation/devicetree/bindings/mfd/qcom-rpm.txt ++++ b/Documentation/devicetree/bindings/mfd/qcom-rpm.txt +@@ -61,6 +61,7 @@ Regulator nodes are identified by their + "qcom,rpm-pm8901-regulators" + "qcom,rpm-pm8921-regulators" + "qcom,rpm-pm8018-regulators" ++ "qcom,rpm-smb208-regulators" + + - vdd_l0_l1_lvs-supply: + - vdd_l2_l11_l12-supply: +@@ -171,6 +172,9 @@ pm8018: + s1, s2, s3, s4, s5, , l1, l2, l3, l4, l5, l6, l7, l8, l9, l10, l11, + l12, l14, lvs1 + ++smb208: ++ s1a, s1b, s2a, s2b ++ + The content of each sub-node is defined by the standard binding for regulators - + see regulator.txt - with additional custom properties described below: + +--- a/drivers/regulator/qcom_rpm-regulator.c ++++ b/drivers/regulator/qcom_rpm-regulator.c +@@ -925,12 +925,21 @@ static const struct rpm_regulator_data r + { } + }; + ++static const struct rpm_regulator_data rpm_smb208_regulators[] = { ++ { "s1a", QCOM_RPM_SMB208_S1a, &smb208_smps, "vin_s1a" }, ++ { "s1b", QCOM_RPM_SMB208_S1b, &smb208_smps, "vin_s1b" }, ++ { "s2a", QCOM_RPM_SMB208_S2a, &smb208_smps, "vin_s2a" }, ++ { "s2b", QCOM_RPM_SMB208_S2b, &smb208_smps, "vin_s2b" }, ++ { } ++}; ++ + static const struct of_device_id rpm_of_match[] = { + { .compatible = "qcom,rpm-pm8018-regulators", + .data = &rpm_pm8018_regulators }, + { .compatible = "qcom,rpm-pm8058-regulators", .data = &rpm_pm8058_regulators }, + { .compatible = "qcom,rpm-pm8901-regulators", .data = &rpm_pm8901_regulators }, + { .compatible = "qcom,rpm-pm8921-regulators", .data = &rpm_pm8921_regulators }, ++ { .compatible = "qcom,rpm-smb208-regulators", .data = &rpm_smb208_regulators }, + { } + }; + MODULE_DEVICE_TABLE(of, rpm_of_match); diff --git a/target/linux/ipq806x/patches-5.10/092-1-v5.7-qcom-cpufreq-nvmem-Add-support-for-krait-based-socs.patch b/target/linux/ipq806x/patches-5.10/092-1-v5.7-qcom-cpufreq-nvmem-Add-support-for-krait-based-socs.patch new file mode 100644 index 0000000000..be20756a10 --- /dev/null +++ b/target/linux/ipq806x/patches-5.10/092-1-v5.7-qcom-cpufreq-nvmem-Add-support-for-krait-based-socs.patch @@ -0,0 +1,361 @@ +From a8811ec764f95a04ba82f6f457e28c5e9e36e36b Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Fri, 13 Mar 2020 18:52:13 +0100 +Subject: cpufreq: qcom: Add support for krait based socs + +In Certain QCOM SoCs like ipq8064, apq8064, msm8960, msm8974 +that has KRAIT processors the voltage/current value of each OPP +varies based on the silicon variant in use. + +The required OPP related data is determined based on +the efuse value. This is similar to the existing code for +kryo cores. So adding support for krait cores here. + +Signed-off-by: Sricharan R +Signed-off-by: Ansuel Smith +Signed-off-by: Viresh Kumar +--- + .../devicetree/bindings/opp/qcom-nvmem-cpufreq.txt | 3 +- + drivers/cpufreq/Kconfig.arm | 2 +- + drivers/cpufreq/cpufreq-dt-platdev.c | 5 + + drivers/cpufreq/qcom-cpufreq-nvmem.c | 191 +++++++++++++++++++-- + 4 files changed, 183 insertions(+), 18 deletions(-) + +--- a/Documentation/devicetree/bindings/opp/qcom-nvmem-cpufreq.txt ++++ b/Documentation/devicetree/bindings/opp/qcom-nvmem-cpufreq.txt +@@ -19,7 +19,8 @@ In 'cpu' nodes: + + In 'operating-points-v2' table: + - compatible: Should be +- - 'operating-points-v2-kryo-cpu' for apq8096 and msm8996. ++ - 'operating-points-v2-kryo-cpu' for apq8096, msm8996, msm8974, ++ apq8064, ipq8064, msm8960 and ipq8074. + + Optional properties: + -------------------- +--- a/drivers/cpufreq/Kconfig.arm ++++ b/drivers/cpufreq/Kconfig.arm +@@ -135,7 +135,7 @@ config ARM_OMAP2PLUS_CPUFREQ + + config ARM_QCOM_CPUFREQ_NVMEM + tristate "Qualcomm nvmem based CPUFreq" +- depends on ARM64 ++ depends on ARCH_QCOM + depends on QCOM_QFPROM + depends on QCOM_SMEM + select PM_OPP +--- a/drivers/cpufreq/cpufreq-dt-platdev.c ++++ b/drivers/cpufreq/cpufreq-dt-platdev.c +@@ -138,6 +138,11 @@ static const struct of_device_id blackli + { .compatible = "ti,am43", }, + { .compatible = "ti,dra7", }, + ++ { .compatible = "qcom,ipq8064", }, ++ { .compatible = "qcom,apq8064", }, ++ { .compatible = "qcom,msm8974", }, ++ { .compatible = "qcom,msm8960", }, ++ + { } + }; + +--- a/drivers/cpufreq/qcom-cpufreq-nvmem.c ++++ b/drivers/cpufreq/qcom-cpufreq-nvmem.c +@@ -49,12 +49,14 @@ struct qcom_cpufreq_drv; + struct qcom_cpufreq_match_data { + int (*get_version)(struct device *cpu_dev, + struct nvmem_cell *speedbin_nvmem, ++ char **pvs_name, + struct qcom_cpufreq_drv *drv); + const char **genpd_names; + }; + + struct qcom_cpufreq_drv { +- struct opp_table **opp_tables; ++ struct opp_table **names_opp_tables; ++ struct opp_table **hw_opp_tables; + struct opp_table **genpd_opp_tables; + u32 versions; + const struct qcom_cpufreq_match_data *data; +@@ -62,6 +64,84 @@ struct qcom_cpufreq_drv { + + static struct platform_device *cpufreq_dt_pdev, *cpufreq_pdev; + ++static void get_krait_bin_format_a(struct device *cpu_dev, ++ int *speed, int *pvs, int *pvs_ver, ++ struct nvmem_cell *pvs_nvmem, u8 *buf) ++{ ++ u32 pte_efuse; ++ ++ pte_efuse = *((u32 *)buf); ++ ++ *speed = pte_efuse & 0xf; ++ if (*speed == 0xf) ++ *speed = (pte_efuse >> 4) & 0xf; ++ ++ if (*speed == 0xf) { ++ *speed = 0; ++ dev_warn(cpu_dev, "Speed bin: Defaulting to %d\n", *speed); ++ } else { ++ dev_dbg(cpu_dev, "Speed bin: %d\n", *speed); ++ } ++ ++ *pvs = (pte_efuse >> 10) & 0x7; ++ if (*pvs == 0x7) ++ *pvs = (pte_efuse >> 13) & 0x7; ++ ++ if (*pvs == 0x7) { ++ *pvs = 0; ++ dev_warn(cpu_dev, "PVS bin: Defaulting to %d\n", *pvs); ++ } else { ++ dev_dbg(cpu_dev, "PVS bin: %d\n", *pvs); ++ } ++} ++ ++static void get_krait_bin_format_b(struct device *cpu_dev, ++ int *speed, int *pvs, int *pvs_ver, ++ struct nvmem_cell *pvs_nvmem, u8 *buf) ++{ ++ u32 pte_efuse, redundant_sel; ++ ++ pte_efuse = *((u32 *)buf); ++ redundant_sel = (pte_efuse >> 24) & 0x7; ++ ++ *pvs_ver = (pte_efuse >> 4) & 0x3; ++ ++ switch (redundant_sel) { ++ case 1: ++ *pvs = ((pte_efuse >> 28) & 0x8) | ((pte_efuse >> 6) & 0x7); ++ *speed = (pte_efuse >> 27) & 0xf; ++ break; ++ case 2: ++ *pvs = (pte_efuse >> 27) & 0xf; ++ *speed = pte_efuse & 0x7; ++ break; ++ default: ++ /* 4 bits of PVS are in efuse register bits 31, 8-6. */ ++ *pvs = ((pte_efuse >> 28) & 0x8) | ((pte_efuse >> 6) & 0x7); ++ *speed = pte_efuse & 0x7; ++ } ++ ++ /* Check SPEED_BIN_BLOW_STATUS */ ++ if (pte_efuse & BIT(3)) { ++ dev_dbg(cpu_dev, "Speed bin: %d\n", *speed); ++ } else { ++ dev_warn(cpu_dev, "Speed bin not set. Defaulting to 0!\n"); ++ *speed = 0; ++ } ++ ++ /* Check PVS_BLOW_STATUS */ ++ pte_efuse = *(((u32 *)buf) + 4); ++ pte_efuse &= BIT(21); ++ if (pte_efuse) { ++ dev_dbg(cpu_dev, "PVS bin: %d\n", *pvs); ++ } else { ++ dev_warn(cpu_dev, "PVS bin not set. Defaulting to 0!\n"); ++ *pvs = 0; ++ } ++ ++ dev_dbg(cpu_dev, "PVS version: %d\n", *pvs_ver); ++} ++ + static enum _msm8996_version qcom_cpufreq_get_msm_id(void) + { + size_t len; +@@ -93,11 +173,13 @@ static enum _msm8996_version qcom_cpufre + + static int qcom_cpufreq_kryo_name_version(struct device *cpu_dev, + struct nvmem_cell *speedbin_nvmem, ++ char **pvs_name, + struct qcom_cpufreq_drv *drv) + { + size_t len; + u8 *speedbin; + enum _msm8996_version msm8996_version; ++ *pvs_name = NULL; + + msm8996_version = qcom_cpufreq_get_msm_id(); + if (NUM_OF_MSM8996_VERSIONS == msm8996_version) { +@@ -125,10 +207,51 @@ static int qcom_cpufreq_kryo_name_versio + return 0; + } + ++static int qcom_cpufreq_krait_name_version(struct device *cpu_dev, ++ struct nvmem_cell *speedbin_nvmem, ++ char **pvs_name, ++ struct qcom_cpufreq_drv *drv) ++{ ++ int speed = 0, pvs = 0, pvs_ver = 0; ++ u8 *speedbin; ++ size_t len; ++ ++ speedbin = nvmem_cell_read(speedbin_nvmem, &len); ++ ++ if (IS_ERR(speedbin)) ++ return PTR_ERR(speedbin); ++ ++ switch (len) { ++ case 4: ++ get_krait_bin_format_a(cpu_dev, &speed, &pvs, &pvs_ver, ++ speedbin_nvmem, speedbin); ++ break; ++ case 8: ++ get_krait_bin_format_b(cpu_dev, &speed, &pvs, &pvs_ver, ++ speedbin_nvmem, speedbin); ++ break; ++ default: ++ dev_err(cpu_dev, "Unable to read nvmem data. Defaulting to 0!\n"); ++ return -ENODEV; ++ } ++ ++ snprintf(*pvs_name, sizeof("speedXX-pvsXX-vXX"), "speed%d-pvs%d-v%d", ++ speed, pvs, pvs_ver); ++ ++ drv->versions = (1 << speed); ++ ++ kfree(speedbin); ++ return 0; ++} ++ + static const struct qcom_cpufreq_match_data match_data_kryo = { + .get_version = qcom_cpufreq_kryo_name_version, + }; + ++static const struct qcom_cpufreq_match_data match_data_krait = { ++ .get_version = qcom_cpufreq_krait_name_version, ++}; ++ + static const char *qcs404_genpd_names[] = { "cpr", NULL }; + + static const struct qcom_cpufreq_match_data match_data_qcs404 = { +@@ -141,6 +264,7 @@ static int qcom_cpufreq_probe(struct pla + struct nvmem_cell *speedbin_nvmem; + struct device_node *np; + struct device *cpu_dev; ++ char *pvs_name = "speedXX-pvsXX-vXX"; + unsigned cpu; + const struct of_device_id *match; + int ret; +@@ -153,7 +277,7 @@ static int qcom_cpufreq_probe(struct pla + if (!np) + return -ENOENT; + +- ret = of_device_is_compatible(np, "operating-points-v2-kryo-cpu"); ++ ret = of_device_is_compatible(np, "operating-points-v2-qcom-cpu"); + if (!ret) { + of_node_put(np); + return -ENOENT; +@@ -181,7 +305,8 @@ static int qcom_cpufreq_probe(struct pla + goto free_drv; + } + +- ret = drv->data->get_version(cpu_dev, speedbin_nvmem, drv); ++ ret = drv->data->get_version(cpu_dev, ++ speedbin_nvmem, &pvs_name, drv); + if (ret) { + nvmem_cell_put(speedbin_nvmem); + goto free_drv; +@@ -190,12 +315,20 @@ static int qcom_cpufreq_probe(struct pla + } + of_node_put(np); + +- drv->opp_tables = kcalloc(num_possible_cpus(), sizeof(*drv->opp_tables), ++ drv->names_opp_tables = kcalloc(num_possible_cpus(), ++ sizeof(*drv->names_opp_tables), + GFP_KERNEL); +- if (!drv->opp_tables) { ++ if (!drv->names_opp_tables) { + ret = -ENOMEM; + goto free_drv; + } ++ drv->hw_opp_tables = kcalloc(num_possible_cpus(), ++ sizeof(*drv->hw_opp_tables), ++ GFP_KERNEL); ++ if (!drv->hw_opp_tables) { ++ ret = -ENOMEM; ++ goto free_opp_names; ++ } + + drv->genpd_opp_tables = kcalloc(num_possible_cpus(), + sizeof(*drv->genpd_opp_tables), +@@ -213,11 +346,23 @@ static int qcom_cpufreq_probe(struct pla + } + + if (drv->data->get_version) { +- drv->opp_tables[cpu] = +- dev_pm_opp_set_supported_hw(cpu_dev, +- &drv->versions, 1); +- if (IS_ERR(drv->opp_tables[cpu])) { +- ret = PTR_ERR(drv->opp_tables[cpu]); ++ ++ if (pvs_name) { ++ drv->names_opp_tables[cpu] = dev_pm_opp_set_prop_name( ++ cpu_dev, ++ pvs_name); ++ if (IS_ERR(drv->names_opp_tables[cpu])) { ++ ret = PTR_ERR(drv->names_opp_tables[cpu]); ++ dev_err(cpu_dev, "Failed to add OPP name %s\n", ++ pvs_name); ++ goto free_opp; ++ } ++ } ++ ++ drv->hw_opp_tables[cpu] = dev_pm_opp_set_supported_hw( ++ cpu_dev, &drv->versions, 1); ++ if (IS_ERR(drv->hw_opp_tables[cpu])) { ++ ret = PTR_ERR(drv->hw_opp_tables[cpu]); + dev_err(cpu_dev, + "Failed to set supported hardware\n"); + goto free_genpd_opp; +@@ -259,11 +404,18 @@ free_genpd_opp: + kfree(drv->genpd_opp_tables); + free_opp: + for_each_possible_cpu(cpu) { +- if (IS_ERR_OR_NULL(drv->opp_tables[cpu])) ++ if (IS_ERR_OR_NULL(drv->names_opp_tables[cpu])) ++ break; ++ dev_pm_opp_put_prop_name(drv->names_opp_tables[cpu]); ++ } ++ for_each_possible_cpu(cpu) { ++ if (IS_ERR_OR_NULL(drv->hw_opp_tables[cpu])) + break; +- dev_pm_opp_put_supported_hw(drv->opp_tables[cpu]); ++ dev_pm_opp_put_supported_hw(drv->hw_opp_tables[cpu]); + } +- kfree(drv->opp_tables); ++ kfree(drv->hw_opp_tables); ++free_opp_names: ++ kfree(drv->names_opp_tables); + free_drv: + kfree(drv); + +@@ -278,13 +430,16 @@ static int qcom_cpufreq_remove(struct pl + platform_device_unregister(cpufreq_dt_pdev); + + for_each_possible_cpu(cpu) { +- if (drv->opp_tables[cpu]) +- dev_pm_opp_put_supported_hw(drv->opp_tables[cpu]); ++ if (drv->names_opp_tables[cpu]) ++ dev_pm_opp_put_supported_hw(drv->names_opp_tables[cpu]); ++ if (drv->hw_opp_tables[cpu]) ++ dev_pm_opp_put_supported_hw(drv->hw_opp_tables[cpu]); + if (drv->genpd_opp_tables[cpu]) + dev_pm_opp_detach_genpd(drv->genpd_opp_tables[cpu]); + } + +- kfree(drv->opp_tables); ++ kfree(drv->names_opp_tables); ++ kfree(drv->hw_opp_tables); + kfree(drv->genpd_opp_tables); + kfree(drv); + +@@ -303,6 +458,10 @@ static const struct of_device_id qcom_cp + { .compatible = "qcom,apq8096", .data = &match_data_kryo }, + { .compatible = "qcom,msm8996", .data = &match_data_kryo }, + { .compatible = "qcom,qcs404", .data = &match_data_qcs404 }, ++ { .compatible = "qcom,ipq8064", .data = &match_data_krait }, ++ { .compatible = "qcom,apq8064", .data = &match_data_krait }, ++ { .compatible = "qcom,msm8974", .data = &match_data_krait }, ++ { .compatible = "qcom,msm8960", .data = &match_data_krait }, + {}, + }; + MODULE_DEVICE_TABLE(of, qcom_cpufreq_match_list); diff --git a/target/linux/ipq806x/patches-5.10/092-2-v5.7-cpufreq-qcom-fix-wrong-compatible-binding.patch b/target/linux/ipq806x/patches-5.10/092-2-v5.7-cpufreq-qcom-fix-wrong-compatible-binding.patch new file mode 100644 index 0000000000..764a917c1f --- /dev/null +++ b/target/linux/ipq806x/patches-5.10/092-2-v5.7-cpufreq-qcom-fix-wrong-compatible-binding.patch @@ -0,0 +1,26 @@ +From 2dea651680cea1f3a29925de51002f33d1f55711 Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Fri, 1 May 2020 00:22:25 +0200 +Subject: cpufreq: qcom: fix wrong compatible binding + +Binding in Documentation is still "operating-points-v2-kryo-cpu". +Restore the old binding to fix the compatibility problem. + +Fixes: a8811ec764f9 ("cpufreq: qcom: Add support for krait based socs") +Signed-off-by: Ansuel Smith +Signed-off-by: Viresh Kumar +--- + drivers/cpufreq/qcom-cpufreq-nvmem.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/cpufreq/qcom-cpufreq-nvmem.c ++++ b/drivers/cpufreq/qcom-cpufreq-nvmem.c +@@ -277,7 +277,7 @@ static int qcom_cpufreq_probe(struct pla + if (!np) + return -ENOENT; + +- ret = of_device_is_compatible(np, "operating-points-v2-qcom-cpu"); ++ ret = of_device_is_compatible(np, "operating-points-v2-kryo-cpu"); + if (!ret) { + of_node_put(np); + return -ENOENT; diff --git a/target/linux/ipq806x/patches-5.10/093-4-v5.8-ipq806x-PCI-qcom-Use-bulk-clk-api-and-assert-on-error.patch b/target/linux/ipq806x/patches-5.10/093-4-v5.8-ipq806x-PCI-qcom-Use-bulk-clk-api-and-assert-on-error.patch new file mode 100644 index 0000000000..95531508b6 --- /dev/null +++ b/target/linux/ipq806x/patches-5.10/093-4-v5.8-ipq806x-PCI-qcom-Use-bulk-clk-api-and-assert-on-error.patch @@ -0,0 +1,228 @@ +From 6a114526af4689938863bf34976c83bfd279f517 Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Mon, 15 Jun 2020 23:06:02 +0200 +Subject: PCI: qcom: Use bulk clk api and assert on error + +Rework 2.1.0 revision to use bulk clk api and fix missing assert on +reset_control_deassert error. + +Link: https://lore.kernel.org/r/20200615210608.21469-7-ansuelsmth@gmail.com +Signed-off-by: Ansuel Smith +Signed-off-by: Lorenzo Pieralisi +Reviewed-by: Rob Herring +Acked-by: Stanimir Varbanov +--- + drivers/pci/controller/dwc/pcie-qcom.c | 131 ++++++++++++--------------------- + 1 file changed, 46 insertions(+), 85 deletions(-) + +--- a/drivers/pci/controller/dwc/pcie-qcom.c ++++ b/drivers/pci/controller/dwc/pcie-qcom.c +@@ -99,12 +99,9 @@ + #define SLV_ADDR_SPACE_SZ 0x10000000 + + #define QCOM_PCIE_2_1_0_MAX_SUPPLY 3 ++#define QCOM_PCIE_2_1_0_MAX_CLOCKS 5 + struct qcom_pcie_resources_2_1_0 { +- struct clk *iface_clk; +- struct clk *core_clk; +- struct clk *phy_clk; +- struct clk *aux_clk; +- struct clk *ref_clk; ++ struct clk_bulk_data clks[QCOM_PCIE_2_1_0_MAX_CLOCKS]; + struct reset_control *pci_reset; + struct reset_control *axi_reset; + struct reset_control *ahb_reset; +@@ -244,25 +241,21 @@ static int qcom_pcie_get_resources_2_1_0 + if (ret) + return ret; + +- res->iface_clk = devm_clk_get(dev, "iface"); +- if (IS_ERR(res->iface_clk)) +- return PTR_ERR(res->iface_clk); +- +- res->core_clk = devm_clk_get(dev, "core"); +- if (IS_ERR(res->core_clk)) +- return PTR_ERR(res->core_clk); +- +- res->phy_clk = devm_clk_get(dev, "phy"); +- if (IS_ERR(res->phy_clk)) +- return PTR_ERR(res->phy_clk); +- +- res->aux_clk = devm_clk_get_optional(dev, "aux"); +- if (IS_ERR(res->aux_clk)) +- return PTR_ERR(res->aux_clk); +- +- res->ref_clk = devm_clk_get_optional(dev, "ref"); +- if (IS_ERR(res->ref_clk)) +- return PTR_ERR(res->ref_clk); ++ res->clks[0].id = "iface"; ++ res->clks[1].id = "core"; ++ res->clks[2].id = "phy"; ++ res->clks[3].id = "aux"; ++ res->clks[4].id = "ref"; ++ ++ /* iface, core, phy are required */ ++ ret = devm_clk_bulk_get(dev, 3, res->clks); ++ if (ret < 0) ++ return ret; ++ ++ /* aux, ref are optional */ ++ ret = devm_clk_bulk_get_optional(dev, 2, res->clks + 3); ++ if (ret < 0) ++ return ret; + + res->pci_reset = devm_reset_control_get_exclusive(dev, "pci"); + if (IS_ERR(res->pci_reset)) +@@ -292,17 +285,13 @@ static void qcom_pcie_deinit_2_1_0(struc + { + struct qcom_pcie_resources_2_1_0 *res = &pcie->res.v2_1_0; + +- clk_disable_unprepare(res->phy_clk); ++ clk_bulk_disable_unprepare(ARRAY_SIZE(res->clks), res->clks); + reset_control_assert(res->pci_reset); + reset_control_assert(res->axi_reset); + reset_control_assert(res->ahb_reset); + reset_control_assert(res->por_reset); + reset_control_assert(res->ext_reset); + reset_control_assert(res->phy_reset); +- clk_disable_unprepare(res->iface_clk); +- clk_disable_unprepare(res->core_clk); +- clk_disable_unprepare(res->aux_clk); +- clk_disable_unprepare(res->ref_clk); + + writel(1, pcie->parf + PCIE20_PARF_PHY_CTRL); + +@@ -334,47 +323,45 @@ static int qcom_pcie_init_2_1_0(struct q + return ret; + } + +- ret = reset_control_assert(res->ahb_reset); ++ ret = reset_control_deassert(res->ahb_reset); + if (ret) { +- dev_err(dev, "cannot assert ahb reset\n"); +- goto err_assert_ahb; ++ dev_err(dev, "cannot deassert ahb reset\n"); ++ goto err_deassert_ahb; + } + +- ret = clk_prepare_enable(res->iface_clk); ++ ret = reset_control_deassert(res->ext_reset); + if (ret) { +- dev_err(dev, "cannot prepare/enable iface clock\n"); +- goto err_assert_ahb; ++ dev_err(dev, "cannot deassert ext reset\n"); ++ goto err_deassert_ext; + } + +- ret = clk_prepare_enable(res->core_clk); ++ ret = reset_control_deassert(res->phy_reset); + if (ret) { +- dev_err(dev, "cannot prepare/enable core clock\n"); +- goto err_clk_core; ++ dev_err(dev, "cannot deassert phy reset\n"); ++ goto err_deassert_phy; + } + +- ret = clk_prepare_enable(res->aux_clk); ++ ret = reset_control_deassert(res->pci_reset); + if (ret) { +- dev_err(dev, "cannot prepare/enable aux clock\n"); +- goto err_clk_aux; ++ dev_err(dev, "cannot deassert pci reset\n"); ++ goto err_deassert_pci; + } + +- ret = clk_prepare_enable(res->ref_clk); ++ ret = reset_control_deassert(res->por_reset); + if (ret) { +- dev_err(dev, "cannot prepare/enable ref clock\n"); +- goto err_clk_ref; ++ dev_err(dev, "cannot deassert por reset\n"); ++ goto err_deassert_por; + } + +- ret = reset_control_deassert(res->ahb_reset); ++ ret = reset_control_deassert(res->axi_reset); + if (ret) { +- dev_err(dev, "cannot deassert ahb reset\n"); +- goto err_deassert_ahb; ++ dev_err(dev, "cannot deassert axi reset\n"); ++ goto err_deassert_axi; + } + +- ret = reset_control_deassert(res->ext_reset); +- if (ret) { +- dev_err(dev, "cannot deassert ext reset\n"); +- goto err_deassert_ahb; +- } ++ ret = clk_bulk_prepare_enable(ARRAY_SIZE(res->clks), res->clks); ++ if (ret) ++ goto err_clks; + + /* enable PCIe clocks and resets */ + val = readl(pcie->parf + PCIE20_PARF_PHY_CTRL); +@@ -406,36 +393,6 @@ static int qcom_pcie_init_2_1_0(struct q + val |= PHY_REFCLK_SSP_EN; + writel(val, pcie->parf + PCIE20_PARF_PHY_REFCLK); + +- ret = reset_control_deassert(res->phy_reset); +- if (ret) { +- dev_err(dev, "cannot deassert phy reset\n"); +- return ret; +- } +- +- ret = reset_control_deassert(res->pci_reset); +- if (ret) { +- dev_err(dev, "cannot deassert pci reset\n"); +- return ret; +- } +- +- ret = reset_control_deassert(res->por_reset); +- if (ret) { +- dev_err(dev, "cannot deassert por reset\n"); +- return ret; +- } +- +- ret = reset_control_deassert(res->axi_reset); +- if (ret) { +- dev_err(dev, "cannot deassert axi reset\n"); +- return ret; +- } +- +- ret = clk_prepare_enable(res->phy_clk); +- if (ret) { +- dev_err(dev, "cannot prepare/enable phy clock\n"); +- goto err_deassert_ahb; +- } +- + /* wait for clock acquisition */ + usleep_range(1000, 1500); + +@@ -448,15 +405,19 @@ static int qcom_pcie_init_2_1_0(struct q + + return 0; + ++err_clks: ++ reset_control_assert(res->axi_reset); ++err_deassert_axi: ++ reset_control_assert(res->por_reset); ++err_deassert_por: ++ reset_control_assert(res->pci_reset); ++err_deassert_pci: ++ reset_control_assert(res->phy_reset); ++err_deassert_phy: ++ reset_control_assert(res->ext_reset); ++err_deassert_ext: ++ reset_control_assert(res->ahb_reset); + err_deassert_ahb: +- clk_disable_unprepare(res->ref_clk); +-err_clk_ref: +- clk_disable_unprepare(res->aux_clk); +-err_clk_aux: +- clk_disable_unprepare(res->core_clk); +-err_clk_core: +- clk_disable_unprepare(res->iface_clk); +-err_assert_ahb: + regulator_bulk_disable(ARRAY_SIZE(res->supplies), res->supplies); + + return ret; diff --git a/target/linux/ipq806x/patches-5.10/093-7-v5.8-ipq806x-PCI-qcom-Add-ipq8064-rev2-variant.patch b/target/linux/ipq806x/patches-5.10/093-7-v5.8-ipq806x-PCI-qcom-Add-ipq8064-rev2-variant.patch new file mode 100644 index 0000000000..c3d61f164c --- /dev/null +++ b/target/linux/ipq806x/patches-5.10/093-7-v5.8-ipq806x-PCI-qcom-Add-ipq8064-rev2-variant.patch @@ -0,0 +1,36 @@ +From 8df093fe2ae1717389df0dcdc620c02cc35abb21 Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Mon, 15 Jun 2020 23:06:05 +0200 +Subject: PCI: qcom: Add ipq8064 rev2 variant + +Ipq8064-v2 have tx term offset set to 0. Introduce this variant to permit +different offset based on the revision. + +Link: https://lore.kernel.org/r/20200615210608.21469-10-ansuelsmth@gmail.com +Signed-off-by: Ansuel Smith +Signed-off-by: Lorenzo Pieralisi +Acked-by: Stanimir Varbanov +--- + drivers/pci/controller/dwc/pcie-qcom.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +--- a/drivers/pci/controller/dwc/pcie-qcom.c ++++ b/drivers/pci/controller/dwc/pcie-qcom.c +@@ -368,7 +368,8 @@ static int qcom_pcie_init_2_1_0(struct q + val &= ~BIT(0); + writel(val, pcie->parf + PCIE20_PARF_PHY_CTRL); + +- if (of_device_is_compatible(node, "qcom,pcie-ipq8064")) { ++ if (of_device_is_compatible(node, "qcom,pcie-ipq8064") || ++ of_device_is_compatible(node, "qcom,pcie-ipq8064-v2")) { + writel(PCS_DEEMPH_TX_DEEMPH_GEN1(24) | + PCS_DEEMPH_TX_DEEMPH_GEN2_3_5DB(24) | + PCS_DEEMPH_TX_DEEMPH_GEN2_6DB(34), +@@ -1328,6 +1329,7 @@ err_pm_runtime_put: + static const struct of_device_id qcom_pcie_match[] = { + { .compatible = "qcom,pcie-apq8084", .data = &ops_1_0_0 }, + { .compatible = "qcom,pcie-ipq8064", .data = &ops_2_1_0 }, ++ { .compatible = "qcom,pcie-ipq8064-v2", .data = &ops_2_1_0 }, + { .compatible = "qcom,pcie-apq8064", .data = &ops_2_1_0 }, + { .compatible = "qcom,pcie-msm8996", .data = &ops_2_3_2 }, + { .compatible = "qcom,pcie-ipq8074", .data = &ops_2_3_3 }, diff --git a/target/linux/ipq806x/patches-5.10/093-8-v5.8-ipq806x-PCI-qcom-Support-pci-speed-set-for-ipq806x.patch b/target/linux/ipq806x/patches-5.10/093-8-v5.8-ipq806x-PCI-qcom-Support-pci-speed-set-for-ipq806x.patch new file mode 100644 index 0000000000..02ac7460e8 --- /dev/null +++ b/target/linux/ipq806x/patches-5.10/093-8-v5.8-ipq806x-PCI-qcom-Support-pci-speed-set-for-ipq806x.patch @@ -0,0 +1,74 @@ +From 51ed2c2b60265006bde7531d10993cf24def0aee Mon Sep 17 00:00:00 2001 +From: Sham Muthayyan +Date: Mon, 15 Jun 2020 23:06:07 +0200 +Subject: PCI: qcom: Support pci speed set for ipq806x + +Some SoC based on ipq8064/5 needs to be limited to pci GEN1 speed due to +some hardware limitations. Add support for speed setting defined by the +max-link-speed binding. If not defined the max speed is set to GEN2 by +default. + +Link: https://lore.kernel.org/r/20200615210608.21469-12-ansuelsmth@gmail.com +Signed-off-by: Sham Muthayyan +Signed-off-by: Ansuel Smith +Signed-off-by: Lorenzo Pieralisi +Reviewed-by: Rob Herring +Acked-by: Stanimir Varbanov +--- + +Backported with light changes: +* One include is missing in kernel 5.4 + + drivers/pci/controller/dwc/pcie-qcom.c | 13 +++++++++++++ + 1 file changed, 13 insertions(+) + +--- a/drivers/pci/controller/dwc/pcie-qcom.c ++++ b/drivers/pci/controller/dwc/pcie-qcom.c +@@ -27,6 +27,7 @@ + #include + #include + ++#include "../../pci.h" + #include "pcie-designware.h" + + #define PCIE20_PARF_SYS_CTRL 0x00 +@@ -98,6 +99,8 @@ + #define PCIE20_v3_PARF_SLV_ADDR_SPACE_SIZE 0x358 + #define SLV_ADDR_SPACE_SZ 0x10000000 + ++#define PCIE20_LNK_CONTROL2_LINK_STATUS2 0xa0 ++ + #define QCOM_PCIE_2_1_0_MAX_SUPPLY 3 + #define QCOM_PCIE_2_1_0_MAX_CLOCKS 5 + struct qcom_pcie_resources_2_1_0 { +@@ -184,6 +187,7 @@ struct qcom_pcie { + struct phy *phy; + struct gpio_desc *reset; + const struct qcom_pcie_ops *ops; ++ int gen; + }; + + #define to_qcom_pcie(x) dev_get_drvdata((x)->dev) +@@ -397,6 +401,11 @@ static int qcom_pcie_init_2_1_0(struct q + /* wait for clock acquisition */ + usleep_range(1000, 1500); + ++ if (pcie->gen == 1) { ++ val = readl(pci->dbi_base + PCIE20_LNK_CONTROL2_LINK_STATUS2); ++ val |= PCI_EXP_LNKSTA_CLS_2_5GB; ++ writel(val, pci->dbi_base + PCIE20_LNK_CONTROL2_LINK_STATUS2); ++ } + + /* Set the Max TLP size to 2K, instead of using default of 4K */ + writel(CFG_REMOTE_RD_REQ_BRIDGE_SIZE_2K, +@@ -1261,6 +1270,10 @@ static int qcom_pcie_probe(struct platfo + goto err_pm_runtime_put; + } + ++ pcie->gen = of_pci_get_max_link_speed(pdev->dev.of_node); ++ if (pcie->gen < 0) ++ pcie->gen = 2; ++ + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "parf"); + pcie->parf = devm_ioremap_resource(dev, res); + if (IS_ERR(pcie->parf)) { diff --git a/target/linux/ipq806x/patches-5.10/094-v5.7-ipq806x-net-mdio-add-ipq8064-mdio-driver.patch b/target/linux/ipq806x/patches-5.10/094-v5.7-ipq806x-net-mdio-add-ipq8064-mdio-driver.patch new file mode 100644 index 0000000000..328942dad9 --- /dev/null +++ b/target/linux/ipq806x/patches-5.10/094-v5.7-ipq806x-net-mdio-add-ipq8064-mdio-driver.patch @@ -0,0 +1,216 @@ +From caaa71fac36ec8c19145dbf8262a9b77ab09f1a1 Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Wed, 4 Mar 2020 22:38:32 +0100 +Subject: net: mdio: add ipq8064 mdio driver + +Currently ipq806x soc use generic bitbang driver to +comunicate with the gmac ethernet interface. +Add a dedicated driver created by chunkeey to fix this. + +Co-developed-by: Christian Lamparter +Signed-off-by: Christian Lamparter +Signed-off-by: Ansuel Smith +Signed-off-by: David S. Miller +--- + drivers/net/phy/Kconfig | 8 ++ + drivers/net/phy/Makefile | 1 + + drivers/net/phy/mdio-ipq8064.c | 166 +++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 175 insertions(+) + create mode 100644 drivers/net/phy/mdio-ipq8064.c + +--- a/drivers/net/phy/Kconfig ++++ b/drivers/net/phy/Kconfig +@@ -156,6 +156,14 @@ config MDIO_I2C + + This is library mode. + ++config MDIO_IPQ8064 ++ tristate "Qualcomm IPQ8064 MDIO interface support" ++ depends on HAS_IOMEM && OF_MDIO ++ depends on MFD_SYSCON ++ help ++ This driver supports the MDIO interface found in the network ++ interface units of the IPQ8064 SoC ++ + config MDIO_MOXART + tristate "MOXA ART MDIO interface support" + depends on ARCH_MOXART || COMPILE_TEST +--- a/drivers/net/phy/Makefile ++++ b/drivers/net/phy/Makefile +@@ -50,6 +50,7 @@ obj-$(CONFIG_MDIO_CAVIUM) += mdio-cavium + obj-$(CONFIG_MDIO_GPIO) += mdio-gpio.o + obj-$(CONFIG_MDIO_HISI_FEMAC) += mdio-hisi-femac.o + obj-$(CONFIG_MDIO_I2C) += mdio-i2c.o ++obj-$(CONFIG_MDIO_IPQ8064) += mdio-ipq8064.o + obj-$(CONFIG_MDIO_MOXART) += mdio-moxart.o + obj-$(CONFIG_MDIO_MSCC_MIIM) += mdio-mscc-miim.o + obj-$(CONFIG_MDIO_OCTEON) += mdio-octeon.o +--- /dev/null ++++ b/drivers/net/phy/mdio-ipq8064.c +@@ -0,0 +1,166 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* Qualcomm IPQ8064 MDIO interface driver ++ * ++ * Copyright (C) 2019 Christian Lamparter ++ * Copyright (C) 2020 Ansuel Smith ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* MII address register definitions */ ++#define MII_ADDR_REG_ADDR 0x10 ++#define MII_BUSY BIT(0) ++#define MII_WRITE BIT(1) ++#define MII_CLKRANGE_60_100M (0 << 2) ++#define MII_CLKRANGE_100_150M (1 << 2) ++#define MII_CLKRANGE_20_35M (2 << 2) ++#define MII_CLKRANGE_35_60M (3 << 2) ++#define MII_CLKRANGE_150_250M (4 << 2) ++#define MII_CLKRANGE_250_300M (5 << 2) ++#define MII_CLKRANGE_MASK GENMASK(4, 2) ++#define MII_REG_SHIFT 6 ++#define MII_REG_MASK GENMASK(10, 6) ++#define MII_ADDR_SHIFT 11 ++#define MII_ADDR_MASK GENMASK(15, 11) ++ ++#define MII_DATA_REG_ADDR 0x14 ++ ++#define MII_MDIO_DELAY_USEC (1000) ++#define MII_MDIO_RETRY_MSEC (10) ++ ++struct ipq8064_mdio { ++ struct regmap *base; /* NSS_GMAC0_BASE */ ++}; ++ ++static int ++ipq8064_mdio_wait_busy(struct ipq8064_mdio *priv) ++{ ++ u32 busy; ++ ++ return regmap_read_poll_timeout(priv->base, MII_ADDR_REG_ADDR, busy, ++ !(busy & MII_BUSY), MII_MDIO_DELAY_USEC, ++ MII_MDIO_RETRY_MSEC * USEC_PER_MSEC); ++} ++ ++static int ++ipq8064_mdio_read(struct mii_bus *bus, int phy_addr, int reg_offset) ++{ ++ u32 miiaddr = MII_BUSY | MII_CLKRANGE_250_300M; ++ struct ipq8064_mdio *priv = bus->priv; ++ u32 ret_val; ++ int err; ++ ++ /* Reject clause 45 */ ++ if (reg_offset & MII_ADDR_C45) ++ return -EOPNOTSUPP; ++ ++ miiaddr |= ((phy_addr << MII_ADDR_SHIFT) & MII_ADDR_MASK) | ++ ((reg_offset << MII_REG_SHIFT) & MII_REG_MASK); ++ ++ regmap_write(priv->base, MII_ADDR_REG_ADDR, miiaddr); ++ usleep_range(8, 10); ++ ++ err = ipq8064_mdio_wait_busy(priv); ++ if (err) ++ return err; ++ ++ regmap_read(priv->base, MII_DATA_REG_ADDR, &ret_val); ++ return (int)ret_val; ++} ++ ++static int ++ipq8064_mdio_write(struct mii_bus *bus, int phy_addr, int reg_offset, u16 data) ++{ ++ u32 miiaddr = MII_WRITE | MII_BUSY | MII_CLKRANGE_250_300M; ++ struct ipq8064_mdio *priv = bus->priv; ++ ++ /* Reject clause 45 */ ++ if (reg_offset & MII_ADDR_C45) ++ return -EOPNOTSUPP; ++ ++ regmap_write(priv->base, MII_DATA_REG_ADDR, data); ++ ++ miiaddr |= ((phy_addr << MII_ADDR_SHIFT) & MII_ADDR_MASK) | ++ ((reg_offset << MII_REG_SHIFT) & MII_REG_MASK); ++ ++ regmap_write(priv->base, MII_ADDR_REG_ADDR, miiaddr); ++ usleep_range(8, 10); ++ ++ return ipq8064_mdio_wait_busy(priv); ++} ++ ++static int ++ipq8064_mdio_probe(struct platform_device *pdev) ++{ ++ struct device_node *np = pdev->dev.of_node; ++ struct ipq8064_mdio *priv; ++ struct mii_bus *bus; ++ int ret; ++ ++ bus = devm_mdiobus_alloc_size(&pdev->dev, sizeof(*priv)); ++ if (!bus) ++ return -ENOMEM; ++ ++ bus->name = "ipq8064_mdio_bus"; ++ bus->read = ipq8064_mdio_read; ++ bus->write = ipq8064_mdio_write; ++ snprintf(bus->id, MII_BUS_ID_SIZE, "%s-mii", dev_name(&pdev->dev)); ++ bus->parent = &pdev->dev; ++ ++ priv = bus->priv; ++ priv->base = device_node_to_regmap(np); ++ if (IS_ERR(priv->base)) { ++ if (priv->base == ERR_PTR(-EPROBE_DEFER)) ++ return -EPROBE_DEFER; ++ ++ dev_err(&pdev->dev, "error getting device regmap, error=%pe\n", ++ priv->base); ++ return PTR_ERR(priv->base); ++ } ++ ++ ret = of_mdiobus_register(bus, np); ++ if (ret) ++ return ret; ++ ++ platform_set_drvdata(pdev, bus); ++ return 0; ++} ++ ++static int ++ipq8064_mdio_remove(struct platform_device *pdev) ++{ ++ struct mii_bus *bus = platform_get_drvdata(pdev); ++ ++ mdiobus_unregister(bus); ++ ++ return 0; ++} ++ ++static const struct of_device_id ipq8064_mdio_dt_ids[] = { ++ { .compatible = "qcom,ipq8064-mdio" }, ++ { } ++}; ++MODULE_DEVICE_TABLE(of, ipq8064_mdio_dt_ids); ++ ++static struct platform_driver ipq8064_mdio_driver = { ++ .probe = ipq8064_mdio_probe, ++ .remove = ipq8064_mdio_remove, ++ .driver = { ++ .name = "ipq8064-mdio", ++ .of_match_table = ipq8064_mdio_dt_ids, ++ }, ++}; ++ ++module_platform_driver(ipq8064_mdio_driver); ++ ++MODULE_DESCRIPTION("Qualcomm IPQ8064 MDIO interface driver"); ++MODULE_AUTHOR("Christian Lamparter "); ++MODULE_AUTHOR("Ansuel Smith "); ++MODULE_LICENSE("GPL"); diff --git a/target/linux/ipq806x/patches-5.10/095-1-v5.9-phy-qualcomm-add-qcom-ipq806x-dwc-usb-phy-driver.patch b/target/linux/ipq806x/patches-5.10/095-1-v5.9-phy-qualcomm-add-qcom-ipq806x-dwc-usb-phy-driver.patch new file mode 100644 index 0000000000..47dc455715 --- /dev/null +++ b/target/linux/ipq806x/patches-5.10/095-1-v5.9-phy-qualcomm-add-qcom-ipq806x-dwc-usb-phy-driver.patch @@ -0,0 +1,621 @@ +From ef19b117b83466e1c030368101a24367a34be7f0 Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Fri, 17 Jul 2020 15:16:31 +0200 +Subject: phy: qualcomm: add qcom ipq806x dwc usb phy driver + +This has lost in the original push for the dwc3 qcom driver. +This is needed for ipq806x SoC as without this the usb ports +doesn't work at all. + +Signed-off-by: Andy Gross +Signed-off-by: Ansuel Smith +Tested-by: Jonathan McDowell +Link: https://lore.kernel.org/r/20200717131635.11076-1-ansuelsmth@gmail.com +Signed-off-by: Vinod Koul +--- + +Light modification to Kconfig as some config are missing in kernel 5.4 + + drivers/phy/qualcomm/Kconfig | 10 + + drivers/phy/qualcomm/Makefile | 1 + + drivers/phy/qualcomm/phy-qcom-ipq806x-usb.c | 571 ++++++++++++++++++++++++++++ + 3 files changed, 582 insertions(+) + create mode 100644 drivers/phy/qualcomm/phy-qcom-ipq806x-usb.c + +--- a/drivers/phy/qualcomm/Kconfig ++++ b/drivers/phy/qualcomm/Kconfig +@@ -91,3 +91,13 @@ config PHY_QCOM_USB_HSIC + select GENERIC_PHY + help + Support for the USB HSIC ULPI compliant PHY on QCOM chipsets. ++ ++config PHY_QCOM_IPQ806X_USB ++ tristate "Qualcomm IPQ806x DWC3 USB PHY driver" ++ depends on HAS_IOMEM ++ depends on OF && (ARCH_QCOM || COMPILE_TEST) ++ select GENERIC_PHY ++ help ++ This option enables support for the Synopsis PHYs present inside the ++ Qualcomm USB3.0 DWC3 controller on ipq806x SoC. This driver supports ++ both HS and SS PHY controllers. +--- a/drivers/phy/qualcomm/Makefile ++++ b/drivers/phy/qualcomm/Makefile +@@ -10,3 +10,4 @@ obj-$(CONFIG_PHY_QCOM_UFS_14NM) += phy- + obj-$(CONFIG_PHY_QCOM_UFS_20NM) += phy-qcom-ufs-qmp-20nm.o + obj-$(CONFIG_PHY_QCOM_USB_HS) += phy-qcom-usb-hs.o + obj-$(CONFIG_PHY_QCOM_USB_HSIC) += phy-qcom-usb-hsic.o ++obj-$(CONFIG_PHY_QCOM_IPQ806X_USB) += phy-qcom-ipq806x-usb.o +--- /dev/null ++++ b/drivers/phy/qualcomm/phy-qcom-ipq806x-usb.c +@@ -0,0 +1,571 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* USB QSCRATCH Hardware registers */ ++#define QSCRATCH_GENERAL_CFG (0x08) ++#define HSUSB_PHY_CTRL_REG (0x10) ++ ++/* PHY_CTRL_REG */ ++#define HSUSB_CTRL_DMSEHV_CLAMP BIT(24) ++#define HSUSB_CTRL_USB2_SUSPEND BIT(23) ++#define HSUSB_CTRL_UTMI_CLK_EN BIT(21) ++#define HSUSB_CTRL_UTMI_OTG_VBUS_VALID BIT(20) ++#define HSUSB_CTRL_USE_CLKCORE BIT(18) ++#define HSUSB_CTRL_DPSEHV_CLAMP BIT(17) ++#define HSUSB_CTRL_COMMONONN BIT(11) ++#define HSUSB_CTRL_ID_HV_CLAMP BIT(9) ++#define HSUSB_CTRL_OTGSESSVLD_CLAMP BIT(8) ++#define HSUSB_CTRL_CLAMP_EN BIT(7) ++#define HSUSB_CTRL_RETENABLEN BIT(1) ++#define HSUSB_CTRL_POR BIT(0) ++ ++/* QSCRATCH_GENERAL_CFG */ ++#define HSUSB_GCFG_XHCI_REV BIT(2) ++ ++/* USB QSCRATCH Hardware registers */ ++#define SSUSB_PHY_CTRL_REG (0x00) ++#define SSUSB_PHY_PARAM_CTRL_1 (0x04) ++#define SSUSB_PHY_PARAM_CTRL_2 (0x08) ++#define CR_PROTOCOL_DATA_IN_REG (0x0c) ++#define CR_PROTOCOL_DATA_OUT_REG (0x10) ++#define CR_PROTOCOL_CAP_ADDR_REG (0x14) ++#define CR_PROTOCOL_CAP_DATA_REG (0x18) ++#define CR_PROTOCOL_READ_REG (0x1c) ++#define CR_PROTOCOL_WRITE_REG (0x20) ++ ++/* PHY_CTRL_REG */ ++#define SSUSB_CTRL_REF_USE_PAD BIT(28) ++#define SSUSB_CTRL_TEST_POWERDOWN BIT(27) ++#define SSUSB_CTRL_LANE0_PWR_PRESENT BIT(24) ++#define SSUSB_CTRL_SS_PHY_EN BIT(8) ++#define SSUSB_CTRL_SS_PHY_RESET BIT(7) ++ ++/* SSPHY control registers - Does this need 0x30? */ ++#define SSPHY_CTRL_RX_OVRD_IN_HI(lane) (0x1006 + 0x100 * (lane)) ++#define SSPHY_CTRL_TX_OVRD_DRV_LO(lane) (0x1002 + 0x100 * (lane)) ++ ++/* SSPHY SoC version specific values */ ++#define SSPHY_RX_EQ_VALUE 4 /* Override value for rx_eq */ ++/* Override value for transmit preemphasis */ ++#define SSPHY_TX_DEEMPH_3_5DB 23 ++/* Override value for mpll */ ++#define SSPHY_MPLL_VALUE 0 ++ ++/* QSCRATCH PHY_PARAM_CTRL1 fields */ ++#define PHY_PARAM_CTRL1_TX_FULL_SWING_MASK GENMASK(26, 19) ++#define PHY_PARAM_CTRL1_TX_DEEMPH_6DB_MASK GENMASK(19, 13) ++#define PHY_PARAM_CTRL1_TX_DEEMPH_3_5DB_MASK GENMASK(13, 7) ++#define PHY_PARAM_CTRL1_LOS_BIAS_MASK GENMASK(7, 2) ++ ++#define PHY_PARAM_CTRL1_MASK \ ++ (PHY_PARAM_CTRL1_TX_FULL_SWING_MASK | \ ++ PHY_PARAM_CTRL1_TX_DEEMPH_6DB_MASK | \ ++ PHY_PARAM_CTRL1_TX_DEEMPH_3_5DB_MASK | \ ++ PHY_PARAM_CTRL1_LOS_BIAS_MASK) ++ ++#define PHY_PARAM_CTRL1_TX_FULL_SWING(x) \ ++ (((x) << 20) & PHY_PARAM_CTRL1_TX_FULL_SWING_MASK) ++#define PHY_PARAM_CTRL1_TX_DEEMPH_6DB(x) \ ++ (((x) << 14) & PHY_PARAM_CTRL1_TX_DEEMPH_6DB_MASK) ++#define PHY_PARAM_CTRL1_TX_DEEMPH_3_5DB(x) \ ++ (((x) << 8) & PHY_PARAM_CTRL1_TX_DEEMPH_3_5DB_MASK) ++#define PHY_PARAM_CTRL1_LOS_BIAS(x) \ ++ (((x) << 3) & PHY_PARAM_CTRL1_LOS_BIAS_MASK) ++ ++/* RX OVRD IN HI bits */ ++#define RX_OVRD_IN_HI_RX_RESET_OVRD BIT(13) ++#define RX_OVRD_IN_HI_RX_RX_RESET BIT(12) ++#define RX_OVRD_IN_HI_RX_EQ_OVRD BIT(11) ++#define RX_OVRD_IN_HI_RX_EQ_MASK GENMASK(10, 7) ++#define RX_OVRD_IN_HI_RX_EQ(x) ((x) << 8) ++#define RX_OVRD_IN_HI_RX_EQ_EN_OVRD BIT(7) ++#define RX_OVRD_IN_HI_RX_EQ_EN BIT(6) ++#define RX_OVRD_IN_HI_RX_LOS_FILTER_OVRD BIT(5) ++#define RX_OVRD_IN_HI_RX_LOS_FILTER_MASK GENMASK(4, 2) ++#define RX_OVRD_IN_HI_RX_RATE_OVRD BIT(2) ++#define RX_OVRD_IN_HI_RX_RATE_MASK GENMASK(2, 0) ++ ++/* TX OVRD DRV LO register bits */ ++#define TX_OVRD_DRV_LO_AMPLITUDE_MASK GENMASK(6, 0) ++#define TX_OVRD_DRV_LO_PREEMPH_MASK GENMASK(13, 6) ++#define TX_OVRD_DRV_LO_PREEMPH(x) ((x) << 7) ++#define TX_OVRD_DRV_LO_EN BIT(14) ++ ++/* MPLL bits */ ++#define SSPHY_MPLL_MASK GENMASK(8, 5) ++#define SSPHY_MPLL(x) ((x) << 5) ++ ++/* SS CAP register bits */ ++#define SS_CR_CAP_ADDR_REG BIT(0) ++#define SS_CR_CAP_DATA_REG BIT(0) ++#define SS_CR_READ_REG BIT(0) ++#define SS_CR_WRITE_REG BIT(0) ++ ++struct usb_phy { ++ void __iomem *base; ++ struct device *dev; ++ struct clk *xo_clk; ++ struct clk *ref_clk; ++ u32 rx_eq; ++ u32 tx_deamp_3_5db; ++ u32 mpll; ++}; ++ ++struct phy_drvdata { ++ struct phy_ops ops; ++ u32 clk_rate; ++}; ++ ++/** ++ * Write register and read back masked value to confirm it is written ++ * ++ * @base - QCOM DWC3 PHY base virtual address. ++ * @offset - register offset. ++ * @mask - register bitmask specifying what should be updated ++ * @val - value to write. ++ */ ++static inline void usb_phy_write_readback(struct usb_phy *phy_dwc3, ++ u32 offset, ++ const u32 mask, u32 val) ++{ ++ u32 write_val, tmp = readl(phy_dwc3->base + offset); ++ ++ tmp &= ~mask; /* retain other bits */ ++ write_val = tmp | val; ++ ++ writel(write_val, phy_dwc3->base + offset); ++ ++ /* Read back to see if val was written */ ++ tmp = readl(phy_dwc3->base + offset); ++ tmp &= mask; /* clear other bits */ ++ ++ if (tmp != val) ++ dev_err(phy_dwc3->dev, "write: %x to QSCRATCH: %x FAILED\n", val, offset); ++} ++ ++static int wait_for_latch(void __iomem *addr) ++{ ++ u32 retry = 10; ++ ++ while (true) { ++ if (!readl(addr)) ++ break; ++ ++ if (--retry == 0) ++ return -ETIMEDOUT; ++ ++ usleep_range(10, 20); ++ } ++ ++ return 0; ++} ++ ++/** ++ * Write SSPHY register ++ * ++ * @base - QCOM DWC3 PHY base virtual address. ++ * @addr - SSPHY address to write. ++ * @val - value to write. ++ */ ++static int usb_ss_write_phycreg(struct usb_phy *phy_dwc3, ++ u32 addr, u32 val) ++{ ++ int ret; ++ ++ writel(addr, phy_dwc3->base + CR_PROTOCOL_DATA_IN_REG); ++ writel(SS_CR_CAP_ADDR_REG, ++ phy_dwc3->base + CR_PROTOCOL_CAP_ADDR_REG); ++ ++ ret = wait_for_latch(phy_dwc3->base + CR_PROTOCOL_CAP_ADDR_REG); ++ if (ret) ++ goto err_wait; ++ ++ writel(val, phy_dwc3->base + CR_PROTOCOL_DATA_IN_REG); ++ writel(SS_CR_CAP_DATA_REG, ++ phy_dwc3->base + CR_PROTOCOL_CAP_DATA_REG); ++ ++ ret = wait_for_latch(phy_dwc3->base + CR_PROTOCOL_CAP_DATA_REG); ++ if (ret) ++ goto err_wait; ++ ++ writel(SS_CR_WRITE_REG, phy_dwc3->base + CR_PROTOCOL_WRITE_REG); ++ ++ ret = wait_for_latch(phy_dwc3->base + CR_PROTOCOL_WRITE_REG); ++ ++err_wait: ++ if (ret) ++ dev_err(phy_dwc3->dev, "timeout waiting for latch\n"); ++ return ret; ++} ++ ++/** ++ * Read SSPHY register. ++ * ++ * @base - QCOM DWC3 PHY base virtual address. ++ * @addr - SSPHY address to read. ++ */ ++static int usb_ss_read_phycreg(struct usb_phy *phy_dwc3, ++ u32 addr, u32 *val) ++{ ++ int ret; ++ ++ writel(addr, phy_dwc3->base + CR_PROTOCOL_DATA_IN_REG); ++ writel(SS_CR_CAP_ADDR_REG, ++ phy_dwc3->base + CR_PROTOCOL_CAP_ADDR_REG); ++ ++ ret = wait_for_latch(phy_dwc3->base + CR_PROTOCOL_CAP_ADDR_REG); ++ if (ret) ++ goto err_wait; ++ ++ /* ++ * Due to hardware bug, first read of SSPHY register might be ++ * incorrect. Hence as workaround, SW should perform SSPHY register ++ * read twice, but use only second read and ignore first read. ++ */ ++ writel(SS_CR_READ_REG, phy_dwc3->base + CR_PROTOCOL_READ_REG); ++ ++ ret = wait_for_latch(phy_dwc3->base + CR_PROTOCOL_READ_REG); ++ if (ret) ++ goto err_wait; ++ ++ /* throwaway read */ ++ readl(phy_dwc3->base + CR_PROTOCOL_DATA_OUT_REG); ++ ++ writel(SS_CR_READ_REG, phy_dwc3->base + CR_PROTOCOL_READ_REG); ++ ++ ret = wait_for_latch(phy_dwc3->base + CR_PROTOCOL_READ_REG); ++ if (ret) ++ goto err_wait; ++ ++ *val = readl(phy_dwc3->base + CR_PROTOCOL_DATA_OUT_REG); ++ ++err_wait: ++ return ret; ++} ++ ++static int qcom_ipq806x_usb_hs_phy_init(struct phy *phy) ++{ ++ struct usb_phy *phy_dwc3 = phy_get_drvdata(phy); ++ int ret; ++ u32 val; ++ ++ ret = clk_prepare_enable(phy_dwc3->xo_clk); ++ if (ret) ++ return ret; ++ ++ ret = clk_prepare_enable(phy_dwc3->ref_clk); ++ if (ret) { ++ clk_disable_unprepare(phy_dwc3->xo_clk); ++ return ret; ++ } ++ ++ /* ++ * HSPHY Initialization: Enable UTMI clock, select 19.2MHz fsel ++ * enable clamping, and disable RETENTION (power-on default is ENABLED) ++ */ ++ val = HSUSB_CTRL_DPSEHV_CLAMP | HSUSB_CTRL_DMSEHV_CLAMP | ++ HSUSB_CTRL_RETENABLEN | HSUSB_CTRL_COMMONONN | ++ HSUSB_CTRL_OTGSESSVLD_CLAMP | HSUSB_CTRL_ID_HV_CLAMP | ++ HSUSB_CTRL_DPSEHV_CLAMP | HSUSB_CTRL_UTMI_OTG_VBUS_VALID | ++ HSUSB_CTRL_UTMI_CLK_EN | HSUSB_CTRL_CLAMP_EN | 0x70; ++ ++ /* use core clock if external reference is not present */ ++ if (!phy_dwc3->xo_clk) ++ val |= HSUSB_CTRL_USE_CLKCORE; ++ ++ writel(val, phy_dwc3->base + HSUSB_PHY_CTRL_REG); ++ usleep_range(2000, 2200); ++ ++ /* Disable (bypass) VBUS and ID filters */ ++ writel(HSUSB_GCFG_XHCI_REV, phy_dwc3->base + QSCRATCH_GENERAL_CFG); ++ ++ return 0; ++} ++ ++static int qcom_ipq806x_usb_hs_phy_exit(struct phy *phy) ++{ ++ struct usb_phy *phy_dwc3 = phy_get_drvdata(phy); ++ ++ clk_disable_unprepare(phy_dwc3->ref_clk); ++ clk_disable_unprepare(phy_dwc3->xo_clk); ++ ++ return 0; ++} ++ ++static int qcom_ipq806x_usb_ss_phy_init(struct phy *phy) ++{ ++ struct usb_phy *phy_dwc3 = phy_get_drvdata(phy); ++ int ret; ++ u32 data; ++ ++ ret = clk_prepare_enable(phy_dwc3->xo_clk); ++ if (ret) ++ return ret; ++ ++ ret = clk_prepare_enable(phy_dwc3->ref_clk); ++ if (ret) { ++ clk_disable_unprepare(phy_dwc3->xo_clk); ++ return ret; ++ } ++ ++ /* reset phy */ ++ data = readl(phy_dwc3->base + SSUSB_PHY_CTRL_REG); ++ writel(data | SSUSB_CTRL_SS_PHY_RESET, ++ phy_dwc3->base + SSUSB_PHY_CTRL_REG); ++ usleep_range(2000, 2200); ++ writel(data, phy_dwc3->base + SSUSB_PHY_CTRL_REG); ++ ++ /* clear REF_PAD if we don't have XO clk */ ++ if (!phy_dwc3->xo_clk) ++ data &= ~SSUSB_CTRL_REF_USE_PAD; ++ else ++ data |= SSUSB_CTRL_REF_USE_PAD; ++ ++ writel(data, phy_dwc3->base + SSUSB_PHY_CTRL_REG); ++ ++ /* wait for ref clk to become stable, this can take up to 30ms */ ++ msleep(30); ++ ++ data |= SSUSB_CTRL_SS_PHY_EN | SSUSB_CTRL_LANE0_PWR_PRESENT; ++ writel(data, phy_dwc3->base + SSUSB_PHY_CTRL_REG); ++ ++ /* ++ * WORKAROUND: There is SSPHY suspend bug due to which USB enumerates ++ * in HS mode instead of SS mode. Workaround it by asserting ++ * LANE0.TX_ALT_BLOCK.EN_ALT_BUS to enable TX to use alt bus mode ++ */ ++ ret = usb_ss_read_phycreg(phy_dwc3, 0x102D, &data); ++ if (ret) ++ goto err_phy_trans; ++ ++ data |= (1 << 7); ++ ret = usb_ss_write_phycreg(phy_dwc3, 0x102D, data); ++ if (ret) ++ goto err_phy_trans; ++ ++ ret = usb_ss_read_phycreg(phy_dwc3, 0x1010, &data); ++ if (ret) ++ goto err_phy_trans; ++ ++ data &= ~0xff0; ++ data |= 0x20; ++ ret = usb_ss_write_phycreg(phy_dwc3, 0x1010, data); ++ if (ret) ++ goto err_phy_trans; ++ ++ /* ++ * Fix RX Equalization setting as follows ++ * LANE0.RX_OVRD_IN_HI. RX_EQ_EN set to 0 ++ * LANE0.RX_OVRD_IN_HI.RX_EQ_EN_OVRD set to 1 ++ * LANE0.RX_OVRD_IN_HI.RX_EQ set based on SoC version ++ * LANE0.RX_OVRD_IN_HI.RX_EQ_OVRD set to 1 ++ */ ++ ret = usb_ss_read_phycreg(phy_dwc3, SSPHY_CTRL_RX_OVRD_IN_HI(0), &data); ++ if (ret) ++ goto err_phy_trans; ++ ++ data &= ~RX_OVRD_IN_HI_RX_EQ_EN; ++ data |= RX_OVRD_IN_HI_RX_EQ_EN_OVRD; ++ data &= ~RX_OVRD_IN_HI_RX_EQ_MASK; ++ data |= RX_OVRD_IN_HI_RX_EQ(phy_dwc3->rx_eq); ++ data |= RX_OVRD_IN_HI_RX_EQ_OVRD; ++ ret = usb_ss_write_phycreg(phy_dwc3, ++ SSPHY_CTRL_RX_OVRD_IN_HI(0), data); ++ if (ret) ++ goto err_phy_trans; ++ ++ /* ++ * Set EQ and TX launch amplitudes as follows ++ * LANE0.TX_OVRD_DRV_LO.PREEMPH set based on SoC version ++ * LANE0.TX_OVRD_DRV_LO.AMPLITUDE set to 110 ++ * LANE0.TX_OVRD_DRV_LO.EN set to 1. ++ */ ++ ret = usb_ss_read_phycreg(phy_dwc3, ++ SSPHY_CTRL_TX_OVRD_DRV_LO(0), &data); ++ if (ret) ++ goto err_phy_trans; ++ ++ data &= ~TX_OVRD_DRV_LO_PREEMPH_MASK; ++ data |= TX_OVRD_DRV_LO_PREEMPH(phy_dwc3->tx_deamp_3_5db); ++ data &= ~TX_OVRD_DRV_LO_AMPLITUDE_MASK; ++ data |= 0x6E; ++ data |= TX_OVRD_DRV_LO_EN; ++ ret = usb_ss_write_phycreg(phy_dwc3, ++ SSPHY_CTRL_TX_OVRD_DRV_LO(0), data); ++ if (ret) ++ goto err_phy_trans; ++ ++ data = 0; ++ data &= ~SSPHY_MPLL_MASK; ++ data |= SSPHY_MPLL(phy_dwc3->mpll); ++ usb_ss_write_phycreg(phy_dwc3, 0x30, data); ++ ++ /* ++ * Set the QSCRATCH PHY_PARAM_CTRL1 parameters as follows ++ * TX_FULL_SWING [26:20] amplitude to 110 ++ * TX_DEEMPH_6DB [19:14] to 32 ++ * TX_DEEMPH_3_5DB [13:8] set based on SoC version ++ * LOS_BIAS [7:3] to 9 ++ */ ++ data = readl(phy_dwc3->base + SSUSB_PHY_PARAM_CTRL_1); ++ ++ data &= ~PHY_PARAM_CTRL1_MASK; ++ ++ data |= PHY_PARAM_CTRL1_TX_FULL_SWING(0x6e) | ++ PHY_PARAM_CTRL1_TX_DEEMPH_6DB(0x20) | ++ PHY_PARAM_CTRL1_TX_DEEMPH_3_5DB(phy_dwc3->tx_deamp_3_5db) | ++ PHY_PARAM_CTRL1_LOS_BIAS(0x9); ++ ++ usb_phy_write_readback(phy_dwc3, SSUSB_PHY_PARAM_CTRL_1, ++ PHY_PARAM_CTRL1_MASK, data); ++ ++err_phy_trans: ++ return ret; ++} ++ ++static int qcom_ipq806x_usb_ss_phy_exit(struct phy *phy) ++{ ++ struct usb_phy *phy_dwc3 = phy_get_drvdata(phy); ++ ++ /* Sequence to put SSPHY in low power state: ++ * 1. Clear REF_PHY_EN in PHY_CTRL_REG ++ * 2. Clear REF_USE_PAD in PHY_CTRL_REG ++ * 3. Set TEST_POWERED_DOWN in PHY_CTRL_REG to enable PHY retention ++ */ ++ usb_phy_write_readback(phy_dwc3, SSUSB_PHY_CTRL_REG, ++ SSUSB_CTRL_SS_PHY_EN, 0x0); ++ usb_phy_write_readback(phy_dwc3, SSUSB_PHY_CTRL_REG, ++ SSUSB_CTRL_REF_USE_PAD, 0x0); ++ usb_phy_write_readback(phy_dwc3, SSUSB_PHY_CTRL_REG, ++ SSUSB_CTRL_TEST_POWERDOWN, 0x0); ++ ++ clk_disable_unprepare(phy_dwc3->ref_clk); ++ clk_disable_unprepare(phy_dwc3->xo_clk); ++ ++ return 0; ++} ++ ++static const struct phy_drvdata qcom_ipq806x_usb_hs_drvdata = { ++ .ops = { ++ .init = qcom_ipq806x_usb_hs_phy_init, ++ .exit = qcom_ipq806x_usb_hs_phy_exit, ++ .owner = THIS_MODULE, ++ }, ++ .clk_rate = 60000000, ++}; ++ ++static const struct phy_drvdata qcom_ipq806x_usb_ss_drvdata = { ++ .ops = { ++ .init = qcom_ipq806x_usb_ss_phy_init, ++ .exit = qcom_ipq806x_usb_ss_phy_exit, ++ .owner = THIS_MODULE, ++ }, ++ .clk_rate = 125000000, ++}; ++ ++static const struct of_device_id qcom_ipq806x_usb_phy_table[] = { ++ { .compatible = "qcom,ipq806x-usb-phy-hs", ++ .data = &qcom_ipq806x_usb_hs_drvdata }, ++ { .compatible = "qcom,ipq806x-usb-phy-ss", ++ .data = &qcom_ipq806x_usb_ss_drvdata }, ++ { /* Sentinel */ } ++}; ++MODULE_DEVICE_TABLE(of, qcom_ipq806x_usb_phy_table); ++ ++static int qcom_ipq806x_usb_phy_probe(struct platform_device *pdev) ++{ ++ struct resource *res; ++ resource_size_t size; ++ struct phy *generic_phy; ++ struct usb_phy *phy_dwc3; ++ const struct phy_drvdata *data; ++ struct phy_provider *phy_provider; ++ ++ phy_dwc3 = devm_kzalloc(&pdev->dev, sizeof(*phy_dwc3), GFP_KERNEL); ++ if (!phy_dwc3) ++ return -ENOMEM; ++ ++ data = of_device_get_match_data(&pdev->dev); ++ ++ phy_dwc3->dev = &pdev->dev; ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (!res) ++ return -EINVAL; ++ size = resource_size(res); ++ phy_dwc3->base = devm_ioremap(phy_dwc3->dev, res->start, size); ++ ++ if (IS_ERR(phy_dwc3->base)) { ++ dev_err(phy_dwc3->dev, "failed to map reg\n"); ++ return PTR_ERR(phy_dwc3->base); ++ } ++ ++ phy_dwc3->ref_clk = devm_clk_get(phy_dwc3->dev, "ref"); ++ if (IS_ERR(phy_dwc3->ref_clk)) { ++ dev_dbg(phy_dwc3->dev, "cannot get reference clock\n"); ++ return PTR_ERR(phy_dwc3->ref_clk); ++ } ++ ++ clk_set_rate(phy_dwc3->ref_clk, data->clk_rate); ++ ++ phy_dwc3->xo_clk = devm_clk_get(phy_dwc3->dev, "xo"); ++ if (IS_ERR(phy_dwc3->xo_clk)) { ++ dev_dbg(phy_dwc3->dev, "cannot get TCXO clock\n"); ++ phy_dwc3->xo_clk = NULL; ++ } ++ ++ /* Parse device node to probe HSIO settings */ ++ if (device_property_read_u32(&pdev->dev, "qcom,rx-eq", ++ &phy_dwc3->rx_eq)) ++ phy_dwc3->rx_eq = SSPHY_RX_EQ_VALUE; ++ ++ if (device_property_read_u32(&pdev->dev, "qcom,tx-deamp_3_5db", ++ &phy_dwc3->tx_deamp_3_5db)) ++ phy_dwc3->rx_eq = SSPHY_TX_DEEMPH_3_5DB; ++ ++ if (device_property_read_u32(&pdev->dev, "qcom,mpll", &phy_dwc3->mpll)) ++ phy_dwc3->mpll = SSPHY_MPLL_VALUE; ++ ++ generic_phy = devm_phy_create(phy_dwc3->dev, pdev->dev.of_node, &data->ops); ++ ++ if (IS_ERR(generic_phy)) ++ return PTR_ERR(generic_phy); ++ ++ phy_set_drvdata(generic_phy, phy_dwc3); ++ platform_set_drvdata(pdev, phy_dwc3); ++ ++ phy_provider = devm_of_phy_provider_register(phy_dwc3->dev, ++ of_phy_simple_xlate); ++ ++ if (IS_ERR(phy_provider)) ++ return PTR_ERR(phy_provider); ++ ++ return 0; ++} ++ ++static struct platform_driver qcom_ipq806x_usb_phy_driver = { ++ .probe = qcom_ipq806x_usb_phy_probe, ++ .driver = { ++ .name = "qcom-ipq806x-usb-phy", ++ .owner = THIS_MODULE, ++ .of_match_table = qcom_ipq806x_usb_phy_table, ++ }, ++}; ++ ++module_platform_driver(qcom_ipq806x_usb_phy_driver); ++ ++MODULE_ALIAS("platform:phy-qcom-ipq806x-usb"); ++MODULE_LICENSE("GPL v2"); ++MODULE_AUTHOR("Andy Gross "); ++MODULE_AUTHOR("Ivan T. Ivanov "); ++MODULE_DESCRIPTION("DesignWare USB3 QCOM PHY driver"); diff --git a/target/linux/ipq806x/patches-5.10/095-2-v5.9-phy-qualcomm-fix-setting-of-tx_deamp_3_5db-when-device-property-read-fails.patch b/target/linux/ipq806x/patches-5.10/095-2-v5.9-phy-qualcomm-fix-setting-of-tx_deamp_3_5db-when-device-property-read-fails.patch new file mode 100644 index 0000000000..dedbb51049 --- /dev/null +++ b/target/linux/ipq806x/patches-5.10/095-2-v5.9-phy-qualcomm-fix-setting-of-tx_deamp_3_5db-when-device-property-read-fails.patch @@ -0,0 +1,31 @@ +From 3d7b0ca5300bd01b176f2b4c10e173db802560d8 Mon Sep 17 00:00:00 2001 +From: Colin Ian King +Date: Tue, 21 Jul 2020 16:06:13 +0100 +Subject: phy: qualcomm: fix setting of tx_deamp_3_5db when device property + read fails + +Currently when reading of the device property for "qcom,tx-deamp_3_5db" +fails the default is being assigned incorrectly to phy_dwc3->rx_eq. This +looks like a copy-n-paste error and in fact should be assigning the +default instead to phy_dwc3->tx_deamp_3_5db + +Addresses-Coverity: ("Copy-paste error") +Fixes: ef19b117b834 ("phy: qualcomm: add qcom ipq806x dwc usb phy driver") +Signed-off-by: Colin Ian King +Link: https://lore.kernel.org/r/20200721150613.416876-1-colin.king@canonical.com +Signed-off-by: Vinod Koul +--- + drivers/phy/qualcomm/phy-qcom-ipq806x-usb.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/phy/qualcomm/phy-qcom-ipq806x-usb.c ++++ b/drivers/phy/qualcomm/phy-qcom-ipq806x-usb.c +@@ -531,7 +531,7 @@ static int qcom_ipq806x_usb_phy_probe(st + + if (device_property_read_u32(&pdev->dev, "qcom,tx-deamp_3_5db", + &phy_dwc3->tx_deamp_3_5db)) +- phy_dwc3->rx_eq = SSPHY_TX_DEEMPH_3_5DB; ++ phy_dwc3->tx_deamp_3_5db = SSPHY_TX_DEEMPH_3_5DB; + + if (device_property_read_u32(&pdev->dev, "qcom,mpll", &phy_dwc3->mpll)) + phy_dwc3->mpll = SSPHY_MPLL_VALUE; diff --git a/target/linux/ipq806x/patches-5.10/850-soc-add-qualcomm-syscon.patch b/target/linux/ipq806x/patches-5.10/850-soc-add-qualcomm-syscon.patch new file mode 100644 index 0000000000..9e1ac7db04 --- /dev/null +++ b/target/linux/ipq806x/patches-5.10/850-soc-add-qualcomm-syscon.patch @@ -0,0 +1,121 @@ +From: Christian Lamparter +Subject: SoC: add qualcomm syscon +--- a/drivers/soc/qcom/Makefile ++++ b/drivers/soc/qcom/Makefile +@@ -20,6 +20,7 @@ obj-$(CONFIG_QCOM_SMP2P) += smp2p.o + obj-$(CONFIG_QCOM_SMSM) += smsm.o + obj-$(CONFIG_QCOM_SOCINFO) += socinfo.o + obj-$(CONFIG_QCOM_WCNSS_CTRL) += wcnss_ctrl.o ++obj-$(CONFIG_QCOM_TCSR) += qcom_tcsr.o + obj-$(CONFIG_QCOM_APR) += apr.o + obj-$(CONFIG_QCOM_LLCC) += llcc-slice.o + obj-$(CONFIG_QCOM_SDM845_LLCC) += llcc-sdm845.o +--- a/drivers/soc/qcom/Kconfig ++++ b/drivers/soc/qcom/Kconfig +@@ -183,6 +183,13 @@ config QCOM_SOCINFO + Say yes here to support the Qualcomm socinfo driver, providing + information about the SoC to user space. + ++config QCOM_TCSR ++ tristate "QCOM Top Control and Status Registers" ++ depends on ARCH_QCOM ++ help ++ Say y here to enable TCSR support. The TCSR provides control ++ functions for various peripherals. ++ + config QCOM_WCNSS_CTRL + tristate "Qualcomm WCNSS control driver" + depends on ARCH_QCOM || COMPILE_TEST +--- /dev/null ++++ b/drivers/soc/qcom/qcom_tcsr.c +@@ -0,0 +1,64 @@ ++/* ++ * Copyright (c) 2014, The Linux foundation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License rev 2 and ++ * only rev 2 as published by the free Software foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or fITNESS fOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define TCSR_USB_PORT_SEL 0xb0 ++ ++static int tcsr_probe(struct platform_device *pdev) ++{ ++ struct resource *res; ++ const struct device_node *node = pdev->dev.of_node; ++ void __iomem *base; ++ u32 val; ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ base = devm_ioremap_resource(&pdev->dev, res); ++ if (IS_ERR(base)) ++ return PTR_ERR(base); ++ ++ if (!of_property_read_u32(node, "qcom,usb-ctrl-select", &val)) { ++ dev_err(&pdev->dev, "setting usb port select = %d\n", val); ++ writel(val, base + TCSR_USB_PORT_SEL); ++ } ++ ++ return 0; ++} ++ ++static const struct of_device_id tcsr_dt_match[] = { ++ { .compatible = "qcom,tcsr", }, ++ { }, ++}; ++ ++MODULE_DEVICE_TABLE(of, tcsr_dt_match); ++ ++static struct platform_driver tcsr_driver = { ++ .driver = { ++ .name = "tcsr", ++ .owner = THIS_MODULE, ++ .of_match_table = tcsr_dt_match, ++ }, ++ .probe = tcsr_probe, ++}; ++ ++module_platform_driver(tcsr_driver); ++ ++MODULE_AUTHOR("Andy Gross "); ++MODULE_DESCRIPTION("QCOM TCSR driver"); ++MODULE_LICENSE("GPL v2"); +--- /dev/null ++++ b/include/dt-bindings/soc/qcom,tcsr.h +@@ -0,0 +1,23 @@ ++/* Copyright (c) 2014, The Linux Foundation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 and ++ * only version 2 as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ */ ++#ifndef __DT_BINDINGS_QCOM_TCSR_H ++#define __DT_BINDINGS_QCOM_TCSR_H ++ ++#define TCSR_USB_SELECT_USB3_P0 0x1 ++#define TCSR_USB_SELECT_USB3_P1 0x2 ++#define TCSR_USB_SELECT_USB3_DUAL 0x3 ++ ++/* TCSR A/B REG */ ++#define IPQ806X_TCSR_REG_A_ADM_CRCI_MUX_SEL 0 ++#define IPQ806X_TCSR_REG_B_ADM_CRCI_MUX_SEL 1 ++ ++#endif diff --git a/target/linux/ipq806x/patches-5.10/851-add-gsbi1-dts.patch b/target/linux/ipq806x/patches-5.10/851-add-gsbi1-dts.patch new file mode 100644 index 0000000000..f75f994904 --- /dev/null +++ b/target/linux/ipq806x/patches-5.10/851-add-gsbi1-dts.patch @@ -0,0 +1,44 @@ +--- a/arch/arm/boot/dts/qcom-ipq8064.dtsi ++++ b/arch/arm/boot/dts/qcom-ipq8064.dtsi +@@ -865,6 +865,41 @@ + reg = <0x12100000 0x10000>; + }; + ++ gsbi1: gsbi@12440000 { ++ compatible = "qcom,gsbi-v1.0.0"; ++ cell-index = <1>; ++ reg = <0x12440000 0x100>; ++ clocks = <&gcc GSBI1_H_CLK>; ++ clock-names = "iface"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ranges; ++ status = "disabled"; ++ ++ syscon-tcsr = <&tcsr>; ++ ++ gsbi1_serial: serial@12450000 { ++ compatible = "qcom,msm-uartdm-v1.3", "qcom,msm-uartdm"; ++ reg = <0x12450000 0x100>, ++ <0x12400000 0x03>; ++ interrupts = ; ++ clocks = <&gcc GSBI1_UART_CLK>, <&gcc GSBI1_H_CLK>; ++ clock-names = "core", "iface"; ++ status = "disabled"; ++ }; ++ ++ gsbi1_i2c: i2c@12460000 { ++ compatible = "qcom,i2c-qup-v1.1.1"; ++ reg = <0x12460000 0x1000>; ++ interrupts = ; ++ clocks = <&gcc GSBI1_QUP_CLK>, <&gcc GSBI1_H_CLK>; ++ clock-names = "core", "iface"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ }; ++ + gsbi2: gsbi@12480000 { + compatible = "qcom,gsbi-v1.0.0"; + cell-index = <2>; diff --git a/target/linux/ipq806x/patches-5.10/900-arm-add-cmdline-override.patch b/target/linux/ipq806x/patches-5.10/900-arm-add-cmdline-override.patch new file mode 100644 index 0000000000..49cd68b68d --- /dev/null +++ b/target/linux/ipq806x/patches-5.10/900-arm-add-cmdline-override.patch @@ -0,0 +1,37 @@ +--- a/arch/arm/Kconfig ++++ b/arch/arm/Kconfig +@@ -1840,6 +1840,14 @@ config ARM_ATAG_DTB_COMPAT_CMDLINE_MANGL + + endchoice + ++config CMDLINE_OVERRIDE ++ bool "Use alternative cmdline from device tree" ++ help ++ Some bootloaders may have uneditable bootargs. While CMDLINE_FORCE can ++ be used, this is not a good option for kernels that are shared across ++ devices. This setting enables using "chosen/cmdline-override" as the ++ cmdline if it exists in the device tree. ++ + config CMDLINE + string "Default kernel command string" + default "" +--- a/drivers/of/fdt.c ++++ b/drivers/of/fdt.c +@@ -1060,6 +1060,17 @@ int __init early_init_dt_scan_chosen(uns + if (p != NULL && l > 0) + strlcpy(data, p, min(l, COMMAND_LINE_SIZE)); + ++ /* CONFIG_CMDLINE_OVERRIDE is used to fallback to a different ++ * device tree option of chosen/bootargs-override. This is ++ * helpful on boards where u-boot sets bootargs, and is unable ++ * to be modified. ++ */ ++#ifdef CONFIG_CMDLINE_OVERRIDE ++ p = of_get_flat_dt_prop(node, "bootargs-override", &l); ++ if (p != NULL && l > 0) ++ strlcpy(data, p, min((int)l, COMMAND_LINE_SIZE)); ++#endif ++ + /* + * CONFIG_CMDLINE is meant to be a default in case nothing else + * managed to set the command line, unless CONFIG_CMDLINE_FORCE diff --git a/target/linux/ipq806x/patches-5.10/997-device_tree_cmdline.patch b/target/linux/ipq806x/patches-5.10/997-device_tree_cmdline.patch new file mode 100644 index 0000000000..b6b1b04765 --- /dev/null +++ b/target/linux/ipq806x/patches-5.10/997-device_tree_cmdline.patch @@ -0,0 +1,12 @@ +--- a/drivers/of/fdt.c ++++ b/drivers/of/fdt.c +@@ -1059,6 +1059,9 @@ int __init early_init_dt_scan_chosen(uns + p = of_get_flat_dt_prop(node, "bootargs", &l); + if (p != NULL && l > 0) + strlcpy(data, p, min(l, COMMAND_LINE_SIZE)); ++ p = of_get_flat_dt_prop(node, "bootargs-append", &l); ++ if (p != NULL && l > 0) ++ strlcat(data, p, min_t(int, strlen(data) + (int)l, COMMAND_LINE_SIZE)); + + /* CONFIG_CMDLINE_OVERRIDE is used to fallback to a different + * device tree option of chosen/bootargs-override. This is From 96f10c9d7a88717e84782449122b958e5a15eddd Mon Sep 17 00:00:00 2001 From: Ansuel Smith Date: Mon, 1 Mar 2021 01:02:09 +0100 Subject: [PATCH 14/62] ipq806x: use newer tsens patch Use improved tsens patch proposed upstream. Signed-off-by: Ansuel Smith --- .../0063-1-ipq806x-tsens-driver.patch | 616 ------------------ ...sens-support-configurable-interrupts.patch | 437 ------------- .../0063-3-tsens-fix-kernel-5_4.patch | 68 -- .../0063-4-ip806x-tsense-rework-driver.patch | 107 --- ...hermal-tsens-Add-VER_0-tsens-version.patch | 292 +++++++++ ...al-tsens-Don-t-hardcode-sensor-slope.patch | 33 + ...l-tsens-Convert-msm8960-to-reg_field.patch | 124 ++++ ...al-tsens-Use-init_common-for-msm8960.patch | 86 +++ ...tsens-Fix-bug-in-sensor-enable-for-m.patch | 71 ++ ...tsens-Replace-custom-8960-apis-with-.patch | 114 ++++ ...tsens-Drop-unused-define-for-msm8960.patch | 70 ++ ...-tsens-Add-support-for-ipq8064-tsens.patch | 31 + ...rmal-tsens-Document-ipq8064-bindings.patch | 115 ++++ ...al-tsens-Fix-wrong-slope-on-msm-8960.patch | 37 ++ 14 files changed, 973 insertions(+), 1228 deletions(-) delete mode 100644 target/linux/ipq806x/patches-5.10/0063-1-ipq806x-tsens-driver.patch delete mode 100644 target/linux/ipq806x/patches-5.10/0063-2-tsens-support-configurable-interrupts.patch delete mode 100644 target/linux/ipq806x/patches-5.10/0063-3-tsens-fix-kernel-5_4.patch delete mode 100644 target/linux/ipq806x/patches-5.10/0063-4-ip806x-tsense-rework-driver.patch create mode 100644 target/linux/ipq806x/patches-5.10/104-1-drivers-thermal-tsens-Add-VER_0-tsens-version.patch create mode 100644 target/linux/ipq806x/patches-5.10/104-2-drivers-thermal-tsens-Don-t-hardcode-sensor-slope.patch create mode 100644 target/linux/ipq806x/patches-5.10/104-3-drivers-thermal-tsens-Convert-msm8960-to-reg_field.patch create mode 100644 target/linux/ipq806x/patches-5.10/104-4-drivers-thermal-tsens-Use-init_common-for-msm8960.patch create mode 100644 target/linux/ipq806x/patches-5.10/104-5-drivers-thermal-tsens-Fix-bug-in-sensor-enable-for-m.patch create mode 100644 target/linux/ipq806x/patches-5.10/104-6-drivers-thermal-tsens-Replace-custom-8960-apis-with-.patch create mode 100644 target/linux/ipq806x/patches-5.10/104-7-drivers-thermal-tsens-Drop-unused-define-for-msm8960.patch create mode 100644 target/linux/ipq806x/patches-5.10/104-8-drivers-thermal-tsens-Add-support-for-ipq8064-tsens.patch create mode 100644 target/linux/ipq806x/patches-5.10/104-9-dt-bindings-thermal-tsens-Document-ipq8064-bindings.patch create mode 100644 target/linux/ipq806x/patches-5.10/105-10-drivers-thermal-tsens-Fix-wrong-slope-on-msm-8960.patch diff --git a/target/linux/ipq806x/patches-5.10/0063-1-ipq806x-tsens-driver.patch b/target/linux/ipq806x/patches-5.10/0063-1-ipq806x-tsens-driver.patch deleted file mode 100644 index 80954c17fd..0000000000 --- a/target/linux/ipq806x/patches-5.10/0063-1-ipq806x-tsens-driver.patch +++ /dev/null @@ -1,616 +0,0 @@ -From 3302e1e1a3cfa4e67fda2a61d6f0c42205d40932 Mon Sep 17 00:00:00 2001 -From: Rajith Cherian -Date: Tue, 14 Feb 2017 18:30:43 +0530 -Subject: [PATCH] ipq8064: tsens: Base tsens driver for IPQ8064 - -Add TSENS driver template to support IPQ8064. -This is a base file copied from tsens-8960.c - -Change-Id: I47c573fdfa2d898243c6a6ba952d1632f91391f7 -Signed-off-by: Rajith Cherian - -ipq8064: tsens: TSENS driver support for IPQ8064 - -Support for IPQ8064 tsens driver. The driver works -with the thermal framework. The driver overrides the -following fucntionalities: - -1. Get current temperature. -2. Get/Set trip temperatures. -3. Enabled/Disable trip points. -4. ISR for threshold generated interrupt. -5. Notify userspace when trip points are hit. - -Change-Id: I8bc7204fd627d10875ab13fc1de8cb6c2ed7a918 -Signed-off-by: Rajith Cherian ---- - ---- a/drivers/thermal/qcom/Makefile -+++ b/drivers/thermal/qcom/Makefile -@@ -2,5 +2,5 @@ - obj-$(CONFIG_QCOM_TSENS) += qcom_tsens.o - - qcom_tsens-y += tsens.o tsens-common.o tsens-v0_1.o \ -- tsens-8960.o tsens-v2.o tsens-v1.o -+ tsens-8960.o tsens-v2.o tsens-v1.o tsens-ipq8064.o - obj-$(CONFIG_QCOM_SPMI_TEMP_ALARM) += qcom-spmi-temp-alarm.o ---- /dev/null -+++ b/drivers/thermal/qcom/tsens-ipq8064.c -@@ -0,0 +1,551 @@ -+/* -+ * Copyright (c) 2015, The Linux Foundation. All rights reserved. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 and -+ * only version 2 as published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include "tsens.h" -+ -+#define CAL_MDEGC 30000 -+ -+#define CONFIG_ADDR 0x3640 -+/* CONFIG_ADDR bitmasks */ -+#define CONFIG 0x9b -+#define CONFIG_MASK 0xf -+#define CONFIG_SHIFT 0 -+ -+#define STATUS_CNTL_8064 0x3660 -+#define CNTL_ADDR 0x3620 -+/* CNTL_ADDR bitmasks */ -+#define EN BIT(0) -+#define SW_RST BIT(1) -+#define SENSOR0_EN BIT(3) -+#define SLP_CLK_ENA BIT(26) -+#define MEASURE_PERIOD 1 -+#define SENSOR0_SHIFT 3 -+ -+/* INT_STATUS_ADDR bitmasks */ -+#define MIN_STATUS_MASK BIT(0) -+#define LOWER_STATUS_CLR BIT(1) -+#define UPPER_STATUS_CLR BIT(2) -+#define MAX_STATUS_MASK BIT(3) -+ -+#define THRESHOLD_ADDR 0x3624 -+/* THRESHOLD_ADDR bitmasks */ -+#define THRESHOLD_MAX_CODE 0x20000 -+#define THRESHOLD_MIN_CODE 0 -+#define THRESHOLD_MAX_LIMIT_SHIFT 24 -+#define THRESHOLD_MIN_LIMIT_SHIFT 16 -+#define THRESHOLD_UPPER_LIMIT_SHIFT 8 -+#define THRESHOLD_LOWER_LIMIT_SHIFT 0 -+#define THRESHOLD_MAX_LIMIT_MASK (THRESHOLD_MAX_CODE << \ -+ THRESHOLD_MAX_LIMIT_SHIFT) -+#define THRESHOLD_MIN_LIMIT_MASK (THRESHOLD_MAX_CODE << \ -+ THRESHOLD_MIN_LIMIT_SHIFT) -+#define THRESHOLD_UPPER_LIMIT_MASK (THRESHOLD_MAX_CODE << \ -+ THRESHOLD_UPPER_LIMIT_SHIFT) -+#define THRESHOLD_LOWER_LIMIT_MASK (THRESHOLD_MAX_CODE << \ -+ THRESHOLD_LOWER_LIMIT_SHIFT) -+ -+/* Initial temperature threshold values */ -+#define LOWER_LIMIT_TH 0x9d /* 95C */ -+#define UPPER_LIMIT_TH 0xa6 /* 105C */ -+#define MIN_LIMIT_TH 0x0 -+#define MAX_LIMIT_TH 0xff -+ -+#define S0_STATUS_ADDR 0x3628 -+#define STATUS_ADDR_OFFSET 2 -+#define SENSOR_STATUS_SIZE 4 -+#define INT_STATUS_ADDR 0x363c -+#define TRDY_MASK BIT(7) -+#define TIMEOUT_US 100 -+ -+#define TSENS_EN BIT(0) -+#define TSENS_SW_RST BIT(1) -+#define TSENS_ADC_CLK_SEL BIT(2) -+#define SENSOR0_EN BIT(3) -+#define SENSOR1_EN BIT(4) -+#define SENSOR2_EN BIT(5) -+#define SENSOR3_EN BIT(6) -+#define SENSOR4_EN BIT(7) -+#define SENSORS_EN (SENSOR0_EN | SENSOR1_EN | \ -+ SENSOR2_EN | SENSOR3_EN | SENSOR4_EN) -+#define TSENS_8064_SENSOR5_EN BIT(8) -+#define TSENS_8064_SENSOR6_EN BIT(9) -+#define TSENS_8064_SENSOR7_EN BIT(10) -+#define TSENS_8064_SENSOR8_EN BIT(11) -+#define TSENS_8064_SENSOR9_EN BIT(12) -+#define TSENS_8064_SENSOR10_EN BIT(13) -+#define TSENS_8064_SENSORS_EN (SENSORS_EN | \ -+ TSENS_8064_SENSOR5_EN | \ -+ TSENS_8064_SENSOR6_EN | \ -+ TSENS_8064_SENSOR7_EN | \ -+ TSENS_8064_SENSOR8_EN | \ -+ TSENS_8064_SENSOR9_EN | \ -+ TSENS_8064_SENSOR10_EN) -+ -+#define TSENS_8064_SEQ_SENSORS 5 -+#define TSENS_8064_S4_S5_OFFSET 40 -+#define TSENS_FACTOR 1 -+ -+/* Trips: from very hot to very cold */ -+enum tsens_trip_type { -+ TSENS_TRIP_STAGE3 = 0, -+ TSENS_TRIP_STAGE2, -+ TSENS_TRIP_STAGE1, -+ TSENS_TRIP_STAGE0, -+ TSENS_TRIP_NUM, -+}; -+ -+u32 tsens_8064_slope[] = { -+ 1176, 1176, 1154, 1176, -+ 1111, 1132, 1132, 1199, -+ 1132, 1199, 1132 -+ }; -+ -+/* Temperature on y axis and ADC-code on x-axis */ -+static inline int code_to_degC(u32 adc_code, const struct tsens_sensor *s) -+{ -+ int degcbeforefactor, degc; -+ -+ degcbeforefactor = (adc_code * s->slope) + s->offset; -+ -+ if (degcbeforefactor == 0) -+ degc = degcbeforefactor; -+ else if (degcbeforefactor > 0) -+ degc = (degcbeforefactor + TSENS_FACTOR/2) -+ / TSENS_FACTOR; -+ else -+ degc = (degcbeforefactor - TSENS_FACTOR/2) -+ / TSENS_FACTOR; -+ -+ return degc; -+} -+ -+static int degC_to_code(int degC, const struct tsens_sensor *s) -+{ -+ int code = ((degC * TSENS_FACTOR - s->offset) + (s->slope/2)) -+ / s->slope; -+ -+ if (code > THRESHOLD_MAX_CODE) -+ code = THRESHOLD_MAX_CODE; -+ else if (code < THRESHOLD_MIN_CODE) -+ code = THRESHOLD_MIN_CODE; -+ return code; -+} -+ -+static int suspend_ipq8064(struct tsens_priv *priv) -+{ -+ int ret; -+ unsigned int mask; -+ struct regmap *map = priv->tm_map; -+ -+ ret = regmap_read(map, THRESHOLD_ADDR, &priv->ctx.threshold); -+ if (ret) -+ return ret; -+ -+ ret = regmap_read(map, CNTL_ADDR, &priv->ctx.control); -+ if (ret) -+ return ret; -+ -+ mask = SLP_CLK_ENA | EN; -+ -+ ret = regmap_update_bits(map, CNTL_ADDR, mask, 0); -+ if (ret) -+ return ret; -+ -+ return 0; -+} -+ -+static int resume_ipq8064(struct tsens_priv *priv) -+{ -+ int ret; -+ struct regmap *map = priv->tm_map; -+ -+ ret = regmap_update_bits(map, CNTL_ADDR, SW_RST, SW_RST); -+ if (ret) -+ return ret; -+ -+ ret = regmap_update_bits(map, CONFIG_ADDR, CONFIG_MASK, CONFIG); -+ if (ret) -+ return ret; -+ -+ ret = regmap_write(map, THRESHOLD_ADDR, priv->ctx.threshold); -+ if (ret) -+ return ret; -+ -+ ret = regmap_write(map, CNTL_ADDR, priv->ctx.control); -+ if (ret) -+ return ret; -+ -+ return 0; -+} -+ -+static void notify_uspace_tsens_fn(struct work_struct *work) -+{ -+ struct tsens_sensor *s = container_of(work, struct tsens_sensor, -+ notify_work); -+ -+ sysfs_notify(&s->tzd->device.kobj, NULL, "type"); -+} -+ -+static void tsens_scheduler_fn(struct work_struct *work) -+{ -+ struct tsens_priv *priv = container_of(work, struct tsens_priv, -+ tsens_work); -+ unsigned int threshold, threshold_low, code, reg, sensor, mask; -+ unsigned int sensor_addr; -+ bool upper_th_x, lower_th_x; -+ int adc_code, ret; -+ -+ ret = regmap_read(priv->tm_map, STATUS_CNTL_8064, ®); -+ if (ret) -+ return; -+ reg = reg | LOWER_STATUS_CLR | UPPER_STATUS_CLR; -+ ret = regmap_write(priv->tm_map, STATUS_CNTL_8064, reg); -+ if (ret) -+ return; -+ -+ mask = ~(LOWER_STATUS_CLR | UPPER_STATUS_CLR); -+ ret = regmap_read(priv->tm_map, THRESHOLD_ADDR, &threshold); -+ if (ret) -+ return; -+ threshold_low = (threshold & THRESHOLD_LOWER_LIMIT_MASK) -+ >> THRESHOLD_LOWER_LIMIT_SHIFT; -+ threshold = (threshold & THRESHOLD_UPPER_LIMIT_MASK) -+ >> THRESHOLD_UPPER_LIMIT_SHIFT; -+ -+ ret = regmap_read(priv->tm_map, STATUS_CNTL_8064, ®); -+ if (ret) -+ return; -+ -+ ret = regmap_read(priv->tm_map, CNTL_ADDR, &sensor); -+ if (ret) -+ return; -+ sensor &= (uint32_t) TSENS_8064_SENSORS_EN; -+ sensor >>= SENSOR0_SHIFT; -+ -+ /* Constraint: There is only 1 interrupt control register for all -+ * 11 temperature sensor. So monitoring more than 1 sensor based -+ * on interrupts will yield inconsistent result. To overcome this -+ * issue we will monitor only sensor 0 which is the master sensor. -+ */ -+ -+ /* Skip if the sensor is disabled */ -+ if (sensor & 1) { -+ ret = regmap_read(priv->tm_map, priv->sensor[0].status, &code); -+ if (ret) -+ return; -+ upper_th_x = code >= threshold; -+ lower_th_x = code <= threshold_low; -+ if (upper_th_x) -+ mask |= UPPER_STATUS_CLR; -+ if (lower_th_x) -+ mask |= LOWER_STATUS_CLR; -+ if (upper_th_x || lower_th_x) { -+ /* Notify user space */ -+ schedule_work(&priv->sensor[0].notify_work); -+ regmap_read(priv->tm_map, sensor_addr, &adc_code); -+ pr_debug("Trigger (%d degrees) for sensor %d\n", -+ code_to_degC(adc_code, &priv->sensor[0]), 0); -+ } -+ } -+ regmap_write(priv->tm_map, STATUS_CNTL_8064, reg & mask); -+ -+ /* force memory to sync */ -+ mb(); -+} -+ -+static irqreturn_t tsens_isr(int irq, void *data) -+{ -+ struct tsens_priv *priv = data; -+ -+ schedule_work(&priv->tsens_work); -+ return IRQ_HANDLED; -+} -+ -+static void hw_init(struct tsens_priv *priv) -+{ -+ int ret; -+ unsigned int reg_cntl = 0, reg_cfg = 0, reg_thr = 0; -+ unsigned int reg_status_cntl = 0; -+ -+ regmap_read(priv->tm_map, CNTL_ADDR, ®_cntl); -+ regmap_write(priv->tm_map, CNTL_ADDR, reg_cntl | TSENS_SW_RST); -+ -+ reg_cntl |= SLP_CLK_ENA | (MEASURE_PERIOD << 18) -+ | (((1 << priv->num_sensors) - 1) << SENSOR0_SHIFT); -+ regmap_write(priv->tm_map, CNTL_ADDR, reg_cntl); -+ regmap_read(priv->tm_map, STATUS_CNTL_8064, ®_status_cntl); -+ reg_status_cntl |= LOWER_STATUS_CLR | UPPER_STATUS_CLR -+ | MIN_STATUS_MASK | MAX_STATUS_MASK; -+ regmap_write(priv->tm_map, STATUS_CNTL_8064, reg_status_cntl); -+ reg_cntl |= TSENS_EN; -+ regmap_write(priv->tm_map, CNTL_ADDR, reg_cntl); -+ -+ regmap_read(priv->tm_map, CONFIG_ADDR, ®_cfg); -+ reg_cfg = (reg_cfg & ~CONFIG_MASK) | (CONFIG << CONFIG_SHIFT); -+ regmap_write(priv->tm_map, CONFIG_ADDR, reg_cfg); -+ -+ reg_thr |= (LOWER_LIMIT_TH << THRESHOLD_LOWER_LIMIT_SHIFT) -+ | (UPPER_LIMIT_TH << THRESHOLD_UPPER_LIMIT_SHIFT) -+ | (MIN_LIMIT_TH << THRESHOLD_MIN_LIMIT_SHIFT) -+ | (MAX_LIMIT_TH << THRESHOLD_MAX_LIMIT_SHIFT); -+ -+ regmap_write(priv->tm_map, THRESHOLD_ADDR, reg_thr); -+ -+ ret = devm_request_irq(priv->dev, priv->tsens_irq, tsens_isr, -+ IRQF_TRIGGER_RISING, "tsens_interrupt", priv); -+ if (ret < 0) { -+ pr_err("%s: request_irq FAIL: %d\n", __func__, ret); -+ return; -+ } -+ -+ INIT_WORK(&priv->tsens_work, tsens_scheduler_fn); -+} -+ -+static int init_ipq8064(struct tsens_priv *priv) -+{ -+ int ret, i; -+ u32 reg_cntl, offset = 0; -+ -+ init_common(priv); -+ if (!priv->tm_map) -+ return -ENODEV; -+ -+ /* -+ * The status registers for each sensor are discontiguous -+ * because some SoCs have 5 sensors while others have more -+ * but the control registers stay in the same place, i.e -+ * directly after the first 5 status registers. -+ */ -+ for (i = 0; i < priv->num_sensors; i++) { -+ if (i >= TSENS_8064_SEQ_SENSORS) -+ offset = TSENS_8064_S4_S5_OFFSET; -+ -+ priv->sensor[i].status = S0_STATUS_ADDR + offset -+ + (i << STATUS_ADDR_OFFSET); -+ priv->sensor[i].slope = tsens_8064_slope[i]; -+ INIT_WORK(&priv->sensor[i].notify_work, -+ notify_uspace_tsens_fn); -+ } -+ -+ reg_cntl = SW_RST; -+ ret = regmap_update_bits(priv->tm_map, CNTL_ADDR, SW_RST, reg_cntl); -+ if (ret) -+ return ret; -+ -+ reg_cntl |= SLP_CLK_ENA | (MEASURE_PERIOD << 18); -+ reg_cntl &= ~SW_RST; -+ ret = regmap_update_bits(priv->tm_map, CONFIG_ADDR, -+ CONFIG_MASK, CONFIG); -+ -+ reg_cntl |= GENMASK(priv->num_sensors - 1, 0) << SENSOR0_SHIFT; -+ ret = regmap_write(priv->tm_map, CNTL_ADDR, reg_cntl); -+ if (ret) -+ return ret; -+ -+ reg_cntl |= EN; -+ ret = regmap_write(priv->tm_map, CNTL_ADDR, reg_cntl); -+ if (ret) -+ return ret; -+ -+ return 0; -+} -+ -+static int calibrate_ipq8064(struct tsens_priv *priv) -+{ -+ int i; -+ char *data, *data_backup; -+ -+ ssize_t num_read = priv->num_sensors; -+ struct tsens_sensor *s = priv->sensor; -+ -+ data = qfprom_read(priv->dev, "calib"); -+ if (IS_ERR(data)) { -+ pr_err("Calibration not found.\n"); -+ return PTR_ERR(data); -+ } -+ -+ data_backup = qfprom_read(priv->dev, "calib_backup"); -+ if (IS_ERR(data_backup)) { -+ pr_err("Backup calibration not found.\n"); -+ return PTR_ERR(data_backup); -+ } -+ -+ for (i = 0; i < num_read; i++) { -+ s[i].calib_data = readb_relaxed(data + i); -+ s[i].calib_data_backup = readb_relaxed(data_backup + i); -+ -+ if (s[i].calib_data_backup) -+ s[i].calib_data = s[i].calib_data_backup; -+ if (!s[i].calib_data) { -+ pr_err("QFPROM TSENS calibration data not present\n"); -+ return -ENODEV; -+ } -+ s[i].slope = tsens_8064_slope[i]; -+ s[i].offset = CAL_MDEGC - (s[i].calib_data * s[i].slope); -+ } -+ -+ hw_init(priv); -+ -+ return 0; -+} -+ -+static int get_temp_ipq8064(struct tsens_priv *priv, int id, int *temp) -+{ -+ int ret; -+ u32 code, trdy; -+ const struct tsens_sensor *s = &priv->sensor[id]; -+ unsigned long timeout; -+ -+ timeout = jiffies + usecs_to_jiffies(TIMEOUT_US); -+ do { -+ ret = regmap_read(priv->tm_map, INT_STATUS_ADDR, &trdy); -+ if (ret) -+ return ret; -+ if (!(trdy & TRDY_MASK)) -+ continue; -+ ret = regmap_read(priv->tm_map, s->status, &code); -+ if (ret) -+ return ret; -+ *temp = code_to_degC(code, s); -+ return 0; -+ } while (time_before(jiffies, timeout)); -+ -+ return -ETIMEDOUT; -+} -+ -+static int set_trip_temp_ipq8064(void *data, int trip, int temp) -+{ -+ unsigned int reg_th, reg_cntl; -+ int ret, code, code_chk, hi_code, lo_code; -+ const struct tsens_sensor *s = data; -+ struct tsens_priv *priv = s->priv; -+ -+ code_chk = code = degC_to_code(temp, s); -+ -+ if (code < THRESHOLD_MIN_CODE || code > THRESHOLD_MAX_CODE) -+ return -EINVAL; -+ -+ ret = regmap_read(priv->tm_map, STATUS_CNTL_8064, ®_cntl); -+ if (ret) -+ return ret; -+ -+ ret = regmap_read(priv->tm_map, THRESHOLD_ADDR, ®_th); -+ if (ret) -+ return ret; -+ -+ hi_code = (reg_th & THRESHOLD_UPPER_LIMIT_MASK) -+ >> THRESHOLD_UPPER_LIMIT_SHIFT; -+ lo_code = (reg_th & THRESHOLD_LOWER_LIMIT_MASK) -+ >> THRESHOLD_LOWER_LIMIT_SHIFT; -+ -+ switch (trip) { -+ case TSENS_TRIP_STAGE3: -+ code <<= THRESHOLD_MAX_LIMIT_SHIFT; -+ reg_th &= ~THRESHOLD_MAX_LIMIT_MASK; -+ break; -+ case TSENS_TRIP_STAGE2: -+ if (code_chk <= lo_code) -+ return -EINVAL; -+ code <<= THRESHOLD_UPPER_LIMIT_SHIFT; -+ reg_th &= ~THRESHOLD_UPPER_LIMIT_MASK; -+ break; -+ case TSENS_TRIP_STAGE1: -+ if (code_chk >= hi_code) -+ return -EINVAL; -+ code <<= THRESHOLD_LOWER_LIMIT_SHIFT; -+ reg_th &= ~THRESHOLD_LOWER_LIMIT_MASK; -+ break; -+ case TSENS_TRIP_STAGE0: -+ code <<= THRESHOLD_MIN_LIMIT_SHIFT; -+ reg_th &= ~THRESHOLD_MIN_LIMIT_MASK; -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ ret = regmap_write(priv->tm_map, THRESHOLD_ADDR, reg_th | code); -+ if (ret) -+ return ret; -+ -+ return 0; -+} -+ -+static int set_trip_activate_ipq8064(void *data, int trip, -+ enum thermal_trip_activation_mode mode) -+{ -+ unsigned int reg_cntl, mask, val; -+ const struct tsens_sensor *s = data; -+ struct tsens_priv *priv = s->priv; -+ int ret; -+ -+ if (!priv || trip < 0) -+ return -EINVAL; -+ -+ ret = regmap_read(priv->tm_map, STATUS_CNTL_8064, ®_cntl); -+ if (ret) -+ return ret; -+ -+ switch (trip) { -+ case TSENS_TRIP_STAGE3: -+ mask = MAX_STATUS_MASK; -+ break; -+ case TSENS_TRIP_STAGE2: -+ mask = UPPER_STATUS_CLR; -+ break; -+ case TSENS_TRIP_STAGE1: -+ mask = LOWER_STATUS_CLR; -+ break; -+ case TSENS_TRIP_STAGE0: -+ mask = MIN_STATUS_MASK; -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ if (mode == THERMAL_TRIP_ACTIVATION_DISABLED) -+ val = reg_cntl | mask; -+ else -+ val = reg_cntl & ~mask; -+ -+ ret = regmap_write(priv->tm_map, STATUS_CNTL_8064, val); -+ if (ret) -+ return ret; -+ -+ /* force memory to sync */ -+ mb(); -+ return 0; -+} -+ -+const struct tsens_ops ops_ipq8064 = { -+ .init = init_ipq8064, -+ .calibrate = calibrate_ipq8064, -+ .get_temp = get_temp_ipq8064, -+ .suspend = suspend_ipq8064, -+ .resume = resume_ipq8064, -+ .set_trip_temp = set_trip_temp_ipq8064, -+ .set_trip_activate = set_trip_activate_ipq8064, -+}; -+ -+const struct tsens_plat_data data_ipq8064 = { -+ .num_sensors = 11, -+ .ops = &ops_ipq8064, -+}; ---- a/drivers/thermal/qcom/tsens.c -+++ b/drivers/thermal/qcom/tsens.c -@@ -69,8 +69,11 @@ static const struct of_device_id tsens_t - }, { - .compatible = "qcom,tsens-v2", - .data = &data_tsens_v2, -+ }, { -+ .compatible = "qcom,ipq8064-tsens", -+ .data = &data_ipq8064, - }, -- {} -+ {} - }; - MODULE_DEVICE_TABLE(of, tsens_table); - ---- a/drivers/thermal/qcom/tsens.h -+++ b/drivers/thermal/qcom/tsens.h -@@ -324,7 +324,7 @@ extern const struct tsens_plat_data data - extern const struct tsens_plat_data data_8916, data_8974; - - /* TSENS v1 targets */ --extern const struct tsens_plat_data data_tsens_v1; -+extern const struct tsens_plat_data data_tsens_v1, data_ipq8064; - - /* TSENS v2 targets */ - extern const struct tsens_plat_data data_8996, data_tsens_v2; diff --git a/target/linux/ipq806x/patches-5.10/0063-2-tsens-support-configurable-interrupts.patch b/target/linux/ipq806x/patches-5.10/0063-2-tsens-support-configurable-interrupts.patch deleted file mode 100644 index 585bd62a58..0000000000 --- a/target/linux/ipq806x/patches-5.10/0063-2-tsens-support-configurable-interrupts.patch +++ /dev/null @@ -1,437 +0,0 @@ -From 4e87400732c77765afae2ea89ed43837457aa604 Mon Sep 17 00:00:00 2001 -From: Rajith Cherian -Date: Wed, 1 Feb 2017 19:00:26 +0530 -Subject: [PATCH] ipq8064: tsens: Support for configurable interrupts - -Provide support for adding configurable high and -configurable low trip temperatures. An interrupts is -also triggerred when these trip points are hit. The -interrupts can be activated or deactivated from sysfs. -This functionality is made available only if -CONFIG_THERMAL_WRITABLE_TRIPS is defined. - -Change-Id: Ib73f3f9459de4fffce7bb985a0312a88291f4934 -Signed-off-by: Rajith Cherian ---- - .../devicetree/bindings/thermal/qcom-tsens.txt | 4 ++ - drivers/thermal/of-thermal.c | 63 ++++++++++++++++++---- - drivers/thermal/qcom/tsens.c | 43 ++++++++++++--- - drivers/thermal/qcom/tsens.h | 11 ++++ - drivers/thermal/thermal_core.c | 44 ++++++++++++++- - include/linux/thermal.h | 14 +++++ - 6 files changed, 162 insertions(+), 17 deletions(-) - ---- a/drivers/thermal/of-thermal.c -+++ b/drivers/thermal/of-thermal.c -@@ -91,7 +91,7 @@ static int of_thermal_get_temp(struct th - { - struct __thermal_zone *data = tz->devdata; - -- if (!data->ops->get_temp) -+ if (!data->ops->get_temp || (data->mode == THERMAL_DEVICE_DISABLED)) - return -EINVAL; - - return data->ops->get_temp(data->sensor_data, temp); -@@ -102,7 +102,8 @@ static int of_thermal_set_trips(struct t - { - struct __thermal_zone *data = tz->devdata; - -- if (!data->ops || !data->ops->set_trips) -+ if (!data->ops || !data->ops->set_trips -+ || (data->mode == THERMAL_DEVICE_DISABLED)) - return -EINVAL; - - return data->ops->set_trips(data->sensor_data, low, high); -@@ -188,6 +189,9 @@ static int of_thermal_set_emul_temp(stru - { - struct __thermal_zone *data = tz->devdata; - -+ if (data->mode == THERMAL_DEVICE_DISABLED) -+ return -EINVAL; -+ - return data->ops->set_emul_temp(data->sensor_data, temp); - } - -@@ -196,7 +200,7 @@ static int of_thermal_get_trend(struct t - { - struct __thermal_zone *data = tz->devdata; - -- if (!data->ops->get_trend) -+ if (!data->ops->get_trend || (data->mode == THERMAL_DEVICE_DISABLED)) - return -EINVAL; - - return data->ops->get_trend(data->sensor_data, trip, trend); -@@ -297,7 +301,9 @@ static int of_thermal_set_mode(struct th - mutex_unlock(&tz->lock); - - data->mode = mode; -- thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED); -+ -+ if (mode == THERMAL_DEVICE_ENABLED) -+ thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED); - - return 0; - } -@@ -307,7 +313,8 @@ static int of_thermal_get_trip_type(stru - { - struct __thermal_zone *data = tz->devdata; - -- if (trip >= data->ntrips || trip < 0) -+ if (trip >= data->ntrips || trip < 0 -+ || (data->mode == THERMAL_DEVICE_DISABLED)) - return -EDOM; - - *type = data->trips[trip].type; -@@ -315,12 +322,39 @@ static int of_thermal_get_trip_type(stru - return 0; - } - -+static int of_thermal_activate_trip_type(struct thermal_zone_device *tz, -+ int trip, enum thermal_trip_activation_mode mode) -+{ -+ struct __thermal_zone *data = tz->devdata; -+ -+ if (trip >= data->ntrips || trip < 0 -+ || (data->mode == THERMAL_DEVICE_DISABLED)) -+ return -EDOM; -+ -+ /* -+ * The configurable_hi and configurable_lo trip points can be -+ * activated and deactivated. -+ */ -+ -+ if (data->ops->set_trip_activate) { -+ int ret; -+ -+ ret = data->ops->set_trip_activate(data->sensor_data, -+ trip, mode); -+ if (ret) -+ return ret; -+ } -+ -+ return 0; -+} -+ - static int of_thermal_get_trip_temp(struct thermal_zone_device *tz, int trip, - int *temp) - { - struct __thermal_zone *data = tz->devdata; - -- if (trip >= data->ntrips || trip < 0) -+ if (trip >= data->ntrips || trip < 0 -+ || (data->mode == THERMAL_DEVICE_DISABLED)) - return -EDOM; - - *temp = data->trips[trip].temperature; -@@ -333,7 +367,8 @@ static int of_thermal_set_trip_temp(stru - { - struct __thermal_zone *data = tz->devdata; - -- if (trip >= data->ntrips || trip < 0) -+ if (trip >= data->ntrips || trip < 0 -+ || (data->mode == THERMAL_DEVICE_DISABLED)) - return -EDOM; - - if (data->ops->set_trip_temp) { -@@ -355,7 +390,8 @@ static int of_thermal_get_trip_hyst(stru - { - struct __thermal_zone *data = tz->devdata; - -- if (trip >= data->ntrips || trip < 0) -+ if (trip >= data->ntrips || trip < 0 -+ || (data->mode == THERMAL_DEVICE_DISABLED)) - return -EDOM; - - *hyst = data->trips[trip].hysteresis; -@@ -368,7 +404,8 @@ static int of_thermal_set_trip_hyst(stru - { - struct __thermal_zone *data = tz->devdata; - -- if (trip >= data->ntrips || trip < 0) -+ if (trip >= data->ntrips || trip < 0 -+ || (data->mode == THERMAL_DEVICE_DISABLED)) - return -EDOM; - - /* thermal framework should take care of data->mask & (1 << trip) */ -@@ -443,6 +480,9 @@ thermal_zone_of_add_sensor(struct device - if (ops->set_emul_temp) - tzd->ops->set_emul_temp = of_thermal_set_emul_temp; - -+ if (ops->set_trip_activate) -+ tzd->ops->set_trip_activate = of_thermal_activate_trip_type; -+ - mutex_unlock(&tzd->lock); - - return tzd; -@@ -762,7 +802,10 @@ static const char * const trip_types[] = - [THERMAL_TRIP_ACTIVE] = "active", - [THERMAL_TRIP_PASSIVE] = "passive", - [THERMAL_TRIP_HOT] = "hot", -- [THERMAL_TRIP_CRITICAL] = "critical", -+ [THERMAL_TRIP_CRITICAL] = "critical_high", -+ [THERMAL_TRIP_CONFIGURABLE_HI] = "configurable_hi", -+ [THERMAL_TRIP_CONFIGURABLE_LOW] = "configurable_lo", -+ [THERMAL_TRIP_CRITICAL_LOW] = "critical_low", - }; - - /** ---- a/drivers/thermal/qcom/tsens.c -+++ b/drivers/thermal/qcom/tsens.c -@@ -22,7 +22,7 @@ static int tsens_get_temp(void *data, in - - static int tsens_get_trend(void *data, int trip, enum thermal_trend *trend) - { -- const struct tsens_sensor *s = data; -+ struct tsens_sensor *s = data; - struct tsens_priv *priv = s->priv; - - if (priv->ops->get_trend) -@@ -31,9 +31,10 @@ static int tsens_get_trend(void *data, i - return -ENOTSUPP; - } - --static int __maybe_unused tsens_suspend(struct device *dev) -+static int __maybe_unused tsens_suspend(void *data) - { -- struct tsens_priv *priv = dev_get_drvdata(dev); -+ struct tsens_sensor *s = data; -+ struct tsens_priv *priv = s->priv; - - if (priv->ops && priv->ops->suspend) - return priv->ops->suspend(priv); -@@ -41,9 +42,10 @@ static int __maybe_unused tsens_suspend - return 0; - } - --static int __maybe_unused tsens_resume(struct device *dev) -+static int __maybe_unused tsens_resume(void *data) - { -- struct tsens_priv *priv = dev_get_drvdata(dev); -+ struct tsens_sensor *s = data; -+ struct tsens_priv *priv = s->priv; - - if (priv->ops && priv->ops->resume) - return priv->ops->resume(priv); -@@ -51,6 +53,30 @@ static int __maybe_unused tsens_resume(s - return 0; - } - -+static int __maybe_unused tsens_set_trip_temp(void *data, int trip, int temp) -+{ -+ struct tsens_sensor *s = data; -+ struct tsens_priv *priv = s->priv; -+ -+ if (priv->ops && priv->ops->set_trip_temp) -+ return priv->ops->set_trip_temp(s, trip, temp); -+ -+ return 0; -+} -+ -+static int __maybe_unused tsens_activate_trip_type(void *data, int trip, -+ enum thermal_trip_activation_mode mode) -+{ -+ struct tsens_sensor *s = data; -+ struct tsens_priv *priv = s->priv; -+ -+ if (priv->ops && priv->ops->set_trip_activate) -+ return priv->ops->set_trip_activate(s, trip, mode); -+ -+ return 0; -+} -+ -+ - static SIMPLE_DEV_PM_OPS(tsens_pm_ops, tsens_suspend, tsens_resume); - - static const struct of_device_id tsens_table[] = { -@@ -80,6 +106,8 @@ MODULE_DEVICE_TABLE(of, tsens_table); - static const struct thermal_zone_of_device_ops tsens_of_ops = { - .get_temp = tsens_get_temp, - .get_trend = tsens_get_trend, -+ .set_trip_temp = tsens_set_trip_temp, -+ .set_trip_activate = tsens_activate_trip_type, - }; - - static int tsens_register(struct tsens_priv *priv) -@@ -123,7 +151,7 @@ static int tsens_probe(struct platform_d - if (id) - data = id->data; - else -- data = &data_8960; -+ return -EINVAL; - - num_sensors = data->num_sensors; - -@@ -144,6 +172,9 @@ static int tsens_probe(struct platform_d - priv->dev = dev; - priv->num_sensors = num_sensors; - priv->ops = data->ops; -+ -+ priv->tsens_irq = platform_get_irq(pdev, 0); -+ - for (i = 0; i < priv->num_sensors; i++) { - if (data->hw_ids) - priv->sensor[i].hw_id = data->hw_ids[i]; ---- a/drivers/thermal/qcom/tsens.h -+++ b/drivers/thermal/qcom/tsens.h -@@ -40,9 +40,12 @@ enum tsens_ver { - struct tsens_sensor { - struct tsens_priv *priv; - struct thermal_zone_device *tzd; -+ struct work_struct notify_work; - int offset; - unsigned int id; - unsigned int hw_id; -+ int calib_data; -+ int calib_data_backup; - int slope; - u32 status; - }; -@@ -57,6 +60,9 @@ struct tsens_sensor { - * @suspend: Function to suspend the tsens device - * @resume: Function to resume the tsens device - * @get_trend: Function to get the thermal/temp trend -+ * @set_trip_temp: Function to set trip temp -+ * @get_trip_temp: Function to get trip temp -+ * @set_trip_activate: Function to activate trip points - */ - struct tsens_ops { - /* mandatory callbacks */ -@@ -69,6 +75,9 @@ struct tsens_ops { - int (*suspend)(struct tsens_priv *priv); - int (*resume)(struct tsens_priv *priv); - int (*get_trend)(struct tsens_priv *priv, int i, enum thermal_trend *trend); -+ int (*set_trip_temp)(void *data, int trip, int temp); -+ int (*set_trip_activate)(void *data, int trip, -+ enum thermal_trip_activation_mode mode); - }; - - #define REG_FIELD_FOR_EACH_SENSOR11(_name, _offset, _startbit, _stopbit) \ -@@ -300,6 +309,7 @@ struct tsens_context { - struct tsens_priv { - struct device *dev; - u32 num_sensors; -+ u32 tsens_irq; - struct regmap *tm_map; - struct regmap *srot_map; - u32 tm_offset; -@@ -308,6 +318,7 @@ struct tsens_priv { - const struct tsens_features *feat; - const struct reg_field *fields; - const struct tsens_ops *ops; -+ struct work_struct tsens_work; - struct tsens_sensor sensor[0]; - }; - ---- a/drivers/thermal/thermal_sysfs.c -+++ b/drivers/thermal/thermal_sysfs.c -@@ -113,12 +113,48 @@ trip_point_type_show(struct device *dev, - return sprintf(buf, "passive\n"); - case THERMAL_TRIP_ACTIVE: - return sprintf(buf, "active\n"); -+ case THERMAL_TRIP_CONFIGURABLE_HI: -+ return sprintf(buf, "configurable_hi\n"); -+ case THERMAL_TRIP_CONFIGURABLE_LOW: -+ return sprintf(buf, "configurable_low\n"); -+ case THERMAL_TRIP_CRITICAL_LOW: -+ return sprintf(buf, "critical_low\n"); - default: - return sprintf(buf, "unknown\n"); - } - } - - static ssize_t -+trip_point_type_activate(struct device *dev, struct device_attribute *attr, -+ const char *buf, size_t count) -+{ -+ struct thermal_zone_device *tz = to_thermal_zone(dev); -+ int trip, ret; -+ char *enabled = "enabled"; -+ char *disabled = "disabled"; -+ -+ if (!tz->ops->set_trip_activate) -+ return -EPERM; -+ -+ if (!sscanf(attr->attr.name, "trip_point_%d_type", &trip)) -+ return -EINVAL; -+ -+ if (!strncmp(buf, enabled, strlen(enabled))) -+ ret = tz->ops->set_trip_activate(tz, trip, -+ THERMAL_TRIP_ACTIVATION_ENABLED); -+ else if (!strncmp(buf, disabled, strlen(disabled))) -+ ret = tz->ops->set_trip_activate(tz, trip, -+ THERMAL_TRIP_ACTIVATION_DISABLED); -+ else -+ ret = -EINVAL; -+ -+ if (ret) -+ return ret; -+ -+ return count; -+} -+ -+static ssize_t - trip_point_temp_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) - { -@@ -559,6 +595,12 @@ static int create_trip_attrs(struct ther - tz->trip_type_attrs[indx].attr.show = trip_point_type_show; - attrs[indx] = &tz->trip_type_attrs[indx].attr.attr; - -+ if (IS_ENABLED(CONFIG_THERMAL_WRITABLE_TRIPS)) { -+ tz->trip_type_attrs[indx].attr.store -+ = trip_point_type_activate; -+ tz->trip_type_attrs[indx].attr.attr.mode |= S_IWUSR; -+ } -+ - /* create trip temp attribute */ - snprintf(tz->trip_temp_attrs[indx].name, THERMAL_NAME_LENGTH, - "trip_point_%d_temp", indx); ---- a/include/linux/thermal.h -+++ b/include/linux/thermal.h -@@ -63,11 +63,19 @@ enum thermal_device_mode { - THERMAL_DEVICE_ENABLED, - }; - -+enum thermal_trip_activation_mode { -+ THERMAL_TRIP_ACTIVATION_DISABLED = 0, -+ THERMAL_TRIP_ACTIVATION_ENABLED, -+}; -+ - enum thermal_trip_type { - THERMAL_TRIP_ACTIVE = 0, - THERMAL_TRIP_PASSIVE, - THERMAL_TRIP_HOT, - THERMAL_TRIP_CRITICAL, -+ THERMAL_TRIP_CONFIGURABLE_HI, -+ THERMAL_TRIP_CONFIGURABLE_LOW, -+ THERMAL_TRIP_CRITICAL_LOW, - }; - - enum thermal_trend { -@@ -105,6 +113,8 @@ struct thermal_zone_device_ops { - enum thermal_trip_type *); - int (*get_trip_temp) (struct thermal_zone_device *, int, int *); - int (*set_trip_temp) (struct thermal_zone_device *, int, int); -+ int (*set_trip_activate) (struct thermal_zone_device *, int, -+ enum thermal_trip_activation_mode); - int (*get_trip_hyst) (struct thermal_zone_device *, int, int *); - int (*set_trip_hyst) (struct thermal_zone_device *, int, int); - int (*get_crit_temp) (struct thermal_zone_device *, int *); -@@ -349,6 +359,8 @@ struct thermal_genl_event { - * temperature. - * @set_trip_temp: a pointer to a function that sets the trip temperature on - * hardware. -+ * @activate_trip_type: a pointer to a function to enable/disable trip -+ * temperature interrupts - */ - struct thermal_zone_of_device_ops { - int (*get_temp)(void *, int *); -@@ -356,6 +368,8 @@ struct thermal_zone_of_device_ops { - int (*set_trips)(void *, int, int); - int (*set_emul_temp)(void *, int); - int (*set_trip_temp)(void *, int, int); -+ int (*set_trip_activate)(void *, int, -+ enum thermal_trip_activation_mode); - }; - - /** diff --git a/target/linux/ipq806x/patches-5.10/0063-3-tsens-fix-kernel-5_4.patch b/target/linux/ipq806x/patches-5.10/0063-3-tsens-fix-kernel-5_4.patch deleted file mode 100644 index 6c056db3b7..0000000000 --- a/target/linux/ipq806x/patches-5.10/0063-3-tsens-fix-kernel-5_4.patch +++ /dev/null @@ -1,68 +0,0 @@ ---- a/drivers/thermal/qcom/tsens-ipq8064.c -+++ b/drivers/thermal/qcom/tsens-ipq8064.c -@@ -18,6 +18,7 @@ - #include - #include - #include -+#include - #include - #include - #include "tsens.h" -@@ -320,15 +321,42 @@ static void hw_init(struct tsens_priv *p - INIT_WORK(&priv->tsens_work, tsens_scheduler_fn); - } - -+static const struct regmap_config tsens_config = { -+ .name = "tm", -+ .reg_bits = 32, -+ .val_bits = 32, -+ .reg_stride = 4, -+}; -+ - static int init_ipq8064(struct tsens_priv *priv) - { -- int ret, i; -+ struct device *dev = priv->dev; - u32 reg_cntl, offset = 0; -+ struct resource *res; -+ resource_size_t size; -+ void __iomem *base; -+ int ret, i; -+ struct platform_device *op = of_find_device_by_node(priv->dev->of_node); -+ -+ if (!op) -+ return -EINVAL; - -- init_common(priv); -- if (!priv->tm_map) -- return -ENODEV; -+ /* old DTs where SROT and TM were in a contiguous 2K block */ -+ priv->tm_offset = 0x1000; - -+ res = platform_get_resource(op, IORESOURCE_MEM, 0); -+ size = resource_size(res); -+ base = devm_ioremap(&op->dev, res->start, size); -+ if (IS_ERR(base)) { -+ ret = PTR_ERR(base); -+ goto err_put_device; -+ } -+ -+ priv->tm_map = devm_regmap_init_mmio(dev, base, &tsens_config); -+ if (IS_ERR(priv->tm_map)) { -+ ret = PTR_ERR(priv->tm_map); -+ goto err_put_device; -+ } - /* - * The status registers for each sensor are discontiguous - * because some SoCs have 5 sensors while others have more -@@ -367,6 +395,10 @@ static int init_ipq8064(struct tsens_pri - return ret; - - return 0; -+ -+err_put_device: -+ put_device(&op->dev); -+ return ret; - } - - static int calibrate_ipq8064(struct tsens_priv *priv) diff --git a/target/linux/ipq806x/patches-5.10/0063-4-ip806x-tsense-rework-driver.patch b/target/linux/ipq806x/patches-5.10/0063-4-ip806x-tsense-rework-driver.patch deleted file mode 100644 index 67fc8db7a3..0000000000 --- a/target/linux/ipq806x/patches-5.10/0063-4-ip806x-tsense-rework-driver.patch +++ /dev/null @@ -1,107 +0,0 @@ ---- a/drivers/thermal/qcom/tsens-ipq8064.c -+++ b/drivers/thermal/qcom/tsens-ipq8064.c -@@ -13,10 +13,12 @@ - */ - - #include -+#include - #include - #include - #include - #include -+#include - #include - #include - #include -@@ -211,9 +213,8 @@ static void tsens_scheduler_fn(struct wo - struct tsens_priv *priv = container_of(work, struct tsens_priv, - tsens_work); - unsigned int threshold, threshold_low, code, reg, sensor, mask; -- unsigned int sensor_addr; - bool upper_th_x, lower_th_x; -- int adc_code, ret; -+ int ret; - - ret = regmap_read(priv->tm_map, STATUS_CNTL_8064, ®); - if (ret) -@@ -262,9 +263,8 @@ static void tsens_scheduler_fn(struct wo - if (upper_th_x || lower_th_x) { - /* Notify user space */ - schedule_work(&priv->sensor[0].notify_work); -- regmap_read(priv->tm_map, sensor_addr, &adc_code); - pr_debug("Trigger (%d degrees) for sensor %d\n", -- code_to_degC(adc_code, &priv->sensor[0]), 0); -+ code_to_degC(code, &priv->sensor[0]), 0); - } - } - regmap_write(priv->tm_map, STATUS_CNTL_8064, reg & mask); -@@ -404,40 +404,55 @@ err_put_device: - static int calibrate_ipq8064(struct tsens_priv *priv) - { - int i; -- char *data, *data_backup; -- -+ int ret = 0; -+ u8 *data, *data_backup; -+ struct device *dev = priv->dev; - ssize_t num_read = priv->num_sensors; - struct tsens_sensor *s = priv->sensor; - -- data = qfprom_read(priv->dev, "calib"); -+ data = qfprom_read(dev, "calib"); - if (IS_ERR(data)) { -- pr_err("Calibration not found.\n"); -- return PTR_ERR(data); -+ ret = PTR_ERR(data); -+ if (ret != -EPROBE_DEFER) -+ dev_err(dev, "Calibration not found."); -+ goto exit; - } - -- data_backup = qfprom_read(priv->dev, "calib_backup"); -+ data_backup = qfprom_read(dev, "calib_backup"); - if (IS_ERR(data_backup)) { -- pr_err("Backup calibration not found.\n"); -- return PTR_ERR(data_backup); -+ ret = PTR_ERR(data_backup); -+ if (ret != -EPROBE_DEFER) -+ dev_err(dev, "Backup Calibration not found."); -+ goto free_data; - } - - for (i = 0; i < num_read; i++) { - s[i].calib_data = readb_relaxed(data + i); -- s[i].calib_data_backup = readb_relaxed(data_backup + i); -+ -+ if (!s[i].calib_data) { -+ s[i].calib_data_backup = readb_relaxed(data_backup + i); -+ -+ if (!s[i].calib_data_backup) { -+ dev_err(dev, "QFPROM TSENS calibration data not present"); -+ ret = -ENODEV; -+ goto free_backup; -+ } - -- if (s[i].calib_data_backup) - s[i].calib_data = s[i].calib_data_backup; -- if (!s[i].calib_data) { -- pr_err("QFPROM TSENS calibration data not present\n"); -- return -ENODEV; - } -+ - s[i].slope = tsens_8064_slope[i]; - s[i].offset = CAL_MDEGC - (s[i].calib_data * s[i].slope); - } - - hw_init(priv); - -- return 0; -+free_backup: -+ kfree(data_backup); -+free_data: -+ kfree(data); -+exit: -+ return ret; - } - - static int get_temp_ipq8064(struct tsens_priv *priv, int id, int *temp) diff --git a/target/linux/ipq806x/patches-5.10/104-1-drivers-thermal-tsens-Add-VER_0-tsens-version.patch b/target/linux/ipq806x/patches-5.10/104-1-drivers-thermal-tsens-Add-VER_0-tsens-version.patch new file mode 100644 index 0000000000..d4c85a06a5 --- /dev/null +++ b/target/linux/ipq806x/patches-5.10/104-1-drivers-thermal-tsens-Add-VER_0-tsens-version.patch @@ -0,0 +1,292 @@ +From 5c7d1181056feef0b58fb2f556f55e170ba5b479 Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Sat, 25 Jul 2020 19:14:59 +0200 +Subject: [PATCH 01/10] drivers: thermal: tsens: Add VER_0 tsens version + +VER_0 is used to describe device based on tsens version before v0.1. +These device are devices based on msm8960 for example apq8064 or +ipq806x. + +Signed-off-by: Ansuel Smith +Reviewed-by: Thara Gopinath +Reported-by: kernel test robot +Reported-by: Dan Carpenter +--- + drivers/thermal/qcom/tsens.c | 150 ++++++++++++++++++++++++++++------- + drivers/thermal/qcom/tsens.h | 4 +- + 2 files changed, 124 insertions(+), 30 deletions(-) + +diff --git a/drivers/thermal/qcom/tsens.c b/drivers/thermal/qcom/tsens.c +index d8ce3a687b80..9a7e991d4bd2 100644 +--- a/drivers/thermal/qcom/tsens.c ++++ b/drivers/thermal/qcom/tsens.c +@@ -12,6 +12,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -515,6 +516,15 @@ static irqreturn_t tsens_irq_thread(int irq, void *data) + dev_dbg(priv->dev, "[%u] %s: no violation: %d\n", + hw_id, __func__, temp); + } ++ ++ if (tsens_version(priv) < VER_0_1) { ++ /* Constraint: There is only 1 interrupt control register for all ++ * 11 temperature sensor. So monitoring more than 1 sensor based ++ * on interrupts will yield inconsistent result. To overcome this ++ * issue we will monitor only sensor 0 which is the master sensor. ++ */ ++ break; ++ } + } + + return IRQ_HANDLED; +@@ -530,6 +540,13 @@ static int tsens_set_trips(void *_sensor, int low, int high) + int high_val, low_val, cl_high, cl_low; + u32 hw_id = s->hw_id; + ++ if (tsens_version(priv) < VER_0_1) { ++ /* Pre v0.1 IP had a single register for each type of interrupt ++ * and thresholds ++ */ ++ hw_id = 0; ++ } ++ + dev_dbg(dev, "[%u] %s: proposed thresholds: (%d:%d)\n", + hw_id, __func__, low, high); + +@@ -584,18 +601,21 @@ int get_temp_tsens_valid(const struct tsens_sensor *s, int *temp) + u32 valid; + int ret; + +- ret = regmap_field_read(priv->rf[valid_idx], &valid); +- if (ret) +- return ret; +- while (!valid) { +- /* Valid bit is 0 for 6 AHB clock cycles. +- * At 19.2MHz, 1 AHB clock is ~60ns. +- * We should enter this loop very, very rarely. +- */ +- ndelay(400); ++ /* VER_0 doesn't have VALID bit */ ++ if (tsens_version(priv) >= VER_0_1) { + ret = regmap_field_read(priv->rf[valid_idx], &valid); + if (ret) + return ret; ++ while (!valid) { ++ /* Valid bit is 0 for 6 AHB clock cycles. ++ * At 19.2MHz, 1 AHB clock is ~60ns. ++ * We should enter this loop very, very rarely. ++ */ ++ ndelay(400); ++ ret = regmap_field_read(priv->rf[valid_idx], &valid); ++ if (ret) ++ return ret; ++ } + } + + /* Valid bit is set, OK to read the temperature */ +@@ -608,15 +628,29 @@ int get_temp_common(const struct tsens_sensor *s, int *temp) + { + struct tsens_priv *priv = s->priv; + int hw_id = s->hw_id; +- int last_temp = 0, ret; ++ int last_temp = 0, ret, trdy; ++ unsigned long timeout; + +- ret = regmap_field_read(priv->rf[LAST_TEMP_0 + hw_id], &last_temp); +- if (ret) +- return ret; ++ timeout = jiffies + usecs_to_jiffies(TIMEOUT_US); ++ do { ++ if (tsens_version(priv) == VER_0) { ++ ret = regmap_field_read(priv->rf[TRDY], &trdy); ++ if (ret) ++ return ret; ++ if (!trdy) ++ continue; ++ } + +- *temp = code_to_degc(last_temp, s) * 1000; ++ ret = regmap_field_read(priv->rf[LAST_TEMP_0 + hw_id], &last_temp); ++ if (ret) ++ return ret; + +- return 0; ++ *temp = code_to_degc(last_temp, s) * 1000; ++ ++ return 0; ++ } while (time_before(jiffies, timeout)); ++ ++ return -ETIMEDOUT; + } + + #ifdef CONFIG_DEBUG_FS +@@ -738,19 +772,34 @@ int __init init_common(struct tsens_priv *priv) + priv->tm_offset = 0x1000; + } + +- res = platform_get_resource(op, IORESOURCE_MEM, 0); +- tm_base = devm_ioremap_resource(dev, res); +- if (IS_ERR(tm_base)) { +- ret = PTR_ERR(tm_base); +- goto err_put_device; ++ if (tsens_version(priv) >= VER_0_1) { ++ res = platform_get_resource(op, IORESOURCE_MEM, 0); ++ tm_base = devm_ioremap_resource(dev, res); ++ if (IS_ERR(tm_base)) { ++ ret = PTR_ERR(tm_base); ++ goto err_put_device; ++ } ++ ++ priv->tm_map = devm_regmap_init_mmio(dev, tm_base, &tsens_config); ++ } else { /* VER_0 share the same gcc regs using a syscon */ ++ struct device *parent = priv->dev->parent; ++ ++ if (parent) ++ priv->tm_map = syscon_node_to_regmap(parent->of_node); + } + +- priv->tm_map = devm_regmap_init_mmio(dev, tm_base, &tsens_config); +- if (IS_ERR(priv->tm_map)) { +- ret = PTR_ERR(priv->tm_map); ++ if (IS_ERR_OR_NULL(priv->tm_map)) { ++ if (!priv->tm_map) ++ ret = -ENODEV; ++ else ++ ret = PTR_ERR(priv->tm_map); + goto err_put_device; + } + ++ /* VER_0 have only tm_map */ ++ if (!priv->srot_map) ++ priv->srot_map = priv->tm_map; ++ + if (tsens_version(priv) > VER_0_1) { + for (i = VER_MAJOR; i <= VER_STEP; i++) { + priv->rf[i] = devm_regmap_field_alloc(dev, priv->srot_map, +@@ -769,6 +818,10 @@ int __init init_common(struct tsens_priv *priv) + ret = PTR_ERR(priv->rf[TSENS_EN]); + goto err_put_device; + } ++ /* in VER_0 TSENS need to be explicitly enabled */ ++ if (tsens_version(priv) == VER_0) ++ regmap_field_write(priv->rf[TSENS_EN], 1); ++ + ret = regmap_field_read(priv->rf[TSENS_EN], &enabled); + if (ret) + goto err_put_device; +@@ -791,6 +844,19 @@ int __init init_common(struct tsens_priv *priv) + goto err_put_device; + } + ++ priv->rf[TSENS_SW_RST] = ++ devm_regmap_field_alloc(dev, priv->srot_map, priv->fields[TSENS_SW_RST]); ++ if (IS_ERR(priv->rf[TSENS_SW_RST])) { ++ ret = PTR_ERR(priv->rf[TSENS_SW_RST]); ++ goto err_put_device; ++ } ++ ++ priv->rf[TRDY] = devm_regmap_field_alloc(dev, priv->tm_map, priv->fields[TRDY]); ++ if (IS_ERR(priv->rf[TRDY])) { ++ ret = PTR_ERR(priv->rf[TRDY]); ++ goto err_put_device; ++ } ++ + /* This loop might need changes if enum regfield_ids is reordered */ + for (j = LAST_TEMP_0; j <= UP_THRESH_15; j += 16) { + for (i = 0; i < priv->feat->max_sensors; i++) { +@@ -806,7 +872,7 @@ int __init init_common(struct tsens_priv *priv) + } + } + +- if (priv->feat->crit_int) { ++ if (priv->feat->crit_int || tsens_version(priv) < VER_0_1) { + /* Loop might need changes if enum regfield_ids is reordered */ + for (j = CRITICAL_STATUS_0; j <= CRIT_THRESH_15; j += 16) { + for (i = 0; i < priv->feat->max_sensors; i++) { +@@ -844,7 +910,11 @@ int __init init_common(struct tsens_priv *priv) + } + + spin_lock_init(&priv->ul_lock); +- tsens_enable_irq(priv); ++ ++ /* VER_0 interrupt doesn't need to be enabled */ ++ if (tsens_version(priv) >= VER_0_1) ++ tsens_enable_irq(priv); ++ + tsens_debug_init(op); + + err_put_device: +@@ -943,10 +1013,19 @@ static int tsens_register_irq(struct tsens_priv *priv, char *irqname, + if (irq == -ENXIO) + ret = 0; + } else { +- ret = devm_request_threaded_irq(&pdev->dev, irq, +- NULL, thread_fn, +- IRQF_ONESHOT, +- dev_name(&pdev->dev), priv); ++ /* VER_0 interrupt is TRIGGER_RISING, VER_0_1 and up is ONESHOT */ ++ if (tsens_version(priv) == VER_0) ++ ret = devm_request_threaded_irq(&pdev->dev, irq, ++ thread_fn, NULL, ++ IRQF_TRIGGER_RISING, ++ dev_name(&pdev->dev), ++ priv); ++ else ++ ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, ++ thread_fn, IRQF_ONESHOT, ++ dev_name(&pdev->dev), ++ priv); ++ + if (ret) + dev_err(&pdev->dev, "%s: failed to get irq\n", + __func__); +@@ -975,6 +1054,19 @@ static int tsens_register(struct tsens_priv *priv) + priv->ops->enable(priv, i); + } + ++ /* VER_0 require to set MIN and MAX THRESH ++ * These 2 regs are set using the: ++ * - CRIT_THRESH_0 for MAX THRESH hardcoded to 120°C ++ * - CRIT_THRESH_1 for MIN THRESH hardcoded to 0°C ++ */ ++ if (tsens_version(priv) < VER_0_1) { ++ regmap_field_write(priv->rf[CRIT_THRESH_0], ++ tsens_mC_to_hw(priv->sensor, 120000)); ++ ++ regmap_field_write(priv->rf[CRIT_THRESH_1], ++ tsens_mC_to_hw(priv->sensor, 0)); ++ } ++ + ret = tsens_register_irq(priv, "uplow", tsens_irq_thread); + if (ret < 0) + return ret; +diff --git a/drivers/thermal/qcom/tsens.h b/drivers/thermal/qcom/tsens.h +index f40b625f897e..8e6c1fd3ccf5 100644 +--- a/drivers/thermal/qcom/tsens.h ++++ b/drivers/thermal/qcom/tsens.h +@@ -13,6 +13,7 @@ + #define CAL_DEGC_PT2 120 + #define SLOPE_FACTOR 1000 + #define SLOPE_DEFAULT 3200 ++#define TIMEOUT_US 100 + #define THRESHOLD_MAX_ADC_CODE 0x3ff + #define THRESHOLD_MIN_ADC_CODE 0x0 + +@@ -25,7 +26,8 @@ struct tsens_priv; + + /* IP version numbers in ascending order */ + enum tsens_ver { +- VER_0_1 = 0, ++ VER_0 = 0, ++ VER_0_1, + VER_1_X, + VER_2_X, + }; +-- +2.30.2 + diff --git a/target/linux/ipq806x/patches-5.10/104-2-drivers-thermal-tsens-Don-t-hardcode-sensor-slope.patch b/target/linux/ipq806x/patches-5.10/104-2-drivers-thermal-tsens-Don-t-hardcode-sensor-slope.patch new file mode 100644 index 0000000000..44de19b7a8 --- /dev/null +++ b/target/linux/ipq806x/patches-5.10/104-2-drivers-thermal-tsens-Don-t-hardcode-sensor-slope.patch @@ -0,0 +1,33 @@ +From efa0d50a6c5ec7619371dfe4d3e6ca54b73787d5 Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Wed, 25 Nov 2020 16:47:21 +0100 +Subject: [PATCH 02/10] drivers: thermal: tsens: Don't hardcode sensor slope + +Function compute_intercept_slope hardcode the sensor slope to +SLOPE_DEFAULT. Change this and use the default value only if a slope is +not defined. This is needed for tsens VER_0 that has a hardcoded slope +table. + +Signed-off-by: Ansuel Smith +Reviewed-by: Thara Gopinath +--- + drivers/thermal/qcom/tsens.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/thermal/qcom/tsens.c b/drivers/thermal/qcom/tsens.c +index 9a7e991d4bd2..38b9936def1a 100644 +--- a/drivers/thermal/qcom/tsens.c ++++ b/drivers/thermal/qcom/tsens.c +@@ -86,7 +86,8 @@ void compute_intercept_slope(struct tsens_priv *priv, u32 *p1, + "%s: sensor%d - data_point1:%#x data_point2:%#x\n", + __func__, i, p1[i], p2[i]); + +- priv->sensor[i].slope = SLOPE_DEFAULT; ++ if (!priv->sensor[i].slope) ++ priv->sensor[i].slope = SLOPE_DEFAULT; + if (mode == TWO_PT_CALIB) { + /* + * slope (m) = adc_code2 - adc_code1 (y2 - y1)/ +-- +2.30.2 + diff --git a/target/linux/ipq806x/patches-5.10/104-3-drivers-thermal-tsens-Convert-msm8960-to-reg_field.patch b/target/linux/ipq806x/patches-5.10/104-3-drivers-thermal-tsens-Convert-msm8960-to-reg_field.patch new file mode 100644 index 0000000000..d8779c689a --- /dev/null +++ b/target/linux/ipq806x/patches-5.10/104-3-drivers-thermal-tsens-Convert-msm8960-to-reg_field.patch @@ -0,0 +1,124 @@ +From 6bac2e2fa36c2d7c304768a689d8b73155b90aa2 Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Wed, 25 Nov 2020 17:15:51 +0100 +Subject: [PATCH 03/10] drivers: thermal: tsens: Convert msm8960 to reg_field + +Convert msm9860 driver to reg_field to use the init_common +function. + +Signed-off-by: Ansuel Smith +Acked-by: Thara Gopinath +--- + drivers/thermal/qcom/tsens-8960.c | 80 ++++++++++++++++++++++++++++++- + 1 file changed, 79 insertions(+), 1 deletion(-) + +diff --git a/drivers/thermal/qcom/tsens-8960.c b/drivers/thermal/qcom/tsens-8960.c +index 2a28a5af209e..3f4fc1ffe679 100644 +--- a/drivers/thermal/qcom/tsens-8960.c ++++ b/drivers/thermal/qcom/tsens-8960.c +@@ -51,11 +51,22 @@ + #define MIN_LIMIT_TH 0x0 + #define MAX_LIMIT_TH 0xff + +-#define S0_STATUS_ADDR 0x3628 + #define INT_STATUS_ADDR 0x363c + #define TRDY_MASK BIT(7) + #define TIMEOUT_US 100 + ++#define S0_STATUS_OFF 0x3628 ++#define S1_STATUS_OFF 0x362c ++#define S2_STATUS_OFF 0x3630 ++#define S3_STATUS_OFF 0x3634 ++#define S4_STATUS_OFF 0x3638 ++#define S5_STATUS_OFF 0x3664 /* Sensors 5-10 found on apq8064/msm8960 */ ++#define S6_STATUS_OFF 0x3668 ++#define S7_STATUS_OFF 0x366c ++#define S8_STATUS_OFF 0x3670 ++#define S9_STATUS_OFF 0x3674 ++#define S10_STATUS_OFF 0x3678 ++ + static int suspend_8960(struct tsens_priv *priv) + { + int ret; +@@ -269,6 +280,71 @@ static int get_temp_8960(const struct tsens_sensor *s, int *temp) + return -ETIMEDOUT; + } + ++static struct tsens_features tsens_8960_feat = { ++ .ver_major = VER_0, ++ .crit_int = 0, ++ .adc = 1, ++ .srot_split = 0, ++ .max_sensors = 11, ++}; ++ ++static const struct reg_field tsens_8960_regfields[MAX_REGFIELDS] = { ++ /* ----- SROT ------ */ ++ /* No VERSION information */ ++ ++ /* CNTL */ ++ [TSENS_EN] = REG_FIELD(CNTL_ADDR, 0, 0), ++ [TSENS_SW_RST] = REG_FIELD(CNTL_ADDR, 1, 1), ++ /* 8960 has 5 sensors, 8660 has 11, we only handle 5 */ ++ [SENSOR_EN] = REG_FIELD(CNTL_ADDR, 3, 7), ++ ++ /* ----- TM ------ */ ++ /* INTERRUPT ENABLE */ ++ /* NO INTERRUPT ENABLE */ ++ ++ /* Single UPPER/LOWER TEMPERATURE THRESHOLD for all sensors */ ++ [LOW_THRESH_0] = REG_FIELD(THRESHOLD_ADDR, 0, 7), ++ [UP_THRESH_0] = REG_FIELD(THRESHOLD_ADDR, 8, 15), ++ /* MIN_THRESH_0 and MAX_THRESH_0 are not present in the regfield ++ * Recycle CRIT_THRESH_0 and 1 to set the required regs to hardcoded temp ++ * MIN_THRESH_0 -> CRIT_THRESH_1 ++ * MAX_THRESH_0 -> CRIT_THRESH_0 ++ */ ++ [CRIT_THRESH_1] = REG_FIELD(THRESHOLD_ADDR, 16, 23), ++ [CRIT_THRESH_0] = REG_FIELD(THRESHOLD_ADDR, 24, 31), ++ ++ /* UPPER/LOWER INTERRUPT [CLEAR/STATUS] */ ++ /* 1 == clear, 0 == normal operation */ ++ [LOW_INT_CLEAR_0] = REG_FIELD(CNTL_ADDR, 9, 9), ++ [UP_INT_CLEAR_0] = REG_FIELD(CNTL_ADDR, 10, 10), ++ ++ /* NO CRITICAL INTERRUPT SUPPORT on 8960 */ ++ ++ /* Sn_STATUS */ ++ [LAST_TEMP_0] = REG_FIELD(S0_STATUS_OFF, 0, 7), ++ [LAST_TEMP_1] = REG_FIELD(S1_STATUS_OFF, 0, 7), ++ [LAST_TEMP_2] = REG_FIELD(S2_STATUS_OFF, 0, 7), ++ [LAST_TEMP_3] = REG_FIELD(S3_STATUS_OFF, 0, 7), ++ [LAST_TEMP_4] = REG_FIELD(S4_STATUS_OFF, 0, 7), ++ [LAST_TEMP_5] = REG_FIELD(S5_STATUS_OFF, 0, 7), ++ [LAST_TEMP_6] = REG_FIELD(S6_STATUS_OFF, 0, 7), ++ [LAST_TEMP_7] = REG_FIELD(S7_STATUS_OFF, 0, 7), ++ [LAST_TEMP_8] = REG_FIELD(S8_STATUS_OFF, 0, 7), ++ [LAST_TEMP_9] = REG_FIELD(S9_STATUS_OFF, 0, 7), ++ [LAST_TEMP_10] = REG_FIELD(S10_STATUS_OFF, 0, 7), ++ ++ /* No VALID field on 8960 */ ++ /* TSENS_INT_STATUS bits: 1 == threshold violated */ ++ [MIN_STATUS_0] = REG_FIELD(INT_STATUS_ADDR, 0, 0), ++ [LOWER_STATUS_0] = REG_FIELD(INT_STATUS_ADDR, 1, 1), ++ [UPPER_STATUS_0] = REG_FIELD(INT_STATUS_ADDR, 2, 2), ++ /* No CRITICAL field on 8960 */ ++ [MAX_STATUS_0] = REG_FIELD(INT_STATUS_ADDR, 3, 3), ++ ++ /* TRDY: 1=ready, 0=in progress */ ++ [TRDY] = REG_FIELD(INT_STATUS_ADDR, 7, 7), ++}; ++ + static const struct tsens_ops ops_8960 = { + .init = init_8960, + .calibrate = calibrate_8960, +@@ -282,4 +358,6 @@ static const struct tsens_ops ops_8960 = { + struct tsens_plat_data data_8960 = { + .num_sensors = 11, + .ops = &ops_8960, ++ .feat = &tsens_8960_feat, ++ .fields = tsens_8960_regfields, + }; +-- +2.30.2 + diff --git a/target/linux/ipq806x/patches-5.10/104-4-drivers-thermal-tsens-Use-init_common-for-msm8960.patch b/target/linux/ipq806x/patches-5.10/104-4-drivers-thermal-tsens-Use-init_common-for-msm8960.patch new file mode 100644 index 0000000000..4b12609e96 --- /dev/null +++ b/target/linux/ipq806x/patches-5.10/104-4-drivers-thermal-tsens-Use-init_common-for-msm8960.patch @@ -0,0 +1,86 @@ +From c04f98a496929f75d75c65115d5717423c3d0634 Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Wed, 25 Nov 2020 17:16:36 +0100 +Subject: [PATCH 04/10] drivers: thermal: tsens: Use init_common for msm8960 + +Use init_common and drop custom init for msm8960. + +Signed-off-by: Ansuel Smith +Reviewed-by: Thara Gopinath +--- + drivers/thermal/qcom/tsens-8960.c | 52 +------------------------------ + 1 file changed, 1 insertion(+), 51 deletions(-) + +diff --git a/drivers/thermal/qcom/tsens-8960.c b/drivers/thermal/qcom/tsens-8960.c +index 3f4fc1ffe679..86585f439985 100644 +--- a/drivers/thermal/qcom/tsens-8960.c ++++ b/drivers/thermal/qcom/tsens-8960.c +@@ -173,56 +173,6 @@ static void disable_8960(struct tsens_priv *priv) + regmap_write(priv->tm_map, CNTL_ADDR, reg_cntl); + } + +-static int init_8960(struct tsens_priv *priv) +-{ +- int ret, i; +- u32 reg_cntl; +- +- priv->tm_map = dev_get_regmap(priv->dev, NULL); +- if (!priv->tm_map) +- return -ENODEV; +- +- /* +- * The status registers for each sensor are discontiguous +- * because some SoCs have 5 sensors while others have more +- * but the control registers stay in the same place, i.e +- * directly after the first 5 status registers. +- */ +- for (i = 0; i < priv->num_sensors; i++) { +- if (i >= 5) +- priv->sensor[i].status = S0_STATUS_ADDR + 40; +- priv->sensor[i].status += i * 4; +- } +- +- reg_cntl = SW_RST; +- ret = regmap_update_bits(priv->tm_map, CNTL_ADDR, SW_RST, reg_cntl); +- if (ret) +- return ret; +- +- if (priv->num_sensors > 1) { +- reg_cntl |= SLP_CLK_ENA | (MEASURE_PERIOD << 18); +- reg_cntl &= ~SW_RST; +- ret = regmap_update_bits(priv->tm_map, CONFIG_ADDR, +- CONFIG_MASK, CONFIG); +- } else { +- reg_cntl |= SLP_CLK_ENA_8660 | (MEASURE_PERIOD << 16); +- reg_cntl &= ~CONFIG_MASK_8660; +- reg_cntl |= CONFIG_8660 << CONFIG_SHIFT_8660; +- } +- +- reg_cntl |= GENMASK(priv->num_sensors - 1, 0) << SENSOR0_SHIFT; +- ret = regmap_write(priv->tm_map, CNTL_ADDR, reg_cntl); +- if (ret) +- return ret; +- +- reg_cntl |= EN; +- ret = regmap_write(priv->tm_map, CNTL_ADDR, reg_cntl); +- if (ret) +- return ret; +- +- return 0; +-} +- + static int calibrate_8960(struct tsens_priv *priv) + { + int i; +@@ -346,7 +296,7 @@ static const struct reg_field tsens_8960_regfields[MAX_REGFIELDS] = { + }; + + static const struct tsens_ops ops_8960 = { +- .init = init_8960, ++ .init = init_common, + .calibrate = calibrate_8960, + .get_temp = get_temp_8960, + .enable = enable_8960, +-- +2.30.2 + diff --git a/target/linux/ipq806x/patches-5.10/104-5-drivers-thermal-tsens-Fix-bug-in-sensor-enable-for-m.patch b/target/linux/ipq806x/patches-5.10/104-5-drivers-thermal-tsens-Fix-bug-in-sensor-enable-for-m.patch new file mode 100644 index 0000000000..4f8a6769a0 --- /dev/null +++ b/target/linux/ipq806x/patches-5.10/104-5-drivers-thermal-tsens-Fix-bug-in-sensor-enable-for-m.patch @@ -0,0 +1,71 @@ +From b3e8bd33b84a6b6c863bd1733bd15b5f1483b8ab Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Wed, 25 Nov 2020 17:06:55 +0100 +Subject: [PATCH 05/10] drivers: thermal: tsens: Fix bug in sensor enable for + msm8960 + +Device based on tsens VER_0 contains a hardware bug that results in some +problem with sensor enablement. Sensor id 6-11 can't be enabled +selectively and all of them must be enabled in one step. + +Signed-off-by: Ansuel Smith +Acked-by: Thara Gopinath +--- + drivers/thermal/qcom/tsens-8960.c | 23 ++++++++++++++++++++--- + 1 file changed, 20 insertions(+), 3 deletions(-) + +diff --git a/drivers/thermal/qcom/tsens-8960.c b/drivers/thermal/qcom/tsens-8960.c +index 86585f439985..95fcccafae14 100644 +--- a/drivers/thermal/qcom/tsens-8960.c ++++ b/drivers/thermal/qcom/tsens-8960.c +@@ -27,9 +27,9 @@ + #define EN BIT(0) + #define SW_RST BIT(1) + #define SENSOR0_EN BIT(3) ++#define MEASURE_PERIOD BIT(18) + #define SLP_CLK_ENA BIT(26) + #define SLP_CLK_ENA_8660 BIT(24) +-#define MEASURE_PERIOD 1 + #define SENSOR0_SHIFT 3 + + /* INT_STATUS_ADDR bitmasks */ +@@ -126,17 +126,34 @@ static int resume_8960(struct tsens_priv *priv) + static int enable_8960(struct tsens_priv *priv, int id) + { + int ret; +- u32 reg, mask; ++ u32 reg, mask = BIT(id); + + ret = regmap_read(priv->tm_map, CNTL_ADDR, ®); + if (ret) + return ret; + +- mask = BIT(id + SENSOR0_SHIFT); ++ /* HARDWARE BUG: ++ * On platforms with more than 6 sensors, all remaining sensors ++ * must be enabled together, otherwise undefined results are expected. ++ * (Sensor 6-7 disabled, Sensor 3 disabled...) In the original driver, ++ * all the sensors are enabled in one step hence this bug is not ++ * triggered. ++ */ ++ if (id > 5) ++ mask = GENMASK(10, 6); ++ ++ mask <<= SENSOR0_SHIFT; ++ ++ /* Sensors already enabled. Skip. */ ++ if ((reg & mask) == mask) ++ return 0; ++ + ret = regmap_write(priv->tm_map, CNTL_ADDR, reg | SW_RST); + if (ret) + return ret; + ++ reg |= MEASURE_PERIOD; ++ + if (priv->num_sensors > 1) + reg |= mask | SLP_CLK_ENA | EN; + else +-- +2.30.2 + diff --git a/target/linux/ipq806x/patches-5.10/104-6-drivers-thermal-tsens-Replace-custom-8960-apis-with-.patch b/target/linux/ipq806x/patches-5.10/104-6-drivers-thermal-tsens-Replace-custom-8960-apis-with-.patch new file mode 100644 index 0000000000..657f8b801b --- /dev/null +++ b/target/linux/ipq806x/patches-5.10/104-6-drivers-thermal-tsens-Replace-custom-8960-apis-with-.patch @@ -0,0 +1,114 @@ +From 1ff9f982051759e0387e8c7e793b49c48eae291d Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Wed, 25 Nov 2020 17:11:05 +0100 +Subject: [PATCH 06/10] drivers: thermal: tsens: Replace custom 8960 apis with + generic apis + +Rework calibrate function to use common function. Derive the offset from +a missing hardcoded slope table and the data from the nvmem calib +efuses. +Drop custom get_temp function and use generic api. + +Signed-off-by: Ansuel Smith +Acked-by: Thara Gopinath +--- + drivers/thermal/qcom/tsens-8960.c | 56 +++++++++---------------------- + 1 file changed, 15 insertions(+), 41 deletions(-) + +diff --git a/drivers/thermal/qcom/tsens-8960.c b/drivers/thermal/qcom/tsens-8960.c +index 95fcccafae14..9cc8a7dd23ae 100644 +--- a/drivers/thermal/qcom/tsens-8960.c ++++ b/drivers/thermal/qcom/tsens-8960.c +@@ -67,6 +67,13 @@ + #define S9_STATUS_OFF 0x3674 + #define S10_STATUS_OFF 0x3678 + ++/* Original slope - 200 to compensate mC to C inaccuracy */ ++static u32 tsens_msm8960_slope[] = { ++ 976, 976, 954, 976, ++ 911, 932, 932, 999, ++ 932, 999, 932 ++ }; ++ + static int suspend_8960(struct tsens_priv *priv) + { + int ret; +@@ -194,9 +201,7 @@ static int calibrate_8960(struct tsens_priv *priv) + { + int i; + char *data; +- +- ssize_t num_read = priv->num_sensors; +- struct tsens_sensor *s = priv->sensor; ++ u32 p1[11]; + + data = qfprom_read(priv->dev, "calib"); + if (IS_ERR(data)) +@@ -204,49 +209,18 @@ static int calibrate_8960(struct tsens_priv *priv) + if (IS_ERR(data)) + return PTR_ERR(data); + +- for (i = 0; i < num_read; i++, s++) +- s->offset = data[i]; ++ for (i = 0; i < priv->num_sensors; i++) { ++ p1[i] = data[i]; ++ priv->sensor[i].slope = tsens_msm8960_slope[i]; ++ } ++ ++ compute_intercept_slope(priv, p1, NULL, ONE_PT_CALIB); + + kfree(data); + + return 0; + } + +-/* Temperature on y axis and ADC-code on x-axis */ +-static inline int code_to_mdegC(u32 adc_code, const struct tsens_sensor *s) +-{ +- int slope, offset; +- +- slope = thermal_zone_get_slope(s->tzd); +- offset = CAL_MDEGC - slope * s->offset; +- +- return adc_code * slope + offset; +-} +- +-static int get_temp_8960(const struct tsens_sensor *s, int *temp) +-{ +- int ret; +- u32 code, trdy; +- struct tsens_priv *priv = s->priv; +- unsigned long timeout; +- +- timeout = jiffies + usecs_to_jiffies(TIMEOUT_US); +- do { +- ret = regmap_read(priv->tm_map, INT_STATUS_ADDR, &trdy); +- if (ret) +- return ret; +- if (!(trdy & TRDY_MASK)) +- continue; +- ret = regmap_read(priv->tm_map, s->status, &code); +- if (ret) +- return ret; +- *temp = code_to_mdegC(code, s); +- return 0; +- } while (time_before(jiffies, timeout)); +- +- return -ETIMEDOUT; +-} +- + static struct tsens_features tsens_8960_feat = { + .ver_major = VER_0, + .crit_int = 0, +@@ -315,7 +289,7 @@ static const struct reg_field tsens_8960_regfields[MAX_REGFIELDS] = { + static const struct tsens_ops ops_8960 = { + .init = init_common, + .calibrate = calibrate_8960, +- .get_temp = get_temp_8960, ++ .get_temp = get_temp_common, + .enable = enable_8960, + .disable = disable_8960, + .suspend = suspend_8960, +-- +2.30.2 + diff --git a/target/linux/ipq806x/patches-5.10/104-7-drivers-thermal-tsens-Drop-unused-define-for-msm8960.patch b/target/linux/ipq806x/patches-5.10/104-7-drivers-thermal-tsens-Drop-unused-define-for-msm8960.patch new file mode 100644 index 0000000000..d0e383d035 --- /dev/null +++ b/target/linux/ipq806x/patches-5.10/104-7-drivers-thermal-tsens-Drop-unused-define-for-msm8960.patch @@ -0,0 +1,70 @@ +From 5716a61239c6ac9ceb137e825e93c3aea06c4634 Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Fri, 19 Mar 2021 00:48:23 +0100 +Subject: [PATCH 07/10] drivers: thermal: tsens: Drop unused define for msm8960 + +Drop unused define for msm8960 replaced by generic api and reg_field. + +Signed-off-by: Ansuel Smith +Reviewed-by: Thara Gopinath +--- + drivers/thermal/qcom/tsens-8960.c | 24 +----------------------- + 1 file changed, 1 insertion(+), 23 deletions(-) + +diff --git a/drivers/thermal/qcom/tsens-8960.c b/drivers/thermal/qcom/tsens-8960.c +index 9cc8a7dd23ae..58d09e927383 100644 +--- a/drivers/thermal/qcom/tsens-8960.c ++++ b/drivers/thermal/qcom/tsens-8960.c +@@ -10,8 +10,6 @@ + #include + #include "tsens.h" + +-#define CAL_MDEGC 30000 +- + #define CONFIG_ADDR 0x3640 + #define CONFIG_ADDR_8660 0x3620 + /* CONFIG_ADDR bitmasks */ +@@ -21,39 +19,19 @@ + #define CONFIG_SHIFT_8660 28 + #define CONFIG_MASK_8660 (3 << CONFIG_SHIFT_8660) + +-#define STATUS_CNTL_ADDR_8064 0x3660 + #define CNTL_ADDR 0x3620 + /* CNTL_ADDR bitmasks */ + #define EN BIT(0) + #define SW_RST BIT(1) +-#define SENSOR0_EN BIT(3) ++ + #define MEASURE_PERIOD BIT(18) + #define SLP_CLK_ENA BIT(26) + #define SLP_CLK_ENA_8660 BIT(24) + #define SENSOR0_SHIFT 3 + +-/* INT_STATUS_ADDR bitmasks */ +-#define MIN_STATUS_MASK BIT(0) +-#define LOWER_STATUS_CLR BIT(1) +-#define UPPER_STATUS_CLR BIT(2) +-#define MAX_STATUS_MASK BIT(3) +- + #define THRESHOLD_ADDR 0x3624 +-/* THRESHOLD_ADDR bitmasks */ +-#define THRESHOLD_MAX_LIMIT_SHIFT 24 +-#define THRESHOLD_MIN_LIMIT_SHIFT 16 +-#define THRESHOLD_UPPER_LIMIT_SHIFT 8 +-#define THRESHOLD_LOWER_LIMIT_SHIFT 0 +- +-/* Initial temperature threshold values */ +-#define LOWER_LIMIT_TH 0x50 +-#define UPPER_LIMIT_TH 0xdf +-#define MIN_LIMIT_TH 0x0 +-#define MAX_LIMIT_TH 0xff + + #define INT_STATUS_ADDR 0x363c +-#define TRDY_MASK BIT(7) +-#define TIMEOUT_US 100 + + #define S0_STATUS_OFF 0x3628 + #define S1_STATUS_OFF 0x362c +-- +2.30.2 + diff --git a/target/linux/ipq806x/patches-5.10/104-8-drivers-thermal-tsens-Add-support-for-ipq8064-tsens.patch b/target/linux/ipq806x/patches-5.10/104-8-drivers-thermal-tsens-Add-support-for-ipq8064-tsens.patch new file mode 100644 index 0000000000..928e8fd695 --- /dev/null +++ b/target/linux/ipq806x/patches-5.10/104-8-drivers-thermal-tsens-Add-support-for-ipq8064-tsens.patch @@ -0,0 +1,31 @@ +From 0d0c22a59bf2672b57e23da9a9ea743e91b71f54 Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Sat, 25 Jul 2020 19:55:57 +0200 +Subject: [PATCH 08/10] drivers: thermal: tsens: Add support for ipq8064-tsens + +Add support for tsens present in ipq806x SoCs based on generic msm8960 +tsens driver. + +Signed-off-by: Ansuel Smith +Reviewed-by: Thara Gopinath +--- + drivers/thermal/qcom/tsens.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/thermal/qcom/tsens.c b/drivers/thermal/qcom/tsens.c +index 38b9936def1a..58073dc5d30b 100644 +--- a/drivers/thermal/qcom/tsens.c ++++ b/drivers/thermal/qcom/tsens.c +@@ -966,6 +966,9 @@ static SIMPLE_DEV_PM_OPS(tsens_pm_ops, tsens_suspend, tsens_resume); + + static const struct of_device_id tsens_table[] = { + { ++ .compatible = "qcom,ipq8064-tsens", ++ .data = &data_8960, ++ }, { + .compatible = "qcom,msm8916-tsens", + .data = &data_8916, + }, { +-- +2.30.2 + diff --git a/target/linux/ipq806x/patches-5.10/104-9-dt-bindings-thermal-tsens-Document-ipq8064-bindings.patch b/target/linux/ipq806x/patches-5.10/104-9-dt-bindings-thermal-tsens-Document-ipq8064-bindings.patch new file mode 100644 index 0000000000..121f857182 --- /dev/null +++ b/target/linux/ipq806x/patches-5.10/104-9-dt-bindings-thermal-tsens-Document-ipq8064-bindings.patch @@ -0,0 +1,115 @@ +From ac369071920d427dd484cf74cddba2774bba45f5 Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Thu, 9 Jul 2020 22:35:54 +0200 +Subject: [PATCH 09/10] dt-bindings: thermal: tsens: Document ipq8064 bindings + +Document the use of bindings used for msm8960 tsens based devices. +msm8960 use the same gcc regs and is set as a child of the qcom gcc. + +Signed-off-by: Ansuel Smith +Reviewed-by: Rob Herring +--- + .../bindings/thermal/qcom-tsens.yaml | 56 ++++++++++++++++--- + 1 file changed, 48 insertions(+), 8 deletions(-) + +diff --git a/Documentation/devicetree/bindings/thermal/qcom-tsens.yaml b/Documentation/devicetree/bindings/thermal/qcom-tsens.yaml +index 95462e071ab4..1785b1c75a3c 100644 +--- a/Documentation/devicetree/bindings/thermal/qcom-tsens.yaml ++++ b/Documentation/devicetree/bindings/thermal/qcom-tsens.yaml +@@ -19,6 +19,11 @@ description: | + properties: + compatible: + oneOf: ++ - description: msm9860 TSENS based ++ items: ++ - enum: ++ - qcom,ipq8064-tsens ++ + - description: v0.1 of TSENS + items: + - enum: +@@ -73,7 +78,9 @@ properties: + maxItems: 2 + items: + - const: calib +- - const: calib_sel ++ - enum: ++ - calib_backup ++ - calib_sel + + "#qcom,sensors": + description: +@@ -88,12 +95,20 @@ properties: + Number of cells required to uniquely identify the thermal sensors. Since + we have multiple sensors this is set to 1 + ++required: ++ - compatible ++ - interrupts ++ - interrupt-names ++ - "#thermal-sensor-cells" ++ - "#qcom,sensors" ++ + allOf: + - if: + properties: + compatible: + contains: + enum: ++ - qcom,ipq8064-tsens + - qcom,msm8916-tsens + - qcom,msm8974-tsens + - qcom,msm8976-tsens +@@ -114,17 +129,42 @@ allOf: + interrupt-names: + minItems: 2 + +-required: +- - compatible +- - reg +- - "#qcom,sensors" +- - interrupts +- - interrupt-names +- - "#thermal-sensor-cells" ++ - if: ++ properties: ++ compatible: ++ contains: ++ enum: ++ - qcom,tsens-v0_1 ++ - qcom,tsens-v1 ++ - qcom,tsens-v2 ++ ++ then: ++ required: ++ - reg + + additionalProperties: false + + examples: ++ - | ++ #include ++ // Example msm9860 based SoC (ipq8064): ++ gcc: clock-controller { ++ ++ /* ... */ ++ ++ tsens: thermal-sensor { ++ compatible = "qcom,ipq8064-tsens"; ++ ++ nvmem-cells = <&tsens_calib>, <&tsens_calib_backup>; ++ nvmem-cell-names = "calib", "calib_backup"; ++ interrupts = ; ++ interrupt-names = "uplow"; ++ ++ #qcom,sensors = <11>; ++ #thermal-sensor-cells = <1>; ++ }; ++ }; ++ + - | + #include + // Example 1 (legacy: for pre v1 IP): +-- +2.30.2 + diff --git a/target/linux/ipq806x/patches-5.10/105-10-drivers-thermal-tsens-Fix-wrong-slope-on-msm-8960.patch b/target/linux/ipq806x/patches-5.10/105-10-drivers-thermal-tsens-Fix-wrong-slope-on-msm-8960.patch new file mode 100644 index 0000000000..2212d41caf --- /dev/null +++ b/target/linux/ipq806x/patches-5.10/105-10-drivers-thermal-tsens-Fix-wrong-slope-on-msm-8960.patch @@ -0,0 +1,37 @@ +From 68e720ed73c8f038c8c500e4c49c1e65a993a448 Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Tue, 6 Apr 2021 04:45:31 +0200 +Subject: [PATCH 10/10] drivers: thermal: tsens: Fix wrong slope on msm-8960 + +Some user using some stats with the old legacy implementation and the +new implementation using the compute_intercept_slope reported an offset +of 3C. Fix the slope table to reflect the original temp. + +Signed-off-by: Ansuel Smith +--- + drivers/thermal/qcom/tsens-8960.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/thermal/qcom/tsens-8960.c b/drivers/thermal/qcom/tsens-8960.c +index 58d09e927383..5cc5b3527f1f 100644 +--- a/drivers/thermal/qcom/tsens-8960.c ++++ b/drivers/thermal/qcom/tsens-8960.c +@@ -45,11 +45,11 @@ + #define S9_STATUS_OFF 0x3674 + #define S10_STATUS_OFF 0x3678 + +-/* Original slope - 200 to compensate mC to C inaccuracy */ ++/* Original slope - 350 to compensate mC to C inaccuracy */ + static u32 tsens_msm8960_slope[] = { +- 976, 976, 954, 976, +- 911, 932, 932, 999, +- 932, 999, 932 ++ 826, 826, 804, 826, ++ 761, 782, 782, 849, ++ 782, 849, 782 + }; + + static int suspend_8960(struct tsens_priv *priv) +-- +2.30.2 + From cde218d14b118e76099b0b0af992b3d3126c8035 Mon Sep 17 00:00:00 2001 From: Ansuel Smith Date: Mon, 1 Mar 2021 01:03:55 +0100 Subject: [PATCH 15/62] ipq806x: fix missing clk and reset Patch 0030 wrongly disables gsbi1 instead of gsbi4. Fix the wrong patch and also include other fix from the original qsdk source. Signed-off-by: Ansuel Smith --- ...0030-clk-Disable-i2c-device-on-gsbi4.patch | 40 -- ...7-1-ipq806x-gcc-add-missing-clk-flag.patch | 120 ++++++ .../097-2-ipq806x-lcc-add-missing-reset.patch | 66 +++ ...com-krait-add-missing-enable-disable.patch | 62 +++ ...missing-clk-and-reset-for-crypto-eng.patch | 381 ++++++++++++++++++ 5 files changed, 629 insertions(+), 40 deletions(-) delete mode 100644 target/linux/ipq806x/patches-5.10/0030-clk-Disable-i2c-device-on-gsbi4.patch create mode 100644 target/linux/ipq806x/patches-5.10/097-1-ipq806x-gcc-add-missing-clk-flag.patch create mode 100644 target/linux/ipq806x/patches-5.10/097-2-ipq806x-lcc-add-missing-reset.patch create mode 100644 target/linux/ipq806x/patches-5.10/097-3-clk-qcom-krait-add-missing-enable-disable.patch create mode 100644 target/linux/ipq806x/patches-5.10/097-4-ipq806x-gcc-add-missing-clk-and-reset-for-crypto-eng.patch diff --git a/target/linux/ipq806x/patches-5.10/0030-clk-Disable-i2c-device-on-gsbi4.patch b/target/linux/ipq806x/patches-5.10/0030-clk-Disable-i2c-device-on-gsbi4.patch deleted file mode 100644 index a5fb714e6c..0000000000 --- a/target/linux/ipq806x/patches-5.10/0030-clk-Disable-i2c-device-on-gsbi4.patch +++ /dev/null @@ -1,40 +0,0 @@ -From 0c974b87829e007dc4fae94e20d488204e20e662 Mon Sep 17 00:00:00 2001 -From: John Crispin -Date: Thu, 9 Mar 2017 08:16:10 +0100 -Subject: [PATCH 30/69] clk: Disable i2c device on gsbi4 - -This patch was not annotated and comes from the v4.4 tree. - -Signed-off-by: John Crispin ---- - drivers/clk/qcom/gcc-ipq806x.c | 5 +++-- - 1 file changed, 3 insertions(+), 2 deletions(-) - ---- a/drivers/clk/qcom/gcc-ipq806x.c -+++ b/drivers/clk/qcom/gcc-ipq806x.c -@@ -365,7 +365,7 @@ static struct clk_rcg gsbi1_uart_src = { - .parent_names = gcc_pxo_pll8, - .num_parents = 2, - .ops = &clk_rcg_ops, -- .flags = CLK_SET_PARENT_GATE, -+ .flags = CLK_SET_PARENT_GATE | CLK_IGNORE_UNUSED, - }, - }, - }; -@@ -383,7 +383,7 @@ static struct clk_branch gsbi1_uart_clk - }, - .num_parents = 1, - .ops = &clk_branch_ops, -- .flags = CLK_SET_RATE_PARENT, -+ .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, - }, - }, - }; -@@ -961,6 +961,7 @@ static struct clk_branch gsbi1_h_clk = { - .hw.init = &(struct clk_init_data){ - .name = "gsbi1_h_clk", - .ops = &clk_branch_ops, -+ .flags = CLK_IGNORE_UNUSED, - }, - }, - }; diff --git a/target/linux/ipq806x/patches-5.10/097-1-ipq806x-gcc-add-missing-clk-flag.patch b/target/linux/ipq806x/patches-5.10/097-1-ipq806x-gcc-add-missing-clk-flag.patch new file mode 100644 index 0000000000..a09453e142 --- /dev/null +++ b/target/linux/ipq806x/patches-5.10/097-1-ipq806x-gcc-add-missing-clk-flag.patch @@ -0,0 +1,120 @@ +From 0af44917941cbfecdc86bb9bf05ff01d22a88973 Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Sun, 7 Feb 2021 16:52:56 +0100 +Subject: [PATCH 1/4] ipq806x: gcc: add missing clk flag + +Some flag are missing from the original code. +These clk can't be set using the protected-clock proprities as they +cause the malfunction of the serial interface. +These clks are needed for the rpm interface to work proprely or the +cpu regulators starts to fail as soon as they are disabled by the +kernel. + +Signed-off-by: Ansuel Smith +--- + drivers/clk/qcom/gcc-ipq806x.c | 19 +++++++++++++------ + 1 file changed, 13 insertions(+), 6 deletions(-) + +diff --git a/drivers/clk/qcom/gcc-ipq806x.c b/drivers/clk/qcom/gcc-ipq806x.c +index d6b7adb4be38..fbb8644c4a43 100644 +--- a/drivers/clk/qcom/gcc-ipq806x.c ++++ b/drivers/clk/qcom/gcc-ipq806x.c +@@ -65,6 +65,7 @@ static struct clk_pll pll3 = { + .parent_names = (const char *[]){ "pxo" }, + .num_parents = 1, + .ops = &clk_pll_ops, ++ .flags = CLK_IS_CRITICAL, + }, + }; + +@@ -782,7 +783,7 @@ static struct clk_rcg gsbi4_qup_src = { + .parent_names = gcc_pxo_pll8, + .num_parents = 2, + .ops = &clk_rcg_ops, +- .flags = CLK_SET_PARENT_GATE, ++ .flags = CLK_SET_PARENT_GATE | CLK_IGNORE_UNUSED, + }, + }, + }; +@@ -798,7 +799,7 @@ static struct clk_branch gsbi4_qup_clk = { + .parent_names = (const char *[]){ "gsbi4_qup_src" }, + .num_parents = 1, + .ops = &clk_branch_ops, +- .flags = CLK_SET_RATE_PARENT, ++ .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, + }, + }; +@@ -880,7 +881,7 @@ static struct clk_rcg gsbi6_qup_src = { + .parent_names = gcc_pxo_pll8, + .num_parents = 2, + .ops = &clk_rcg_ops, +- .flags = CLK_SET_PARENT_GATE, ++ .flags = CLK_SET_PARENT_GATE | CLK_IGNORE_UNUSED, + }, + }, + }; +@@ -945,7 +946,7 @@ static struct clk_branch gsbi7_qup_clk = { + .parent_names = (const char *[]){ "gsbi7_qup_src" }, + .num_parents = 1, + .ops = &clk_branch_ops, +- .flags = CLK_SET_RATE_PARENT, ++ .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, + }, + }; +@@ -991,6 +992,7 @@ static struct clk_branch gsbi4_h_clk = { + .hw.init = &(struct clk_init_data){ + .name = "gsbi4_h_clk", + .ops = &clk_branch_ops, ++ .flags = CLK_IGNORE_UNUSED, + }, + }, + }; +@@ -1293,6 +1295,7 @@ static struct clk_rcg sdc1_src = { + .parent_names = gcc_pxo_pll8, + .num_parents = 2, + .ops = &clk_rcg_ops, ++ .flags = CLK_SET_RATE_GATE, + }, + } + }; +@@ -1341,6 +1344,7 @@ static struct clk_rcg sdc3_src = { + .parent_names = gcc_pxo_pll8, + .num_parents = 2, + .ops = &clk_rcg_ops, ++ .flags = CLK_SET_RATE_GATE, + }, + } + }; +@@ -1424,6 +1428,7 @@ static struct clk_rcg tsif_ref_src = { + .parent_names = gcc_pxo_pll8, + .num_parents = 2, + .ops = &clk_rcg_ops, ++ .flags = CLK_SET_RATE_GATE, + }, + } + }; +@@ -2694,7 +2699,8 @@ static struct clk_dyn_rcg ubi32_core1_src_clk = { + .parent_names = gcc_pxo_pll8_pll14_pll18_pll0, + .num_parents = 5, + .ops = &clk_dyn_rcg_ops, +- .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE, ++ .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE | ++ CLK_IGNORE_UNUSED, + }, + }, + }; +@@ -2747,7 +2753,8 @@ static struct clk_dyn_rcg ubi32_core2_src_clk = { + .parent_names = gcc_pxo_pll8_pll14_pll18_pll0, + .num_parents = 5, + .ops = &clk_dyn_rcg_ops, +- .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE, ++ .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE | ++ CLK_IGNORE_UNUSED, + }, + }, + }; +-- +2.29.2 + diff --git a/target/linux/ipq806x/patches-5.10/097-2-ipq806x-lcc-add-missing-reset.patch b/target/linux/ipq806x/patches-5.10/097-2-ipq806x-lcc-add-missing-reset.patch new file mode 100644 index 0000000000..877f751537 --- /dev/null +++ b/target/linux/ipq806x/patches-5.10/097-2-ipq806x-lcc-add-missing-reset.patch @@ -0,0 +1,66 @@ +From 3a5f1793c0bf4a6b536751886b0a44589fe05f35 Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Sun, 7 Feb 2021 17:00:07 +0100 +Subject: [PATCH 2/4] ipq806x: lcc: add missing reset + +Add missing reset for ipq806x lcc clk + +Signed-off-by: Ansuel Smith +--- + drivers/clk/qcom/lcc-ipq806x.c | 8 ++++++++ + include/dt-bindings/clock/qcom,lcc-ipq806x.h | 1 + + 2 files changed, 9 insertions(+) + +diff --git a/drivers/clk/qcom/lcc-ipq806x.c b/drivers/clk/qcom/lcc-ipq806x.c +index 1a2be4aeb31d..ee48642bb872 100644 +--- a/drivers/clk/qcom/lcc-ipq806x.c ++++ b/drivers/clk/qcom/lcc-ipq806x.c +@@ -12,6 +12,7 @@ + #include + #include + #include ++#include + + #include + +@@ -22,6 +23,7 @@ + #include "clk-branch.h" + #include "clk-regmap-divider.h" + #include "clk-regmap-mux.h" ++#include "reset.h" + + static struct clk_pll pll4 = { + .l_reg = 0x4, +@@ -39,6 +41,10 @@ static struct clk_pll pll4 = { + }, + }; + ++static const struct qcom_reset_map lcc_ipq806x_resets[] = { ++ [LCC_PCM_RESET] = { 0x54, 13 }, ++}; ++ + static const struct pll_config pll4_config = { + .l = 0xf, + .m = 0x91, +@@ -417,6 +423,8 @@ static const struct qcom_cc_desc lcc_ipq806x_desc = { + .config = &lcc_ipq806x_regmap_config, + .clks = lcc_ipq806x_clks, + .num_clks = ARRAY_SIZE(lcc_ipq806x_clks), ++ .resets = lcc_ipq806x_resets, ++ .num_resets = ARRAY_SIZE(lcc_ipq806x_resets), + }; + + static const struct of_device_id lcc_ipq806x_match_table[] = { +diff --git a/include/dt-bindings/clock/qcom,lcc-ipq806x.h b/include/dt-bindings/clock/qcom,lcc-ipq806x.h +index 25b92bbf0ab4..73318b1ce29e 100644 +--- a/include/dt-bindings/clock/qcom,lcc-ipq806x.h ++++ b/include/dt-bindings/clock/qcom,lcc-ipq806x.h +@@ -19,4 +19,5 @@ + #define SPDIF_CLK 10 + #define AHBIX_CLK 11 + ++#define LCC_PCM_RESET 0 + #endif +-- +2.29.2 + diff --git a/target/linux/ipq806x/patches-5.10/097-3-clk-qcom-krait-add-missing-enable-disable.patch b/target/linux/ipq806x/patches-5.10/097-3-clk-qcom-krait-add-missing-enable-disable.patch new file mode 100644 index 0000000000..777c54c83a --- /dev/null +++ b/target/linux/ipq806x/patches-5.10/097-3-clk-qcom-krait-add-missing-enable-disable.patch @@ -0,0 +1,62 @@ +From f8fdbecdaca97f0f2eebd77256e2eca4a8da6c39 Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Sun, 7 Feb 2021 17:08:16 +0100 +Subject: [PATCH 3/4] clk: qcom: krait: add missing enable disable + +Add missing enable disable mux function. Add extra check to +div2_round_rate. + +Signed-off-by: Ansuel Smith +--- + drivers/clk/qcom/clk-krait.c | 27 +++++++++++++++++++++++++-- + 1 file changed, 25 insertions(+), 2 deletions(-) + +diff --git a/drivers/clk/qcom/clk-krait.c b/drivers/clk/qcom/clk-krait.c +index 59f1af415b58..ba796b621669 100644 +--- a/drivers/clk/qcom/clk-krait.c ++++ b/drivers/clk/qcom/clk-krait.c +@@ -68,7 +68,25 @@ static u8 krait_mux_get_parent(struct clk_hw *hw) + return clk_mux_val_to_index(hw, mux->parent_map, 0, sel); + } + ++static int krait_mux_enable(struct clk_hw *hw) ++{ ++ struct krait_mux_clk *mux = to_krait_mux_clk(hw); ++ ++ __krait_mux_set_sel(mux, mux->en_mask); ++ ++ return 0; ++} ++ ++static void krait_mux_disable(struct clk_hw *hw) ++{ ++ struct krait_mux_clk *mux = to_krait_mux_clk(hw); ++ ++ __krait_mux_set_sel(mux, mux->safe_sel); ++} ++ + const struct clk_ops krait_mux_clk_ops = { ++ .enable = krait_mux_enable, ++ .disable = krait_mux_disable, + .set_parent = krait_mux_set_parent, + .get_parent = krait_mux_get_parent, + .determine_rate = __clk_mux_determine_rate_closest, +@@ -79,8 +97,13 @@ EXPORT_SYMBOL_GPL(krait_mux_clk_ops); + static long krait_div2_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate) + { +- *parent_rate = clk_hw_round_rate(clk_hw_get_parent(hw), rate * 2); +- return DIV_ROUND_UP(*parent_rate, 2); ++ struct clk_hw *hw_parent = clk_hw_get_parent(hw); ++ ++ if (hw_parent) { ++ *parent_rate = clk_hw_round_rate(hw_parent, rate * 2); ++ return DIV_ROUND_UP(*parent_rate, 2); ++ } else ++ return -1; + } + + static int krait_div2_set_rate(struct clk_hw *hw, unsigned long rate, +-- +2.29.2 + diff --git a/target/linux/ipq806x/patches-5.10/097-4-ipq806x-gcc-add-missing-clk-and-reset-for-crypto-eng.patch b/target/linux/ipq806x/patches-5.10/097-4-ipq806x-gcc-add-missing-clk-and-reset-for-crypto-eng.patch new file mode 100644 index 0000000000..1231f88e9b --- /dev/null +++ b/target/linux/ipq806x/patches-5.10/097-4-ipq806x-gcc-add-missing-clk-and-reset-for-crypto-eng.patch @@ -0,0 +1,381 @@ +From 22a0f55b0e505fbbbb680e451a62878bc97f7ff1 Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Sun, 7 Feb 2021 17:23:38 +0100 +Subject: [PATCH 4/4] ipq806x: gcc: add missing clk and reset for crypto engine + +Add missing clk and reset needed for nss additional core and crypto +engine. + +Signed-off-by: Ansuel Smith +--- + drivers/clk/qcom/gcc-ipq806x.c | 250 +++++++++++++++++++ + include/dt-bindings/clock/qcom,gcc-ipq806x.h | 5 +- + include/dt-bindings/reset/qcom,gcc-ipq806x.h | 5 + + 3 files changed, 259 insertions(+), 1 deletion(-) + +diff --git a/drivers/clk/qcom/gcc-ipq806x.c b/drivers/clk/qcom/gcc-ipq806x.c +index fbb8644c4a43..c36bcdf013d0 100644 +--- a/drivers/clk/qcom/gcc-ipq806x.c ++++ b/drivers/clk/qcom/gcc-ipq806x.c +@@ -223,7 +223,9 @@ static struct clk_regmap pll14_vote = { + + static struct pll_freq_tbl pll18_freq_tbl[] = { + NSS_PLL_RATE(550000000, 44, 0, 1, 0x01495625), ++ NSS_PLL_RATE(600000000, 48, 0, 1, 0x01495625), + NSS_PLL_RATE(733000000, 58, 16, 25, 0x014b5625), ++ NSS_PLL_RATE(800000000, 64, 0, 1, 0x01495625), + }; + + static struct clk_pll pll18 = { +@@ -245,6 +247,22 @@ static struct clk_pll pll18 = { + }, + }; + ++static struct clk_pll pll11 = { ++ .l_reg = 0x3184, ++ .m_reg = 0x3188, ++ .n_reg = 0x318c, ++ .config_reg = 0x3194, ++ .mode_reg = 0x3180, ++ .status_reg = 0x3198, ++ .status_bit = 16, ++ .clkr.hw.init = &(struct clk_init_data){ ++ .name = "pll11", ++ .parent_names = (const char *[]){ "pxo" }, ++ .num_parents = 1, ++ .ops = &clk_pll_ops, ++ }, ++}; ++ + enum { + P_PXO, + P_PLL8, +@@ -253,6 +271,7 @@ enum { + P_CXO, + P_PLL14, + P_PLL18, ++ P_PLL11, + }; + + static const struct parent_map gcc_pxo_pll8_map[] = { +@@ -320,6 +339,42 @@ static const char * const gcc_pxo_pll8_pll14_pll18_pll0[] = { + "pll18", + }; + ++static const struct parent_map gcc_pxo_pll8_pll0_pll14_pll18_pll11_map[] = { ++ { P_PXO, 0 }, ++ { P_PLL8, 4 }, ++ { P_PLL0, 2 }, ++ { P_PLL14, 5 }, ++ { P_PLL18, 1 }, ++ { P_PLL11, 3 }, ++}; ++ ++static const char *gcc_pxo_pll8_pll0_pll14_pll18_pll11[] = { ++ "pxo", ++ "pll8_vote", ++ "pll0_vote", ++ "pll14", ++ "pll18", ++ "pll11" ++}; ++ ++static const struct parent_map gcc_pxo_pll3_pll0_pll14_pll18_pll11_map[] = { ++ { P_PXO, 0 }, ++ { P_PLL3, 6 }, ++ { P_PLL0, 2 }, ++ { P_PLL14, 5 }, ++ { P_PLL18, 1 }, ++ { P_PLL11, 3 }, ++}; ++ ++static const char *gcc_pxo_pll3_pll0_pll14_pll18_pll11[] = { ++ "pxo", ++ "pll3", ++ "pll0_vote", ++ "pll14", ++ "pll18", ++ "pll11" ++}; ++ + static struct freq_tbl clk_tbl_gsbi_uart[] = { + { 1843200, P_PLL8, 2, 6, 625 }, + { 3686400, P_PLL8, 2, 12, 625 }, +@@ -1261,6 +1316,7 @@ static const struct freq_tbl clk_tbl_sdc[] = { + { 20210000, P_PLL8, 1, 1, 19 }, + { 24000000, P_PLL8, 4, 1, 4 }, + { 48000000, P_PLL8, 4, 1, 2 }, ++ { 52000000, P_PLL8, 1, 2, 15 }, /* 51.2 Mhz */ + { 64000000, P_PLL8, 3, 1, 2 }, + { 96000000, P_PLL8, 4, 0, 0 }, + { 192000000, P_PLL8, 2, 0, 0 }, +@@ -2647,7 +2703,9 @@ static const struct freq_tbl clk_tbl_nss[] = { + { 110000000, P_PLL18, 1, 1, 5 }, + { 275000000, P_PLL18, 2, 0, 0 }, + { 550000000, P_PLL18, 1, 0, 0 }, ++ { 600000000, P_PLL18, 1, 0, 0 }, + { 733000000, P_PLL18, 1, 0, 0 }, ++ { 800000000, P_PLL18, 1, 0, 0 }, + { } + }; + +@@ -2759,6 +2817,186 @@ static struct clk_dyn_rcg ubi32_core2_src_clk = { + }, + }; + ++static const struct freq_tbl clk_tbl_ce5_core[] = { ++ { 150000000, P_PLL3, 8, 1, 1 }, ++ { 213200000, P_PLL11, 5, 1, 1 }, ++ { } ++}; ++ ++static struct clk_dyn_rcg ce5_core_src = { ++ .ns_reg[0] = 0x36C4, ++ .ns_reg[1] = 0x36C8, ++ .bank_reg = 0x36C0, ++ .s[0] = { ++ .src_sel_shift = 0, ++ .parent_map = gcc_pxo_pll3_pll0_pll14_pll18_pll11_map, ++ }, ++ .s[1] = { ++ .src_sel_shift = 0, ++ .parent_map = gcc_pxo_pll3_pll0_pll14_pll18_pll11_map, ++ }, ++ .p[0] = { ++ .pre_div_shift = 3, ++ .pre_div_width = 4, ++ }, ++ .p[1] = { ++ .pre_div_shift = 3, ++ .pre_div_width = 4, ++ }, ++ .mux_sel_bit = 0, ++ .freq_tbl = clk_tbl_ce5_core, ++ .clkr = { ++ .enable_reg = 0x36C0, ++ .enable_mask = BIT(1), ++ .hw.init = &(struct clk_init_data){ ++ .name = "ce5_core_src", ++ .parent_names = gcc_pxo_pll3_pll0_pll14_pll18_pll11, ++ .num_parents = 6, ++ .ops = &clk_dyn_rcg_ops, ++ }, ++ }, ++}; ++ ++static struct clk_branch ce5_core_clk = { ++ .halt_reg = 0x2FDC, ++ .halt_bit = 5, ++ .hwcg_reg = 0x36CC, ++ .hwcg_bit = 6, ++ .clkr = { ++ .enable_reg = 0x36CC, ++ .enable_mask = BIT(4), ++ .hw.init = &(struct clk_init_data){ ++ .name = "ce5_core_clk", ++ .parent_names = (const char *[]){ ++ "ce5_core_src", ++ }, ++ .num_parents = 1, ++ .ops = &clk_branch_ops, ++ .flags = CLK_SET_RATE_PARENT, ++ }, ++ }, ++}; ++ ++static const struct freq_tbl clk_tbl_ce5_a_clk[] = { ++ { 160000000, P_PLL0, 5, 1, 1 }, ++ { 213200000, P_PLL11, 5, 1, 1 }, ++ { } ++}; ++ ++static struct clk_dyn_rcg ce5_a_clk_src = { ++ .ns_reg[0] = 0x3d84, ++ .ns_reg[1] = 0x3d88, ++ .bank_reg = 0x3d80, ++ .s[0] = { ++ .src_sel_shift = 0, ++ .parent_map = gcc_pxo_pll8_pll0_pll14_pll18_pll11_map, ++ }, ++ .s[1] = { ++ .src_sel_shift = 0, ++ .parent_map = gcc_pxo_pll8_pll0_pll14_pll18_pll11_map, ++ }, ++ .p[0] = { ++ .pre_div_shift = 3, ++ .pre_div_width = 4, ++ }, ++ .p[1] = { ++ .pre_div_shift = 3, ++ .pre_div_width = 4, ++ }, ++ .mux_sel_bit = 0, ++ .freq_tbl = clk_tbl_ce5_a_clk, ++ .clkr = { ++ .enable_reg = 0x3d80, ++ .enable_mask = BIT(1), ++ .hw.init = &(struct clk_init_data){ ++ .name = "ce5_a_clk_src", ++ .parent_names = gcc_pxo_pll8_pll0_pll14_pll18_pll11, ++ .num_parents = 6, ++ .ops = &clk_dyn_rcg_ops, ++ }, ++ }, ++}; ++ ++static struct clk_branch ce5_a_clk = { ++ .halt_reg = 0x3c20, ++ .halt_bit = 12, ++ .hwcg_reg = 0x3d8c, ++ .hwcg_bit = 6, ++ .clkr = { ++ .enable_reg = 0x3d8c, ++ .enable_mask = BIT(4), ++ .hw.init = &(struct clk_init_data){ ++ .name = "ce5_a_clk", ++ .parent_names = (const char *[]){ ++ "ce5_a_clk_src", ++ }, ++ .num_parents = 1, ++ .ops = &clk_branch_ops, ++ .flags = CLK_SET_RATE_PARENT, ++ }, ++ }, ++}; ++ ++static const struct freq_tbl clk_tbl_ce5_h_clk[] = { ++ { 160000000, P_PLL0, 5, 1, 1 }, ++ { 213200000, P_PLL11, 5, 1, 1 }, ++ { } ++}; ++ ++static struct clk_dyn_rcg ce5_h_clk_src = { ++ .ns_reg[0] = 0x3c64, ++ .ns_reg[1] = 0x3c68, ++ .bank_reg = 0x3c60, ++ .s[0] = { ++ .src_sel_shift = 0, ++ .parent_map = gcc_pxo_pll8_pll0_pll14_pll18_pll11_map, ++ }, ++ .s[1] = { ++ .src_sel_shift = 0, ++ .parent_map = gcc_pxo_pll8_pll0_pll14_pll18_pll11_map, ++ }, ++ .p[0] = { ++ .pre_div_shift = 3, ++ .pre_div_width = 4, ++ }, ++ .p[1] = { ++ .pre_div_shift = 3, ++ .pre_div_width = 4, ++ }, ++ .mux_sel_bit = 0, ++ .freq_tbl = clk_tbl_ce5_h_clk, ++ .clkr = { ++ .enable_reg = 0x3c60, ++ .enable_mask = BIT(1), ++ .hw.init = &(struct clk_init_data){ ++ .name = "ce5_h_clk_src", ++ .parent_names = gcc_pxo_pll8_pll0_pll14_pll18_pll11, ++ .num_parents = 6, ++ .ops = &clk_dyn_rcg_ops, ++ }, ++ }, ++}; ++ ++static struct clk_branch ce5_h_clk = { ++ .halt_reg = 0x3c20, ++ .halt_bit = 11, ++ .hwcg_reg = 0x3c6c, ++ .hwcg_bit = 6, ++ .clkr = { ++ .enable_reg = 0x3c6c, ++ .enable_mask = BIT(4), ++ .hw.init = &(struct clk_init_data){ ++ .name = "ce5_h_clk", ++ .parent_names = (const char *[]){ ++ "ce5_h_clk_src", ++ }, ++ .num_parents = 1, ++ .ops = &clk_branch_ops, ++ .flags = CLK_SET_RATE_PARENT, ++ }, ++ }, ++}; ++ + static struct clk_regmap *gcc_ipq806x_clks[] = { + [PLL0] = &pll0.clkr, + [PLL0_VOTE] = &pll0_vote, +@@ -2766,6 +3004,7 @@ static struct clk_regmap *gcc_ipq806x_clks[] = { + [PLL4_VOTE] = &pll4_vote, + [PLL8] = &pll8.clkr, + [PLL8_VOTE] = &pll8_vote, ++ [PLL11] = &pll11.clkr, + [PLL14] = &pll14.clkr, + [PLL14_VOTE] = &pll14_vote, + [PLL18] = &pll18.clkr, +@@ -2880,6 +3119,12 @@ static struct clk_regmap *gcc_ipq806x_clks[] = { + [PLL9] = &hfpll0.clkr, + [PLL10] = &hfpll1.clkr, + [PLL12] = &hfpll_l2.clkr, ++ [CE5_A_CLK_SRC] = &ce5_a_clk_src.clkr, ++ [CE5_A_CLK] = &ce5_a_clk.clkr, ++ [CE5_H_CLK_SRC] = &ce5_h_clk_src.clkr, ++ [CE5_H_CLK] = &ce5_h_clk.clkr, ++ [CE5_CORE_CLK_SRC] = &ce5_core_src.clkr, ++ [CE5_CORE_CLK] = &ce5_core_clk.clkr, + }; + + static const struct qcom_reset_map gcc_ipq806x_resets[] = { +@@ -3011,6 +3256,11 @@ static const struct qcom_reset_map gcc_ipq806x_resets[] = { + [GMAC_CORE3_RESET] = { 0x3cfc, 0 }, + [GMAC_CORE4_RESET] = { 0x3d1c, 0 }, + [GMAC_AHB_RESET] = { 0x3e24, 0 }, ++ [CRYPTO_ENG1_RESET] = { 0x3e00, 0}, ++ [CRYPTO_ENG2_RESET] = { 0x3e04, 0}, ++ [CRYPTO_ENG3_RESET] = { 0x3e08, 0}, ++ [CRYPTO_ENG4_RESET] = { 0x3e0c, 0}, ++ [CRYPTO_AHB_RESET] = { 0x3e10, 0}, + [NSS_CH0_RST_RX_CLK_N_RESET] = { 0x3b60, 0 }, + [NSS_CH0_RST_TX_CLK_N_RESET] = { 0x3b60, 1 }, + [NSS_CH0_RST_RX_125M_N_RESET] = { 0x3b60, 2 }, +diff --git a/include/dt-bindings/clock/qcom,gcc-ipq806x.h b/include/dt-bindings/clock/qcom,gcc-ipq806x.h +index 7deec14a6dee..02262d2ac899 100644 +--- a/include/dt-bindings/clock/qcom,gcc-ipq806x.h ++++ b/include/dt-bindings/clock/qcom,gcc-ipq806x.h +@@ -240,7 +240,7 @@ + #define PLL14 232 + #define PLL14_VOTE 233 + #define PLL18 234 +-#define CE5_SRC 235 ++#define CE5_A_CLK 235 + #define CE5_H_CLK 236 + #define CE5_CORE_CLK 237 + #define CE3_SLEEP_CLK 238 +@@ -283,5 +283,8 @@ + #define EBI2_AON_CLK 281 + #define NSSTCM_CLK_SRC 282 + #define NSSTCM_CLK 283 ++#define CE5_A_CLK_SRC 285 ++#define CE5_H_CLK_SRC 286 ++#define CE5_CORE_CLK_SRC 287 + + #endif +diff --git a/include/dt-bindings/reset/qcom,gcc-ipq806x.h b/include/dt-bindings/reset/qcom,gcc-ipq806x.h +index 26b6f9200620..020c9cf18751 100644 +--- a/include/dt-bindings/reset/qcom,gcc-ipq806x.h ++++ b/include/dt-bindings/reset/qcom,gcc-ipq806x.h +@@ -163,5 +163,10 @@ + #define NSS_CAL_PRBS_RST_N_RESET 154 + #define NSS_LCKDT_RST_N_RESET 155 + #define NSS_SRDS_N_RESET 156 ++#define CRYPTO_ENG1_RESET 157 ++#define CRYPTO_ENG2_RESET 158 ++#define CRYPTO_ENG3_RESET 159 ++#define CRYPTO_ENG4_RESET 160 ++#define CRYPTO_AHB_RESET 161 + + #endif +-- +2.29.2 + From c864f587a25effa1cb18c63ec7eee6a966618b59 Mon Sep 17 00:00:00 2001 From: Ansuel Smith Date: Mon, 1 Mar 2021 01:06:22 +0100 Subject: [PATCH 16/62] ipq806x: backport mtd adm and smem driver - Backport mtd adm driver from kernel 5.12 - Backport mtd parser smem from kernel 5.11 - Fix mtd rootfs patch - Update qcom,smem compatible to qcom,smem-parts Signed-off-by: Ansuel Smith --- target/linux/ipq806x/config-5.4 | 2 +- .../arch/arm/boot/dts/qcom-ipq8064-ap148.dts | 4 +- .../arch/arm/boot/dts/qcom-ipq8064-ap161.dts | 4 +- .../arch/arm/boot/dts/qcom-ipq8064-g10.dts | 2 +- .../arm/boot/dts/qcom-ipq8065-nbg6817.dts | 2 +- .../arm/boot/dts/qcom-ipq8068-ecw5410.dts | 2 +- ...d-add-SMEM-parser-for-QCOM-platforms.patch | 282 ---------------- ...conflicts-with-OpenWrt-auto-mounting.patch | 23 -- ...v5.11-dmaengine-qcom-add_ADM_driver.patch} | 301 +++++++++--------- ....12-mtd-parsers-Add-Qcom-SMEM-parser.patch | 227 +++++++++++++ ...conflicts-with-OpenWrt-auto-mounting.patch | 24 ++ ...d-add-SMEM-parser-for-QCOM-platforms.patch | 282 ---------------- ...conflicts-with-OpenWrt-auto-mounting.patch | 23 -- ...v5.11-dmaengine-qcom-add_ADM_driver.patch} | 301 +++++++++--------- ....12-mtd-parsers-Add-Qcom-SMEM-parser.patch | 227 +++++++++++++ ...conflicts-with-OpenWrt-auto-mounting.patch | 24 ++ 16 files changed, 820 insertions(+), 910 deletions(-) delete mode 100644 target/linux/ipq806x/patches-5.10/0031-mtd-add-SMEM-parser-for-QCOM-platforms.patch delete mode 100644 target/linux/ipq806x/patches-5.10/0061-mtd-rootfs-conflicts-with-OpenWrt-auto-mounting.patch rename target/linux/ipq806x/patches-5.10/{0002-dmaengine-Add-ADM-driver.patch => 100-v5.11-dmaengine-qcom-add_ADM_driver.patch} (80%) create mode 100644 target/linux/ipq806x/patches-5.10/101-5.12-mtd-parsers-Add-Qcom-SMEM-parser.patch create mode 100644 target/linux/ipq806x/patches-5.10/102-mtd-rootfs-conflicts-with-OpenWrt-auto-mounting.patch delete mode 100644 target/linux/ipq806x/patches-5.4/0031-mtd-add-SMEM-parser-for-QCOM-platforms.patch delete mode 100644 target/linux/ipq806x/patches-5.4/0061-mtd-rootfs-conflicts-with-OpenWrt-auto-mounting.patch rename target/linux/ipq806x/patches-5.4/{0002-dmaengine-Add-ADM-driver.patch => 100-v5.11-dmaengine-qcom-add_ADM_driver.patch} (80%) create mode 100644 target/linux/ipq806x/patches-5.4/101-5.12-mtd-parsers-Add-Qcom-SMEM-parser.patch create mode 100644 target/linux/ipq806x/patches-5.4/102-mtd-rootfs-conflicts-with-OpenWrt-auto-mounting.patch diff --git a/target/linux/ipq806x/config-5.4 b/target/linux/ipq806x/config-5.4 index 78a9ad7077..c582b7a52b 100644 --- a/target/linux/ipq806x/config-5.4 +++ b/target/linux/ipq806x/config-5.4 @@ -313,7 +313,7 @@ CONFIG_MTD_CMDLINE_PARTS=y CONFIG_MTD_NAND_CORE=y CONFIG_MTD_NAND_ECC_SW_HAMMING=y CONFIG_MTD_NAND_QCOM=y -CONFIG_MTD_QCOM_SMEM_PARTS=y +CONFIG_MTD_QCOMSMEM_PARTS=y CONFIG_MTD_RAW_NAND=y CONFIG_MTD_SPI_NOR=y CONFIG_MTD_SPLIT_FIRMWARE=y diff --git a/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-ap148.dts b/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-ap148.dts index b2fdc427e2..29476e3877 100644 --- a/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-ap148.dts +++ b/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-ap148.dts @@ -30,7 +30,7 @@ &flash { partitions { - compatible = "qcom,smem"; + compatible = "qcom,smem-part"; }; }; @@ -66,7 +66,7 @@ nand-ecc-step-size = <512>; partitions { - compatible = "qcom,smem"; + compatible = "qcom,smem-part"; }; }; }; diff --git a/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-ap161.dts b/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-ap161.dts index 6ba3d70808..914c370552 100644 --- a/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-ap161.dts +++ b/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-ap161.dts @@ -38,7 +38,7 @@ &flash { partitions { - compatible = "qcom,smem"; + compatible = "qcom,smem-part"; }; }; @@ -78,7 +78,7 @@ nand-ecc-step-size = <512>; partitions { - compatible = "qcom,smem"; + compatible = "qcom,smem-part"; }; }; }; diff --git a/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-g10.dts b/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-g10.dts index 15ed5b4773..ccefc23011 100644 --- a/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-g10.dts +++ b/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-g10.dts @@ -179,7 +179,7 @@ nand-ecc-step-size = <512>; partitions { - compatible = "qcom,smem"; + compatible = "qcom,smem-part"; }; }; }; diff --git a/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8065-nbg6817.dts b/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8065-nbg6817.dts index 119598d074..34b9c5fc87 100644 --- a/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8065-nbg6817.dts +++ b/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8065-nbg6817.dts @@ -182,7 +182,7 @@ reg = <0>; partitions { - compatible = "qcom,smem"; + compatible = "qcom,smem-part"; }; }; }; diff --git a/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8068-ecw5410.dts b/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8068-ecw5410.dts index 712910c261..9b14bb2c29 100644 --- a/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8068-ecw5410.dts +++ b/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8068-ecw5410.dts @@ -184,7 +184,7 @@ reg = <0>; partitions { - compatible = "qcom,smem"; + compatible = "qcom,smem-part"; }; }; }; diff --git a/target/linux/ipq806x/patches-5.10/0031-mtd-add-SMEM-parser-for-QCOM-platforms.patch b/target/linux/ipq806x/patches-5.10/0031-mtd-add-SMEM-parser-for-QCOM-platforms.patch deleted file mode 100644 index 6aa404c8c5..0000000000 --- a/target/linux/ipq806x/patches-5.10/0031-mtd-add-SMEM-parser-for-QCOM-platforms.patch +++ /dev/null @@ -1,282 +0,0 @@ -From d8eeb4de90e968ba32d956728c866f20752cf2c3 Mon Sep 17 00:00:00 2001 -From: Mathieu Olivari -Date: Thu, 9 Mar 2017 08:18:08 +0100 -Subject: [PATCH 31/69] mtd: add SMEM parser for QCOM platforms - -On QCOM platforms using MTD devices storage (such as IPQ806x), SMEM is -used to store partition layout. This new parser can now be used to read -SMEM and use it to register an MTD layout according to its content. - -Signed-off-by: Mathieu Olivari -Signed-off-by: Ram Chandra Jangir ---- - drivers/mtd/parsers/Kconfig | 7 ++ - drivers/mtd/parsers/Makefile | 1 + - drivers/mtd/parsers/qcom_smem_part.c | 228 +++++++++++++++++++++++++++++++++++++++++++ - 3 files changed, 236 insertions(+) - create mode 100644 drivers/mtd/parsers/qcom_smem_part.c - ---- a/drivers/mtd/parsers/Kconfig -+++ b/drivers/mtd/parsers/Kconfig -@@ -119,6 +119,13 @@ config MTD_PARSER_TRX - This driver will parse TRX header and report at least two partitions: - kernel and rootfs. - -+config MTD_QCOM_SMEM_PARTS -+ tristate "QCOM SMEM partitioning support" -+ depends on QCOM_SMEM -+ help -+ This provides partitions parser for QCOM devices using SMEM -+ such as IPQ806x. -+ - config MTD_SHARPSL_PARTS - tristate "Sharp SL Series NAND flash partition parser" - depends on MTD_NAND_SHARPSL || MTD_NAND_TMIO || COMPILE_TEST ---- a/drivers/mtd/parsers/Makefile -+++ b/drivers/mtd/parsers/Makefile -@@ -8,6 +8,7 @@ obj-$(CONFIG_MTD_OF_PARTS) += ofpart.o - obj-$(CONFIG_MTD_PARSER_IMAGETAG) += parser_imagetag.o - obj-$(CONFIG_MTD_AFS_PARTS) += afs.o - obj-$(CONFIG_MTD_PARSER_TRX) += parser_trx.o -+obj-$(CONFIG_MTD_QCOM_SMEM_PARTS) += qcom_smem_part.o - obj-$(CONFIG_MTD_SHARPSL_PARTS) += sharpslpart.o - obj-$(CONFIG_MTD_REDBOOT_PARTS) += redboot.o - obj-$(CONFIG_MTD_ROUTERBOOT_PARTS) += routerbootpart.o ---- /dev/null -+++ b/drivers/mtd/parsers/qcom_smem_part.c -@@ -0,0 +1,235 @@ -+/* -+ * Copyright (c) 2015, The Linux Foundation. All rights reserved. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 and -+ * only version 2 as published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ */ -+ -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+ -+#include -+ -+/* Processor/host identifier for the application processor */ -+#define SMEM_HOST_APPS 0 -+ -+/* SMEM items index */ -+#define SMEM_AARM_PARTITION_TABLE 9 -+#define SMEM_BOOT_FLASH_TYPE 421 -+#define SMEM_BOOT_FLASH_BLOCK_SIZE 424 -+ -+/* SMEM Flash types */ -+#define SMEM_FLASH_NAND 2 -+#define SMEM_FLASH_SPI 6 -+ -+#define SMEM_PART_NAME_SZ 16 -+#define SMEM_PARTS_MAX 32 -+ -+struct smem_partition { -+ char name[SMEM_PART_NAME_SZ]; -+ __le32 start; -+ __le32 size; -+ __le32 attr; -+}; -+ -+struct smem_partition_table { -+ u8 magic[8]; -+ __le32 version; -+ __le32 len; -+ struct smem_partition parts[SMEM_PARTS_MAX]; -+}; -+ -+/* SMEM Magic values in partition table */ -+static const u8 SMEM_PTABLE_MAGIC[] = { -+ 0xaa, 0x73, 0xee, 0x55, -+ 0xdb, 0xbd, 0x5e, 0xe3, -+}; -+ -+static int qcom_smem_get_flash_blksz(u64 **smem_blksz) -+{ -+ size_t size; -+ -+ *smem_blksz = qcom_smem_get(SMEM_HOST_APPS, SMEM_BOOT_FLASH_BLOCK_SIZE, -+ &size); -+ -+ if (IS_ERR(*smem_blksz)) { -+ pr_err("Unable to read flash blksz from SMEM\n"); -+ return -ENOENT; -+ } -+ -+ if (size != sizeof(**smem_blksz)) { -+ pr_err("Invalid flash blksz size in SMEM\n"); -+ return -EINVAL; -+ } -+ -+ return 0; -+} -+ -+static int qcom_smem_get_flash_type(u64 **smem_flash_type) -+{ -+ size_t size; -+ -+ *smem_flash_type = qcom_smem_get(SMEM_HOST_APPS, SMEM_BOOT_FLASH_TYPE, -+ &size); -+ -+ if (IS_ERR(*smem_flash_type)) { -+ pr_err("Unable to read flash type from SMEM\n"); -+ return -ENOENT; -+ } -+ -+ if (size != sizeof(**smem_flash_type)) { -+ pr_err("Invalid flash type size in SMEM\n"); -+ return -EINVAL; -+ } -+ -+ return 0; -+} -+ -+static int qcom_smem_get_flash_partitions(struct smem_partition_table **pparts) -+{ -+ size_t size; -+ -+ *pparts = qcom_smem_get(SMEM_HOST_APPS, SMEM_AARM_PARTITION_TABLE, -+ &size); -+ -+ if (IS_ERR(*pparts)) { -+ pr_err("Unable to read partition table from SMEM\n"); -+ return -ENOENT; -+ } -+ -+ return 0; -+} -+ -+static int of_dev_node_match(struct device *dev, const void *data) -+{ -+ return dev->of_node == data; -+} -+ -+static bool is_spi_device(struct device_node *np) -+{ -+ struct device *dev; -+ -+ dev = bus_find_device(&spi_bus_type, NULL, np, of_dev_node_match); -+ if (!dev) -+ return false; -+ -+ put_device(dev); -+ return true; -+} -+ -+static int parse_qcom_smem_partitions(struct mtd_info *master, -+ const struct mtd_partition **pparts, -+ struct mtd_part_parser_data *data) -+{ -+ struct smem_partition_table *smem_parts; -+ u64 *smem_flash_type, *smem_blksz; -+ struct mtd_partition *mtd_parts; -+ struct device_node *of_node = master->dev.of_node; -+ int i, ret; -+ -+ /* -+ * SMEM will only store the partition table of the boot device. -+ * If this is not the boot device, do not return any partition. -+ */ -+ ret = qcom_smem_get_flash_type(&smem_flash_type); -+ if (ret < 0) -+ return ret; -+ -+ if ((*smem_flash_type == SMEM_FLASH_NAND && !mtd_type_is_nand(master)) -+ || (*smem_flash_type == SMEM_FLASH_SPI && !is_spi_device(of_node))) -+ return 0; -+ -+ /* -+ * Just for sanity purpose, make sure the block size in SMEM matches the -+ * block size of the MTD device -+ */ -+ ret = qcom_smem_get_flash_blksz(&smem_blksz); -+ if (ret < 0) -+ return ret; -+ -+ if (*smem_blksz != master->erasesize) { -+ pr_err("SMEM block size differs from MTD block size\n"); -+ return -EINVAL; -+ } -+ -+ /* Get partition pointer from SMEM */ -+ ret = qcom_smem_get_flash_partitions(&smem_parts); -+ if (ret < 0) -+ return ret; -+ -+ if (memcmp(SMEM_PTABLE_MAGIC, smem_parts->magic, -+ sizeof(SMEM_PTABLE_MAGIC))) { -+ pr_err("SMEM partition magic invalid\n"); -+ return -EINVAL; -+ } -+ -+ /* Allocate and populate the mtd structures */ -+ mtd_parts = kcalloc(le32_to_cpu(smem_parts->len), sizeof(*mtd_parts), -+ GFP_KERNEL); -+ if (!mtd_parts) -+ return -ENOMEM; -+ -+ for (i = 0; i < smem_parts->len; i++) { -+ struct smem_partition *s_part = &smem_parts->parts[i]; -+ struct mtd_partition *m_part = &mtd_parts[i]; -+ -+ m_part->name = s_part->name; -+ m_part->size = le32_to_cpu(s_part->size) * (*smem_blksz); -+ m_part->offset = le32_to_cpu(s_part->start) * (*smem_blksz); -+ -+ /* -+ * The last SMEM partition may have its size marked as -+ * something like 0xffffffff, which means "until the end of the -+ * flash device". In this case, truncate it. -+ */ -+ if (m_part->offset + m_part->size > master->size) -+ m_part->size = master->size - m_part->offset; -+ } -+ -+ *pparts = mtd_parts; -+ -+ return smem_parts->len; -+} -+ -+static const struct of_device_id qcom_smem_of_match_table[] = { -+ { .compatible = "qcom,smem" }, -+ {}, -+}; -+MODULE_DEVICE_TABLE(of, qcom_smem_of_match_table); -+ -+static struct mtd_part_parser qcom_smem_parser = { -+ .owner = THIS_MODULE, -+ .parse_fn = parse_qcom_smem_partitions, -+ .name = "qcom-smem", -+ .of_match_table = qcom_smem_of_match_table, -+}; -+ -+static int __init qcom_smem_parser_init(void) -+{ -+ register_mtd_parser(&qcom_smem_parser); -+ return 0; -+} -+ -+static void __exit qcom_smem_parser_exit(void) -+{ -+ deregister_mtd_parser(&qcom_smem_parser); -+} -+ -+module_init(qcom_smem_parser_init); -+module_exit(qcom_smem_parser_exit); -+ -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("Mathieu Olivari "); -+MODULE_DESCRIPTION("Parsing code for SMEM based partition tables"); diff --git a/target/linux/ipq806x/patches-5.10/0061-mtd-rootfs-conflicts-with-OpenWrt-auto-mounting.patch b/target/linux/ipq806x/patches-5.10/0061-mtd-rootfs-conflicts-with-OpenWrt-auto-mounting.patch deleted file mode 100644 index ff6f6edf49..0000000000 --- a/target/linux/ipq806x/patches-5.10/0061-mtd-rootfs-conflicts-with-OpenWrt-auto-mounting.patch +++ /dev/null @@ -1,23 +0,0 @@ -From 5001f2e1a325b68dbf225bd17f69a4d3d975cca5 Mon Sep 17 00:00:00 2001 -From: John Crispin -Date: Thu, 9 Mar 2017 09:31:44 +0100 -Subject: [PATCH 61/69] mtd: "rootfs" conflicts with OpenWrt auto mounting - -Signed-off-by: John Crispin ---- - drivers/mtd/parsers/qcom_smem_part.c | 4 ++++ - 1 file changed, 4 insertions(+) - ---- a/drivers/mtd/parsers/qcom_smem_part.c -+++ b/drivers/mtd/parsers/qcom_smem_part.c -@@ -189,6 +189,10 @@ static int parse_qcom_smem_partitions(st - m_part->size = le32_to_cpu(s_part->size) * (*smem_blksz); - m_part->offset = le32_to_cpu(s_part->start) * (*smem_blksz); - -+ /* "rootfs" conflicts with OpenWrt auto mounting */ -+ if (mtd_type_is_nand(master) && !strcmp(m_part->name, "rootfs")) -+ m_part->name = "ubi"; -+ - /* - * The last SMEM partition may have its size marked as - * something like 0xffffffff, which means "until the end of the diff --git a/target/linux/ipq806x/patches-5.10/0002-dmaengine-Add-ADM-driver.patch b/target/linux/ipq806x/patches-5.10/100-v5.11-dmaengine-qcom-add_ADM_driver.patch similarity index 80% rename from target/linux/ipq806x/patches-5.10/0002-dmaengine-Add-ADM-driver.patch rename to target/linux/ipq806x/patches-5.10/100-v5.11-dmaengine-qcom-add_ADM_driver.patch index aa7d2e791e..45062d52fc 100644 --- a/target/linux/ipq806x/patches-5.10/0002-dmaengine-Add-ADM-driver.patch +++ b/target/linux/ipq806x/patches-5.10/100-v5.11-dmaengine-qcom-add_ADM_driver.patch @@ -1,86 +1,95 @@ -From 563fa24db4e529c5a3311928d73a8a90531ee527 Mon Sep 17 00:00:00 2001 -From: Thomas Pedersen -Date: Mon, 16 May 2016 17:58:51 -0700 -Subject: [PATCH 02/69] dmaengine: Add ADM driver - -Original patch by Andy Gross. +From 5c9f8c2dbdbe53818bcde6aa6695e1331e5f841f Mon Sep 17 00:00:00 2001 +From: Jonathan McDowell +Date: Sat, 14 Nov 2020 14:02:33 +0000 +Subject: dmaengine: qcom: Add ADM driver Add the DMA engine driver for the QCOM Application Data Mover (ADM) DMA controller found in the MSM8x60 and IPQ/APQ8064 platforms. The ADM supports both memory to memory transactions and memory -to/from peripheral device transactions. The controller also provides flow -control capabilities for transactions to/from peripheral devices. +to/from peripheral device transactions. The controller also provides +flow control capabilities for transactions to/from peripheral devices. -The initial release of this driver supports slave transfers to/from peripherals -and also incorporates CRCI (client rate control interface) flow control. +The initial release of this driver supports slave transfers to/from +peripherals and also incorporates CRCI (client rate control interface) +flow control. + +The hardware only supports a 32 bit physical address, so specifying +!PHYS_ADDR_T_64BIT gives maximum COMPILE_TEST coverage without having to +spend effort on kludging things in the code that will never actually be +needed on real hardware. Signed-off-by: Andy Gross Signed-off-by: Thomas Pedersen +Signed-off-by: Jonathan McDowell +Link: https://lore.kernel.org/r/20201114140233.GM32650@earth.li +Signed-off-by: Vinod Koul --- - drivers/dma/qcom/Kconfig | 10 + + drivers/dma/qcom/Kconfig | 11 + drivers/dma/qcom/Makefile | 1 + - drivers/dma/qcom/qcom_adm.c | 900 ++++++++++++++++++++++++++++++++++++++++++++ - 3 files changed, 911 insertions(+) + drivers/dma/qcom/qcom_adm.c | 903 ++++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 915 insertions(+) create mode 100644 drivers/dma/qcom/qcom_adm.c +diff --git a/drivers/dma/qcom/Kconfig b/drivers/dma/qcom/Kconfig +index 3bcb689162c67..0389d60d2604a 100644 --- a/drivers/dma/qcom/Kconfig +++ b/drivers/dma/qcom/Kconfig -@@ -28,3 +28,13 @@ config QCOM_HIDMA - (user to kernel, kernel to kernel, etc.). It only supports - memcpy interface. The core is not intended for general - purpose slave DMA. -+ +@@ -1,4 +1,15 @@ + # SPDX-License-Identifier: GPL-2.0-only +config QCOM_ADM + tristate "Qualcomm ADM support" -+ depends on ARCH_QCOM || (COMPILE_TEST && OF && ARM) ++ depends on (ARCH_QCOM || COMPILE_TEST) && !PHYS_ADDR_T_64BIT + select DMA_ENGINE + select DMA_VIRTUAL_CHANNELS -+ ---help--- -+ Enable support for the Qualcomm ADM DMA controller. This controller -+ provides DMA capabilities for both general purpose and on-chip -+ peripheral devices. ++ help ++ Enable support for the Qualcomm Application Data Mover (ADM) DMA ++ controller, as present on MSM8x60, APQ8064, and IPQ8064 devices. ++ This controller provides DMA capabilities for both general purpose ++ and on-chip peripheral devices. ++ + config QCOM_BAM_DMA + tristate "QCOM BAM DMA support" + depends on ARCH_QCOM || (COMPILE_TEST && OF && ARM) +diff --git a/drivers/dma/qcom/Makefile b/drivers/dma/qcom/Makefile +index 1ae92da88b0c9..346e643fbb6db 100644 --- a/drivers/dma/qcom/Makefile +++ b/drivers/dma/qcom/Makefile -@@ -4,3 +4,4 @@ obj-$(CONFIG_QCOM_HIDMA_MGMT) += hdma_mg - hdma_mgmt-objs := hidma_mgmt.o hidma_mgmt_sys.o - obj-$(CONFIG_QCOM_HIDMA) += hdma.o - hdma-objs := hidma_ll.o hidma.o hidma_dbg.o +@@ -1,4 +1,5 @@ + # SPDX-License-Identifier: GPL-2.0 +obj-$(CONFIG_QCOM_ADM) += qcom_adm.o + obj-$(CONFIG_QCOM_BAM_DMA) += bam_dma.o + obj-$(CONFIG_QCOM_HIDMA_MGMT) += hdma_mgmt.o + hdma_mgmt-objs := hidma_mgmt.o hidma_mgmt_sys.o +diff --git a/drivers/dma/qcom/qcom_adm.c b/drivers/dma/qcom/qcom_adm.c +new file mode 100644 +index 0000000000000..9b6f8e050ecce --- /dev/null +++ b/drivers/dma/qcom/qcom_adm.c -@@ -0,0 +1,914 @@ +@@ -0,0 +1,903 @@ ++// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 and -+ * only version 2 as published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * + */ + -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include ++#include ++#include +#include -+#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include +#include +#include +#include +#include ++#include +#include -+#include -+#include ++#include ++#include + +#include "../dmaengine.h" +#include "../virt-dma.h" @@ -90,10 +99,10 @@ Signed-off-by: Thomas Pedersen +#define ADM_CI_MULTI 0x4 +#define ADM_CRCI_MULTI 0x4 +#define ADM_EE_MULTI 0x800 -+#define ADM_CHAN_OFFS(chan) (ADM_CHAN_MULTI * chan) -+#define ADM_EE_OFFS(ee) (ADM_EE_MULTI * ee) ++#define ADM_CHAN_OFFS(chan) (ADM_CHAN_MULTI * (chan)) ++#define ADM_EE_OFFS(ee) (ADM_EE_MULTI * (ee)) +#define ADM_CHAN_EE_OFFS(chan, ee) (ADM_CHAN_OFFS(chan) + ADM_EE_OFFS(ee)) -+#define ADM_CHAN_OFFS(chan) (ADM_CHAN_MULTI * chan) ++#define ADM_CHAN_OFFS(chan) (ADM_CHAN_MULTI * (chan)) +#define ADM_CI_OFFS(ci) (ADM_CHAN_OFF(ci)) +#define ADM_CH_CMD_PTR(chan, ee) (ADM_CHAN_EE_OFFS(chan, ee)) +#define ADM_CH_RSLT(chan, ee) (0x40 + ADM_CHAN_EE_OFFS(chan, ee)) @@ -102,62 +111,62 @@ Signed-off-by: Thomas Pedersen +#define ADM_CH_CONF(chan) (0x240 + ADM_CHAN_OFFS(chan)) +#define ADM_CH_RSLT_CONF(chan, ee) (0x300 + ADM_CHAN_EE_OFFS(chan, ee)) +#define ADM_SEC_DOMAIN_IRQ_STATUS(ee) (0x380 + ADM_EE_OFFS(ee)) -+#define ADM_CI_CONF(ci) (0x390 + ci * ADM_CI_MULTI) ++#define ADM_CI_CONF(ci) (0x390 + (ci) * ADM_CI_MULTI) +#define ADM_GP_CTL 0x3d8 -+#define ADM_CRCI_CTL(crci, ee) (0x400 + crci * ADM_CRCI_MULTI + \ ++#define ADM_CRCI_CTL(crci, ee) (0x400 + (crci) * ADM_CRCI_MULTI + \ + ADM_EE_OFFS(ee)) + +/* channel status */ -+#define ADM_CH_STATUS_VALID BIT(1) ++#define ADM_CH_STATUS_VALID BIT(1) + +/* channel result */ -+#define ADM_CH_RSLT_VALID BIT(31) -+#define ADM_CH_RSLT_ERR BIT(3) -+#define ADM_CH_RSLT_FLUSH BIT(2) -+#define ADM_CH_RSLT_TPD BIT(1) ++#define ADM_CH_RSLT_VALID BIT(31) ++#define ADM_CH_RSLT_ERR BIT(3) ++#define ADM_CH_RSLT_FLUSH BIT(2) ++#define ADM_CH_RSLT_TPD BIT(1) + +/* channel conf */ +#define ADM_CH_CONF_SHADOW_EN BIT(12) +#define ADM_CH_CONF_MPU_DISABLE BIT(11) +#define ADM_CH_CONF_PERM_MPU_CONF BIT(9) +#define ADM_CH_CONF_FORCE_RSLT_EN BIT(7) -+#define ADM_CH_CONF_SEC_DOMAIN(ee) (((ee & 0x3) << 4) | ((ee & 0x4) << 11)) ++#define ADM_CH_CONF_SEC_DOMAIN(ee) ((((ee) & 0x3) << 4) | (((ee) & 0x4) << 11)) + +/* channel result conf */ +#define ADM_CH_RSLT_CONF_FLUSH_EN BIT(1) +#define ADM_CH_RSLT_CONF_IRQ_EN BIT(0) + +/* CRCI CTL */ -+#define ADM_CRCI_CTL_MUX_SEL BIT(18) -+#define ADM_CRCI_CTL_RST BIT(17) ++#define ADM_CRCI_CTL_MUX_SEL BIT(18) ++#define ADM_CRCI_CTL_RST BIT(17) + +/* CI configuration */ -+#define ADM_CI_RANGE_END(x) (x << 24) -+#define ADM_CI_RANGE_START(x) (x << 16) -+#define ADM_CI_BURST_4_WORDS BIT(2) -+#define ADM_CI_BURST_8_WORDS BIT(3) ++#define ADM_CI_RANGE_END(x) ((x) << 24) ++#define ADM_CI_RANGE_START(x) ((x) << 16) ++#define ADM_CI_BURST_4_WORDS BIT(2) ++#define ADM_CI_BURST_8_WORDS BIT(3) + +/* GP CTL */ -+#define ADM_GP_CTL_LP_EN BIT(12) -+#define ADM_GP_CTL_LP_CNT(x) (x << 8) ++#define ADM_GP_CTL_LP_EN BIT(12) ++#define ADM_GP_CTL_LP_CNT(x) ((x) << 8) + +/* Command pointer list entry */ -+#define ADM_CPLE_LP BIT(31) -+#define ADM_CPLE_CMD_PTR_LIST BIT(29) ++#define ADM_CPLE_LP BIT(31) ++#define ADM_CPLE_CMD_PTR_LIST BIT(29) + +/* Command list entry */ -+#define ADM_CMD_LC BIT(31) -+#define ADM_CMD_DST_CRCI(n) (((n) & 0xf) << 7) -+#define ADM_CMD_SRC_CRCI(n) (((n) & 0xf) << 3) ++#define ADM_CMD_LC BIT(31) ++#define ADM_CMD_DST_CRCI(n) (((n) & 0xf) << 7) ++#define ADM_CMD_SRC_CRCI(n) (((n) & 0xf) << 3) + -+#define ADM_CMD_TYPE_SINGLE 0x0 -+#define ADM_CMD_TYPE_BOX 0x3 ++#define ADM_CMD_TYPE_SINGLE 0x0 ++#define ADM_CMD_TYPE_BOX 0x3 + -+#define ADM_CRCI_MUX_SEL BIT(4) -+#define ADM_DESC_ALIGN 8 -+#define ADM_MAX_XFER (SZ_64K-1) -+#define ADM_MAX_ROWS (SZ_64K-1) -+#define ADM_MAX_CHANNELS 16 ++#define ADM_CRCI_MUX_SEL BIT(4) ++#define ADM_DESC_ALIGN 8 ++#define ADM_MAX_XFER (SZ_64K - 1) ++#define ADM_MAX_ROWS (SZ_64K - 1) ++#define ADM_MAX_CHANNELS 16 + +struct adm_desc_hw_box { + u32 cmd; @@ -255,7 +264,7 @@ Signed-off-by: Thomas Pedersen + case 32: + case 64: + case 128: -+ ret = ffs(burst>>4) - 1; ++ ret = ffs(burst >> 4) - 1; + break; + case 192: + ret = 4; @@ -281,9 +290,10 @@ Signed-off-by: Thomas Pedersen + * @burst: Burst size of transaction + * @direction: DMA transfer direction + */ -+static void *adm_process_fc_descriptors(struct adm_chan *achan, -+ void *desc, struct scatterlist *sg, u32 crci, u32 burst, -+ enum dma_transfer_direction direction) ++static void *adm_process_fc_descriptors(struct adm_chan *achan, void *desc, ++ struct scatterlist *sg, u32 crci, ++ u32 burst, ++ enum dma_transfer_direction direction) +{ + struct adm_desc_hw_box *box_desc = NULL; + struct adm_desc_hw_single *single_desc; @@ -349,9 +359,9 @@ Signed-off-by: Thomas Pedersen + * @sg: Scatterlist entry + * @direction: DMA transfer direction + */ -+static void *adm_process_non_fc_descriptors(struct adm_chan *achan, -+ void *desc, struct scatterlist *sg, -+ enum dma_transfer_direction direction) ++static void *adm_process_non_fc_descriptors(struct adm_chan *achan, void *desc, ++ struct scatterlist *sg, ++ enum dma_transfer_direction direction) +{ + struct adm_desc_hw_single *single_desc; + u32 remainder = sg_dma_len(sg); @@ -398,9 +408,11 @@ Signed-off-by: Thomas Pedersen + * @context: transfer context (unused) + */ +static struct dma_async_tx_descriptor *adm_prep_slave_sg(struct dma_chan *chan, -+ struct scatterlist *sgl, unsigned int sg_len, -+ enum dma_transfer_direction direction, unsigned long flags, -+ void *context) ++ struct scatterlist *sgl, ++ unsigned int sg_len, ++ enum dma_transfer_direction direction, ++ unsigned long flags, ++ void *context) +{ + struct adm_chan *achan = to_adm_chan(chan); + struct adm_device *adev = achan->adev; @@ -427,7 +439,6 @@ Signed-off-by: Thomas Pedersen + + /* if using flow control, validate burst and crci values */ + if (achan->slave.device_fc) { -+ + blk_size = adm_get_blksize(burst); + if (blk_size < 0) { + dev_err(adev->dev, "invalid burst value: %d\n", @@ -455,7 +466,7 @@ Signed-off-by: Thomas Pedersen + } + } + -+ async_desc = kzalloc(sizeof(*async_desc), GFP_ATOMIC); ++ async_desc = kzalloc(sizeof(*async_desc), GFP_NOWAIT); + if (!async_desc) + return ERR_PTR(-ENOMEM); + @@ -468,7 +479,7 @@ Signed-off-by: Thomas Pedersen + box_count * sizeof(struct adm_desc_hw_box) + + sizeof(*cple) + 2 * ADM_DESC_ALIGN; + -+ async_desc->cpl = kzalloc(async_desc->dma_len, GFP_ATOMIC); ++ async_desc->cpl = kzalloc(async_desc->dma_len, GFP_NOWAIT); + if (!async_desc->cpl) + goto free; + @@ -483,10 +494,10 @@ Signed-off-by: Thomas Pedersen + + if (achan->slave.device_fc) + desc = adm_process_fc_descriptors(achan, desc, sg, crci, -+ burst, direction); ++ burst, direction); + else + desc = adm_process_non_fc_descriptors(achan, desc, sg, -+ direction); ++ direction); + } + + async_desc->dma_addr = dma_map_single(adev->dev, async_desc->cpl, @@ -532,7 +543,7 @@ Signed-off-by: Thomas Pedersen + + /* send flush command to terminate current transaction */ + writel_relaxed(0x0, -+ adev->regs + ADM_CH_FLUSH_STATE0(achan->id, adev->ee)); ++ adev->regs + ADM_CH_FLUSH_STATE0(achan->id, adev->ee)); + + spin_unlock_irqrestore(&achan->vc.lock, flags); + @@ -586,7 +597,7 @@ Signed-off-by: Thomas Pedersen + adev->regs + ADM_CH_CONF(achan->id)); + + writel(ADM_CH_RSLT_CONF_IRQ_EN | ADM_CH_RSLT_CONF_FLUSH_EN, -+ adev->regs + ADM_CH_RSLT_CONF(achan->id, adev->ee)); ++ adev->regs + ADM_CH_RSLT_CONF(achan->id, adev->ee)); + + achan->initialized = 1; + } @@ -594,7 +605,7 @@ Signed-off-by: Thomas Pedersen + /* set the crci block size if this transaction requires CRCI */ + if (async_desc->crci) { + writel(async_desc->mux | async_desc->blk_size, -+ adev->regs + ADM_CRCI_CTL(async_desc->crci, adev->ee)); ++ adev->regs + ADM_CRCI_CTL(async_desc->crci, adev->ee)); + } + + /* make sure IRQ enable doesn't get reordered */ @@ -602,7 +613,7 @@ Signed-off-by: Thomas Pedersen + + /* write next command list out to the CMD FIFO */ + writel(ALIGN(async_desc->dma_addr, ADM_DESC_ALIGN) >> 3, -+ adev->regs + ADM_CH_CMD_PTR(achan->id, adev->ee)); ++ adev->regs + ADM_CH_CMD_PTR(achan->id, adev->ee)); +} + +/** @@ -628,7 +639,7 @@ Signed-off-by: Thomas Pedersen + + if (srcs & BIT(i)) { + status = readl_relaxed(adev->regs + -+ ADM_CH_STATUS_SD(i, adev->ee)); ++ ADM_CH_STATUS_SD(i, adev->ee)); + + /* if no result present, skip */ + if (!(status & ADM_CH_STATUS_VALID)) @@ -673,7 +684,7 @@ Signed-off-by: Thomas Pedersen + * Return status of dma transaction + */ +static enum dma_status adm_tx_status(struct dma_chan *chan, dma_cookie_t cookie, -+ struct dma_tx_state *txstate) ++ struct dma_tx_state *txstate) +{ + struct adm_chan *achan = to_adm_chan(chan); + struct virt_dma_desc *vd; @@ -697,7 +708,7 @@ Signed-off-by: Thomas Pedersen + * residue is either the full length if it is in the issued list, or 0 + * if it is in progress. We have no reliable way of determining + * anything inbetween -+ */ ++ */ + dma_set_residue(txstate, residue); + + if (achan->error) @@ -741,7 +752,7 @@ Signed-off-by: Thomas Pedersen +} + +static void adm_channel_init(struct adm_device *adev, struct adm_chan *achan, -+ u32 index) ++ u32 index) +{ + achan->id = index; + achan->adev = adev; @@ -753,7 +764,6 @@ Signed-off-by: Thomas Pedersen +static int adm_dma_probe(struct platform_device *pdev) +{ + struct adm_device *adev; -+ struct resource *iores; + int ret; + u32 i; + @@ -763,8 +773,7 @@ Signed-off-by: Thomas Pedersen + + adev->dev = &pdev->dev; + -+ iores = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ adev->regs = devm_ioremap_resource(&pdev->dev, iores); ++ adev->regs = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(adev->regs)) + return PTR_ERR(adev->regs); + @@ -782,64 +791,60 @@ Signed-off-by: Thomas Pedersen + if (IS_ERR(adev->core_clk)) + return PTR_ERR(adev->core_clk); + ++ adev->iface_clk = devm_clk_get(adev->dev, "iface"); ++ if (IS_ERR(adev->iface_clk)) ++ return PTR_ERR(adev->iface_clk); ++ ++ adev->clk_reset = devm_reset_control_get_exclusive(&pdev->dev, "clk"); ++ if (IS_ERR(adev->clk_reset)) { ++ dev_err(adev->dev, "failed to get ADM0 reset\n"); ++ return PTR_ERR(adev->clk_reset); ++ } ++ ++ adev->c0_reset = devm_reset_control_get_exclusive(&pdev->dev, "c0"); ++ if (IS_ERR(adev->c0_reset)) { ++ dev_err(adev->dev, "failed to get ADM0 C0 reset\n"); ++ return PTR_ERR(adev->c0_reset); ++ } ++ ++ adev->c1_reset = devm_reset_control_get_exclusive(&pdev->dev, "c1"); ++ if (IS_ERR(adev->c1_reset)) { ++ dev_err(adev->dev, "failed to get ADM0 C1 reset\n"); ++ return PTR_ERR(adev->c1_reset); ++ } ++ ++ adev->c2_reset = devm_reset_control_get_exclusive(&pdev->dev, "c2"); ++ if (IS_ERR(adev->c2_reset)) { ++ dev_err(adev->dev, "failed to get ADM0 C2 reset\n"); ++ return PTR_ERR(adev->c2_reset); ++ } ++ + ret = clk_prepare_enable(adev->core_clk); + if (ret) { + dev_err(adev->dev, "failed to prepare/enable core clock\n"); + return ret; + } + -+ adev->iface_clk = devm_clk_get(adev->dev, "iface"); -+ if (IS_ERR(adev->iface_clk)) { -+ ret = PTR_ERR(adev->iface_clk); -+ goto err_disable_core_clk; -+ } -+ + ret = clk_prepare_enable(adev->iface_clk); + if (ret) { + dev_err(adev->dev, "failed to prepare/enable iface clock\n"); + goto err_disable_core_clk; + } + -+ adev->clk_reset = devm_reset_control_get(&pdev->dev, "clk"); -+ if (IS_ERR(adev->clk_reset)) { -+ dev_err(adev->dev, "failed to get ADM0 reset\n"); -+ ret = PTR_ERR(adev->clk_reset); -+ goto err_disable_clks; -+ } -+ -+ adev->c0_reset = devm_reset_control_get(&pdev->dev, "c0"); -+ if (IS_ERR(adev->c0_reset)) { -+ dev_err(adev->dev, "failed to get ADM0 C0 reset\n"); -+ ret = PTR_ERR(adev->c0_reset); -+ goto err_disable_clks; -+ } -+ -+ adev->c1_reset = devm_reset_control_get(&pdev->dev, "c1"); -+ if (IS_ERR(adev->c1_reset)) { -+ dev_err(adev->dev, "failed to get ADM0 C1 reset\n"); -+ ret = PTR_ERR(adev->c1_reset); -+ goto err_disable_clks; -+ } -+ -+ adev->c2_reset = devm_reset_control_get(&pdev->dev, "c2"); -+ if (IS_ERR(adev->c2_reset)) { -+ dev_err(adev->dev, "failed to get ADM0 C2 reset\n"); -+ ret = PTR_ERR(adev->c2_reset); -+ goto err_disable_clks; -+ } -+ + reset_control_assert(adev->clk_reset); + reset_control_assert(adev->c0_reset); + reset_control_assert(adev->c1_reset); + reset_control_assert(adev->c2_reset); + ++ udelay(2); ++ + reset_control_deassert(adev->clk_reset); + reset_control_deassert(adev->c0_reset); + reset_control_deassert(adev->c1_reset); + reset_control_deassert(adev->c2_reset); + + adev->channels = devm_kcalloc(adev->dev, ADM_MAX_CHANNELS, -+ sizeof(*adev->channels), GFP_KERNEL); ++ sizeof(*adev->channels), GFP_KERNEL); + + if (!adev->channels) { + ret = -ENOMEM; @@ -859,16 +864,16 @@ Signed-off-by: Thomas Pedersen + + /* configure client interfaces */ + writel(ADM_CI_RANGE_START(0x40) | ADM_CI_RANGE_END(0xb0) | -+ ADM_CI_BURST_8_WORDS, adev->regs + ADM_CI_CONF(0)); ++ ADM_CI_BURST_8_WORDS, adev->regs + ADM_CI_CONF(0)); + writel(ADM_CI_RANGE_START(0x2a) | ADM_CI_RANGE_END(0x2c) | -+ ADM_CI_BURST_8_WORDS, adev->regs + ADM_CI_CONF(1)); ++ ADM_CI_BURST_8_WORDS, adev->regs + ADM_CI_CONF(1)); + writel(ADM_CI_RANGE_START(0x12) | ADM_CI_RANGE_END(0x28) | -+ ADM_CI_BURST_8_WORDS, adev->regs + ADM_CI_CONF(2)); ++ ADM_CI_BURST_8_WORDS, adev->regs + ADM_CI_CONF(2)); + writel(ADM_GP_CTL_LP_EN | ADM_GP_CTL_LP_CNT(0xf), -+ adev->regs + ADM_GP_CTL); ++ adev->regs + ADM_GP_CTL); + + ret = devm_request_irq(adev->dev, adev->irq, adm_dma_irq, -+ 0, "adm_dma", adev); ++ 0, "adm_dma", adev); + if (ret) + goto err_disable_clks; + @@ -933,6 +938,7 @@ Signed-off-by: Thomas Pedersen + /* mask IRQs for this channel/EE pair */ + writel(0, adev->regs + ADM_CH_RSLT_CONF(achan->id, adev->ee)); + ++ tasklet_kill(&adev->channels[i].vc.task); + adm_terminate_all(&adev->channels[i].vc.chan); + } + @@ -964,3 +970,6 @@ Signed-off-by: Thomas Pedersen +MODULE_AUTHOR("Andy Gross "); +MODULE_DESCRIPTION("QCOM ADM DMA engine driver"); +MODULE_LICENSE("GPL v2"); +-- +cgit 1.2.3-1.el7 + diff --git a/target/linux/ipq806x/patches-5.10/101-5.12-mtd-parsers-Add-Qcom-SMEM-parser.patch b/target/linux/ipq806x/patches-5.10/101-5.12-mtd-parsers-Add-Qcom-SMEM-parser.patch new file mode 100644 index 0000000000..7aec4fcc83 --- /dev/null +++ b/target/linux/ipq806x/patches-5.10/101-5.12-mtd-parsers-Add-Qcom-SMEM-parser.patch @@ -0,0 +1,227 @@ +From 803eb124e1a64e42888542c3444bfe6dac412c7f Mon Sep 17 00:00:00 2001 +From: Manivannan Sadhasivam +Date: Mon, 4 Jan 2021 09:41:35 +0530 +Subject: mtd: parsers: Add Qcom SMEM parser + +NAND based Qualcomm platforms have the partition table populated in the +Shared Memory (SMEM). Hence, add a parser for parsing the partitions +from it. + +Signed-off-by: Manivannan Sadhasivam +Signed-off-by: Miquel Raynal +Link: https://lore.kernel.org/linux-mtd/20210104041137.113075-3-manivannan.sadhasivam@linaro.org +--- + drivers/mtd/parsers/Kconfig | 8 ++ + drivers/mtd/parsers/Makefile | 1 + + drivers/mtd/parsers/qcomsmempart.c | 170 +++++++++++++++++++++++++++++++++++++ + 3 files changed, 179 insertions(+) + create mode 100644 drivers/mtd/parsers/qcomsmempart.c + +diff --git a/drivers/mtd/parsers/Kconfig b/drivers/mtd/parsers/Kconfig +index e72354322f628..d90c302290522 100644 +--- a/drivers/mtd/parsers/Kconfig ++++ b/drivers/mtd/parsers/Kconfig +@@ -160,6 +160,14 @@ config MTD_REDBOOT_PARTS_READONLY + 'FIS directory' images, enable this option. + + endif # MTD_REDBOOT_PARTS ++ ++config MTD_QCOMSMEM_PARTS ++ tristate "Qualcomm SMEM NAND flash partition parser" ++ depends on MTD_NAND_QCOM || COMPILE_TEST ++ depends on QCOM_SMEM ++ help ++ This provides support for parsing partitions from Shared Memory (SMEM) ++ for NAND flash on Qualcomm platforms. + + config MTD_ROUTERBOOT_PARTS + tristate "RouterBoot flash partition parser" +diff --git a/drivers/mtd/parsers/Makefile b/drivers/mtd/parsers/Makefile +index b0c5f62f9e858..50eb0b0a22105 100644 +--- a/drivers/mtd/parsers/Makefile ++++ b/drivers/mtd/parsers/Makefile +@@ -9,4 +9,5 @@ obj-$(CONFIG_MTD_AFS_PARTS) += afs.o + obj-$(CONFIG_MTD_PARSER_TRX) += parser_trx.o + obj-$(CONFIG_MTD_SHARPSL_PARTS) += sharpslpart.o + obj-$(CONFIG_MTD_REDBOOT_PARTS) += redboot.o ++obj-$(CONFIG_MTD_QCOMSMEM_PARTS) += qcomsmempart.o + obj-$(CONFIG_MTD_ROUTERBOOT_PARTS) += routerbootpart.o +diff --git a/drivers/mtd/parsers/qcomsmempart.c b/drivers/mtd/parsers/qcomsmempart.c +new file mode 100644 +index 0000000000000..808cb33d71f8e +--- /dev/null ++++ b/drivers/mtd/parsers/qcomsmempart.c +@@ -0,0 +1,170 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* ++ * Qualcomm SMEM NAND flash partition parser ++ * ++ * Copyright (C) 2020, Linaro Ltd. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define SMEM_AARM_PARTITION_TABLE 9 ++#define SMEM_APPS 0 ++ ++#define SMEM_FLASH_PART_MAGIC1 0x55ee73aa ++#define SMEM_FLASH_PART_MAGIC2 0xe35ebddb ++#define SMEM_FLASH_PTABLE_V3 3 ++#define SMEM_FLASH_PTABLE_V4 4 ++#define SMEM_FLASH_PTABLE_MAX_PARTS_V3 16 ++#define SMEM_FLASH_PTABLE_MAX_PARTS_V4 48 ++#define SMEM_FLASH_PTABLE_HDR_LEN (4 * sizeof(u32)) ++#define SMEM_FLASH_PTABLE_NAME_SIZE 16 ++ ++/** ++ * struct smem_flash_pentry - SMEM Flash partition entry ++ * @name: Name of the partition ++ * @offset: Offset in blocks ++ * @length: Length of the partition in blocks ++ * @attr: Flags for this partition ++ */ ++struct smem_flash_pentry { ++ char name[SMEM_FLASH_PTABLE_NAME_SIZE]; ++ __le32 offset; ++ __le32 length; ++ u8 attr; ++} __packed __aligned(4); ++ ++/** ++ * struct smem_flash_ptable - SMEM Flash partition table ++ * @magic1: Partition table Magic 1 ++ * @magic2: Partition table Magic 2 ++ * @version: Partition table version ++ * @numparts: Number of partitions in this ptable ++ * @pentry: Flash partition entries belonging to this ptable ++ */ ++struct smem_flash_ptable { ++ __le32 magic1; ++ __le32 magic2; ++ __le32 version; ++ __le32 numparts; ++ struct smem_flash_pentry pentry[SMEM_FLASH_PTABLE_MAX_PARTS_V4]; ++} __packed __aligned(4); ++ ++static int parse_qcomsmem_part(struct mtd_info *mtd, ++ const struct mtd_partition **pparts, ++ struct mtd_part_parser_data *data) ++{ ++ struct smem_flash_pentry *pentry; ++ struct smem_flash_ptable *ptable; ++ size_t len = SMEM_FLASH_PTABLE_HDR_LEN; ++ struct mtd_partition *parts; ++ int ret, i, numparts; ++ char *name, *c; ++ ++ pr_debug("Parsing partition table info from SMEM\n"); ++ ptable = qcom_smem_get(SMEM_APPS, SMEM_AARM_PARTITION_TABLE, &len); ++ if (IS_ERR(ptable)) { ++ pr_err("Error reading partition table header\n"); ++ return PTR_ERR(ptable); ++ } ++ ++ /* Verify ptable magic */ ++ if (le32_to_cpu(ptable->magic1) != SMEM_FLASH_PART_MAGIC1 || ++ le32_to_cpu(ptable->magic2) != SMEM_FLASH_PART_MAGIC2) { ++ pr_err("Partition table magic verification failed\n"); ++ return -EINVAL; ++ } ++ ++ /* Ensure that # of partitions is less than the max we have allocated */ ++ numparts = le32_to_cpu(ptable->numparts); ++ if (numparts > SMEM_FLASH_PTABLE_MAX_PARTS_V4) { ++ pr_err("Partition numbers exceed the max limit\n"); ++ return -EINVAL; ++ } ++ ++ /* Find out length of partition data based on table version */ ++ if (le32_to_cpu(ptable->version) <= SMEM_FLASH_PTABLE_V3) { ++ len = SMEM_FLASH_PTABLE_HDR_LEN + SMEM_FLASH_PTABLE_MAX_PARTS_V3 * ++ sizeof(struct smem_flash_pentry); ++ } else if (le32_to_cpu(ptable->version) == SMEM_FLASH_PTABLE_V4) { ++ len = SMEM_FLASH_PTABLE_HDR_LEN + SMEM_FLASH_PTABLE_MAX_PARTS_V4 * ++ sizeof(struct smem_flash_pentry); ++ } else { ++ pr_err("Unknown ptable version (%d)", le32_to_cpu(ptable->version)); ++ return -EINVAL; ++ } ++ ++ /* ++ * Now that the partition table header has been parsed, verified ++ * and the length of the partition table calculated, read the ++ * complete partition table ++ */ ++ ptable = qcom_smem_get(SMEM_APPS, SMEM_AARM_PARTITION_TABLE, &len); ++ if (IS_ERR_OR_NULL(ptable)) { ++ pr_err("Error reading partition table\n"); ++ return PTR_ERR(ptable); ++ } ++ ++ parts = kcalloc(numparts, sizeof(*parts), GFP_KERNEL); ++ if (!parts) ++ return -ENOMEM; ++ ++ for (i = 0; i < numparts; i++) { ++ pentry = &ptable->pentry[i]; ++ if (pentry->name[0] == '\0') ++ continue; ++ ++ name = kstrdup(pentry->name, GFP_KERNEL); ++ if (!name) { ++ ret = -ENOMEM; ++ goto out_free_parts; ++ } ++ ++ /* Convert name to lower case */ ++ for (c = name; *c != '\0'; c++) ++ *c = tolower(*c); ++ ++ parts[i].name = name; ++ parts[i].offset = le32_to_cpu(pentry->offset) * mtd->erasesize; ++ parts[i].mask_flags = pentry->attr; ++ parts[i].size = le32_to_cpu(pentry->length) * mtd->erasesize; ++ pr_debug("%d: %s offs=0x%08x size=0x%08x attr:0x%08x\n", ++ i, pentry->name, le32_to_cpu(pentry->offset), ++ le32_to_cpu(pentry->length), pentry->attr); ++ } ++ ++ pr_debug("SMEM partition table found: ver: %d len: %d\n", ++ le32_to_cpu(ptable->version), numparts); ++ *pparts = parts; ++ ++ return numparts; ++ ++out_free_parts: ++ while (--i >= 0) ++ kfree(parts[i].name); ++ kfree(parts); ++ *pparts = NULL; ++ ++ return ret; ++} ++ ++static const struct of_device_id qcomsmem_of_match_table[] = { ++ { .compatible = "qcom,smem-part" }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, qcomsmem_of_match_table); ++ ++static struct mtd_part_parser mtd_parser_qcomsmem = { ++ .parse_fn = parse_qcomsmem_part, ++ .name = "qcomsmem", ++ .of_match_table = qcomsmem_of_match_table, ++}; ++module_mtd_part_parser(mtd_parser_qcomsmem); ++ ++MODULE_LICENSE("GPL v2"); ++MODULE_AUTHOR("Manivannan Sadhasivam "); ++MODULE_DESCRIPTION("Qualcomm SMEM NAND flash partition parser"); +-- +cgit 1.2.3-1.el7 + diff --git a/target/linux/ipq806x/patches-5.10/102-mtd-rootfs-conflicts-with-OpenWrt-auto-mounting.patch b/target/linux/ipq806x/patches-5.10/102-mtd-rootfs-conflicts-with-OpenWrt-auto-mounting.patch new file mode 100644 index 0000000000..47f3bfba8d --- /dev/null +++ b/target/linux/ipq806x/patches-5.10/102-mtd-rootfs-conflicts-with-OpenWrt-auto-mounting.patch @@ -0,0 +1,24 @@ +From 5001f2e1a325b68dbf225bd17f69a4d3d975cca5 Mon Sep 17 00:00:00 2001 +From: John Crispin +Date: Thu, 9 Mar 2017 09:31:44 +0100 +Subject: [PATCH 61/69] mtd: "rootfs" conflicts with OpenWrt auto mounting + +Signed-off-by: John Crispin +--- + drivers/mtd/parsers/qcomsmempart.c | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/drivers/mtd/parsers/qcomsmempart.c ++++ b/drivers/mtd/parsers/qcomsmempart.c +@@ -189,6 +189,11 @@ static int parse_qcomsmem_part(st + parts[i].offset = le32_to_cpu(pentry->offset) * mtd->erasesize; + parts[i].mask_flags = pentry->attr; + parts[i].size = le32_to_cpu(pentry->length) * mtd->erasesize; ++ ++ /* "rootfs" conflicts with OpenWrt auto mounting */ ++ if (mtd_type_is_nand(mtd) && !strcmp(name, "rootfs")) ++ parts[i].name = "ubi"; ++ + pr_debug("%d: %s offs=0x%08x size=0x%08x attr:0x%08x\n", + i, pentry->name, le32_to_cpu(pentry->offset), + le32_to_cpu(pentry->length), pentry->attr); diff --git a/target/linux/ipq806x/patches-5.4/0031-mtd-add-SMEM-parser-for-QCOM-platforms.patch b/target/linux/ipq806x/patches-5.4/0031-mtd-add-SMEM-parser-for-QCOM-platforms.patch deleted file mode 100644 index 6b7119b8e0..0000000000 --- a/target/linux/ipq806x/patches-5.4/0031-mtd-add-SMEM-parser-for-QCOM-platforms.patch +++ /dev/null @@ -1,282 +0,0 @@ -From d8eeb4de90e968ba32d956728c866f20752cf2c3 Mon Sep 17 00:00:00 2001 -From: Mathieu Olivari -Date: Thu, 9 Mar 2017 08:18:08 +0100 -Subject: [PATCH 31/69] mtd: add SMEM parser for QCOM platforms - -On QCOM platforms using MTD devices storage (such as IPQ806x), SMEM is -used to store partition layout. This new parser can now be used to read -SMEM and use it to register an MTD layout according to its content. - -Signed-off-by: Mathieu Olivari -Signed-off-by: Ram Chandra Jangir ---- - drivers/mtd/parsers/Kconfig | 7 ++ - drivers/mtd/parsers/Makefile | 1 + - drivers/mtd/parsers/qcom_smem_part.c | 228 +++++++++++++++++++++++++++++++++++++++++++ - 3 files changed, 236 insertions(+) - create mode 100644 drivers/mtd/parsers/qcom_smem_part.c - ---- a/drivers/mtd/parsers/Kconfig -+++ b/drivers/mtd/parsers/Kconfig -@@ -138,6 +138,13 @@ config MTD_PARSER_TRX - This driver will parse TRX header and report at least two partitions: - kernel and rootfs. - -+config MTD_QCOM_SMEM_PARTS -+ tristate "QCOM SMEM partitioning support" -+ depends on QCOM_SMEM -+ help -+ This provides partitions parser for QCOM devices using SMEM -+ such as IPQ806x. -+ - config MTD_SHARPSL_PARTS - tristate "Sharp SL Series NAND flash partition parser" - depends on MTD_NAND_SHARPSL || MTD_NAND_TMIO || COMPILE_TEST ---- a/drivers/mtd/parsers/Makefile -+++ b/drivers/mtd/parsers/Makefile -@@ -11,6 +11,7 @@ ofpart-$(CONFIG_MTD_OF_PARTS_LINKSYS_NS) - obj-$(CONFIG_MTD_PARSER_IMAGETAG) += parser_imagetag.o - obj-$(CONFIG_MTD_AFS_PARTS) += afs.o - obj-$(CONFIG_MTD_PARSER_TRX) += parser_trx.o -+obj-$(CONFIG_MTD_QCOM_SMEM_PARTS) += qcom_smem_part.o - obj-$(CONFIG_MTD_SHARPSL_PARTS) += sharpslpart.o - obj-$(CONFIG_MTD_REDBOOT_PARTS) += redboot.o - obj-$(CONFIG_MTD_ROUTERBOOT_PARTS) += routerbootpart.o ---- /dev/null -+++ b/drivers/mtd/parsers/qcom_smem_part.c -@@ -0,0 +1,235 @@ -+/* -+ * Copyright (c) 2015, The Linux Foundation. All rights reserved. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 and -+ * only version 2 as published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ */ -+ -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+ -+#include -+ -+/* Processor/host identifier for the application processor */ -+#define SMEM_HOST_APPS 0 -+ -+/* SMEM items index */ -+#define SMEM_AARM_PARTITION_TABLE 9 -+#define SMEM_BOOT_FLASH_TYPE 421 -+#define SMEM_BOOT_FLASH_BLOCK_SIZE 424 -+ -+/* SMEM Flash types */ -+#define SMEM_FLASH_NAND 2 -+#define SMEM_FLASH_SPI 6 -+ -+#define SMEM_PART_NAME_SZ 16 -+#define SMEM_PARTS_MAX 32 -+ -+struct smem_partition { -+ char name[SMEM_PART_NAME_SZ]; -+ __le32 start; -+ __le32 size; -+ __le32 attr; -+}; -+ -+struct smem_partition_table { -+ u8 magic[8]; -+ __le32 version; -+ __le32 len; -+ struct smem_partition parts[SMEM_PARTS_MAX]; -+}; -+ -+/* SMEM Magic values in partition table */ -+static const u8 SMEM_PTABLE_MAGIC[] = { -+ 0xaa, 0x73, 0xee, 0x55, -+ 0xdb, 0xbd, 0x5e, 0xe3, -+}; -+ -+static int qcom_smem_get_flash_blksz(u64 **smem_blksz) -+{ -+ size_t size; -+ -+ *smem_blksz = qcom_smem_get(SMEM_HOST_APPS, SMEM_BOOT_FLASH_BLOCK_SIZE, -+ &size); -+ -+ if (IS_ERR(*smem_blksz)) { -+ pr_err("Unable to read flash blksz from SMEM\n"); -+ return -ENOENT; -+ } -+ -+ if (size != sizeof(**smem_blksz)) { -+ pr_err("Invalid flash blksz size in SMEM\n"); -+ return -EINVAL; -+ } -+ -+ return 0; -+} -+ -+static int qcom_smem_get_flash_type(u64 **smem_flash_type) -+{ -+ size_t size; -+ -+ *smem_flash_type = qcom_smem_get(SMEM_HOST_APPS, SMEM_BOOT_FLASH_TYPE, -+ &size); -+ -+ if (IS_ERR(*smem_flash_type)) { -+ pr_err("Unable to read flash type from SMEM\n"); -+ return -ENOENT; -+ } -+ -+ if (size != sizeof(**smem_flash_type)) { -+ pr_err("Invalid flash type size in SMEM\n"); -+ return -EINVAL; -+ } -+ -+ return 0; -+} -+ -+static int qcom_smem_get_flash_partitions(struct smem_partition_table **pparts) -+{ -+ size_t size; -+ -+ *pparts = qcom_smem_get(SMEM_HOST_APPS, SMEM_AARM_PARTITION_TABLE, -+ &size); -+ -+ if (IS_ERR(*pparts)) { -+ pr_err("Unable to read partition table from SMEM\n"); -+ return -ENOENT; -+ } -+ -+ return 0; -+} -+ -+static int of_dev_node_match(struct device *dev, const void *data) -+{ -+ return dev->of_node == data; -+} -+ -+static bool is_spi_device(struct device_node *np) -+{ -+ struct device *dev; -+ -+ dev = bus_find_device(&spi_bus_type, NULL, np, of_dev_node_match); -+ if (!dev) -+ return false; -+ -+ put_device(dev); -+ return true; -+} -+ -+static int parse_qcom_smem_partitions(struct mtd_info *master, -+ const struct mtd_partition **pparts, -+ struct mtd_part_parser_data *data) -+{ -+ struct smem_partition_table *smem_parts; -+ u64 *smem_flash_type, *smem_blksz; -+ struct mtd_partition *mtd_parts; -+ struct device_node *of_node = master->dev.of_node; -+ int i, ret; -+ -+ /* -+ * SMEM will only store the partition table of the boot device. -+ * If this is not the boot device, do not return any partition. -+ */ -+ ret = qcom_smem_get_flash_type(&smem_flash_type); -+ if (ret < 0) -+ return ret; -+ -+ if ((*smem_flash_type == SMEM_FLASH_NAND && !mtd_type_is_nand(master)) -+ || (*smem_flash_type == SMEM_FLASH_SPI && !is_spi_device(of_node))) -+ return 0; -+ -+ /* -+ * Just for sanity purpose, make sure the block size in SMEM matches the -+ * block size of the MTD device -+ */ -+ ret = qcom_smem_get_flash_blksz(&smem_blksz); -+ if (ret < 0) -+ return ret; -+ -+ if (*smem_blksz != master->erasesize) { -+ pr_err("SMEM block size differs from MTD block size\n"); -+ return -EINVAL; -+ } -+ -+ /* Get partition pointer from SMEM */ -+ ret = qcom_smem_get_flash_partitions(&smem_parts); -+ if (ret < 0) -+ return ret; -+ -+ if (memcmp(SMEM_PTABLE_MAGIC, smem_parts->magic, -+ sizeof(SMEM_PTABLE_MAGIC))) { -+ pr_err("SMEM partition magic invalid\n"); -+ return -EINVAL; -+ } -+ -+ /* Allocate and populate the mtd structures */ -+ mtd_parts = kcalloc(le32_to_cpu(smem_parts->len), sizeof(*mtd_parts), -+ GFP_KERNEL); -+ if (!mtd_parts) -+ return -ENOMEM; -+ -+ for (i = 0; i < smem_parts->len; i++) { -+ struct smem_partition *s_part = &smem_parts->parts[i]; -+ struct mtd_partition *m_part = &mtd_parts[i]; -+ -+ m_part->name = s_part->name; -+ m_part->size = le32_to_cpu(s_part->size) * (*smem_blksz); -+ m_part->offset = le32_to_cpu(s_part->start) * (*smem_blksz); -+ -+ /* -+ * The last SMEM partition may have its size marked as -+ * something like 0xffffffff, which means "until the end of the -+ * flash device". In this case, truncate it. -+ */ -+ if (m_part->offset + m_part->size > master->size) -+ m_part->size = master->size - m_part->offset; -+ } -+ -+ *pparts = mtd_parts; -+ -+ return smem_parts->len; -+} -+ -+static const struct of_device_id qcom_smem_of_match_table[] = { -+ { .compatible = "qcom,smem" }, -+ {}, -+}; -+MODULE_DEVICE_TABLE(of, qcom_smem_of_match_table); -+ -+static struct mtd_part_parser qcom_smem_parser = { -+ .owner = THIS_MODULE, -+ .parse_fn = parse_qcom_smem_partitions, -+ .name = "qcom-smem", -+ .of_match_table = qcom_smem_of_match_table, -+}; -+ -+static int __init qcom_smem_parser_init(void) -+{ -+ register_mtd_parser(&qcom_smem_parser); -+ return 0; -+} -+ -+static void __exit qcom_smem_parser_exit(void) -+{ -+ deregister_mtd_parser(&qcom_smem_parser); -+} -+ -+module_init(qcom_smem_parser_init); -+module_exit(qcom_smem_parser_exit); -+ -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("Mathieu Olivari "); -+MODULE_DESCRIPTION("Parsing code for SMEM based partition tables"); diff --git a/target/linux/ipq806x/patches-5.4/0061-mtd-rootfs-conflicts-with-OpenWrt-auto-mounting.patch b/target/linux/ipq806x/patches-5.4/0061-mtd-rootfs-conflicts-with-OpenWrt-auto-mounting.patch deleted file mode 100644 index ff6f6edf49..0000000000 --- a/target/linux/ipq806x/patches-5.4/0061-mtd-rootfs-conflicts-with-OpenWrt-auto-mounting.patch +++ /dev/null @@ -1,23 +0,0 @@ -From 5001f2e1a325b68dbf225bd17f69a4d3d975cca5 Mon Sep 17 00:00:00 2001 -From: John Crispin -Date: Thu, 9 Mar 2017 09:31:44 +0100 -Subject: [PATCH 61/69] mtd: "rootfs" conflicts with OpenWrt auto mounting - -Signed-off-by: John Crispin ---- - drivers/mtd/parsers/qcom_smem_part.c | 4 ++++ - 1 file changed, 4 insertions(+) - ---- a/drivers/mtd/parsers/qcom_smem_part.c -+++ b/drivers/mtd/parsers/qcom_smem_part.c -@@ -189,6 +189,10 @@ static int parse_qcom_smem_partitions(st - m_part->size = le32_to_cpu(s_part->size) * (*smem_blksz); - m_part->offset = le32_to_cpu(s_part->start) * (*smem_blksz); - -+ /* "rootfs" conflicts with OpenWrt auto mounting */ -+ if (mtd_type_is_nand(master) && !strcmp(m_part->name, "rootfs")) -+ m_part->name = "ubi"; -+ - /* - * The last SMEM partition may have its size marked as - * something like 0xffffffff, which means "until the end of the diff --git a/target/linux/ipq806x/patches-5.4/0002-dmaengine-Add-ADM-driver.patch b/target/linux/ipq806x/patches-5.4/100-v5.11-dmaengine-qcom-add_ADM_driver.patch similarity index 80% rename from target/linux/ipq806x/patches-5.4/0002-dmaengine-Add-ADM-driver.patch rename to target/linux/ipq806x/patches-5.4/100-v5.11-dmaengine-qcom-add_ADM_driver.patch index aa7d2e791e..45062d52fc 100644 --- a/target/linux/ipq806x/patches-5.4/0002-dmaengine-Add-ADM-driver.patch +++ b/target/linux/ipq806x/patches-5.4/100-v5.11-dmaengine-qcom-add_ADM_driver.patch @@ -1,86 +1,95 @@ -From 563fa24db4e529c5a3311928d73a8a90531ee527 Mon Sep 17 00:00:00 2001 -From: Thomas Pedersen -Date: Mon, 16 May 2016 17:58:51 -0700 -Subject: [PATCH 02/69] dmaengine: Add ADM driver - -Original patch by Andy Gross. +From 5c9f8c2dbdbe53818bcde6aa6695e1331e5f841f Mon Sep 17 00:00:00 2001 +From: Jonathan McDowell +Date: Sat, 14 Nov 2020 14:02:33 +0000 +Subject: dmaengine: qcom: Add ADM driver Add the DMA engine driver for the QCOM Application Data Mover (ADM) DMA controller found in the MSM8x60 and IPQ/APQ8064 platforms. The ADM supports both memory to memory transactions and memory -to/from peripheral device transactions. The controller also provides flow -control capabilities for transactions to/from peripheral devices. +to/from peripheral device transactions. The controller also provides +flow control capabilities for transactions to/from peripheral devices. -The initial release of this driver supports slave transfers to/from peripherals -and also incorporates CRCI (client rate control interface) flow control. +The initial release of this driver supports slave transfers to/from +peripherals and also incorporates CRCI (client rate control interface) +flow control. + +The hardware only supports a 32 bit physical address, so specifying +!PHYS_ADDR_T_64BIT gives maximum COMPILE_TEST coverage without having to +spend effort on kludging things in the code that will never actually be +needed on real hardware. Signed-off-by: Andy Gross Signed-off-by: Thomas Pedersen +Signed-off-by: Jonathan McDowell +Link: https://lore.kernel.org/r/20201114140233.GM32650@earth.li +Signed-off-by: Vinod Koul --- - drivers/dma/qcom/Kconfig | 10 + + drivers/dma/qcom/Kconfig | 11 + drivers/dma/qcom/Makefile | 1 + - drivers/dma/qcom/qcom_adm.c | 900 ++++++++++++++++++++++++++++++++++++++++++++ - 3 files changed, 911 insertions(+) + drivers/dma/qcom/qcom_adm.c | 903 ++++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 915 insertions(+) create mode 100644 drivers/dma/qcom/qcom_adm.c +diff --git a/drivers/dma/qcom/Kconfig b/drivers/dma/qcom/Kconfig +index 3bcb689162c67..0389d60d2604a 100644 --- a/drivers/dma/qcom/Kconfig +++ b/drivers/dma/qcom/Kconfig -@@ -28,3 +28,13 @@ config QCOM_HIDMA - (user to kernel, kernel to kernel, etc.). It only supports - memcpy interface. The core is not intended for general - purpose slave DMA. -+ +@@ -1,4 +1,15 @@ + # SPDX-License-Identifier: GPL-2.0-only +config QCOM_ADM + tristate "Qualcomm ADM support" -+ depends on ARCH_QCOM || (COMPILE_TEST && OF && ARM) ++ depends on (ARCH_QCOM || COMPILE_TEST) && !PHYS_ADDR_T_64BIT + select DMA_ENGINE + select DMA_VIRTUAL_CHANNELS -+ ---help--- -+ Enable support for the Qualcomm ADM DMA controller. This controller -+ provides DMA capabilities for both general purpose and on-chip -+ peripheral devices. ++ help ++ Enable support for the Qualcomm Application Data Mover (ADM) DMA ++ controller, as present on MSM8x60, APQ8064, and IPQ8064 devices. ++ This controller provides DMA capabilities for both general purpose ++ and on-chip peripheral devices. ++ + config QCOM_BAM_DMA + tristate "QCOM BAM DMA support" + depends on ARCH_QCOM || (COMPILE_TEST && OF && ARM) +diff --git a/drivers/dma/qcom/Makefile b/drivers/dma/qcom/Makefile +index 1ae92da88b0c9..346e643fbb6db 100644 --- a/drivers/dma/qcom/Makefile +++ b/drivers/dma/qcom/Makefile -@@ -4,3 +4,4 @@ obj-$(CONFIG_QCOM_HIDMA_MGMT) += hdma_mg - hdma_mgmt-objs := hidma_mgmt.o hidma_mgmt_sys.o - obj-$(CONFIG_QCOM_HIDMA) += hdma.o - hdma-objs := hidma_ll.o hidma.o hidma_dbg.o +@@ -1,4 +1,5 @@ + # SPDX-License-Identifier: GPL-2.0 +obj-$(CONFIG_QCOM_ADM) += qcom_adm.o + obj-$(CONFIG_QCOM_BAM_DMA) += bam_dma.o + obj-$(CONFIG_QCOM_HIDMA_MGMT) += hdma_mgmt.o + hdma_mgmt-objs := hidma_mgmt.o hidma_mgmt_sys.o +diff --git a/drivers/dma/qcom/qcom_adm.c b/drivers/dma/qcom/qcom_adm.c +new file mode 100644 +index 0000000000000..9b6f8e050ecce --- /dev/null +++ b/drivers/dma/qcom/qcom_adm.c -@@ -0,0 +1,914 @@ +@@ -0,0 +1,903 @@ ++// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 and -+ * only version 2 as published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * + */ + -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include ++#include ++#include +#include -+#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include +#include +#include +#include +#include ++#include +#include -+#include -+#include ++#include ++#include + +#include "../dmaengine.h" +#include "../virt-dma.h" @@ -90,10 +99,10 @@ Signed-off-by: Thomas Pedersen +#define ADM_CI_MULTI 0x4 +#define ADM_CRCI_MULTI 0x4 +#define ADM_EE_MULTI 0x800 -+#define ADM_CHAN_OFFS(chan) (ADM_CHAN_MULTI * chan) -+#define ADM_EE_OFFS(ee) (ADM_EE_MULTI * ee) ++#define ADM_CHAN_OFFS(chan) (ADM_CHAN_MULTI * (chan)) ++#define ADM_EE_OFFS(ee) (ADM_EE_MULTI * (ee)) +#define ADM_CHAN_EE_OFFS(chan, ee) (ADM_CHAN_OFFS(chan) + ADM_EE_OFFS(ee)) -+#define ADM_CHAN_OFFS(chan) (ADM_CHAN_MULTI * chan) ++#define ADM_CHAN_OFFS(chan) (ADM_CHAN_MULTI * (chan)) +#define ADM_CI_OFFS(ci) (ADM_CHAN_OFF(ci)) +#define ADM_CH_CMD_PTR(chan, ee) (ADM_CHAN_EE_OFFS(chan, ee)) +#define ADM_CH_RSLT(chan, ee) (0x40 + ADM_CHAN_EE_OFFS(chan, ee)) @@ -102,62 +111,62 @@ Signed-off-by: Thomas Pedersen +#define ADM_CH_CONF(chan) (0x240 + ADM_CHAN_OFFS(chan)) +#define ADM_CH_RSLT_CONF(chan, ee) (0x300 + ADM_CHAN_EE_OFFS(chan, ee)) +#define ADM_SEC_DOMAIN_IRQ_STATUS(ee) (0x380 + ADM_EE_OFFS(ee)) -+#define ADM_CI_CONF(ci) (0x390 + ci * ADM_CI_MULTI) ++#define ADM_CI_CONF(ci) (0x390 + (ci) * ADM_CI_MULTI) +#define ADM_GP_CTL 0x3d8 -+#define ADM_CRCI_CTL(crci, ee) (0x400 + crci * ADM_CRCI_MULTI + \ ++#define ADM_CRCI_CTL(crci, ee) (0x400 + (crci) * ADM_CRCI_MULTI + \ + ADM_EE_OFFS(ee)) + +/* channel status */ -+#define ADM_CH_STATUS_VALID BIT(1) ++#define ADM_CH_STATUS_VALID BIT(1) + +/* channel result */ -+#define ADM_CH_RSLT_VALID BIT(31) -+#define ADM_CH_RSLT_ERR BIT(3) -+#define ADM_CH_RSLT_FLUSH BIT(2) -+#define ADM_CH_RSLT_TPD BIT(1) ++#define ADM_CH_RSLT_VALID BIT(31) ++#define ADM_CH_RSLT_ERR BIT(3) ++#define ADM_CH_RSLT_FLUSH BIT(2) ++#define ADM_CH_RSLT_TPD BIT(1) + +/* channel conf */ +#define ADM_CH_CONF_SHADOW_EN BIT(12) +#define ADM_CH_CONF_MPU_DISABLE BIT(11) +#define ADM_CH_CONF_PERM_MPU_CONF BIT(9) +#define ADM_CH_CONF_FORCE_RSLT_EN BIT(7) -+#define ADM_CH_CONF_SEC_DOMAIN(ee) (((ee & 0x3) << 4) | ((ee & 0x4) << 11)) ++#define ADM_CH_CONF_SEC_DOMAIN(ee) ((((ee) & 0x3) << 4) | (((ee) & 0x4) << 11)) + +/* channel result conf */ +#define ADM_CH_RSLT_CONF_FLUSH_EN BIT(1) +#define ADM_CH_RSLT_CONF_IRQ_EN BIT(0) + +/* CRCI CTL */ -+#define ADM_CRCI_CTL_MUX_SEL BIT(18) -+#define ADM_CRCI_CTL_RST BIT(17) ++#define ADM_CRCI_CTL_MUX_SEL BIT(18) ++#define ADM_CRCI_CTL_RST BIT(17) + +/* CI configuration */ -+#define ADM_CI_RANGE_END(x) (x << 24) -+#define ADM_CI_RANGE_START(x) (x << 16) -+#define ADM_CI_BURST_4_WORDS BIT(2) -+#define ADM_CI_BURST_8_WORDS BIT(3) ++#define ADM_CI_RANGE_END(x) ((x) << 24) ++#define ADM_CI_RANGE_START(x) ((x) << 16) ++#define ADM_CI_BURST_4_WORDS BIT(2) ++#define ADM_CI_BURST_8_WORDS BIT(3) + +/* GP CTL */ -+#define ADM_GP_CTL_LP_EN BIT(12) -+#define ADM_GP_CTL_LP_CNT(x) (x << 8) ++#define ADM_GP_CTL_LP_EN BIT(12) ++#define ADM_GP_CTL_LP_CNT(x) ((x) << 8) + +/* Command pointer list entry */ -+#define ADM_CPLE_LP BIT(31) -+#define ADM_CPLE_CMD_PTR_LIST BIT(29) ++#define ADM_CPLE_LP BIT(31) ++#define ADM_CPLE_CMD_PTR_LIST BIT(29) + +/* Command list entry */ -+#define ADM_CMD_LC BIT(31) -+#define ADM_CMD_DST_CRCI(n) (((n) & 0xf) << 7) -+#define ADM_CMD_SRC_CRCI(n) (((n) & 0xf) << 3) ++#define ADM_CMD_LC BIT(31) ++#define ADM_CMD_DST_CRCI(n) (((n) & 0xf) << 7) ++#define ADM_CMD_SRC_CRCI(n) (((n) & 0xf) << 3) + -+#define ADM_CMD_TYPE_SINGLE 0x0 -+#define ADM_CMD_TYPE_BOX 0x3 ++#define ADM_CMD_TYPE_SINGLE 0x0 ++#define ADM_CMD_TYPE_BOX 0x3 + -+#define ADM_CRCI_MUX_SEL BIT(4) -+#define ADM_DESC_ALIGN 8 -+#define ADM_MAX_XFER (SZ_64K-1) -+#define ADM_MAX_ROWS (SZ_64K-1) -+#define ADM_MAX_CHANNELS 16 ++#define ADM_CRCI_MUX_SEL BIT(4) ++#define ADM_DESC_ALIGN 8 ++#define ADM_MAX_XFER (SZ_64K - 1) ++#define ADM_MAX_ROWS (SZ_64K - 1) ++#define ADM_MAX_CHANNELS 16 + +struct adm_desc_hw_box { + u32 cmd; @@ -255,7 +264,7 @@ Signed-off-by: Thomas Pedersen + case 32: + case 64: + case 128: -+ ret = ffs(burst>>4) - 1; ++ ret = ffs(burst >> 4) - 1; + break; + case 192: + ret = 4; @@ -281,9 +290,10 @@ Signed-off-by: Thomas Pedersen + * @burst: Burst size of transaction + * @direction: DMA transfer direction + */ -+static void *adm_process_fc_descriptors(struct adm_chan *achan, -+ void *desc, struct scatterlist *sg, u32 crci, u32 burst, -+ enum dma_transfer_direction direction) ++static void *adm_process_fc_descriptors(struct adm_chan *achan, void *desc, ++ struct scatterlist *sg, u32 crci, ++ u32 burst, ++ enum dma_transfer_direction direction) +{ + struct adm_desc_hw_box *box_desc = NULL; + struct adm_desc_hw_single *single_desc; @@ -349,9 +359,9 @@ Signed-off-by: Thomas Pedersen + * @sg: Scatterlist entry + * @direction: DMA transfer direction + */ -+static void *adm_process_non_fc_descriptors(struct adm_chan *achan, -+ void *desc, struct scatterlist *sg, -+ enum dma_transfer_direction direction) ++static void *adm_process_non_fc_descriptors(struct adm_chan *achan, void *desc, ++ struct scatterlist *sg, ++ enum dma_transfer_direction direction) +{ + struct adm_desc_hw_single *single_desc; + u32 remainder = sg_dma_len(sg); @@ -398,9 +408,11 @@ Signed-off-by: Thomas Pedersen + * @context: transfer context (unused) + */ +static struct dma_async_tx_descriptor *adm_prep_slave_sg(struct dma_chan *chan, -+ struct scatterlist *sgl, unsigned int sg_len, -+ enum dma_transfer_direction direction, unsigned long flags, -+ void *context) ++ struct scatterlist *sgl, ++ unsigned int sg_len, ++ enum dma_transfer_direction direction, ++ unsigned long flags, ++ void *context) +{ + struct adm_chan *achan = to_adm_chan(chan); + struct adm_device *adev = achan->adev; @@ -427,7 +439,6 @@ Signed-off-by: Thomas Pedersen + + /* if using flow control, validate burst and crci values */ + if (achan->slave.device_fc) { -+ + blk_size = adm_get_blksize(burst); + if (blk_size < 0) { + dev_err(adev->dev, "invalid burst value: %d\n", @@ -455,7 +466,7 @@ Signed-off-by: Thomas Pedersen + } + } + -+ async_desc = kzalloc(sizeof(*async_desc), GFP_ATOMIC); ++ async_desc = kzalloc(sizeof(*async_desc), GFP_NOWAIT); + if (!async_desc) + return ERR_PTR(-ENOMEM); + @@ -468,7 +479,7 @@ Signed-off-by: Thomas Pedersen + box_count * sizeof(struct adm_desc_hw_box) + + sizeof(*cple) + 2 * ADM_DESC_ALIGN; + -+ async_desc->cpl = kzalloc(async_desc->dma_len, GFP_ATOMIC); ++ async_desc->cpl = kzalloc(async_desc->dma_len, GFP_NOWAIT); + if (!async_desc->cpl) + goto free; + @@ -483,10 +494,10 @@ Signed-off-by: Thomas Pedersen + + if (achan->slave.device_fc) + desc = adm_process_fc_descriptors(achan, desc, sg, crci, -+ burst, direction); ++ burst, direction); + else + desc = adm_process_non_fc_descriptors(achan, desc, sg, -+ direction); ++ direction); + } + + async_desc->dma_addr = dma_map_single(adev->dev, async_desc->cpl, @@ -532,7 +543,7 @@ Signed-off-by: Thomas Pedersen + + /* send flush command to terminate current transaction */ + writel_relaxed(0x0, -+ adev->regs + ADM_CH_FLUSH_STATE0(achan->id, adev->ee)); ++ adev->regs + ADM_CH_FLUSH_STATE0(achan->id, adev->ee)); + + spin_unlock_irqrestore(&achan->vc.lock, flags); + @@ -586,7 +597,7 @@ Signed-off-by: Thomas Pedersen + adev->regs + ADM_CH_CONF(achan->id)); + + writel(ADM_CH_RSLT_CONF_IRQ_EN | ADM_CH_RSLT_CONF_FLUSH_EN, -+ adev->regs + ADM_CH_RSLT_CONF(achan->id, adev->ee)); ++ adev->regs + ADM_CH_RSLT_CONF(achan->id, adev->ee)); + + achan->initialized = 1; + } @@ -594,7 +605,7 @@ Signed-off-by: Thomas Pedersen + /* set the crci block size if this transaction requires CRCI */ + if (async_desc->crci) { + writel(async_desc->mux | async_desc->blk_size, -+ adev->regs + ADM_CRCI_CTL(async_desc->crci, adev->ee)); ++ adev->regs + ADM_CRCI_CTL(async_desc->crci, adev->ee)); + } + + /* make sure IRQ enable doesn't get reordered */ @@ -602,7 +613,7 @@ Signed-off-by: Thomas Pedersen + + /* write next command list out to the CMD FIFO */ + writel(ALIGN(async_desc->dma_addr, ADM_DESC_ALIGN) >> 3, -+ adev->regs + ADM_CH_CMD_PTR(achan->id, adev->ee)); ++ adev->regs + ADM_CH_CMD_PTR(achan->id, adev->ee)); +} + +/** @@ -628,7 +639,7 @@ Signed-off-by: Thomas Pedersen + + if (srcs & BIT(i)) { + status = readl_relaxed(adev->regs + -+ ADM_CH_STATUS_SD(i, adev->ee)); ++ ADM_CH_STATUS_SD(i, adev->ee)); + + /* if no result present, skip */ + if (!(status & ADM_CH_STATUS_VALID)) @@ -673,7 +684,7 @@ Signed-off-by: Thomas Pedersen + * Return status of dma transaction + */ +static enum dma_status adm_tx_status(struct dma_chan *chan, dma_cookie_t cookie, -+ struct dma_tx_state *txstate) ++ struct dma_tx_state *txstate) +{ + struct adm_chan *achan = to_adm_chan(chan); + struct virt_dma_desc *vd; @@ -697,7 +708,7 @@ Signed-off-by: Thomas Pedersen + * residue is either the full length if it is in the issued list, or 0 + * if it is in progress. We have no reliable way of determining + * anything inbetween -+ */ ++ */ + dma_set_residue(txstate, residue); + + if (achan->error) @@ -741,7 +752,7 @@ Signed-off-by: Thomas Pedersen +} + +static void adm_channel_init(struct adm_device *adev, struct adm_chan *achan, -+ u32 index) ++ u32 index) +{ + achan->id = index; + achan->adev = adev; @@ -753,7 +764,6 @@ Signed-off-by: Thomas Pedersen +static int adm_dma_probe(struct platform_device *pdev) +{ + struct adm_device *adev; -+ struct resource *iores; + int ret; + u32 i; + @@ -763,8 +773,7 @@ Signed-off-by: Thomas Pedersen + + adev->dev = &pdev->dev; + -+ iores = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ adev->regs = devm_ioremap_resource(&pdev->dev, iores); ++ adev->regs = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(adev->regs)) + return PTR_ERR(adev->regs); + @@ -782,64 +791,60 @@ Signed-off-by: Thomas Pedersen + if (IS_ERR(adev->core_clk)) + return PTR_ERR(adev->core_clk); + ++ adev->iface_clk = devm_clk_get(adev->dev, "iface"); ++ if (IS_ERR(adev->iface_clk)) ++ return PTR_ERR(adev->iface_clk); ++ ++ adev->clk_reset = devm_reset_control_get_exclusive(&pdev->dev, "clk"); ++ if (IS_ERR(adev->clk_reset)) { ++ dev_err(adev->dev, "failed to get ADM0 reset\n"); ++ return PTR_ERR(adev->clk_reset); ++ } ++ ++ adev->c0_reset = devm_reset_control_get_exclusive(&pdev->dev, "c0"); ++ if (IS_ERR(adev->c0_reset)) { ++ dev_err(adev->dev, "failed to get ADM0 C0 reset\n"); ++ return PTR_ERR(adev->c0_reset); ++ } ++ ++ adev->c1_reset = devm_reset_control_get_exclusive(&pdev->dev, "c1"); ++ if (IS_ERR(adev->c1_reset)) { ++ dev_err(adev->dev, "failed to get ADM0 C1 reset\n"); ++ return PTR_ERR(adev->c1_reset); ++ } ++ ++ adev->c2_reset = devm_reset_control_get_exclusive(&pdev->dev, "c2"); ++ if (IS_ERR(adev->c2_reset)) { ++ dev_err(adev->dev, "failed to get ADM0 C2 reset\n"); ++ return PTR_ERR(adev->c2_reset); ++ } ++ + ret = clk_prepare_enable(adev->core_clk); + if (ret) { + dev_err(adev->dev, "failed to prepare/enable core clock\n"); + return ret; + } + -+ adev->iface_clk = devm_clk_get(adev->dev, "iface"); -+ if (IS_ERR(adev->iface_clk)) { -+ ret = PTR_ERR(adev->iface_clk); -+ goto err_disable_core_clk; -+ } -+ + ret = clk_prepare_enable(adev->iface_clk); + if (ret) { + dev_err(adev->dev, "failed to prepare/enable iface clock\n"); + goto err_disable_core_clk; + } + -+ adev->clk_reset = devm_reset_control_get(&pdev->dev, "clk"); -+ if (IS_ERR(adev->clk_reset)) { -+ dev_err(adev->dev, "failed to get ADM0 reset\n"); -+ ret = PTR_ERR(adev->clk_reset); -+ goto err_disable_clks; -+ } -+ -+ adev->c0_reset = devm_reset_control_get(&pdev->dev, "c0"); -+ if (IS_ERR(adev->c0_reset)) { -+ dev_err(adev->dev, "failed to get ADM0 C0 reset\n"); -+ ret = PTR_ERR(adev->c0_reset); -+ goto err_disable_clks; -+ } -+ -+ adev->c1_reset = devm_reset_control_get(&pdev->dev, "c1"); -+ if (IS_ERR(adev->c1_reset)) { -+ dev_err(adev->dev, "failed to get ADM0 C1 reset\n"); -+ ret = PTR_ERR(adev->c1_reset); -+ goto err_disable_clks; -+ } -+ -+ adev->c2_reset = devm_reset_control_get(&pdev->dev, "c2"); -+ if (IS_ERR(adev->c2_reset)) { -+ dev_err(adev->dev, "failed to get ADM0 C2 reset\n"); -+ ret = PTR_ERR(adev->c2_reset); -+ goto err_disable_clks; -+ } -+ + reset_control_assert(adev->clk_reset); + reset_control_assert(adev->c0_reset); + reset_control_assert(adev->c1_reset); + reset_control_assert(adev->c2_reset); + ++ udelay(2); ++ + reset_control_deassert(adev->clk_reset); + reset_control_deassert(adev->c0_reset); + reset_control_deassert(adev->c1_reset); + reset_control_deassert(adev->c2_reset); + + adev->channels = devm_kcalloc(adev->dev, ADM_MAX_CHANNELS, -+ sizeof(*adev->channels), GFP_KERNEL); ++ sizeof(*adev->channels), GFP_KERNEL); + + if (!adev->channels) { + ret = -ENOMEM; @@ -859,16 +864,16 @@ Signed-off-by: Thomas Pedersen + + /* configure client interfaces */ + writel(ADM_CI_RANGE_START(0x40) | ADM_CI_RANGE_END(0xb0) | -+ ADM_CI_BURST_8_WORDS, adev->regs + ADM_CI_CONF(0)); ++ ADM_CI_BURST_8_WORDS, adev->regs + ADM_CI_CONF(0)); + writel(ADM_CI_RANGE_START(0x2a) | ADM_CI_RANGE_END(0x2c) | -+ ADM_CI_BURST_8_WORDS, adev->regs + ADM_CI_CONF(1)); ++ ADM_CI_BURST_8_WORDS, adev->regs + ADM_CI_CONF(1)); + writel(ADM_CI_RANGE_START(0x12) | ADM_CI_RANGE_END(0x28) | -+ ADM_CI_BURST_8_WORDS, adev->regs + ADM_CI_CONF(2)); ++ ADM_CI_BURST_8_WORDS, adev->regs + ADM_CI_CONF(2)); + writel(ADM_GP_CTL_LP_EN | ADM_GP_CTL_LP_CNT(0xf), -+ adev->regs + ADM_GP_CTL); ++ adev->regs + ADM_GP_CTL); + + ret = devm_request_irq(adev->dev, adev->irq, adm_dma_irq, -+ 0, "adm_dma", adev); ++ 0, "adm_dma", adev); + if (ret) + goto err_disable_clks; + @@ -933,6 +938,7 @@ Signed-off-by: Thomas Pedersen + /* mask IRQs for this channel/EE pair */ + writel(0, adev->regs + ADM_CH_RSLT_CONF(achan->id, adev->ee)); + ++ tasklet_kill(&adev->channels[i].vc.task); + adm_terminate_all(&adev->channels[i].vc.chan); + } + @@ -964,3 +970,6 @@ Signed-off-by: Thomas Pedersen +MODULE_AUTHOR("Andy Gross "); +MODULE_DESCRIPTION("QCOM ADM DMA engine driver"); +MODULE_LICENSE("GPL v2"); +-- +cgit 1.2.3-1.el7 + diff --git a/target/linux/ipq806x/patches-5.4/101-5.12-mtd-parsers-Add-Qcom-SMEM-parser.patch b/target/linux/ipq806x/patches-5.4/101-5.12-mtd-parsers-Add-Qcom-SMEM-parser.patch new file mode 100644 index 0000000000..7aec4fcc83 --- /dev/null +++ b/target/linux/ipq806x/patches-5.4/101-5.12-mtd-parsers-Add-Qcom-SMEM-parser.patch @@ -0,0 +1,227 @@ +From 803eb124e1a64e42888542c3444bfe6dac412c7f Mon Sep 17 00:00:00 2001 +From: Manivannan Sadhasivam +Date: Mon, 4 Jan 2021 09:41:35 +0530 +Subject: mtd: parsers: Add Qcom SMEM parser + +NAND based Qualcomm platforms have the partition table populated in the +Shared Memory (SMEM). Hence, add a parser for parsing the partitions +from it. + +Signed-off-by: Manivannan Sadhasivam +Signed-off-by: Miquel Raynal +Link: https://lore.kernel.org/linux-mtd/20210104041137.113075-3-manivannan.sadhasivam@linaro.org +--- + drivers/mtd/parsers/Kconfig | 8 ++ + drivers/mtd/parsers/Makefile | 1 + + drivers/mtd/parsers/qcomsmempart.c | 170 +++++++++++++++++++++++++++++++++++++ + 3 files changed, 179 insertions(+) + create mode 100644 drivers/mtd/parsers/qcomsmempart.c + +diff --git a/drivers/mtd/parsers/Kconfig b/drivers/mtd/parsers/Kconfig +index e72354322f628..d90c302290522 100644 +--- a/drivers/mtd/parsers/Kconfig ++++ b/drivers/mtd/parsers/Kconfig +@@ -160,6 +160,14 @@ config MTD_REDBOOT_PARTS_READONLY + 'FIS directory' images, enable this option. + + endif # MTD_REDBOOT_PARTS ++ ++config MTD_QCOMSMEM_PARTS ++ tristate "Qualcomm SMEM NAND flash partition parser" ++ depends on MTD_NAND_QCOM || COMPILE_TEST ++ depends on QCOM_SMEM ++ help ++ This provides support for parsing partitions from Shared Memory (SMEM) ++ for NAND flash on Qualcomm platforms. + + config MTD_ROUTERBOOT_PARTS + tristate "RouterBoot flash partition parser" +diff --git a/drivers/mtd/parsers/Makefile b/drivers/mtd/parsers/Makefile +index b0c5f62f9e858..50eb0b0a22105 100644 +--- a/drivers/mtd/parsers/Makefile ++++ b/drivers/mtd/parsers/Makefile +@@ -9,4 +9,5 @@ obj-$(CONFIG_MTD_AFS_PARTS) += afs.o + obj-$(CONFIG_MTD_PARSER_TRX) += parser_trx.o + obj-$(CONFIG_MTD_SHARPSL_PARTS) += sharpslpart.o + obj-$(CONFIG_MTD_REDBOOT_PARTS) += redboot.o ++obj-$(CONFIG_MTD_QCOMSMEM_PARTS) += qcomsmempart.o + obj-$(CONFIG_MTD_ROUTERBOOT_PARTS) += routerbootpart.o +diff --git a/drivers/mtd/parsers/qcomsmempart.c b/drivers/mtd/parsers/qcomsmempart.c +new file mode 100644 +index 0000000000000..808cb33d71f8e +--- /dev/null ++++ b/drivers/mtd/parsers/qcomsmempart.c +@@ -0,0 +1,170 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* ++ * Qualcomm SMEM NAND flash partition parser ++ * ++ * Copyright (C) 2020, Linaro Ltd. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define SMEM_AARM_PARTITION_TABLE 9 ++#define SMEM_APPS 0 ++ ++#define SMEM_FLASH_PART_MAGIC1 0x55ee73aa ++#define SMEM_FLASH_PART_MAGIC2 0xe35ebddb ++#define SMEM_FLASH_PTABLE_V3 3 ++#define SMEM_FLASH_PTABLE_V4 4 ++#define SMEM_FLASH_PTABLE_MAX_PARTS_V3 16 ++#define SMEM_FLASH_PTABLE_MAX_PARTS_V4 48 ++#define SMEM_FLASH_PTABLE_HDR_LEN (4 * sizeof(u32)) ++#define SMEM_FLASH_PTABLE_NAME_SIZE 16 ++ ++/** ++ * struct smem_flash_pentry - SMEM Flash partition entry ++ * @name: Name of the partition ++ * @offset: Offset in blocks ++ * @length: Length of the partition in blocks ++ * @attr: Flags for this partition ++ */ ++struct smem_flash_pentry { ++ char name[SMEM_FLASH_PTABLE_NAME_SIZE]; ++ __le32 offset; ++ __le32 length; ++ u8 attr; ++} __packed __aligned(4); ++ ++/** ++ * struct smem_flash_ptable - SMEM Flash partition table ++ * @magic1: Partition table Magic 1 ++ * @magic2: Partition table Magic 2 ++ * @version: Partition table version ++ * @numparts: Number of partitions in this ptable ++ * @pentry: Flash partition entries belonging to this ptable ++ */ ++struct smem_flash_ptable { ++ __le32 magic1; ++ __le32 magic2; ++ __le32 version; ++ __le32 numparts; ++ struct smem_flash_pentry pentry[SMEM_FLASH_PTABLE_MAX_PARTS_V4]; ++} __packed __aligned(4); ++ ++static int parse_qcomsmem_part(struct mtd_info *mtd, ++ const struct mtd_partition **pparts, ++ struct mtd_part_parser_data *data) ++{ ++ struct smem_flash_pentry *pentry; ++ struct smem_flash_ptable *ptable; ++ size_t len = SMEM_FLASH_PTABLE_HDR_LEN; ++ struct mtd_partition *parts; ++ int ret, i, numparts; ++ char *name, *c; ++ ++ pr_debug("Parsing partition table info from SMEM\n"); ++ ptable = qcom_smem_get(SMEM_APPS, SMEM_AARM_PARTITION_TABLE, &len); ++ if (IS_ERR(ptable)) { ++ pr_err("Error reading partition table header\n"); ++ return PTR_ERR(ptable); ++ } ++ ++ /* Verify ptable magic */ ++ if (le32_to_cpu(ptable->magic1) != SMEM_FLASH_PART_MAGIC1 || ++ le32_to_cpu(ptable->magic2) != SMEM_FLASH_PART_MAGIC2) { ++ pr_err("Partition table magic verification failed\n"); ++ return -EINVAL; ++ } ++ ++ /* Ensure that # of partitions is less than the max we have allocated */ ++ numparts = le32_to_cpu(ptable->numparts); ++ if (numparts > SMEM_FLASH_PTABLE_MAX_PARTS_V4) { ++ pr_err("Partition numbers exceed the max limit\n"); ++ return -EINVAL; ++ } ++ ++ /* Find out length of partition data based on table version */ ++ if (le32_to_cpu(ptable->version) <= SMEM_FLASH_PTABLE_V3) { ++ len = SMEM_FLASH_PTABLE_HDR_LEN + SMEM_FLASH_PTABLE_MAX_PARTS_V3 * ++ sizeof(struct smem_flash_pentry); ++ } else if (le32_to_cpu(ptable->version) == SMEM_FLASH_PTABLE_V4) { ++ len = SMEM_FLASH_PTABLE_HDR_LEN + SMEM_FLASH_PTABLE_MAX_PARTS_V4 * ++ sizeof(struct smem_flash_pentry); ++ } else { ++ pr_err("Unknown ptable version (%d)", le32_to_cpu(ptable->version)); ++ return -EINVAL; ++ } ++ ++ /* ++ * Now that the partition table header has been parsed, verified ++ * and the length of the partition table calculated, read the ++ * complete partition table ++ */ ++ ptable = qcom_smem_get(SMEM_APPS, SMEM_AARM_PARTITION_TABLE, &len); ++ if (IS_ERR_OR_NULL(ptable)) { ++ pr_err("Error reading partition table\n"); ++ return PTR_ERR(ptable); ++ } ++ ++ parts = kcalloc(numparts, sizeof(*parts), GFP_KERNEL); ++ if (!parts) ++ return -ENOMEM; ++ ++ for (i = 0; i < numparts; i++) { ++ pentry = &ptable->pentry[i]; ++ if (pentry->name[0] == '\0') ++ continue; ++ ++ name = kstrdup(pentry->name, GFP_KERNEL); ++ if (!name) { ++ ret = -ENOMEM; ++ goto out_free_parts; ++ } ++ ++ /* Convert name to lower case */ ++ for (c = name; *c != '\0'; c++) ++ *c = tolower(*c); ++ ++ parts[i].name = name; ++ parts[i].offset = le32_to_cpu(pentry->offset) * mtd->erasesize; ++ parts[i].mask_flags = pentry->attr; ++ parts[i].size = le32_to_cpu(pentry->length) * mtd->erasesize; ++ pr_debug("%d: %s offs=0x%08x size=0x%08x attr:0x%08x\n", ++ i, pentry->name, le32_to_cpu(pentry->offset), ++ le32_to_cpu(pentry->length), pentry->attr); ++ } ++ ++ pr_debug("SMEM partition table found: ver: %d len: %d\n", ++ le32_to_cpu(ptable->version), numparts); ++ *pparts = parts; ++ ++ return numparts; ++ ++out_free_parts: ++ while (--i >= 0) ++ kfree(parts[i].name); ++ kfree(parts); ++ *pparts = NULL; ++ ++ return ret; ++} ++ ++static const struct of_device_id qcomsmem_of_match_table[] = { ++ { .compatible = "qcom,smem-part" }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, qcomsmem_of_match_table); ++ ++static struct mtd_part_parser mtd_parser_qcomsmem = { ++ .parse_fn = parse_qcomsmem_part, ++ .name = "qcomsmem", ++ .of_match_table = qcomsmem_of_match_table, ++}; ++module_mtd_part_parser(mtd_parser_qcomsmem); ++ ++MODULE_LICENSE("GPL v2"); ++MODULE_AUTHOR("Manivannan Sadhasivam "); ++MODULE_DESCRIPTION("Qualcomm SMEM NAND flash partition parser"); +-- +cgit 1.2.3-1.el7 + diff --git a/target/linux/ipq806x/patches-5.4/102-mtd-rootfs-conflicts-with-OpenWrt-auto-mounting.patch b/target/linux/ipq806x/patches-5.4/102-mtd-rootfs-conflicts-with-OpenWrt-auto-mounting.patch new file mode 100644 index 0000000000..e83872935f --- /dev/null +++ b/target/linux/ipq806x/patches-5.4/102-mtd-rootfs-conflicts-with-OpenWrt-auto-mounting.patch @@ -0,0 +1,24 @@ +From 5001f2e1a325b68dbf225bd17f69a4d3d975cca5 Mon Sep 17 00:00:00 2001 +From: John Crispin +Date: Thu, 9 Mar 2017 09:31:44 +0100 +Subject: [PATCH 61/69] mtd: "rootfs" conflicts with OpenWrt auto mounting + +Signed-off-by: John Crispin +--- + drivers/mtd/parsers/qcomsmempart.c | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/drivers/mtd/parsers/qcomsmempart.c ++++ b/drivers/mtd/parsers/qcomsmempart.c +@@ -132,6 +132,11 @@ static int parse_qcomsmem_part(struct mt + parts[i].offset = le32_to_cpu(pentry->offset) * mtd->erasesize; + parts[i].mask_flags = pentry->attr; + parts[i].size = le32_to_cpu(pentry->length) * mtd->erasesize; ++ ++ /* "rootfs" conflicts with OpenWrt auto mounting */ ++ if (mtd_type_is_nand(mtd) && !strcmp(name, "rootfs")) ++ parts[i].name = "ubi"; ++ + pr_debug("%d: %s offs=0x%08x size=0x%08x attr:0x%08x\n", + i, pentry->name, le32_to_cpu(pentry->offset), + le32_to_cpu(pentry->length), pentry->attr); From e2b0ad1114d46bc4dc1c89a9a4a7636e2c209c60 Mon Sep 17 00:00:00 2001 From: Ansuel Smith Date: Mon, 1 Mar 2021 01:08:56 +0100 Subject: [PATCH 17/62] ipq806x: drop cpuidle generic support from QCOM The spm driver now has dedicated support for krait cpu idle state. We don't need to add generic arm cpuidle support for qcom. Signed-off-by: Ansuel Smith --- ...le-Add-cpuidle-support-for-QCOM-cpus.patch | 29 ------------------- 1 file changed, 29 deletions(-) delete mode 100644 target/linux/ipq806x/patches-5.10/0059-ARM-cpuidle-Add-cpuidle-support-for-QCOM-cpus.patch diff --git a/target/linux/ipq806x/patches-5.10/0059-ARM-cpuidle-Add-cpuidle-support-for-QCOM-cpus.patch b/target/linux/ipq806x/patches-5.10/0059-ARM-cpuidle-Add-cpuidle-support-for-QCOM-cpus.patch deleted file mode 100644 index 7d6e3f1605..0000000000 --- a/target/linux/ipq806x/patches-5.10/0059-ARM-cpuidle-Add-cpuidle-support-for-QCOM-cpus.patch +++ /dev/null @@ -1,29 +0,0 @@ -From 04ca10340f1b4d92e849724d322a7ca225d11539 Mon Sep 17 00:00:00 2001 -From: Lina Iyer -Date: Wed, 25 Mar 2015 14:25:29 -0600 -Subject: [PATCH 59/69] ARM: cpuidle: Add cpuidle support for QCOM cpus - -Define ARM_QCOM_CPUIDLE config item to enable cpuidle support. - -Cc: Stephen Boyd -Cc: Arnd Bergmann -Cc: Kevin Hilman -Cc: Daniel Lezcano -Signed-off-by: Lina Iyer ---- - drivers/cpuidle/Kconfig.arm | 7 +++++++ - 1 file changed, 7 insertions(+) - ---- a/drivers/cpuidle/Kconfig.arm -+++ b/drivers/cpuidle/Kconfig.arm -@@ -86,3 +86,10 @@ config ARM_MVEBU_V7_CPUIDLE - depends on ARCH_MVEBU && !ARM64 - help - Select this to enable cpuidle on Armada 370, 38x and XP processors. -+ -+config ARM_QCOM_CPUIDLE -+ bool "CPU Idle Driver for QCOM processors" -+ depends on ARCH_QCOM -+ select ARM_CPUIDLE -+ help -+ Select this to enable cpuidle on QCOM processors. From e17fb62293d59861646ad20aca6d440a7c08b45a Mon Sep 17 00:00:00 2001 From: Ansuel Smith Date: Mon, 1 Mar 2021 01:10:03 +0100 Subject: [PATCH 18/62] ipq806x: drop upstream patch Drop upstream patch already included in the kernel 5.10 Signed-off-by: Ansuel Smith --- ...RM-dts-qcom-add-gpio-ranges-property.patch | 70 -- ...s-qcom-add-scm-definition-to-ipq806x.patch | 29 - ...e-scm_call-to-route-GPIO-irq-to-Apps.patch | 104 --- ...Fixed-missing-RGMII-pincontrol-defin.patch | 56 -- ...t-disable-pretimeout-on-timer-platfo.patch | 98 --- ...ed-the-enable-regs-and-mask-for-PRNG.patch | 28 - .../090-v5.8-clk-clk-rpm-fixes.patch | 90 --- ...91-v5.8-regulator-add-smb208-support.patch | 63 -- ...mem-Add-support-for-krait-based-socs.patch | 361 ---------- ...eq-qcom-fix-wrong-compatible-binding.patch | 26 - ...Use-bulk-clk-api-and-assert-on-error.patch | 228 ------- ...6x-PCI-qcom-Add-ipq8064-rev2-variant.patch | 36 - ...om-Support-pci-speed-set-for-ipq806x.patch | 74 --- ...06x-net-mdio-add-ipq8064-mdio-driver.patch | 216 ------ ...-add-qcom-ipq806x-dwc-usb-phy-driver.patch | 621 ------------------ ..._5db-when-device-property-read-fails.patch | 31 - 16 files changed, 2131 deletions(-) delete mode 100644 target/linux/ipq806x/patches-5.10/080-v5.7-ARM-dts-qcom-add-gpio-ranges-property.patch delete mode 100644 target/linux/ipq806x/patches-5.10/081-v5.8-ARM-dts-qcom-add-scm-definition-to-ipq806x.patch delete mode 100644 target/linux/ipq806x/patches-5.10/086-v5.8-pinctrl-qom-use-scm_call-to-route-GPIO-irq-to-Apps.patch delete mode 100644 target/linux/ipq806x/patches-5.10/087-v5.8-ipq8064-pinctrl-Fixed-missing-RGMII-pincontrol-defin.patch delete mode 100644 target/linux/ipq806x/patches-5.10/088-v5.8-watchdog-qcom-wdt-disable-pretimeout-on-timer-platfo.patch delete mode 100644 target/linux/ipq806x/patches-5.10/089-v5.8-ipq806x-gcc-Added-the-enable-regs-and-mask-for-PRNG.patch delete mode 100644 target/linux/ipq806x/patches-5.10/090-v5.8-clk-clk-rpm-fixes.patch delete mode 100644 target/linux/ipq806x/patches-5.10/091-v5.8-regulator-add-smb208-support.patch delete mode 100644 target/linux/ipq806x/patches-5.10/092-1-v5.7-qcom-cpufreq-nvmem-Add-support-for-krait-based-socs.patch delete mode 100644 target/linux/ipq806x/patches-5.10/092-2-v5.7-cpufreq-qcom-fix-wrong-compatible-binding.patch delete mode 100644 target/linux/ipq806x/patches-5.10/093-4-v5.8-ipq806x-PCI-qcom-Use-bulk-clk-api-and-assert-on-error.patch delete mode 100644 target/linux/ipq806x/patches-5.10/093-7-v5.8-ipq806x-PCI-qcom-Add-ipq8064-rev2-variant.patch delete mode 100644 target/linux/ipq806x/patches-5.10/093-8-v5.8-ipq806x-PCI-qcom-Support-pci-speed-set-for-ipq806x.patch delete mode 100644 target/linux/ipq806x/patches-5.10/094-v5.7-ipq806x-net-mdio-add-ipq8064-mdio-driver.patch delete mode 100644 target/linux/ipq806x/patches-5.10/095-1-v5.9-phy-qualcomm-add-qcom-ipq806x-dwc-usb-phy-driver.patch delete mode 100644 target/linux/ipq806x/patches-5.10/095-2-v5.9-phy-qualcomm-fix-setting-of-tx_deamp_3_5db-when-device-property-read-fails.patch diff --git a/target/linux/ipq806x/patches-5.10/080-v5.7-ARM-dts-qcom-add-gpio-ranges-property.patch b/target/linux/ipq806x/patches-5.10/080-v5.7-ARM-dts-qcom-add-gpio-ranges-property.patch deleted file mode 100644 index 0dc9debbfd..0000000000 --- a/target/linux/ipq806x/patches-5.10/080-v5.7-ARM-dts-qcom-add-gpio-ranges-property.patch +++ /dev/null @@ -1,70 +0,0 @@ -From patchwork Mon May 21 20:57:38 2018 -Content-Type: text/plain; charset="utf-8" -MIME-Version: 1.0 -Content-Transfer-Encoding: 7bit -Subject: [v5,3/4] ARM: dts: qcom: add gpio-ranges property -X-Patchwork-Submitter: Christian Lamparter -X-Patchwork-Id: 917856 -Message-Id: <0ae3376606a89bcdf3fe753a5c967f7103699e09.1526935804.git.chunkeey@gmail.com> -To: linux-gpio@vger.kernel.org, linux-arm-kernel@lists.infradead.org, - linux-arm-msm@vger.kernel.org, devicetree@vger.kernel.org -Cc: Bjorn Andersson , - Linus Walleij , - Stephen Boyd , David Brown , - Rob Herring , Mark Rutland , - Andy Gross , - Sven Eckelmann -Date: Mon, 21 May 2018 22:57:38 +0200 -From: Christian Lamparter -List-Id: - -This patch adds the gpio-ranges property to almost all of -the Qualcomm ARM platforms that utilize the pinctrl-msm -framework. - -The gpio-ranges property is part of the gpiolib subsystem. -As a result, the binding text is available in section -"2.1 gpio- and pin-controller interaction" of -Documentation/devicetree/bindings/gpio/gpio.txt - -For more information please see the patch titled: -"pinctrl: msm: fix gpio-hog related boot issues" from -this series. - -Reported-by: Sven Eckelmann -Tested-by: Sven Eckelmann [ipq4019] -Reviewed-by: Bjorn Andersson -Signed-off-by: Christian Lamparter -Reviewed-by: Linus Walleij ---- -To help with git bisect, the DT update patch has been intentionally -placed after the "pinctrl: msm: fix gpio-hog related boot issues". -Otherwise - if the order was reveresed - and bisect decides to split -between these two patches, the gpiochip_add_pin_ranges() function -will be executed twice with the same parameters for the same pinctrl. ---- - arch/arm/boot/dts/qcom-apq8064.dtsi | 1 + - arch/arm/boot/dts/qcom-apq8084.dtsi | 1 + - arch/arm/boot/dts/qcom-ipq4019.dtsi | 1 + - arch/arm/boot/dts/qcom-ipq8064.dtsi | 1 + - arch/arm/boot/dts/qcom-mdm9615.dtsi | 1 + - arch/arm/boot/dts/qcom-msm8660.dtsi | 1 + - arch/arm/boot/dts/qcom-msm8960.dtsi | 1 + - arch/arm/boot/dts/qcom-msm8974.dtsi | 1 + - arch/arm64/boot/dts/qcom/ipq8074.dtsi | 3 ++- - arch/arm64/boot/dts/qcom/msm8916.dtsi | 1 + - arch/arm64/boot/dts/qcom/msm8992.dtsi | 1 + - arch/arm64/boot/dts/qcom/msm8994.dtsi | 1 + - arch/arm64/boot/dts/qcom/msm8996.dtsi | 1 + - 13 files changed, 14 insertions(+), 1 deletion(-) - ---- a/arch/arm/boot/dts/qcom-ipq8064.dtsi -+++ b/arch/arm/boot/dts/qcom-ipq8064.dtsi -@@ -119,6 +119,7 @@ - reg = <0x800000 0x4000>; - - gpio-controller; -+ gpio-ranges = <&qcom_pinmux 0 0 69>; - #gpio-cells = <2>; - interrupt-controller; - #interrupt-cells = <2>; diff --git a/target/linux/ipq806x/patches-5.10/081-v5.8-ARM-dts-qcom-add-scm-definition-to-ipq806x.patch b/target/linux/ipq806x/patches-5.10/081-v5.8-ARM-dts-qcom-add-scm-definition-to-ipq806x.patch deleted file mode 100644 index f5483ac734..0000000000 --- a/target/linux/ipq806x/patches-5.10/081-v5.8-ARM-dts-qcom-add-scm-definition-to-ipq806x.patch +++ /dev/null @@ -1,29 +0,0 @@ -From 51befb888f62b1a62434fb4b82328d698a30f9de Mon Sep 17 00:00:00 2001 -From: Ansuel Smith -Date: Thu, 19 Mar 2020 23:44:24 +0100 -Subject: ARM: dts: qcom: add scm definition to ipq806x - -Add missing scm definition for ipq806x soc - -Signed-off-by: Ansuel Smith -Link: https://lore.kernel.org/r/20200319224424.18473-1-ansuelsmth@gmail.com -Signed-off-by: Bjorn Andersson ---- - arch/arm/boot/dts/qcom-ipq8064.dtsi | 6 ++++++ - 1 file changed, 6 insertions(+) - ---- a/arch/arm/boot/dts/qcom-ipq8064.dtsi -+++ b/arch/arm/boot/dts/qcom-ipq8064.dtsi -@@ -93,6 +93,12 @@ - }; - }; - -+ firmware { -+ scm { -+ compatible = "qcom,scm-ipq806x", "qcom,scm"; -+ }; -+ }; -+ - soc: soc { - #address-cells = <1>; - #size-cells = <1>; diff --git a/target/linux/ipq806x/patches-5.10/086-v5.8-pinctrl-qom-use-scm_call-to-route-GPIO-irq-to-Apps.patch b/target/linux/ipq806x/patches-5.10/086-v5.8-pinctrl-qom-use-scm_call-to-route-GPIO-irq-to-Apps.patch deleted file mode 100644 index 2b5171fc54..0000000000 --- a/target/linux/ipq806x/patches-5.10/086-v5.8-pinctrl-qom-use-scm_call-to-route-GPIO-irq-to-Apps.patch +++ /dev/null @@ -1,104 +0,0 @@ -From 13bec8d49bdf10aab4e1570ef42417f6bfbb6126 Mon Sep 17 00:00:00 2001 -From: Ajay Kishore -Date: Fri, 27 Mar 2020 23:32:08 +0100 -Subject: pinctrl: qcom: use scm_call to route GPIO irq to Apps - -For IPQ806x targets, TZ protects the registers that are used to -configure the routing of interrupts to a target processor. -To resolve this, this patch uses scm call to route GPIO interrupts -to application processor. Also the scm call interface is changed. - -Signed-off-by: Ajay Kishore -Signed-off-by: Ansuel Smith -Link: https://lore.kernel.org/r/20200327223209.20409-1-ansuelsmth@gmail.com -Reviewed-by: Bjorn Andersson -Signed-off-by: Linus Walleij ---- - drivers/pinctrl/qcom/pinctrl-msm.c | 43 ++++++++++++++++++++++++++++++++------ - 1 file changed, 37 insertions(+), 6 deletions(-) - -(limited to 'drivers/pinctrl/qcom/pinctrl-msm.c') - ---- a/drivers/pinctrl/qcom/pinctrl-msm.c -+++ b/drivers/pinctrl/qcom/pinctrl-msm.c -@@ -22,6 +22,8 @@ - #include - #include - #include -+#include -+#include - - #include "../core.h" - #include "../pinconf.h" -@@ -57,6 +59,8 @@ struct msm_pinctrl { - struct irq_chip irq_chip; - int irq; - -+ bool intr_target_use_scm; -+ - raw_spinlock_t lock; - - DECLARE_BITMAP(dual_edge_irqs, MAX_NR_GPIO); -@@ -64,6 +68,7 @@ struct msm_pinctrl { - - const struct msm_pinctrl_soc_data *soc; - void __iomem *regs[MAX_NR_TILES]; -+ u32 phys_base[MAX_NR_TILES]; - }; - - #define MSM_ACCESSOR(name) \ -@@ -832,11 +837,30 @@ static int msm_gpio_irq_set_type(struct - else - clear_bit(d->hwirq, pctrl->dual_edge_irqs); - -- /* Route interrupts to application cpu */ -- val = msm_readl_intr_target(pctrl, g); -- val &= ~(7 << g->intr_target_bit); -- val |= g->intr_target_kpss_val << g->intr_target_bit; -- msm_writel_intr_target(val, pctrl, g); -+ /* Route interrupts to application cpu. -+ * With intr_target_use_scm interrupts are routed to -+ * application cpu using scm calls. -+ */ -+ if (pctrl->intr_target_use_scm) { -+ u32 addr = pctrl->phys_base[0] + g->intr_target_reg; -+ int ret; -+ -+ qcom_scm_io_readl(addr, &val); -+ -+ val &= ~(7 << g->intr_target_bit); -+ val |= g->intr_target_kpss_val << g->intr_target_bit; -+ -+ ret = qcom_scm_io_writel(addr, val); -+ if (ret) -+ dev_err(pctrl->dev, -+ "Failed routing %lu interrupt to Apps proc", -+ d->hwirq); -+ } else { -+ val = msm_readl_intr_target(pctrl, g); -+ val &= ~(7 << g->intr_target_bit); -+ val |= g->intr_target_kpss_val << g->intr_target_bit; -+ msm_writel_intr_target(val, pctrl, g); -+ } - - /* Update configuration for gpio. - * RAW_STATUS_EN is left on for all gpio irqs. Due to the -@@ -1138,6 +1162,9 @@ int msm_pinctrl_probe(struct platform_de - pctrl->dev = &pdev->dev; - pctrl->soc = soc_data; - pctrl->chip = msm_gpio_template; -+ pctrl->intr_target_use_scm = of_device_is_compatible( -+ pctrl->dev->of_node, -+ "qcom,ipq8064-pinctrl"); - - raw_spin_lock_init(&pctrl->lock); - -@@ -1154,6 +1181,8 @@ int msm_pinctrl_probe(struct platform_de - pctrl->regs[0] = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(pctrl->regs[0])) - return PTR_ERR(pctrl->regs[0]); -+ -+ pctrl->phys_base[0] = res->start; - } - - msm_pinctrl_setup_pm_reset(pctrl); diff --git a/target/linux/ipq806x/patches-5.10/087-v5.8-ipq8064-pinctrl-Fixed-missing-RGMII-pincontrol-defin.patch b/target/linux/ipq806x/patches-5.10/087-v5.8-ipq8064-pinctrl-Fixed-missing-RGMII-pincontrol-defin.patch deleted file mode 100644 index 612c33cd0e..0000000000 --- a/target/linux/ipq806x/patches-5.10/087-v5.8-ipq8064-pinctrl-Fixed-missing-RGMII-pincontrol-defin.patch +++ /dev/null @@ -1,56 +0,0 @@ -From 8d8cec9bf6e9260397872785f249dfb59a417d08 Mon Sep 17 00:00:00 2001 -From: Ansuel Smith -Date: Wed, 19 Feb 2020 18:59:39 +0100 -Subject: ipq8064: pinctrl: Fixed missing RGMII pincontrol definitions - -Add missing gpio definition for mdio and rgmii2. - -Signed-off-by: Ram Chandra Jangir -Signed-off-by: Ansuel Smith -Link: https://lore.kernel.org/r/20200219175940.744-1-ansuelsmth@gmail.com -Acked-by: Bjorn Andersson -Signed-off-by: Linus Walleij ---- - drivers/pinctrl/qcom/pinctrl-ipq8064.c | 10 +++++----- - 1 file changed, 5 insertions(+), 5 deletions(-) - ---- a/drivers/pinctrl/qcom/pinctrl-ipq8064.c -+++ b/drivers/pinctrl/qcom/pinctrl-ipq8064.c -@@ -299,7 +299,7 @@ static const char * const gpio_groups[] - }; - - static const char * const mdio_groups[] = { -- "gpio0", "gpio1", "gpio10", "gpio11", -+ "gpio0", "gpio1", "gpio2", "gpio10", "gpio11", "gpio66", - }; - - static const char * const mi2s_groups[] = { -@@ -403,8 +403,8 @@ static const char * const usb2_hsic_grou - }; - - static const char * const rgmii2_groups[] = { -- "gpio27", "gpio28", "gpio29", "gpio30", "gpio31", "gpio32", -- "gpio51", "gpio52", "gpio59", "gpio60", "gpio61", "gpio62", -+ "gpio2", "gpio27", "gpio28", "gpio29", "gpio30", "gpio31", "gpio32", -+ "gpio51", "gpio52", "gpio59", "gpio60", "gpio61", "gpio62", "gpio66", - }; - - static const char * const sata_groups[] = { -@@ -539,7 +539,7 @@ static const struct msm_function ipq8064 - static const struct msm_pingroup ipq8064_groups[] = { - PINGROUP(0, mdio, NA, NA, NA, NA, NA, NA, NA, NA, NA), - PINGROUP(1, mdio, NA, NA, NA, NA, NA, NA, NA, NA, NA), -- PINGROUP(2, gsbi5_spi_cs3, NA, NA, NA, NA, NA, NA, NA, NA, NA), -+ PINGROUP(2, gsbi5_spi_cs3, rgmii2, mdio, NA, NA, NA, NA, NA, NA, NA), - PINGROUP(3, pcie1_rst, pcie1_prsnt, pdm, NA, NA, NA, NA, NA, NA, NA), - PINGROUP(4, pcie1_pwren_n, pcie1_pwren, NA, NA, NA, NA, NA, NA, NA, NA), - PINGROUP(5, pcie1_clk_req, pcie1_pwrflt, NA, NA, NA, NA, NA, NA, NA, NA), -@@ -603,7 +603,7 @@ static const struct msm_pingroup ipq8064 - PINGROUP(63, pcie3_rst, NA, NA, NA, NA, NA, NA, NA, NA, NA), - PINGROUP(64, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA), - PINGROUP(65, pcie3_clk_req, NA, NA, NA, NA, NA, NA, NA, NA, NA), -- PINGROUP(66, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA), -+ PINGROUP(66, rgmii2, mdio, NA, NA, NA, NA, NA, NA, NA, NA), - PINGROUP(67, usb2_hsic, NA, NA, NA, NA, NA, NA, NA, NA, NA), - PINGROUP(68, usb2_hsic, NA, NA, NA, NA, NA, NA, NA, NA, NA), - SDC_PINGROUP(sdc3_clk, 0x204a, 14, 6), diff --git a/target/linux/ipq806x/patches-5.10/088-v5.8-watchdog-qcom-wdt-disable-pretimeout-on-timer-platfo.patch b/target/linux/ipq806x/patches-5.10/088-v5.8-watchdog-qcom-wdt-disable-pretimeout-on-timer-platfo.patch deleted file mode 100644 index 605eb7d07b..0000000000 --- a/target/linux/ipq806x/patches-5.10/088-v5.8-watchdog-qcom-wdt-disable-pretimeout-on-timer-platfo.patch +++ /dev/null @@ -1,98 +0,0 @@ -From 000de5417107623925a4cf0310579f744ff43c28 Mon Sep 17 00:00:00 2001 -From: Ansuel Smith -Date: Tue, 4 Feb 2020 20:56:48 +0100 -Subject: watchdog: qcom-wdt: disable pretimeout on timer platform - -Some platform like ipq806x doesn't support pretimeout and define -some interrupts used by qcom,msm-timer. Change the driver to check -and use pretimeout only on qcom,kpss-wdt as it's the only platform -that actually supports it. - -Signed-off-by: Ansuel Smith -Reviewed-by: Guenter Roeck -Link: https://lore.kernel.org/r/20200204195648.23350-1-ansuelsmth@gmail.com -[groeck: Conflict resolution] -Signed-off-by: Guenter Roeck -Signed-off-by: Wim Van Sebroeck ---- - drivers/watchdog/qcom-wdt.c | 31 +++++++++++++++++++++++-------- - 1 file changed, 23 insertions(+), 8 deletions(-) - ---- a/drivers/watchdog/qcom-wdt.c -+++ b/drivers/watchdog/qcom-wdt.c -@@ -40,6 +40,11 @@ static const u32 reg_offset_data_kpss[] - [WDT_BITE_TIME] = 0x14, - }; - -+struct qcom_wdt_match_data { -+ const u32 *offset; -+ bool pretimeout; -+}; -+ - struct qcom_wdt { - struct watchdog_device wdd; - unsigned long rate; -@@ -179,19 +184,29 @@ static void qcom_clk_disable_unprepare(v - clk_disable_unprepare(data); - } - -+static const struct qcom_wdt_match_data match_data_apcs_tmr = { -+ .offset = reg_offset_data_apcs_tmr, -+ .pretimeout = false, -+}; -+ -+static const struct qcom_wdt_match_data match_data_kpss = { -+ .offset = reg_offset_data_kpss, -+ .pretimeout = true, -+}; -+ - static int qcom_wdt_probe(struct platform_device *pdev) - { - struct device *dev = &pdev->dev; - struct qcom_wdt *wdt; - struct resource *res; - struct device_node *np = dev->of_node; -- const u32 *regs; -+ const struct qcom_wdt_match_data *data; - u32 percpu_offset; - int irq, ret; - struct clk *clk; - -- regs = of_device_get_match_data(dev); -- if (!regs) { -+ data = of_device_get_match_data(dev); -+ if (!data) { - dev_err(dev, "Unsupported QCOM WDT module\n"); - return -ENODEV; - } -@@ -247,7 +262,7 @@ static int qcom_wdt_probe(struct platfor - - /* check if there is pretimeout support */ - irq = platform_get_irq_optional(pdev, 0); -- if (irq > 0) { -+ if (data->pretimeout && irq > 0) { - ret = devm_request_irq(dev, irq, qcom_wdt_isr, - IRQF_TRIGGER_RISING, - "wdt_bark", &wdt->wdd); -@@ -267,7 +282,7 @@ static int qcom_wdt_probe(struct platfor - wdt->wdd.min_timeout = 1; - wdt->wdd.max_timeout = 0x10000000U / wdt->rate; - wdt->wdd.parent = dev; -- wdt->layout = regs; -+ wdt->layout = data->offset; - - if (readl(wdt_addr(wdt, WDT_STS)) & 1) - wdt->wdd.bootstatus = WDIOF_CARDRESET; -@@ -311,9 +326,9 @@ static int __maybe_unused qcom_wdt_resum - static SIMPLE_DEV_PM_OPS(qcom_wdt_pm_ops, qcom_wdt_suspend, qcom_wdt_resume); - - static const struct of_device_id qcom_wdt_of_table[] = { -- { .compatible = "qcom,kpss-timer", .data = reg_offset_data_apcs_tmr }, -- { .compatible = "qcom,scss-timer", .data = reg_offset_data_apcs_tmr }, -- { .compatible = "qcom,kpss-wdt", .data = reg_offset_data_kpss }, -+ { .compatible = "qcom,kpss-timer", .data = &match_data_apcs_tmr }, -+ { .compatible = "qcom,scss-timer", .data = &match_data_apcs_tmr }, -+ { .compatible = "qcom,kpss-wdt", .data = &match_data_kpss }, - { }, - }; - MODULE_DEVICE_TABLE(of, qcom_wdt_of_table); diff --git a/target/linux/ipq806x/patches-5.10/089-v5.8-ipq806x-gcc-Added-the-enable-regs-and-mask-for-PRNG.patch b/target/linux/ipq806x/patches-5.10/089-v5.8-ipq806x-gcc-Added-the-enable-regs-and-mask-for-PRNG.patch deleted file mode 100644 index 015a917e20..0000000000 --- a/target/linux/ipq806x/patches-5.10/089-v5.8-ipq806x-gcc-Added-the-enable-regs-and-mask-for-PRNG.patch +++ /dev/null @@ -1,28 +0,0 @@ -From 1aec193ea41d672d11592714cdda8167eb3b38fc Mon Sep 17 00:00:00 2001 -From: Abhishek Sahu -Date: Wed, 18 Mar 2020 14:16:56 +0100 -Subject: ipq806x: gcc: Added the enable regs and mask for PRNG - -Kernel got hanged while reading from /dev/hwrng at the -time of PRNG clock enable - -Fixes: 24d8fba44af3 "clk: qcom: Add support for IPQ8064's global clock controller (GCC)" -Signed-off-by: Abhishek Sahu -Signed-off-by: Ansuel Smith -Link: https://lkml.kernel.org/r/20200318131657.345-1-ansuelsmth@gmail.com -Signed-off-by: Stephen Boyd ---- - drivers/clk/qcom/gcc-ipq806x.c | 2 ++ - 1 file changed, 2 insertions(+) - ---- a/drivers/clk/qcom/gcc-ipq806x.c -+++ b/drivers/clk/qcom/gcc-ipq806x.c -@@ -1225,6 +1225,8 @@ static struct clk_rcg prng_src = { - .parent_map = gcc_pxo_pll8_map, - }, - .clkr = { -+ .enable_reg = 0x2e80, -+ .enable_mask = BIT(11), - .hw.init = &(struct clk_init_data){ - .name = "prng_src", - .parent_names = gcc_pxo_pll8, diff --git a/target/linux/ipq806x/patches-5.10/090-v5.8-clk-clk-rpm-fixes.patch b/target/linux/ipq806x/patches-5.10/090-v5.8-clk-clk-rpm-fixes.patch deleted file mode 100644 index a28570974e..0000000000 --- a/target/linux/ipq806x/patches-5.10/090-v5.8-clk-clk-rpm-fixes.patch +++ /dev/null @@ -1,90 +0,0 @@ -From eec152734be10c72d2d413a27ca9d282c28cdb61 Mon Sep 17 00:00:00 2001 -From: Ansuel Smith -Date: Tue, 10 Mar 2020 15:37:56 +0100 -Subject: clk: qcom: clk-rpm: add missing rpm clk for ipq806x - -Add missing definition of rpm clk for ipq806x soc - -Signed-off-by: John Crispin -Signed-off-by: Ansuel Smith -Acked-by: John Crispin -Reviewed-by: Rob Herring -Link: https://lkml.kernel.org/r/20200310143756.244-1-ansuelsmth@gmail.com -Signed-off-by: Stephen Boyd ---- - .../devicetree/bindings/clock/qcom,rpmcc.txt | 1 + - drivers/clk/qcom/clk-rpm.c | 35 ++++++++++++++++++++++ - include/dt-bindings/clock/qcom,rpmcc.h | 4 +++ - 3 files changed, 40 insertions(+) - ---- a/Documentation/devicetree/bindings/clock/qcom,rpmcc.txt -+++ b/Documentation/devicetree/bindings/clock/qcom,rpmcc.txt -@@ -15,6 +15,7 @@ Required properties : - "qcom,rpmcc-msm8916", "qcom,rpmcc" - "qcom,rpmcc-msm8974", "qcom,rpmcc" - "qcom,rpmcc-apq8064", "qcom,rpmcc" -+ "qcom,rpmcc-ipq806x", "qcom,rpmcc" - "qcom,rpmcc-msm8996", "qcom,rpmcc" - "qcom,rpmcc-msm8998", "qcom,rpmcc" - "qcom,rpmcc-qcs404", "qcom,rpmcc" ---- a/drivers/clk/qcom/clk-rpm.c -+++ b/drivers/clk/qcom/clk-rpm.c -@@ -543,10 +543,45 @@ static const struct rpm_clk_desc rpm_clk - .num_clks = ARRAY_SIZE(apq8064_clks), - }; - -+/* ipq806x */ -+DEFINE_CLK_RPM(ipq806x, afab_clk, afab_a_clk, QCOM_RPM_APPS_FABRIC_CLK); -+DEFINE_CLK_RPM(ipq806x, cfpb_clk, cfpb_a_clk, QCOM_RPM_CFPB_CLK); -+DEFINE_CLK_RPM(ipq806x, daytona_clk, daytona_a_clk, QCOM_RPM_DAYTONA_FABRIC_CLK); -+DEFINE_CLK_RPM(ipq806x, ebi1_clk, ebi1_a_clk, QCOM_RPM_EBI1_CLK); -+DEFINE_CLK_RPM(ipq806x, sfab_clk, sfab_a_clk, QCOM_RPM_SYS_FABRIC_CLK); -+DEFINE_CLK_RPM(ipq806x, sfpb_clk, sfpb_a_clk, QCOM_RPM_SFPB_CLK); -+DEFINE_CLK_RPM(ipq806x, nss_fabric_0_clk, nss_fabric_0_a_clk, QCOM_RPM_NSS_FABRIC_0_CLK); -+DEFINE_CLK_RPM(ipq806x, nss_fabric_1_clk, nss_fabric_1_a_clk, QCOM_RPM_NSS_FABRIC_1_CLK); -+ -+static struct clk_rpm *ipq806x_clks[] = { -+ [RPM_APPS_FABRIC_CLK] = &ipq806x_afab_clk, -+ [RPM_APPS_FABRIC_A_CLK] = &ipq806x_afab_a_clk, -+ [RPM_CFPB_CLK] = &ipq806x_cfpb_clk, -+ [RPM_CFPB_A_CLK] = &ipq806x_cfpb_a_clk, -+ [RPM_DAYTONA_FABRIC_CLK] = &ipq806x_daytona_clk, -+ [RPM_DAYTONA_FABRIC_A_CLK] = &ipq806x_daytona_a_clk, -+ [RPM_EBI1_CLK] = &ipq806x_ebi1_clk, -+ [RPM_EBI1_A_CLK] = &ipq806x_ebi1_a_clk, -+ [RPM_SYS_FABRIC_CLK] = &ipq806x_sfab_clk, -+ [RPM_SYS_FABRIC_A_CLK] = &ipq806x_sfab_a_clk, -+ [RPM_SFPB_CLK] = &ipq806x_sfpb_clk, -+ [RPM_SFPB_A_CLK] = &ipq806x_sfpb_a_clk, -+ [RPM_NSS_FABRIC_0_CLK] = &ipq806x_nss_fabric_0_clk, -+ [RPM_NSS_FABRIC_0_A_CLK] = &ipq806x_nss_fabric_0_a_clk, -+ [RPM_NSS_FABRIC_1_CLK] = &ipq806x_nss_fabric_1_clk, -+ [RPM_NSS_FABRIC_1_A_CLK] = &ipq806x_nss_fabric_1_a_clk, -+}; -+ -+static const struct rpm_clk_desc rpm_clk_ipq806x = { -+ .clks = ipq806x_clks, -+ .num_clks = ARRAY_SIZE(ipq806x_clks), -+}; -+ - static const struct of_device_id rpm_clk_match_table[] = { - { .compatible = "qcom,rpmcc-msm8660", .data = &rpm_clk_msm8660 }, - { .compatible = "qcom,rpmcc-apq8060", .data = &rpm_clk_msm8660 }, - { .compatible = "qcom,rpmcc-apq8064", .data = &rpm_clk_apq8064 }, -+ { .compatible = "qcom,rpmcc-ipq806x", .data = &rpm_clk_ipq806x }, - { } - }; - MODULE_DEVICE_TABLE(of, rpm_clk_match_table); ---- a/include/dt-bindings/clock/qcom,rpmcc.h -+++ b/include/dt-bindings/clock/qcom,rpmcc.h -@@ -37,6 +37,10 @@ - #define RPM_XO_A0 27 - #define RPM_XO_A1 28 - #define RPM_XO_A2 29 -+#define RPM_NSS_FABRIC_0_CLK 30 -+#define RPM_NSS_FABRIC_0_A_CLK 31 -+#define RPM_NSS_FABRIC_1_CLK 32 -+#define RPM_NSS_FABRIC_1_A_CLK 33 - - /* SMD RPM clocks */ - #define RPM_SMD_XO_CLK_SRC 0 diff --git a/target/linux/ipq806x/patches-5.10/091-v5.8-regulator-add-smb208-support.patch b/target/linux/ipq806x/patches-5.10/091-v5.8-regulator-add-smb208-support.patch deleted file mode 100644 index 42a02865a3..0000000000 --- a/target/linux/ipq806x/patches-5.10/091-v5.8-regulator-add-smb208-support.patch +++ /dev/null @@ -1,63 +0,0 @@ -From b5f25304aece9f2e7eaab275bbb5461c666bf38c Mon Sep 17 00:00:00 2001 -From: Ansuel Smith -Date: Wed, 19 Feb 2020 17:37:11 +0100 -Subject: regulator: add smb208 support - -Smb208 regulators are used on some ipq806x soc. -Add support for it to make it avaiable on some routers -that use it. - -Signed-off-by: Ansuel Smith -Signed-off-by: Adrian Panella -Acked-by: Lee Jones -Link: https://lore.kernel.org/r/20200219163711.479-1-ansuelsmth@gmail.com -Signed-off-by: Mark Brown ---- - Documentation/devicetree/bindings/mfd/qcom-rpm.txt | 4 ++++ - drivers/regulator/qcom_rpm-regulator.c | 9 +++++++++ - 2 files changed, 13 insertions(+) - ---- a/Documentation/devicetree/bindings/mfd/qcom-rpm.txt -+++ b/Documentation/devicetree/bindings/mfd/qcom-rpm.txt -@@ -61,6 +61,7 @@ Regulator nodes are identified by their - "qcom,rpm-pm8901-regulators" - "qcom,rpm-pm8921-regulators" - "qcom,rpm-pm8018-regulators" -+ "qcom,rpm-smb208-regulators" - - - vdd_l0_l1_lvs-supply: - - vdd_l2_l11_l12-supply: -@@ -171,6 +172,9 @@ pm8018: - s1, s2, s3, s4, s5, , l1, l2, l3, l4, l5, l6, l7, l8, l9, l10, l11, - l12, l14, lvs1 - -+smb208: -+ s1a, s1b, s2a, s2b -+ - The content of each sub-node is defined by the standard binding for regulators - - see regulator.txt - with additional custom properties described below: - ---- a/drivers/regulator/qcom_rpm-regulator.c -+++ b/drivers/regulator/qcom_rpm-regulator.c -@@ -925,12 +925,21 @@ static const struct rpm_regulator_data r - { } - }; - -+static const struct rpm_regulator_data rpm_smb208_regulators[] = { -+ { "s1a", QCOM_RPM_SMB208_S1a, &smb208_smps, "vin_s1a" }, -+ { "s1b", QCOM_RPM_SMB208_S1b, &smb208_smps, "vin_s1b" }, -+ { "s2a", QCOM_RPM_SMB208_S2a, &smb208_smps, "vin_s2a" }, -+ { "s2b", QCOM_RPM_SMB208_S2b, &smb208_smps, "vin_s2b" }, -+ { } -+}; -+ - static const struct of_device_id rpm_of_match[] = { - { .compatible = "qcom,rpm-pm8018-regulators", - .data = &rpm_pm8018_regulators }, - { .compatible = "qcom,rpm-pm8058-regulators", .data = &rpm_pm8058_regulators }, - { .compatible = "qcom,rpm-pm8901-regulators", .data = &rpm_pm8901_regulators }, - { .compatible = "qcom,rpm-pm8921-regulators", .data = &rpm_pm8921_regulators }, -+ { .compatible = "qcom,rpm-smb208-regulators", .data = &rpm_smb208_regulators }, - { } - }; - MODULE_DEVICE_TABLE(of, rpm_of_match); diff --git a/target/linux/ipq806x/patches-5.10/092-1-v5.7-qcom-cpufreq-nvmem-Add-support-for-krait-based-socs.patch b/target/linux/ipq806x/patches-5.10/092-1-v5.7-qcom-cpufreq-nvmem-Add-support-for-krait-based-socs.patch deleted file mode 100644 index be20756a10..0000000000 --- a/target/linux/ipq806x/patches-5.10/092-1-v5.7-qcom-cpufreq-nvmem-Add-support-for-krait-based-socs.patch +++ /dev/null @@ -1,361 +0,0 @@ -From a8811ec764f95a04ba82f6f457e28c5e9e36e36b Mon Sep 17 00:00:00 2001 -From: Ansuel Smith -Date: Fri, 13 Mar 2020 18:52:13 +0100 -Subject: cpufreq: qcom: Add support for krait based socs - -In Certain QCOM SoCs like ipq8064, apq8064, msm8960, msm8974 -that has KRAIT processors the voltage/current value of each OPP -varies based on the silicon variant in use. - -The required OPP related data is determined based on -the efuse value. This is similar to the existing code for -kryo cores. So adding support for krait cores here. - -Signed-off-by: Sricharan R -Signed-off-by: Ansuel Smith -Signed-off-by: Viresh Kumar ---- - .../devicetree/bindings/opp/qcom-nvmem-cpufreq.txt | 3 +- - drivers/cpufreq/Kconfig.arm | 2 +- - drivers/cpufreq/cpufreq-dt-platdev.c | 5 + - drivers/cpufreq/qcom-cpufreq-nvmem.c | 191 +++++++++++++++++++-- - 4 files changed, 183 insertions(+), 18 deletions(-) - ---- a/Documentation/devicetree/bindings/opp/qcom-nvmem-cpufreq.txt -+++ b/Documentation/devicetree/bindings/opp/qcom-nvmem-cpufreq.txt -@@ -19,7 +19,8 @@ In 'cpu' nodes: - - In 'operating-points-v2' table: - - compatible: Should be -- - 'operating-points-v2-kryo-cpu' for apq8096 and msm8996. -+ - 'operating-points-v2-kryo-cpu' for apq8096, msm8996, msm8974, -+ apq8064, ipq8064, msm8960 and ipq8074. - - Optional properties: - -------------------- ---- a/drivers/cpufreq/Kconfig.arm -+++ b/drivers/cpufreq/Kconfig.arm -@@ -135,7 +135,7 @@ config ARM_OMAP2PLUS_CPUFREQ - - config ARM_QCOM_CPUFREQ_NVMEM - tristate "Qualcomm nvmem based CPUFreq" -- depends on ARM64 -+ depends on ARCH_QCOM - depends on QCOM_QFPROM - depends on QCOM_SMEM - select PM_OPP ---- a/drivers/cpufreq/cpufreq-dt-platdev.c -+++ b/drivers/cpufreq/cpufreq-dt-platdev.c -@@ -138,6 +138,11 @@ static const struct of_device_id blackli - { .compatible = "ti,am43", }, - { .compatible = "ti,dra7", }, - -+ { .compatible = "qcom,ipq8064", }, -+ { .compatible = "qcom,apq8064", }, -+ { .compatible = "qcom,msm8974", }, -+ { .compatible = "qcom,msm8960", }, -+ - { } - }; - ---- a/drivers/cpufreq/qcom-cpufreq-nvmem.c -+++ b/drivers/cpufreq/qcom-cpufreq-nvmem.c -@@ -49,12 +49,14 @@ struct qcom_cpufreq_drv; - struct qcom_cpufreq_match_data { - int (*get_version)(struct device *cpu_dev, - struct nvmem_cell *speedbin_nvmem, -+ char **pvs_name, - struct qcom_cpufreq_drv *drv); - const char **genpd_names; - }; - - struct qcom_cpufreq_drv { -- struct opp_table **opp_tables; -+ struct opp_table **names_opp_tables; -+ struct opp_table **hw_opp_tables; - struct opp_table **genpd_opp_tables; - u32 versions; - const struct qcom_cpufreq_match_data *data; -@@ -62,6 +64,84 @@ struct qcom_cpufreq_drv { - - static struct platform_device *cpufreq_dt_pdev, *cpufreq_pdev; - -+static void get_krait_bin_format_a(struct device *cpu_dev, -+ int *speed, int *pvs, int *pvs_ver, -+ struct nvmem_cell *pvs_nvmem, u8 *buf) -+{ -+ u32 pte_efuse; -+ -+ pte_efuse = *((u32 *)buf); -+ -+ *speed = pte_efuse & 0xf; -+ if (*speed == 0xf) -+ *speed = (pte_efuse >> 4) & 0xf; -+ -+ if (*speed == 0xf) { -+ *speed = 0; -+ dev_warn(cpu_dev, "Speed bin: Defaulting to %d\n", *speed); -+ } else { -+ dev_dbg(cpu_dev, "Speed bin: %d\n", *speed); -+ } -+ -+ *pvs = (pte_efuse >> 10) & 0x7; -+ if (*pvs == 0x7) -+ *pvs = (pte_efuse >> 13) & 0x7; -+ -+ if (*pvs == 0x7) { -+ *pvs = 0; -+ dev_warn(cpu_dev, "PVS bin: Defaulting to %d\n", *pvs); -+ } else { -+ dev_dbg(cpu_dev, "PVS bin: %d\n", *pvs); -+ } -+} -+ -+static void get_krait_bin_format_b(struct device *cpu_dev, -+ int *speed, int *pvs, int *pvs_ver, -+ struct nvmem_cell *pvs_nvmem, u8 *buf) -+{ -+ u32 pte_efuse, redundant_sel; -+ -+ pte_efuse = *((u32 *)buf); -+ redundant_sel = (pte_efuse >> 24) & 0x7; -+ -+ *pvs_ver = (pte_efuse >> 4) & 0x3; -+ -+ switch (redundant_sel) { -+ case 1: -+ *pvs = ((pte_efuse >> 28) & 0x8) | ((pte_efuse >> 6) & 0x7); -+ *speed = (pte_efuse >> 27) & 0xf; -+ break; -+ case 2: -+ *pvs = (pte_efuse >> 27) & 0xf; -+ *speed = pte_efuse & 0x7; -+ break; -+ default: -+ /* 4 bits of PVS are in efuse register bits 31, 8-6. */ -+ *pvs = ((pte_efuse >> 28) & 0x8) | ((pte_efuse >> 6) & 0x7); -+ *speed = pte_efuse & 0x7; -+ } -+ -+ /* Check SPEED_BIN_BLOW_STATUS */ -+ if (pte_efuse & BIT(3)) { -+ dev_dbg(cpu_dev, "Speed bin: %d\n", *speed); -+ } else { -+ dev_warn(cpu_dev, "Speed bin not set. Defaulting to 0!\n"); -+ *speed = 0; -+ } -+ -+ /* Check PVS_BLOW_STATUS */ -+ pte_efuse = *(((u32 *)buf) + 4); -+ pte_efuse &= BIT(21); -+ if (pte_efuse) { -+ dev_dbg(cpu_dev, "PVS bin: %d\n", *pvs); -+ } else { -+ dev_warn(cpu_dev, "PVS bin not set. Defaulting to 0!\n"); -+ *pvs = 0; -+ } -+ -+ dev_dbg(cpu_dev, "PVS version: %d\n", *pvs_ver); -+} -+ - static enum _msm8996_version qcom_cpufreq_get_msm_id(void) - { - size_t len; -@@ -93,11 +173,13 @@ static enum _msm8996_version qcom_cpufre - - static int qcom_cpufreq_kryo_name_version(struct device *cpu_dev, - struct nvmem_cell *speedbin_nvmem, -+ char **pvs_name, - struct qcom_cpufreq_drv *drv) - { - size_t len; - u8 *speedbin; - enum _msm8996_version msm8996_version; -+ *pvs_name = NULL; - - msm8996_version = qcom_cpufreq_get_msm_id(); - if (NUM_OF_MSM8996_VERSIONS == msm8996_version) { -@@ -125,10 +207,51 @@ static int qcom_cpufreq_kryo_name_versio - return 0; - } - -+static int qcom_cpufreq_krait_name_version(struct device *cpu_dev, -+ struct nvmem_cell *speedbin_nvmem, -+ char **pvs_name, -+ struct qcom_cpufreq_drv *drv) -+{ -+ int speed = 0, pvs = 0, pvs_ver = 0; -+ u8 *speedbin; -+ size_t len; -+ -+ speedbin = nvmem_cell_read(speedbin_nvmem, &len); -+ -+ if (IS_ERR(speedbin)) -+ return PTR_ERR(speedbin); -+ -+ switch (len) { -+ case 4: -+ get_krait_bin_format_a(cpu_dev, &speed, &pvs, &pvs_ver, -+ speedbin_nvmem, speedbin); -+ break; -+ case 8: -+ get_krait_bin_format_b(cpu_dev, &speed, &pvs, &pvs_ver, -+ speedbin_nvmem, speedbin); -+ break; -+ default: -+ dev_err(cpu_dev, "Unable to read nvmem data. Defaulting to 0!\n"); -+ return -ENODEV; -+ } -+ -+ snprintf(*pvs_name, sizeof("speedXX-pvsXX-vXX"), "speed%d-pvs%d-v%d", -+ speed, pvs, pvs_ver); -+ -+ drv->versions = (1 << speed); -+ -+ kfree(speedbin); -+ return 0; -+} -+ - static const struct qcom_cpufreq_match_data match_data_kryo = { - .get_version = qcom_cpufreq_kryo_name_version, - }; - -+static const struct qcom_cpufreq_match_data match_data_krait = { -+ .get_version = qcom_cpufreq_krait_name_version, -+}; -+ - static const char *qcs404_genpd_names[] = { "cpr", NULL }; - - static const struct qcom_cpufreq_match_data match_data_qcs404 = { -@@ -141,6 +264,7 @@ static int qcom_cpufreq_probe(struct pla - struct nvmem_cell *speedbin_nvmem; - struct device_node *np; - struct device *cpu_dev; -+ char *pvs_name = "speedXX-pvsXX-vXX"; - unsigned cpu; - const struct of_device_id *match; - int ret; -@@ -153,7 +277,7 @@ static int qcom_cpufreq_probe(struct pla - if (!np) - return -ENOENT; - -- ret = of_device_is_compatible(np, "operating-points-v2-kryo-cpu"); -+ ret = of_device_is_compatible(np, "operating-points-v2-qcom-cpu"); - if (!ret) { - of_node_put(np); - return -ENOENT; -@@ -181,7 +305,8 @@ static int qcom_cpufreq_probe(struct pla - goto free_drv; - } - -- ret = drv->data->get_version(cpu_dev, speedbin_nvmem, drv); -+ ret = drv->data->get_version(cpu_dev, -+ speedbin_nvmem, &pvs_name, drv); - if (ret) { - nvmem_cell_put(speedbin_nvmem); - goto free_drv; -@@ -190,12 +315,20 @@ static int qcom_cpufreq_probe(struct pla - } - of_node_put(np); - -- drv->opp_tables = kcalloc(num_possible_cpus(), sizeof(*drv->opp_tables), -+ drv->names_opp_tables = kcalloc(num_possible_cpus(), -+ sizeof(*drv->names_opp_tables), - GFP_KERNEL); -- if (!drv->opp_tables) { -+ if (!drv->names_opp_tables) { - ret = -ENOMEM; - goto free_drv; - } -+ drv->hw_opp_tables = kcalloc(num_possible_cpus(), -+ sizeof(*drv->hw_opp_tables), -+ GFP_KERNEL); -+ if (!drv->hw_opp_tables) { -+ ret = -ENOMEM; -+ goto free_opp_names; -+ } - - drv->genpd_opp_tables = kcalloc(num_possible_cpus(), - sizeof(*drv->genpd_opp_tables), -@@ -213,11 +346,23 @@ static int qcom_cpufreq_probe(struct pla - } - - if (drv->data->get_version) { -- drv->opp_tables[cpu] = -- dev_pm_opp_set_supported_hw(cpu_dev, -- &drv->versions, 1); -- if (IS_ERR(drv->opp_tables[cpu])) { -- ret = PTR_ERR(drv->opp_tables[cpu]); -+ -+ if (pvs_name) { -+ drv->names_opp_tables[cpu] = dev_pm_opp_set_prop_name( -+ cpu_dev, -+ pvs_name); -+ if (IS_ERR(drv->names_opp_tables[cpu])) { -+ ret = PTR_ERR(drv->names_opp_tables[cpu]); -+ dev_err(cpu_dev, "Failed to add OPP name %s\n", -+ pvs_name); -+ goto free_opp; -+ } -+ } -+ -+ drv->hw_opp_tables[cpu] = dev_pm_opp_set_supported_hw( -+ cpu_dev, &drv->versions, 1); -+ if (IS_ERR(drv->hw_opp_tables[cpu])) { -+ ret = PTR_ERR(drv->hw_opp_tables[cpu]); - dev_err(cpu_dev, - "Failed to set supported hardware\n"); - goto free_genpd_opp; -@@ -259,11 +404,18 @@ free_genpd_opp: - kfree(drv->genpd_opp_tables); - free_opp: - for_each_possible_cpu(cpu) { -- if (IS_ERR_OR_NULL(drv->opp_tables[cpu])) -+ if (IS_ERR_OR_NULL(drv->names_opp_tables[cpu])) -+ break; -+ dev_pm_opp_put_prop_name(drv->names_opp_tables[cpu]); -+ } -+ for_each_possible_cpu(cpu) { -+ if (IS_ERR_OR_NULL(drv->hw_opp_tables[cpu])) - break; -- dev_pm_opp_put_supported_hw(drv->opp_tables[cpu]); -+ dev_pm_opp_put_supported_hw(drv->hw_opp_tables[cpu]); - } -- kfree(drv->opp_tables); -+ kfree(drv->hw_opp_tables); -+free_opp_names: -+ kfree(drv->names_opp_tables); - free_drv: - kfree(drv); - -@@ -278,13 +430,16 @@ static int qcom_cpufreq_remove(struct pl - platform_device_unregister(cpufreq_dt_pdev); - - for_each_possible_cpu(cpu) { -- if (drv->opp_tables[cpu]) -- dev_pm_opp_put_supported_hw(drv->opp_tables[cpu]); -+ if (drv->names_opp_tables[cpu]) -+ dev_pm_opp_put_supported_hw(drv->names_opp_tables[cpu]); -+ if (drv->hw_opp_tables[cpu]) -+ dev_pm_opp_put_supported_hw(drv->hw_opp_tables[cpu]); - if (drv->genpd_opp_tables[cpu]) - dev_pm_opp_detach_genpd(drv->genpd_opp_tables[cpu]); - } - -- kfree(drv->opp_tables); -+ kfree(drv->names_opp_tables); -+ kfree(drv->hw_opp_tables); - kfree(drv->genpd_opp_tables); - kfree(drv); - -@@ -303,6 +458,10 @@ static const struct of_device_id qcom_cp - { .compatible = "qcom,apq8096", .data = &match_data_kryo }, - { .compatible = "qcom,msm8996", .data = &match_data_kryo }, - { .compatible = "qcom,qcs404", .data = &match_data_qcs404 }, -+ { .compatible = "qcom,ipq8064", .data = &match_data_krait }, -+ { .compatible = "qcom,apq8064", .data = &match_data_krait }, -+ { .compatible = "qcom,msm8974", .data = &match_data_krait }, -+ { .compatible = "qcom,msm8960", .data = &match_data_krait }, - {}, - }; - MODULE_DEVICE_TABLE(of, qcom_cpufreq_match_list); diff --git a/target/linux/ipq806x/patches-5.10/092-2-v5.7-cpufreq-qcom-fix-wrong-compatible-binding.patch b/target/linux/ipq806x/patches-5.10/092-2-v5.7-cpufreq-qcom-fix-wrong-compatible-binding.patch deleted file mode 100644 index 764a917c1f..0000000000 --- a/target/linux/ipq806x/patches-5.10/092-2-v5.7-cpufreq-qcom-fix-wrong-compatible-binding.patch +++ /dev/null @@ -1,26 +0,0 @@ -From 2dea651680cea1f3a29925de51002f33d1f55711 Mon Sep 17 00:00:00 2001 -From: Ansuel Smith -Date: Fri, 1 May 2020 00:22:25 +0200 -Subject: cpufreq: qcom: fix wrong compatible binding - -Binding in Documentation is still "operating-points-v2-kryo-cpu". -Restore the old binding to fix the compatibility problem. - -Fixes: a8811ec764f9 ("cpufreq: qcom: Add support for krait based socs") -Signed-off-by: Ansuel Smith -Signed-off-by: Viresh Kumar ---- - drivers/cpufreq/qcom-cpufreq-nvmem.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - ---- a/drivers/cpufreq/qcom-cpufreq-nvmem.c -+++ b/drivers/cpufreq/qcom-cpufreq-nvmem.c -@@ -277,7 +277,7 @@ static int qcom_cpufreq_probe(struct pla - if (!np) - return -ENOENT; - -- ret = of_device_is_compatible(np, "operating-points-v2-qcom-cpu"); -+ ret = of_device_is_compatible(np, "operating-points-v2-kryo-cpu"); - if (!ret) { - of_node_put(np); - return -ENOENT; diff --git a/target/linux/ipq806x/patches-5.10/093-4-v5.8-ipq806x-PCI-qcom-Use-bulk-clk-api-and-assert-on-error.patch b/target/linux/ipq806x/patches-5.10/093-4-v5.8-ipq806x-PCI-qcom-Use-bulk-clk-api-and-assert-on-error.patch deleted file mode 100644 index 95531508b6..0000000000 --- a/target/linux/ipq806x/patches-5.10/093-4-v5.8-ipq806x-PCI-qcom-Use-bulk-clk-api-and-assert-on-error.patch +++ /dev/null @@ -1,228 +0,0 @@ -From 6a114526af4689938863bf34976c83bfd279f517 Mon Sep 17 00:00:00 2001 -From: Ansuel Smith -Date: Mon, 15 Jun 2020 23:06:02 +0200 -Subject: PCI: qcom: Use bulk clk api and assert on error - -Rework 2.1.0 revision to use bulk clk api and fix missing assert on -reset_control_deassert error. - -Link: https://lore.kernel.org/r/20200615210608.21469-7-ansuelsmth@gmail.com -Signed-off-by: Ansuel Smith -Signed-off-by: Lorenzo Pieralisi -Reviewed-by: Rob Herring -Acked-by: Stanimir Varbanov ---- - drivers/pci/controller/dwc/pcie-qcom.c | 131 ++++++++++++--------------------- - 1 file changed, 46 insertions(+), 85 deletions(-) - ---- a/drivers/pci/controller/dwc/pcie-qcom.c -+++ b/drivers/pci/controller/dwc/pcie-qcom.c -@@ -99,12 +99,9 @@ - #define SLV_ADDR_SPACE_SZ 0x10000000 - - #define QCOM_PCIE_2_1_0_MAX_SUPPLY 3 -+#define QCOM_PCIE_2_1_0_MAX_CLOCKS 5 - struct qcom_pcie_resources_2_1_0 { -- struct clk *iface_clk; -- struct clk *core_clk; -- struct clk *phy_clk; -- struct clk *aux_clk; -- struct clk *ref_clk; -+ struct clk_bulk_data clks[QCOM_PCIE_2_1_0_MAX_CLOCKS]; - struct reset_control *pci_reset; - struct reset_control *axi_reset; - struct reset_control *ahb_reset; -@@ -244,25 +241,21 @@ static int qcom_pcie_get_resources_2_1_0 - if (ret) - return ret; - -- res->iface_clk = devm_clk_get(dev, "iface"); -- if (IS_ERR(res->iface_clk)) -- return PTR_ERR(res->iface_clk); -- -- res->core_clk = devm_clk_get(dev, "core"); -- if (IS_ERR(res->core_clk)) -- return PTR_ERR(res->core_clk); -- -- res->phy_clk = devm_clk_get(dev, "phy"); -- if (IS_ERR(res->phy_clk)) -- return PTR_ERR(res->phy_clk); -- -- res->aux_clk = devm_clk_get_optional(dev, "aux"); -- if (IS_ERR(res->aux_clk)) -- return PTR_ERR(res->aux_clk); -- -- res->ref_clk = devm_clk_get_optional(dev, "ref"); -- if (IS_ERR(res->ref_clk)) -- return PTR_ERR(res->ref_clk); -+ res->clks[0].id = "iface"; -+ res->clks[1].id = "core"; -+ res->clks[2].id = "phy"; -+ res->clks[3].id = "aux"; -+ res->clks[4].id = "ref"; -+ -+ /* iface, core, phy are required */ -+ ret = devm_clk_bulk_get(dev, 3, res->clks); -+ if (ret < 0) -+ return ret; -+ -+ /* aux, ref are optional */ -+ ret = devm_clk_bulk_get_optional(dev, 2, res->clks + 3); -+ if (ret < 0) -+ return ret; - - res->pci_reset = devm_reset_control_get_exclusive(dev, "pci"); - if (IS_ERR(res->pci_reset)) -@@ -292,17 +285,13 @@ static void qcom_pcie_deinit_2_1_0(struc - { - struct qcom_pcie_resources_2_1_0 *res = &pcie->res.v2_1_0; - -- clk_disable_unprepare(res->phy_clk); -+ clk_bulk_disable_unprepare(ARRAY_SIZE(res->clks), res->clks); - reset_control_assert(res->pci_reset); - reset_control_assert(res->axi_reset); - reset_control_assert(res->ahb_reset); - reset_control_assert(res->por_reset); - reset_control_assert(res->ext_reset); - reset_control_assert(res->phy_reset); -- clk_disable_unprepare(res->iface_clk); -- clk_disable_unprepare(res->core_clk); -- clk_disable_unprepare(res->aux_clk); -- clk_disable_unprepare(res->ref_clk); - - writel(1, pcie->parf + PCIE20_PARF_PHY_CTRL); - -@@ -334,47 +323,45 @@ static int qcom_pcie_init_2_1_0(struct q - return ret; - } - -- ret = reset_control_assert(res->ahb_reset); -+ ret = reset_control_deassert(res->ahb_reset); - if (ret) { -- dev_err(dev, "cannot assert ahb reset\n"); -- goto err_assert_ahb; -+ dev_err(dev, "cannot deassert ahb reset\n"); -+ goto err_deassert_ahb; - } - -- ret = clk_prepare_enable(res->iface_clk); -+ ret = reset_control_deassert(res->ext_reset); - if (ret) { -- dev_err(dev, "cannot prepare/enable iface clock\n"); -- goto err_assert_ahb; -+ dev_err(dev, "cannot deassert ext reset\n"); -+ goto err_deassert_ext; - } - -- ret = clk_prepare_enable(res->core_clk); -+ ret = reset_control_deassert(res->phy_reset); - if (ret) { -- dev_err(dev, "cannot prepare/enable core clock\n"); -- goto err_clk_core; -+ dev_err(dev, "cannot deassert phy reset\n"); -+ goto err_deassert_phy; - } - -- ret = clk_prepare_enable(res->aux_clk); -+ ret = reset_control_deassert(res->pci_reset); - if (ret) { -- dev_err(dev, "cannot prepare/enable aux clock\n"); -- goto err_clk_aux; -+ dev_err(dev, "cannot deassert pci reset\n"); -+ goto err_deassert_pci; - } - -- ret = clk_prepare_enable(res->ref_clk); -+ ret = reset_control_deassert(res->por_reset); - if (ret) { -- dev_err(dev, "cannot prepare/enable ref clock\n"); -- goto err_clk_ref; -+ dev_err(dev, "cannot deassert por reset\n"); -+ goto err_deassert_por; - } - -- ret = reset_control_deassert(res->ahb_reset); -+ ret = reset_control_deassert(res->axi_reset); - if (ret) { -- dev_err(dev, "cannot deassert ahb reset\n"); -- goto err_deassert_ahb; -+ dev_err(dev, "cannot deassert axi reset\n"); -+ goto err_deassert_axi; - } - -- ret = reset_control_deassert(res->ext_reset); -- if (ret) { -- dev_err(dev, "cannot deassert ext reset\n"); -- goto err_deassert_ahb; -- } -+ ret = clk_bulk_prepare_enable(ARRAY_SIZE(res->clks), res->clks); -+ if (ret) -+ goto err_clks; - - /* enable PCIe clocks and resets */ - val = readl(pcie->parf + PCIE20_PARF_PHY_CTRL); -@@ -406,36 +393,6 @@ static int qcom_pcie_init_2_1_0(struct q - val |= PHY_REFCLK_SSP_EN; - writel(val, pcie->parf + PCIE20_PARF_PHY_REFCLK); - -- ret = reset_control_deassert(res->phy_reset); -- if (ret) { -- dev_err(dev, "cannot deassert phy reset\n"); -- return ret; -- } -- -- ret = reset_control_deassert(res->pci_reset); -- if (ret) { -- dev_err(dev, "cannot deassert pci reset\n"); -- return ret; -- } -- -- ret = reset_control_deassert(res->por_reset); -- if (ret) { -- dev_err(dev, "cannot deassert por reset\n"); -- return ret; -- } -- -- ret = reset_control_deassert(res->axi_reset); -- if (ret) { -- dev_err(dev, "cannot deassert axi reset\n"); -- return ret; -- } -- -- ret = clk_prepare_enable(res->phy_clk); -- if (ret) { -- dev_err(dev, "cannot prepare/enable phy clock\n"); -- goto err_deassert_ahb; -- } -- - /* wait for clock acquisition */ - usleep_range(1000, 1500); - -@@ -448,15 +405,19 @@ static int qcom_pcie_init_2_1_0(struct q - - return 0; - -+err_clks: -+ reset_control_assert(res->axi_reset); -+err_deassert_axi: -+ reset_control_assert(res->por_reset); -+err_deassert_por: -+ reset_control_assert(res->pci_reset); -+err_deassert_pci: -+ reset_control_assert(res->phy_reset); -+err_deassert_phy: -+ reset_control_assert(res->ext_reset); -+err_deassert_ext: -+ reset_control_assert(res->ahb_reset); - err_deassert_ahb: -- clk_disable_unprepare(res->ref_clk); --err_clk_ref: -- clk_disable_unprepare(res->aux_clk); --err_clk_aux: -- clk_disable_unprepare(res->core_clk); --err_clk_core: -- clk_disable_unprepare(res->iface_clk); --err_assert_ahb: - regulator_bulk_disable(ARRAY_SIZE(res->supplies), res->supplies); - - return ret; diff --git a/target/linux/ipq806x/patches-5.10/093-7-v5.8-ipq806x-PCI-qcom-Add-ipq8064-rev2-variant.patch b/target/linux/ipq806x/patches-5.10/093-7-v5.8-ipq806x-PCI-qcom-Add-ipq8064-rev2-variant.patch deleted file mode 100644 index c3d61f164c..0000000000 --- a/target/linux/ipq806x/patches-5.10/093-7-v5.8-ipq806x-PCI-qcom-Add-ipq8064-rev2-variant.patch +++ /dev/null @@ -1,36 +0,0 @@ -From 8df093fe2ae1717389df0dcdc620c02cc35abb21 Mon Sep 17 00:00:00 2001 -From: Ansuel Smith -Date: Mon, 15 Jun 2020 23:06:05 +0200 -Subject: PCI: qcom: Add ipq8064 rev2 variant - -Ipq8064-v2 have tx term offset set to 0. Introduce this variant to permit -different offset based on the revision. - -Link: https://lore.kernel.org/r/20200615210608.21469-10-ansuelsmth@gmail.com -Signed-off-by: Ansuel Smith -Signed-off-by: Lorenzo Pieralisi -Acked-by: Stanimir Varbanov ---- - drivers/pci/controller/dwc/pcie-qcom.c | 4 +++- - 1 file changed, 3 insertions(+), 1 deletion(-) - ---- a/drivers/pci/controller/dwc/pcie-qcom.c -+++ b/drivers/pci/controller/dwc/pcie-qcom.c -@@ -368,7 +368,8 @@ static int qcom_pcie_init_2_1_0(struct q - val &= ~BIT(0); - writel(val, pcie->parf + PCIE20_PARF_PHY_CTRL); - -- if (of_device_is_compatible(node, "qcom,pcie-ipq8064")) { -+ if (of_device_is_compatible(node, "qcom,pcie-ipq8064") || -+ of_device_is_compatible(node, "qcom,pcie-ipq8064-v2")) { - writel(PCS_DEEMPH_TX_DEEMPH_GEN1(24) | - PCS_DEEMPH_TX_DEEMPH_GEN2_3_5DB(24) | - PCS_DEEMPH_TX_DEEMPH_GEN2_6DB(34), -@@ -1328,6 +1329,7 @@ err_pm_runtime_put: - static const struct of_device_id qcom_pcie_match[] = { - { .compatible = "qcom,pcie-apq8084", .data = &ops_1_0_0 }, - { .compatible = "qcom,pcie-ipq8064", .data = &ops_2_1_0 }, -+ { .compatible = "qcom,pcie-ipq8064-v2", .data = &ops_2_1_0 }, - { .compatible = "qcom,pcie-apq8064", .data = &ops_2_1_0 }, - { .compatible = "qcom,pcie-msm8996", .data = &ops_2_3_2 }, - { .compatible = "qcom,pcie-ipq8074", .data = &ops_2_3_3 }, diff --git a/target/linux/ipq806x/patches-5.10/093-8-v5.8-ipq806x-PCI-qcom-Support-pci-speed-set-for-ipq806x.patch b/target/linux/ipq806x/patches-5.10/093-8-v5.8-ipq806x-PCI-qcom-Support-pci-speed-set-for-ipq806x.patch deleted file mode 100644 index 02ac7460e8..0000000000 --- a/target/linux/ipq806x/patches-5.10/093-8-v5.8-ipq806x-PCI-qcom-Support-pci-speed-set-for-ipq806x.patch +++ /dev/null @@ -1,74 +0,0 @@ -From 51ed2c2b60265006bde7531d10993cf24def0aee Mon Sep 17 00:00:00 2001 -From: Sham Muthayyan -Date: Mon, 15 Jun 2020 23:06:07 +0200 -Subject: PCI: qcom: Support pci speed set for ipq806x - -Some SoC based on ipq8064/5 needs to be limited to pci GEN1 speed due to -some hardware limitations. Add support for speed setting defined by the -max-link-speed binding. If not defined the max speed is set to GEN2 by -default. - -Link: https://lore.kernel.org/r/20200615210608.21469-12-ansuelsmth@gmail.com -Signed-off-by: Sham Muthayyan -Signed-off-by: Ansuel Smith -Signed-off-by: Lorenzo Pieralisi -Reviewed-by: Rob Herring -Acked-by: Stanimir Varbanov ---- - -Backported with light changes: -* One include is missing in kernel 5.4 - - drivers/pci/controller/dwc/pcie-qcom.c | 13 +++++++++++++ - 1 file changed, 13 insertions(+) - ---- a/drivers/pci/controller/dwc/pcie-qcom.c -+++ b/drivers/pci/controller/dwc/pcie-qcom.c -@@ -27,6 +27,7 @@ - #include - #include - -+#include "../../pci.h" - #include "pcie-designware.h" - - #define PCIE20_PARF_SYS_CTRL 0x00 -@@ -98,6 +99,8 @@ - #define PCIE20_v3_PARF_SLV_ADDR_SPACE_SIZE 0x358 - #define SLV_ADDR_SPACE_SZ 0x10000000 - -+#define PCIE20_LNK_CONTROL2_LINK_STATUS2 0xa0 -+ - #define QCOM_PCIE_2_1_0_MAX_SUPPLY 3 - #define QCOM_PCIE_2_1_0_MAX_CLOCKS 5 - struct qcom_pcie_resources_2_1_0 { -@@ -184,6 +187,7 @@ struct qcom_pcie { - struct phy *phy; - struct gpio_desc *reset; - const struct qcom_pcie_ops *ops; -+ int gen; - }; - - #define to_qcom_pcie(x) dev_get_drvdata((x)->dev) -@@ -397,6 +401,11 @@ static int qcom_pcie_init_2_1_0(struct q - /* wait for clock acquisition */ - usleep_range(1000, 1500); - -+ if (pcie->gen == 1) { -+ val = readl(pci->dbi_base + PCIE20_LNK_CONTROL2_LINK_STATUS2); -+ val |= PCI_EXP_LNKSTA_CLS_2_5GB; -+ writel(val, pci->dbi_base + PCIE20_LNK_CONTROL2_LINK_STATUS2); -+ } - - /* Set the Max TLP size to 2K, instead of using default of 4K */ - writel(CFG_REMOTE_RD_REQ_BRIDGE_SIZE_2K, -@@ -1261,6 +1270,10 @@ static int qcom_pcie_probe(struct platfo - goto err_pm_runtime_put; - } - -+ pcie->gen = of_pci_get_max_link_speed(pdev->dev.of_node); -+ if (pcie->gen < 0) -+ pcie->gen = 2; -+ - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "parf"); - pcie->parf = devm_ioremap_resource(dev, res); - if (IS_ERR(pcie->parf)) { diff --git a/target/linux/ipq806x/patches-5.10/094-v5.7-ipq806x-net-mdio-add-ipq8064-mdio-driver.patch b/target/linux/ipq806x/patches-5.10/094-v5.7-ipq806x-net-mdio-add-ipq8064-mdio-driver.patch deleted file mode 100644 index 328942dad9..0000000000 --- a/target/linux/ipq806x/patches-5.10/094-v5.7-ipq806x-net-mdio-add-ipq8064-mdio-driver.patch +++ /dev/null @@ -1,216 +0,0 @@ -From caaa71fac36ec8c19145dbf8262a9b77ab09f1a1 Mon Sep 17 00:00:00 2001 -From: Ansuel Smith -Date: Wed, 4 Mar 2020 22:38:32 +0100 -Subject: net: mdio: add ipq8064 mdio driver - -Currently ipq806x soc use generic bitbang driver to -comunicate with the gmac ethernet interface. -Add a dedicated driver created by chunkeey to fix this. - -Co-developed-by: Christian Lamparter -Signed-off-by: Christian Lamparter -Signed-off-by: Ansuel Smith -Signed-off-by: David S. Miller ---- - drivers/net/phy/Kconfig | 8 ++ - drivers/net/phy/Makefile | 1 + - drivers/net/phy/mdio-ipq8064.c | 166 +++++++++++++++++++++++++++++++++++++++++ - 3 files changed, 175 insertions(+) - create mode 100644 drivers/net/phy/mdio-ipq8064.c - ---- a/drivers/net/phy/Kconfig -+++ b/drivers/net/phy/Kconfig -@@ -156,6 +156,14 @@ config MDIO_I2C - - This is library mode. - -+config MDIO_IPQ8064 -+ tristate "Qualcomm IPQ8064 MDIO interface support" -+ depends on HAS_IOMEM && OF_MDIO -+ depends on MFD_SYSCON -+ help -+ This driver supports the MDIO interface found in the network -+ interface units of the IPQ8064 SoC -+ - config MDIO_MOXART - tristate "MOXA ART MDIO interface support" - depends on ARCH_MOXART || COMPILE_TEST ---- a/drivers/net/phy/Makefile -+++ b/drivers/net/phy/Makefile -@@ -50,6 +50,7 @@ obj-$(CONFIG_MDIO_CAVIUM) += mdio-cavium - obj-$(CONFIG_MDIO_GPIO) += mdio-gpio.o - obj-$(CONFIG_MDIO_HISI_FEMAC) += mdio-hisi-femac.o - obj-$(CONFIG_MDIO_I2C) += mdio-i2c.o -+obj-$(CONFIG_MDIO_IPQ8064) += mdio-ipq8064.o - obj-$(CONFIG_MDIO_MOXART) += mdio-moxart.o - obj-$(CONFIG_MDIO_MSCC_MIIM) += mdio-mscc-miim.o - obj-$(CONFIG_MDIO_OCTEON) += mdio-octeon.o ---- /dev/null -+++ b/drivers/net/phy/mdio-ipq8064.c -@@ -0,0 +1,166 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* Qualcomm IPQ8064 MDIO interface driver -+ * -+ * Copyright (C) 2019 Christian Lamparter -+ * Copyright (C) 2020 Ansuel Smith -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+/* MII address register definitions */ -+#define MII_ADDR_REG_ADDR 0x10 -+#define MII_BUSY BIT(0) -+#define MII_WRITE BIT(1) -+#define MII_CLKRANGE_60_100M (0 << 2) -+#define MII_CLKRANGE_100_150M (1 << 2) -+#define MII_CLKRANGE_20_35M (2 << 2) -+#define MII_CLKRANGE_35_60M (3 << 2) -+#define MII_CLKRANGE_150_250M (4 << 2) -+#define MII_CLKRANGE_250_300M (5 << 2) -+#define MII_CLKRANGE_MASK GENMASK(4, 2) -+#define MII_REG_SHIFT 6 -+#define MII_REG_MASK GENMASK(10, 6) -+#define MII_ADDR_SHIFT 11 -+#define MII_ADDR_MASK GENMASK(15, 11) -+ -+#define MII_DATA_REG_ADDR 0x14 -+ -+#define MII_MDIO_DELAY_USEC (1000) -+#define MII_MDIO_RETRY_MSEC (10) -+ -+struct ipq8064_mdio { -+ struct regmap *base; /* NSS_GMAC0_BASE */ -+}; -+ -+static int -+ipq8064_mdio_wait_busy(struct ipq8064_mdio *priv) -+{ -+ u32 busy; -+ -+ return regmap_read_poll_timeout(priv->base, MII_ADDR_REG_ADDR, busy, -+ !(busy & MII_BUSY), MII_MDIO_DELAY_USEC, -+ MII_MDIO_RETRY_MSEC * USEC_PER_MSEC); -+} -+ -+static int -+ipq8064_mdio_read(struct mii_bus *bus, int phy_addr, int reg_offset) -+{ -+ u32 miiaddr = MII_BUSY | MII_CLKRANGE_250_300M; -+ struct ipq8064_mdio *priv = bus->priv; -+ u32 ret_val; -+ int err; -+ -+ /* Reject clause 45 */ -+ if (reg_offset & MII_ADDR_C45) -+ return -EOPNOTSUPP; -+ -+ miiaddr |= ((phy_addr << MII_ADDR_SHIFT) & MII_ADDR_MASK) | -+ ((reg_offset << MII_REG_SHIFT) & MII_REG_MASK); -+ -+ regmap_write(priv->base, MII_ADDR_REG_ADDR, miiaddr); -+ usleep_range(8, 10); -+ -+ err = ipq8064_mdio_wait_busy(priv); -+ if (err) -+ return err; -+ -+ regmap_read(priv->base, MII_DATA_REG_ADDR, &ret_val); -+ return (int)ret_val; -+} -+ -+static int -+ipq8064_mdio_write(struct mii_bus *bus, int phy_addr, int reg_offset, u16 data) -+{ -+ u32 miiaddr = MII_WRITE | MII_BUSY | MII_CLKRANGE_250_300M; -+ struct ipq8064_mdio *priv = bus->priv; -+ -+ /* Reject clause 45 */ -+ if (reg_offset & MII_ADDR_C45) -+ return -EOPNOTSUPP; -+ -+ regmap_write(priv->base, MII_DATA_REG_ADDR, data); -+ -+ miiaddr |= ((phy_addr << MII_ADDR_SHIFT) & MII_ADDR_MASK) | -+ ((reg_offset << MII_REG_SHIFT) & MII_REG_MASK); -+ -+ regmap_write(priv->base, MII_ADDR_REG_ADDR, miiaddr); -+ usleep_range(8, 10); -+ -+ return ipq8064_mdio_wait_busy(priv); -+} -+ -+static int -+ipq8064_mdio_probe(struct platform_device *pdev) -+{ -+ struct device_node *np = pdev->dev.of_node; -+ struct ipq8064_mdio *priv; -+ struct mii_bus *bus; -+ int ret; -+ -+ bus = devm_mdiobus_alloc_size(&pdev->dev, sizeof(*priv)); -+ if (!bus) -+ return -ENOMEM; -+ -+ bus->name = "ipq8064_mdio_bus"; -+ bus->read = ipq8064_mdio_read; -+ bus->write = ipq8064_mdio_write; -+ snprintf(bus->id, MII_BUS_ID_SIZE, "%s-mii", dev_name(&pdev->dev)); -+ bus->parent = &pdev->dev; -+ -+ priv = bus->priv; -+ priv->base = device_node_to_regmap(np); -+ if (IS_ERR(priv->base)) { -+ if (priv->base == ERR_PTR(-EPROBE_DEFER)) -+ return -EPROBE_DEFER; -+ -+ dev_err(&pdev->dev, "error getting device regmap, error=%pe\n", -+ priv->base); -+ return PTR_ERR(priv->base); -+ } -+ -+ ret = of_mdiobus_register(bus, np); -+ if (ret) -+ return ret; -+ -+ platform_set_drvdata(pdev, bus); -+ return 0; -+} -+ -+static int -+ipq8064_mdio_remove(struct platform_device *pdev) -+{ -+ struct mii_bus *bus = platform_get_drvdata(pdev); -+ -+ mdiobus_unregister(bus); -+ -+ return 0; -+} -+ -+static const struct of_device_id ipq8064_mdio_dt_ids[] = { -+ { .compatible = "qcom,ipq8064-mdio" }, -+ { } -+}; -+MODULE_DEVICE_TABLE(of, ipq8064_mdio_dt_ids); -+ -+static struct platform_driver ipq8064_mdio_driver = { -+ .probe = ipq8064_mdio_probe, -+ .remove = ipq8064_mdio_remove, -+ .driver = { -+ .name = "ipq8064-mdio", -+ .of_match_table = ipq8064_mdio_dt_ids, -+ }, -+}; -+ -+module_platform_driver(ipq8064_mdio_driver); -+ -+MODULE_DESCRIPTION("Qualcomm IPQ8064 MDIO interface driver"); -+MODULE_AUTHOR("Christian Lamparter "); -+MODULE_AUTHOR("Ansuel Smith "); -+MODULE_LICENSE("GPL"); diff --git a/target/linux/ipq806x/patches-5.10/095-1-v5.9-phy-qualcomm-add-qcom-ipq806x-dwc-usb-phy-driver.patch b/target/linux/ipq806x/patches-5.10/095-1-v5.9-phy-qualcomm-add-qcom-ipq806x-dwc-usb-phy-driver.patch deleted file mode 100644 index 47dc455715..0000000000 --- a/target/linux/ipq806x/patches-5.10/095-1-v5.9-phy-qualcomm-add-qcom-ipq806x-dwc-usb-phy-driver.patch +++ /dev/null @@ -1,621 +0,0 @@ -From ef19b117b83466e1c030368101a24367a34be7f0 Mon Sep 17 00:00:00 2001 -From: Ansuel Smith -Date: Fri, 17 Jul 2020 15:16:31 +0200 -Subject: phy: qualcomm: add qcom ipq806x dwc usb phy driver - -This has lost in the original push for the dwc3 qcom driver. -This is needed for ipq806x SoC as without this the usb ports -doesn't work at all. - -Signed-off-by: Andy Gross -Signed-off-by: Ansuel Smith -Tested-by: Jonathan McDowell -Link: https://lore.kernel.org/r/20200717131635.11076-1-ansuelsmth@gmail.com -Signed-off-by: Vinod Koul ---- - -Light modification to Kconfig as some config are missing in kernel 5.4 - - drivers/phy/qualcomm/Kconfig | 10 + - drivers/phy/qualcomm/Makefile | 1 + - drivers/phy/qualcomm/phy-qcom-ipq806x-usb.c | 571 ++++++++++++++++++++++++++++ - 3 files changed, 582 insertions(+) - create mode 100644 drivers/phy/qualcomm/phy-qcom-ipq806x-usb.c - ---- a/drivers/phy/qualcomm/Kconfig -+++ b/drivers/phy/qualcomm/Kconfig -@@ -91,3 +91,13 @@ config PHY_QCOM_USB_HSIC - select GENERIC_PHY - help - Support for the USB HSIC ULPI compliant PHY on QCOM chipsets. -+ -+config PHY_QCOM_IPQ806X_USB -+ tristate "Qualcomm IPQ806x DWC3 USB PHY driver" -+ depends on HAS_IOMEM -+ depends on OF && (ARCH_QCOM || COMPILE_TEST) -+ select GENERIC_PHY -+ help -+ This option enables support for the Synopsis PHYs present inside the -+ Qualcomm USB3.0 DWC3 controller on ipq806x SoC. This driver supports -+ both HS and SS PHY controllers. ---- a/drivers/phy/qualcomm/Makefile -+++ b/drivers/phy/qualcomm/Makefile -@@ -10,3 +10,4 @@ obj-$(CONFIG_PHY_QCOM_UFS_14NM) += phy- - obj-$(CONFIG_PHY_QCOM_UFS_20NM) += phy-qcom-ufs-qmp-20nm.o - obj-$(CONFIG_PHY_QCOM_USB_HS) += phy-qcom-usb-hs.o - obj-$(CONFIG_PHY_QCOM_USB_HSIC) += phy-qcom-usb-hsic.o -+obj-$(CONFIG_PHY_QCOM_IPQ806X_USB) += phy-qcom-ipq806x-usb.o ---- /dev/null -+++ b/drivers/phy/qualcomm/phy-qcom-ipq806x-usb.c -@@ -0,0 +1,571 @@ -+// SPDX-License-Identifier: GPL-2.0-only -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+/* USB QSCRATCH Hardware registers */ -+#define QSCRATCH_GENERAL_CFG (0x08) -+#define HSUSB_PHY_CTRL_REG (0x10) -+ -+/* PHY_CTRL_REG */ -+#define HSUSB_CTRL_DMSEHV_CLAMP BIT(24) -+#define HSUSB_CTRL_USB2_SUSPEND BIT(23) -+#define HSUSB_CTRL_UTMI_CLK_EN BIT(21) -+#define HSUSB_CTRL_UTMI_OTG_VBUS_VALID BIT(20) -+#define HSUSB_CTRL_USE_CLKCORE BIT(18) -+#define HSUSB_CTRL_DPSEHV_CLAMP BIT(17) -+#define HSUSB_CTRL_COMMONONN BIT(11) -+#define HSUSB_CTRL_ID_HV_CLAMP BIT(9) -+#define HSUSB_CTRL_OTGSESSVLD_CLAMP BIT(8) -+#define HSUSB_CTRL_CLAMP_EN BIT(7) -+#define HSUSB_CTRL_RETENABLEN BIT(1) -+#define HSUSB_CTRL_POR BIT(0) -+ -+/* QSCRATCH_GENERAL_CFG */ -+#define HSUSB_GCFG_XHCI_REV BIT(2) -+ -+/* USB QSCRATCH Hardware registers */ -+#define SSUSB_PHY_CTRL_REG (0x00) -+#define SSUSB_PHY_PARAM_CTRL_1 (0x04) -+#define SSUSB_PHY_PARAM_CTRL_2 (0x08) -+#define CR_PROTOCOL_DATA_IN_REG (0x0c) -+#define CR_PROTOCOL_DATA_OUT_REG (0x10) -+#define CR_PROTOCOL_CAP_ADDR_REG (0x14) -+#define CR_PROTOCOL_CAP_DATA_REG (0x18) -+#define CR_PROTOCOL_READ_REG (0x1c) -+#define CR_PROTOCOL_WRITE_REG (0x20) -+ -+/* PHY_CTRL_REG */ -+#define SSUSB_CTRL_REF_USE_PAD BIT(28) -+#define SSUSB_CTRL_TEST_POWERDOWN BIT(27) -+#define SSUSB_CTRL_LANE0_PWR_PRESENT BIT(24) -+#define SSUSB_CTRL_SS_PHY_EN BIT(8) -+#define SSUSB_CTRL_SS_PHY_RESET BIT(7) -+ -+/* SSPHY control registers - Does this need 0x30? */ -+#define SSPHY_CTRL_RX_OVRD_IN_HI(lane) (0x1006 + 0x100 * (lane)) -+#define SSPHY_CTRL_TX_OVRD_DRV_LO(lane) (0x1002 + 0x100 * (lane)) -+ -+/* SSPHY SoC version specific values */ -+#define SSPHY_RX_EQ_VALUE 4 /* Override value for rx_eq */ -+/* Override value for transmit preemphasis */ -+#define SSPHY_TX_DEEMPH_3_5DB 23 -+/* Override value for mpll */ -+#define SSPHY_MPLL_VALUE 0 -+ -+/* QSCRATCH PHY_PARAM_CTRL1 fields */ -+#define PHY_PARAM_CTRL1_TX_FULL_SWING_MASK GENMASK(26, 19) -+#define PHY_PARAM_CTRL1_TX_DEEMPH_6DB_MASK GENMASK(19, 13) -+#define PHY_PARAM_CTRL1_TX_DEEMPH_3_5DB_MASK GENMASK(13, 7) -+#define PHY_PARAM_CTRL1_LOS_BIAS_MASK GENMASK(7, 2) -+ -+#define PHY_PARAM_CTRL1_MASK \ -+ (PHY_PARAM_CTRL1_TX_FULL_SWING_MASK | \ -+ PHY_PARAM_CTRL1_TX_DEEMPH_6DB_MASK | \ -+ PHY_PARAM_CTRL1_TX_DEEMPH_3_5DB_MASK | \ -+ PHY_PARAM_CTRL1_LOS_BIAS_MASK) -+ -+#define PHY_PARAM_CTRL1_TX_FULL_SWING(x) \ -+ (((x) << 20) & PHY_PARAM_CTRL1_TX_FULL_SWING_MASK) -+#define PHY_PARAM_CTRL1_TX_DEEMPH_6DB(x) \ -+ (((x) << 14) & PHY_PARAM_CTRL1_TX_DEEMPH_6DB_MASK) -+#define PHY_PARAM_CTRL1_TX_DEEMPH_3_5DB(x) \ -+ (((x) << 8) & PHY_PARAM_CTRL1_TX_DEEMPH_3_5DB_MASK) -+#define PHY_PARAM_CTRL1_LOS_BIAS(x) \ -+ (((x) << 3) & PHY_PARAM_CTRL1_LOS_BIAS_MASK) -+ -+/* RX OVRD IN HI bits */ -+#define RX_OVRD_IN_HI_RX_RESET_OVRD BIT(13) -+#define RX_OVRD_IN_HI_RX_RX_RESET BIT(12) -+#define RX_OVRD_IN_HI_RX_EQ_OVRD BIT(11) -+#define RX_OVRD_IN_HI_RX_EQ_MASK GENMASK(10, 7) -+#define RX_OVRD_IN_HI_RX_EQ(x) ((x) << 8) -+#define RX_OVRD_IN_HI_RX_EQ_EN_OVRD BIT(7) -+#define RX_OVRD_IN_HI_RX_EQ_EN BIT(6) -+#define RX_OVRD_IN_HI_RX_LOS_FILTER_OVRD BIT(5) -+#define RX_OVRD_IN_HI_RX_LOS_FILTER_MASK GENMASK(4, 2) -+#define RX_OVRD_IN_HI_RX_RATE_OVRD BIT(2) -+#define RX_OVRD_IN_HI_RX_RATE_MASK GENMASK(2, 0) -+ -+/* TX OVRD DRV LO register bits */ -+#define TX_OVRD_DRV_LO_AMPLITUDE_MASK GENMASK(6, 0) -+#define TX_OVRD_DRV_LO_PREEMPH_MASK GENMASK(13, 6) -+#define TX_OVRD_DRV_LO_PREEMPH(x) ((x) << 7) -+#define TX_OVRD_DRV_LO_EN BIT(14) -+ -+/* MPLL bits */ -+#define SSPHY_MPLL_MASK GENMASK(8, 5) -+#define SSPHY_MPLL(x) ((x) << 5) -+ -+/* SS CAP register bits */ -+#define SS_CR_CAP_ADDR_REG BIT(0) -+#define SS_CR_CAP_DATA_REG BIT(0) -+#define SS_CR_READ_REG BIT(0) -+#define SS_CR_WRITE_REG BIT(0) -+ -+struct usb_phy { -+ void __iomem *base; -+ struct device *dev; -+ struct clk *xo_clk; -+ struct clk *ref_clk; -+ u32 rx_eq; -+ u32 tx_deamp_3_5db; -+ u32 mpll; -+}; -+ -+struct phy_drvdata { -+ struct phy_ops ops; -+ u32 clk_rate; -+}; -+ -+/** -+ * Write register and read back masked value to confirm it is written -+ * -+ * @base - QCOM DWC3 PHY base virtual address. -+ * @offset - register offset. -+ * @mask - register bitmask specifying what should be updated -+ * @val - value to write. -+ */ -+static inline void usb_phy_write_readback(struct usb_phy *phy_dwc3, -+ u32 offset, -+ const u32 mask, u32 val) -+{ -+ u32 write_val, tmp = readl(phy_dwc3->base + offset); -+ -+ tmp &= ~mask; /* retain other bits */ -+ write_val = tmp | val; -+ -+ writel(write_val, phy_dwc3->base + offset); -+ -+ /* Read back to see if val was written */ -+ tmp = readl(phy_dwc3->base + offset); -+ tmp &= mask; /* clear other bits */ -+ -+ if (tmp != val) -+ dev_err(phy_dwc3->dev, "write: %x to QSCRATCH: %x FAILED\n", val, offset); -+} -+ -+static int wait_for_latch(void __iomem *addr) -+{ -+ u32 retry = 10; -+ -+ while (true) { -+ if (!readl(addr)) -+ break; -+ -+ if (--retry == 0) -+ return -ETIMEDOUT; -+ -+ usleep_range(10, 20); -+ } -+ -+ return 0; -+} -+ -+/** -+ * Write SSPHY register -+ * -+ * @base - QCOM DWC3 PHY base virtual address. -+ * @addr - SSPHY address to write. -+ * @val - value to write. -+ */ -+static int usb_ss_write_phycreg(struct usb_phy *phy_dwc3, -+ u32 addr, u32 val) -+{ -+ int ret; -+ -+ writel(addr, phy_dwc3->base + CR_PROTOCOL_DATA_IN_REG); -+ writel(SS_CR_CAP_ADDR_REG, -+ phy_dwc3->base + CR_PROTOCOL_CAP_ADDR_REG); -+ -+ ret = wait_for_latch(phy_dwc3->base + CR_PROTOCOL_CAP_ADDR_REG); -+ if (ret) -+ goto err_wait; -+ -+ writel(val, phy_dwc3->base + CR_PROTOCOL_DATA_IN_REG); -+ writel(SS_CR_CAP_DATA_REG, -+ phy_dwc3->base + CR_PROTOCOL_CAP_DATA_REG); -+ -+ ret = wait_for_latch(phy_dwc3->base + CR_PROTOCOL_CAP_DATA_REG); -+ if (ret) -+ goto err_wait; -+ -+ writel(SS_CR_WRITE_REG, phy_dwc3->base + CR_PROTOCOL_WRITE_REG); -+ -+ ret = wait_for_latch(phy_dwc3->base + CR_PROTOCOL_WRITE_REG); -+ -+err_wait: -+ if (ret) -+ dev_err(phy_dwc3->dev, "timeout waiting for latch\n"); -+ return ret; -+} -+ -+/** -+ * Read SSPHY register. -+ * -+ * @base - QCOM DWC3 PHY base virtual address. -+ * @addr - SSPHY address to read. -+ */ -+static int usb_ss_read_phycreg(struct usb_phy *phy_dwc3, -+ u32 addr, u32 *val) -+{ -+ int ret; -+ -+ writel(addr, phy_dwc3->base + CR_PROTOCOL_DATA_IN_REG); -+ writel(SS_CR_CAP_ADDR_REG, -+ phy_dwc3->base + CR_PROTOCOL_CAP_ADDR_REG); -+ -+ ret = wait_for_latch(phy_dwc3->base + CR_PROTOCOL_CAP_ADDR_REG); -+ if (ret) -+ goto err_wait; -+ -+ /* -+ * Due to hardware bug, first read of SSPHY register might be -+ * incorrect. Hence as workaround, SW should perform SSPHY register -+ * read twice, but use only second read and ignore first read. -+ */ -+ writel(SS_CR_READ_REG, phy_dwc3->base + CR_PROTOCOL_READ_REG); -+ -+ ret = wait_for_latch(phy_dwc3->base + CR_PROTOCOL_READ_REG); -+ if (ret) -+ goto err_wait; -+ -+ /* throwaway read */ -+ readl(phy_dwc3->base + CR_PROTOCOL_DATA_OUT_REG); -+ -+ writel(SS_CR_READ_REG, phy_dwc3->base + CR_PROTOCOL_READ_REG); -+ -+ ret = wait_for_latch(phy_dwc3->base + CR_PROTOCOL_READ_REG); -+ if (ret) -+ goto err_wait; -+ -+ *val = readl(phy_dwc3->base + CR_PROTOCOL_DATA_OUT_REG); -+ -+err_wait: -+ return ret; -+} -+ -+static int qcom_ipq806x_usb_hs_phy_init(struct phy *phy) -+{ -+ struct usb_phy *phy_dwc3 = phy_get_drvdata(phy); -+ int ret; -+ u32 val; -+ -+ ret = clk_prepare_enable(phy_dwc3->xo_clk); -+ if (ret) -+ return ret; -+ -+ ret = clk_prepare_enable(phy_dwc3->ref_clk); -+ if (ret) { -+ clk_disable_unprepare(phy_dwc3->xo_clk); -+ return ret; -+ } -+ -+ /* -+ * HSPHY Initialization: Enable UTMI clock, select 19.2MHz fsel -+ * enable clamping, and disable RETENTION (power-on default is ENABLED) -+ */ -+ val = HSUSB_CTRL_DPSEHV_CLAMP | HSUSB_CTRL_DMSEHV_CLAMP | -+ HSUSB_CTRL_RETENABLEN | HSUSB_CTRL_COMMONONN | -+ HSUSB_CTRL_OTGSESSVLD_CLAMP | HSUSB_CTRL_ID_HV_CLAMP | -+ HSUSB_CTRL_DPSEHV_CLAMP | HSUSB_CTRL_UTMI_OTG_VBUS_VALID | -+ HSUSB_CTRL_UTMI_CLK_EN | HSUSB_CTRL_CLAMP_EN | 0x70; -+ -+ /* use core clock if external reference is not present */ -+ if (!phy_dwc3->xo_clk) -+ val |= HSUSB_CTRL_USE_CLKCORE; -+ -+ writel(val, phy_dwc3->base + HSUSB_PHY_CTRL_REG); -+ usleep_range(2000, 2200); -+ -+ /* Disable (bypass) VBUS and ID filters */ -+ writel(HSUSB_GCFG_XHCI_REV, phy_dwc3->base + QSCRATCH_GENERAL_CFG); -+ -+ return 0; -+} -+ -+static int qcom_ipq806x_usb_hs_phy_exit(struct phy *phy) -+{ -+ struct usb_phy *phy_dwc3 = phy_get_drvdata(phy); -+ -+ clk_disable_unprepare(phy_dwc3->ref_clk); -+ clk_disable_unprepare(phy_dwc3->xo_clk); -+ -+ return 0; -+} -+ -+static int qcom_ipq806x_usb_ss_phy_init(struct phy *phy) -+{ -+ struct usb_phy *phy_dwc3 = phy_get_drvdata(phy); -+ int ret; -+ u32 data; -+ -+ ret = clk_prepare_enable(phy_dwc3->xo_clk); -+ if (ret) -+ return ret; -+ -+ ret = clk_prepare_enable(phy_dwc3->ref_clk); -+ if (ret) { -+ clk_disable_unprepare(phy_dwc3->xo_clk); -+ return ret; -+ } -+ -+ /* reset phy */ -+ data = readl(phy_dwc3->base + SSUSB_PHY_CTRL_REG); -+ writel(data | SSUSB_CTRL_SS_PHY_RESET, -+ phy_dwc3->base + SSUSB_PHY_CTRL_REG); -+ usleep_range(2000, 2200); -+ writel(data, phy_dwc3->base + SSUSB_PHY_CTRL_REG); -+ -+ /* clear REF_PAD if we don't have XO clk */ -+ if (!phy_dwc3->xo_clk) -+ data &= ~SSUSB_CTRL_REF_USE_PAD; -+ else -+ data |= SSUSB_CTRL_REF_USE_PAD; -+ -+ writel(data, phy_dwc3->base + SSUSB_PHY_CTRL_REG); -+ -+ /* wait for ref clk to become stable, this can take up to 30ms */ -+ msleep(30); -+ -+ data |= SSUSB_CTRL_SS_PHY_EN | SSUSB_CTRL_LANE0_PWR_PRESENT; -+ writel(data, phy_dwc3->base + SSUSB_PHY_CTRL_REG); -+ -+ /* -+ * WORKAROUND: There is SSPHY suspend bug due to which USB enumerates -+ * in HS mode instead of SS mode. Workaround it by asserting -+ * LANE0.TX_ALT_BLOCK.EN_ALT_BUS to enable TX to use alt bus mode -+ */ -+ ret = usb_ss_read_phycreg(phy_dwc3, 0x102D, &data); -+ if (ret) -+ goto err_phy_trans; -+ -+ data |= (1 << 7); -+ ret = usb_ss_write_phycreg(phy_dwc3, 0x102D, data); -+ if (ret) -+ goto err_phy_trans; -+ -+ ret = usb_ss_read_phycreg(phy_dwc3, 0x1010, &data); -+ if (ret) -+ goto err_phy_trans; -+ -+ data &= ~0xff0; -+ data |= 0x20; -+ ret = usb_ss_write_phycreg(phy_dwc3, 0x1010, data); -+ if (ret) -+ goto err_phy_trans; -+ -+ /* -+ * Fix RX Equalization setting as follows -+ * LANE0.RX_OVRD_IN_HI. RX_EQ_EN set to 0 -+ * LANE0.RX_OVRD_IN_HI.RX_EQ_EN_OVRD set to 1 -+ * LANE0.RX_OVRD_IN_HI.RX_EQ set based on SoC version -+ * LANE0.RX_OVRD_IN_HI.RX_EQ_OVRD set to 1 -+ */ -+ ret = usb_ss_read_phycreg(phy_dwc3, SSPHY_CTRL_RX_OVRD_IN_HI(0), &data); -+ if (ret) -+ goto err_phy_trans; -+ -+ data &= ~RX_OVRD_IN_HI_RX_EQ_EN; -+ data |= RX_OVRD_IN_HI_RX_EQ_EN_OVRD; -+ data &= ~RX_OVRD_IN_HI_RX_EQ_MASK; -+ data |= RX_OVRD_IN_HI_RX_EQ(phy_dwc3->rx_eq); -+ data |= RX_OVRD_IN_HI_RX_EQ_OVRD; -+ ret = usb_ss_write_phycreg(phy_dwc3, -+ SSPHY_CTRL_RX_OVRD_IN_HI(0), data); -+ if (ret) -+ goto err_phy_trans; -+ -+ /* -+ * Set EQ and TX launch amplitudes as follows -+ * LANE0.TX_OVRD_DRV_LO.PREEMPH set based on SoC version -+ * LANE0.TX_OVRD_DRV_LO.AMPLITUDE set to 110 -+ * LANE0.TX_OVRD_DRV_LO.EN set to 1. -+ */ -+ ret = usb_ss_read_phycreg(phy_dwc3, -+ SSPHY_CTRL_TX_OVRD_DRV_LO(0), &data); -+ if (ret) -+ goto err_phy_trans; -+ -+ data &= ~TX_OVRD_DRV_LO_PREEMPH_MASK; -+ data |= TX_OVRD_DRV_LO_PREEMPH(phy_dwc3->tx_deamp_3_5db); -+ data &= ~TX_OVRD_DRV_LO_AMPLITUDE_MASK; -+ data |= 0x6E; -+ data |= TX_OVRD_DRV_LO_EN; -+ ret = usb_ss_write_phycreg(phy_dwc3, -+ SSPHY_CTRL_TX_OVRD_DRV_LO(0), data); -+ if (ret) -+ goto err_phy_trans; -+ -+ data = 0; -+ data &= ~SSPHY_MPLL_MASK; -+ data |= SSPHY_MPLL(phy_dwc3->mpll); -+ usb_ss_write_phycreg(phy_dwc3, 0x30, data); -+ -+ /* -+ * Set the QSCRATCH PHY_PARAM_CTRL1 parameters as follows -+ * TX_FULL_SWING [26:20] amplitude to 110 -+ * TX_DEEMPH_6DB [19:14] to 32 -+ * TX_DEEMPH_3_5DB [13:8] set based on SoC version -+ * LOS_BIAS [7:3] to 9 -+ */ -+ data = readl(phy_dwc3->base + SSUSB_PHY_PARAM_CTRL_1); -+ -+ data &= ~PHY_PARAM_CTRL1_MASK; -+ -+ data |= PHY_PARAM_CTRL1_TX_FULL_SWING(0x6e) | -+ PHY_PARAM_CTRL1_TX_DEEMPH_6DB(0x20) | -+ PHY_PARAM_CTRL1_TX_DEEMPH_3_5DB(phy_dwc3->tx_deamp_3_5db) | -+ PHY_PARAM_CTRL1_LOS_BIAS(0x9); -+ -+ usb_phy_write_readback(phy_dwc3, SSUSB_PHY_PARAM_CTRL_1, -+ PHY_PARAM_CTRL1_MASK, data); -+ -+err_phy_trans: -+ return ret; -+} -+ -+static int qcom_ipq806x_usb_ss_phy_exit(struct phy *phy) -+{ -+ struct usb_phy *phy_dwc3 = phy_get_drvdata(phy); -+ -+ /* Sequence to put SSPHY in low power state: -+ * 1. Clear REF_PHY_EN in PHY_CTRL_REG -+ * 2. Clear REF_USE_PAD in PHY_CTRL_REG -+ * 3. Set TEST_POWERED_DOWN in PHY_CTRL_REG to enable PHY retention -+ */ -+ usb_phy_write_readback(phy_dwc3, SSUSB_PHY_CTRL_REG, -+ SSUSB_CTRL_SS_PHY_EN, 0x0); -+ usb_phy_write_readback(phy_dwc3, SSUSB_PHY_CTRL_REG, -+ SSUSB_CTRL_REF_USE_PAD, 0x0); -+ usb_phy_write_readback(phy_dwc3, SSUSB_PHY_CTRL_REG, -+ SSUSB_CTRL_TEST_POWERDOWN, 0x0); -+ -+ clk_disable_unprepare(phy_dwc3->ref_clk); -+ clk_disable_unprepare(phy_dwc3->xo_clk); -+ -+ return 0; -+} -+ -+static const struct phy_drvdata qcom_ipq806x_usb_hs_drvdata = { -+ .ops = { -+ .init = qcom_ipq806x_usb_hs_phy_init, -+ .exit = qcom_ipq806x_usb_hs_phy_exit, -+ .owner = THIS_MODULE, -+ }, -+ .clk_rate = 60000000, -+}; -+ -+static const struct phy_drvdata qcom_ipq806x_usb_ss_drvdata = { -+ .ops = { -+ .init = qcom_ipq806x_usb_ss_phy_init, -+ .exit = qcom_ipq806x_usb_ss_phy_exit, -+ .owner = THIS_MODULE, -+ }, -+ .clk_rate = 125000000, -+}; -+ -+static const struct of_device_id qcom_ipq806x_usb_phy_table[] = { -+ { .compatible = "qcom,ipq806x-usb-phy-hs", -+ .data = &qcom_ipq806x_usb_hs_drvdata }, -+ { .compatible = "qcom,ipq806x-usb-phy-ss", -+ .data = &qcom_ipq806x_usb_ss_drvdata }, -+ { /* Sentinel */ } -+}; -+MODULE_DEVICE_TABLE(of, qcom_ipq806x_usb_phy_table); -+ -+static int qcom_ipq806x_usb_phy_probe(struct platform_device *pdev) -+{ -+ struct resource *res; -+ resource_size_t size; -+ struct phy *generic_phy; -+ struct usb_phy *phy_dwc3; -+ const struct phy_drvdata *data; -+ struct phy_provider *phy_provider; -+ -+ phy_dwc3 = devm_kzalloc(&pdev->dev, sizeof(*phy_dwc3), GFP_KERNEL); -+ if (!phy_dwc3) -+ return -ENOMEM; -+ -+ data = of_device_get_match_data(&pdev->dev); -+ -+ phy_dwc3->dev = &pdev->dev; -+ -+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ if (!res) -+ return -EINVAL; -+ size = resource_size(res); -+ phy_dwc3->base = devm_ioremap(phy_dwc3->dev, res->start, size); -+ -+ if (IS_ERR(phy_dwc3->base)) { -+ dev_err(phy_dwc3->dev, "failed to map reg\n"); -+ return PTR_ERR(phy_dwc3->base); -+ } -+ -+ phy_dwc3->ref_clk = devm_clk_get(phy_dwc3->dev, "ref"); -+ if (IS_ERR(phy_dwc3->ref_clk)) { -+ dev_dbg(phy_dwc3->dev, "cannot get reference clock\n"); -+ return PTR_ERR(phy_dwc3->ref_clk); -+ } -+ -+ clk_set_rate(phy_dwc3->ref_clk, data->clk_rate); -+ -+ phy_dwc3->xo_clk = devm_clk_get(phy_dwc3->dev, "xo"); -+ if (IS_ERR(phy_dwc3->xo_clk)) { -+ dev_dbg(phy_dwc3->dev, "cannot get TCXO clock\n"); -+ phy_dwc3->xo_clk = NULL; -+ } -+ -+ /* Parse device node to probe HSIO settings */ -+ if (device_property_read_u32(&pdev->dev, "qcom,rx-eq", -+ &phy_dwc3->rx_eq)) -+ phy_dwc3->rx_eq = SSPHY_RX_EQ_VALUE; -+ -+ if (device_property_read_u32(&pdev->dev, "qcom,tx-deamp_3_5db", -+ &phy_dwc3->tx_deamp_3_5db)) -+ phy_dwc3->rx_eq = SSPHY_TX_DEEMPH_3_5DB; -+ -+ if (device_property_read_u32(&pdev->dev, "qcom,mpll", &phy_dwc3->mpll)) -+ phy_dwc3->mpll = SSPHY_MPLL_VALUE; -+ -+ generic_phy = devm_phy_create(phy_dwc3->dev, pdev->dev.of_node, &data->ops); -+ -+ if (IS_ERR(generic_phy)) -+ return PTR_ERR(generic_phy); -+ -+ phy_set_drvdata(generic_phy, phy_dwc3); -+ platform_set_drvdata(pdev, phy_dwc3); -+ -+ phy_provider = devm_of_phy_provider_register(phy_dwc3->dev, -+ of_phy_simple_xlate); -+ -+ if (IS_ERR(phy_provider)) -+ return PTR_ERR(phy_provider); -+ -+ return 0; -+} -+ -+static struct platform_driver qcom_ipq806x_usb_phy_driver = { -+ .probe = qcom_ipq806x_usb_phy_probe, -+ .driver = { -+ .name = "qcom-ipq806x-usb-phy", -+ .owner = THIS_MODULE, -+ .of_match_table = qcom_ipq806x_usb_phy_table, -+ }, -+}; -+ -+module_platform_driver(qcom_ipq806x_usb_phy_driver); -+ -+MODULE_ALIAS("platform:phy-qcom-ipq806x-usb"); -+MODULE_LICENSE("GPL v2"); -+MODULE_AUTHOR("Andy Gross "); -+MODULE_AUTHOR("Ivan T. Ivanov "); -+MODULE_DESCRIPTION("DesignWare USB3 QCOM PHY driver"); diff --git a/target/linux/ipq806x/patches-5.10/095-2-v5.9-phy-qualcomm-fix-setting-of-tx_deamp_3_5db-when-device-property-read-fails.patch b/target/linux/ipq806x/patches-5.10/095-2-v5.9-phy-qualcomm-fix-setting-of-tx_deamp_3_5db-when-device-property-read-fails.patch deleted file mode 100644 index dedbb51049..0000000000 --- a/target/linux/ipq806x/patches-5.10/095-2-v5.9-phy-qualcomm-fix-setting-of-tx_deamp_3_5db-when-device-property-read-fails.patch +++ /dev/null @@ -1,31 +0,0 @@ -From 3d7b0ca5300bd01b176f2b4c10e173db802560d8 Mon Sep 17 00:00:00 2001 -From: Colin Ian King -Date: Tue, 21 Jul 2020 16:06:13 +0100 -Subject: phy: qualcomm: fix setting of tx_deamp_3_5db when device property - read fails - -Currently when reading of the device property for "qcom,tx-deamp_3_5db" -fails the default is being assigned incorrectly to phy_dwc3->rx_eq. This -looks like a copy-n-paste error and in fact should be assigning the -default instead to phy_dwc3->tx_deamp_3_5db - -Addresses-Coverity: ("Copy-paste error") -Fixes: ef19b117b834 ("phy: qualcomm: add qcom ipq806x dwc usb phy driver") -Signed-off-by: Colin Ian King -Link: https://lore.kernel.org/r/20200721150613.416876-1-colin.king@canonical.com -Signed-off-by: Vinod Koul ---- - drivers/phy/qualcomm/phy-qcom-ipq806x-usb.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - ---- a/drivers/phy/qualcomm/phy-qcom-ipq806x-usb.c -+++ b/drivers/phy/qualcomm/phy-qcom-ipq806x-usb.c -@@ -531,7 +531,7 @@ static int qcom_ipq806x_usb_phy_probe(st - - if (device_property_read_u32(&pdev->dev, "qcom,tx-deamp_3_5db", - &phy_dwc3->tx_deamp_3_5db)) -- phy_dwc3->rx_eq = SSPHY_TX_DEEMPH_3_5DB; -+ phy_dwc3->tx_deamp_3_5db = SSPHY_TX_DEEMPH_3_5DB; - - if (device_property_read_u32(&pdev->dev, "qcom,mpll", &phy_dwc3->mpll)) - phy_dwc3->mpll = SSPHY_MPLL_VALUE; From 5dbbefcbccc06cbcc8da0706afba52f741781d47 Mon Sep 17 00:00:00 2001 From: Ansuel Smith Date: Mon, 1 Mar 2021 01:11:16 +0100 Subject: [PATCH 19/62] ipq806x: introduce dedicated krait cpufreq - Drop cpufreq patchs that tweak the cpufreq-dt driver - Add dedicated krait cpufreq driver Signed-off-by: Ansuel Smith --- ...rt-adjusting-OPP-voltages-at-runtime.patch | 153 ---- ...per-to-get-an-opp-regulator-for-devi.patch | 52 -- ...e-voltage-tolerance-when-adjusting-t.patch | 47 -- ...-dt-Handle-OPP-voltage-adjust-events.patch | 118 --- ...-dt-Add-L2-frequency-scaling-support.patch | 199 ----- ...056-cpufreq-dt-Add-missing-rcu-locks.patch | 23 - ...qcom-cpufreq-nvmem-support-specific-.patch | 56 ++ ...q-add-Krait-dedicated-scaling-driver.patch | 679 ++++++++++++++++++ ...ufreq-add-qcom-krait-cpufreq-binding.patch | 243 +++++++ ...dd-fab-scaling-support-with-cpufreq.patch} | 32 +- 10 files changed, 994 insertions(+), 608 deletions(-) delete mode 100644 target/linux/ipq806x/patches-5.10/0049-PM-OPP-Support-adjusting-OPP-voltages-at-runtime.patch delete mode 100644 target/linux/ipq806x/patches-5.10/0051-PM-OPP-Add-a-helper-to-get-an-opp-regulator-for-devi.patch delete mode 100644 target/linux/ipq806x/patches-5.10/0052-PM-OPP-Update-the-voltage-tolerance-when-adjusting-t.patch delete mode 100644 target/linux/ipq806x/patches-5.10/0054-cpufreq-dt-Handle-OPP-voltage-adjust-events.patch delete mode 100644 target/linux/ipq806x/patches-5.10/0055-cpufreq-dt-Add-L2-frequency-scaling-support.patch delete mode 100644 target/linux/ipq806x/patches-5.10/0056-cpufreq-dt-Add-missing-rcu-locks.patch create mode 100644 target/linux/ipq806x/patches-5.10/093-drivers-cpufreq-qcom-cpufreq-nvmem-support-specific-.patch create mode 100644 target/linux/ipq806x/patches-5.10/098-1-cpufreq-add-Krait-dedicated-scaling-driver.patch create mode 100644 target/linux/ipq806x/patches-5.10/098-2-Documentation-cpufreq-add-qcom-krait-cpufreq-binding.patch rename target/linux/ipq806x/patches-5.10/{0057-add-fab-scaling-support-with-cpufreq.patch => 098-3-add-fab-scaling-support-with-cpufreq.patch} (93%) diff --git a/target/linux/ipq806x/patches-5.10/0049-PM-OPP-Support-adjusting-OPP-voltages-at-runtime.patch b/target/linux/ipq806x/patches-5.10/0049-PM-OPP-Support-adjusting-OPP-voltages-at-runtime.patch deleted file mode 100644 index 9efbd583b4..0000000000 --- a/target/linux/ipq806x/patches-5.10/0049-PM-OPP-Support-adjusting-OPP-voltages-at-runtime.patch +++ /dev/null @@ -1,153 +0,0 @@ -From: Sylwester Nawrocki -To: krzk@kernel.org, vireshk@kernel.org, robh+dt@kernel.org -Cc: sboyd@kernel.org, roger.lu@mediatek.com, - linux-pm@vger.kernel.org, linux-arm-kernel@lists.infradead.org, - linux-samsung-soc@vger.kernel.org, devicetree@vger.kernel.org, - b.zolnierkie@samsung.com, m.szyprowski@samsung.com, - Stephen Boyd , - Sylwester Nawrocki -Subject: [PATCH v5 1/4] PM / OPP: Support adjusting OPP voltages at runtime -Date: Wed, 16 Oct 2019 16:57:53 +0200 -Message-ID: <20191016145756.16004-2-s.nawrocki@samsung.com> (raw) -In-Reply-To: <20191016145756.16004-1-s.nawrocki@samsung.com> - -From: Stephen Boyd - -On some SoCs the Adaptive Voltage Scaling (AVS) technique is -employed to optimize the operating voltage of a device. At a -given frequency, the hardware monitors dynamic factors and either -makes a suggestion for how much to adjust a voltage for the -current frequency, or it automatically adjusts the voltage -without software intervention. Add an API to the OPP library for -the former case, so that AVS type devices can update the voltages -for an OPP when the hardware determines the voltage should -change. The assumption is that drivers like CPUfreq or devfreq -will register for the OPP notifiers and adjust the voltage -according to suggestions that AVS makes. - -This patch is derived from [1] submitted by Stephen. -[1] https://lore.kernel.org/patchwork/patch/599279/ - -Signed-off-by: Stephen Boyd -Signed-off-by: Roger Lu -[s.nawrocki@samsung.com: added handling of OPP min/max voltage] -Signed-off-by: Sylwester Nawrocki ---- - drivers/opp/core.c | 69 ++++++++++++++++++++++++++++++++++++++++++ - include/linux/pm_opp.h | 13 ++++++++ - 2 files changed, 82 insertions(+) - ---- a/drivers/opp/core.c -+++ b/drivers/opp/core.c -@@ -2102,6 +2102,75 @@ put_table: - } - - /** -+ * dev_pm_opp_adjust_voltage() - helper to change the voltage of an OPP -+ * @dev: device for which we do this operation -+ * @freq: OPP frequency to adjust voltage of -+ * @u_volt: new OPP target voltage -+ * @u_volt_min: new OPP min voltage -+ * @u_volt_max: new OPP max voltage -+ * -+ * Return: -EINVAL for bad pointers, -ENOMEM if no memory available for the -+ * copy operation, returns 0 if no modifcation was done OR modification was -+ * successful. -+ */ -+int dev_pm_opp_adjust_voltage(struct device *dev, unsigned long freq, -+ unsigned long u_volt, unsigned long u_volt_min, -+ unsigned long u_volt_max) -+ -+{ -+ struct opp_table *opp_table; -+ struct dev_pm_opp *tmp_opp, *opp = ERR_PTR(-ENODEV); -+ int r = 0; -+ -+ /* Find the opp_table */ -+ opp_table = _find_opp_table(dev); -+ if (IS_ERR(opp_table)) { -+ r = PTR_ERR(opp_table); -+ dev_warn(dev, "%s: Device OPP not found (%d)\n", __func__, r); -+ return r; -+ } -+ -+ mutex_lock(&opp_table->lock); -+ -+ /* Do we have the frequency? */ -+ list_for_each_entry(tmp_opp, &opp_table->opp_list, node) { -+ if (tmp_opp->rate == freq) { -+ opp = tmp_opp; -+ break; -+ } -+ } -+ -+ if (IS_ERR(opp)) { -+ r = PTR_ERR(opp); -+ goto adjust_unlock; -+ } -+ -+ /* Is update really needed? */ -+ if (opp->supplies->u_volt == u_volt) -+ goto adjust_unlock; -+ -+ opp->supplies->u_volt = u_volt; -+ opp->supplies->u_volt_min = u_volt_min; -+ opp->supplies->u_volt_max = u_volt_max; -+ -+ dev_pm_opp_get(opp); -+ mutex_unlock(&opp_table->lock); -+ -+ /* Notify the voltage change of the OPP */ -+ blocking_notifier_call_chain(&opp_table->head, OPP_EVENT_ADJUST_VOLTAGE, -+ opp); -+ -+ dev_pm_opp_put(opp); -+ goto adjust_put_table; -+ -+adjust_unlock: -+ mutex_unlock(&opp_table->lock); -+adjust_put_table: -+ dev_pm_opp_put_opp_table(opp_table); -+ return r; -+} -+ -+/** - * dev_pm_opp_enable() - Enable a specific OPP - * @dev: device for which we do this operation - * @freq: OPP frequency to enable ---- a/include/linux/pm_opp.h -+++ b/include/linux/pm_opp.h -@@ -22,6 +22,7 @@ struct opp_table; - - enum dev_pm_opp_event { - OPP_EVENT_ADD, OPP_EVENT_REMOVE, OPP_EVENT_ENABLE, OPP_EVENT_DISABLE, -+ OPP_EVENT_ADJUST_VOLTAGE, - }; - - /** -@@ -113,6 +114,10 @@ int dev_pm_opp_add(struct device *dev, u - void dev_pm_opp_remove(struct device *dev, unsigned long freq); - void dev_pm_opp_remove_all_dynamic(struct device *dev); - -+int dev_pm_opp_adjust_voltage(struct device *dev, unsigned long freq, -+ unsigned long u_volt, unsigned long u_volt_min, -+ unsigned long u_volt_max); -+ - int dev_pm_opp_enable(struct device *dev, unsigned long freq); - - int dev_pm_opp_disable(struct device *dev, unsigned long freq); -@@ -242,6 +247,14 @@ static inline void dev_pm_opp_remove_all - { - } - -+static inline int -+dev_pm_opp_adjust_voltage(struct device *dev, unsigned long freq, -+ unsigned long u_volt, unsigned long u_volt_min, -+ unsigned long u_volt_max) -+{ -+ return 0; -+} -+ - static inline int dev_pm_opp_enable(struct device *dev, unsigned long freq) - { - return 0; diff --git a/target/linux/ipq806x/patches-5.10/0051-PM-OPP-Add-a-helper-to-get-an-opp-regulator-for-devi.patch b/target/linux/ipq806x/patches-5.10/0051-PM-OPP-Add-a-helper-to-get-an-opp-regulator-for-devi.patch deleted file mode 100644 index 35fe45fca7..0000000000 --- a/target/linux/ipq806x/patches-5.10/0051-PM-OPP-Add-a-helper-to-get-an-opp-regulator-for-devi.patch +++ /dev/null @@ -1,52 +0,0 @@ -From d06ca5e7a3cf726f5be5ffd96e93ccd798b8c09a Mon Sep 17 00:00:00 2001 -From: Georgi Djakov -Date: Thu, 12 May 2016 14:41:33 +0300 -Subject: [PATCH 51/69] PM / OPP: Add a helper to get an opp regulator for - device - -Signed-off-by: Georgi Djakov ---- - drivers/opp/core.c | 21 +++++++++++++++++++++ - include/linux/pm_opp.h | 1 + - 2 files changed, 22 insertions(+) - ---- a/drivers/opp/core.c -+++ b/drivers/opp/core.c -@@ -127,6 +127,27 @@ unsigned long dev_pm_opp_get_freq(struct - } - EXPORT_SYMBOL_GPL(dev_pm_opp_get_freq); - -+struct regulator *dev_pm_opp_get_regulator(struct device *dev) -+{ -+ struct opp_table *opp_table; -+ struct regulator *reg; -+ -+ rcu_read_lock(); -+ -+ opp_table = _find_opp_table(dev); -+ if (IS_ERR(opp_table)) { -+ rcu_read_unlock(); -+ return ERR_CAST(opp_table); -+ } -+ -+ reg = opp_table->regulators[0]; -+ -+ rcu_read_unlock(); -+ -+ return reg; -+} -+EXPORT_SYMBOL_GPL(dev_pm_opp_get_regulator); -+ - /** - * dev_pm_opp_get_level() - Gets the level corresponding to an available opp - * @opp: opp for which level value has to be returned for ---- a/include/linux/pm_opp.h -+++ b/include/linux/pm_opp.h -@@ -83,6 +83,7 @@ void dev_pm_opp_put_opp_table(struct opp - unsigned long dev_pm_opp_get_voltage(struct dev_pm_opp *opp); - - unsigned long dev_pm_opp_get_freq(struct dev_pm_opp *opp); -+struct regulator *dev_pm_opp_get_regulator(struct device *dev); - - unsigned int dev_pm_opp_get_level(struct dev_pm_opp *opp); - diff --git a/target/linux/ipq806x/patches-5.10/0052-PM-OPP-Update-the-voltage-tolerance-when-adjusting-t.patch b/target/linux/ipq806x/patches-5.10/0052-PM-OPP-Update-the-voltage-tolerance-when-adjusting-t.patch deleted file mode 100644 index 8498a0b6df..0000000000 --- a/target/linux/ipq806x/patches-5.10/0052-PM-OPP-Update-the-voltage-tolerance-when-adjusting-t.patch +++ /dev/null @@ -1,47 +0,0 @@ -From 4533c285c2aedce6d4434d7b877066de3b1ecb33 Mon Sep 17 00:00:00 2001 -From: Georgi Djakov -Date: Thu, 25 Aug 2016 18:43:35 +0300 -Subject: [PATCH 52/69] PM / OPP: Update the voltage tolerance when adjusting - the OPP - -When the voltage is adjusted, the voltage tolerance is not updated. -This can lead to situations where the voltage min value is greater -than the voltage max value. The final result is triggering a BUG() -in the regulator core. -Fix this by updating the voltage tolerance values too. - -Signed-off-by: Georgi Djakov ---- - drivers/opp/core.c | 5 +++++ - 1 file changed, 5 insertions(+) - ---- a/drivers/opp/core.c -+++ b/drivers/opp/core.c -@@ -2142,6 +2142,7 @@ int dev_pm_opp_adjust_voltage(struct dev - struct opp_table *opp_table; - struct dev_pm_opp *tmp_opp, *opp = ERR_PTR(-ENODEV); - int r = 0; -+ unsigned long tol; - - /* Find the opp_table */ - opp_table = _find_opp_table(dev); -@@ -2171,8 +2172,17 @@ int dev_pm_opp_adjust_voltage(struct dev - goto adjust_unlock; - - opp->supplies->u_volt = u_volt; -- opp->supplies->u_volt_min = u_volt_min; -- opp->supplies->u_volt_max = u_volt_max; -+ -+ tol = u_volt * opp_table->voltage_tolerance_v1 / 100; -+ if ( u_volt_min == u_volt ) -+ opp->supplies->u_volt_min = u_volt - tol; -+ else -+ opp->supplies->u_volt_min = u_volt_min; -+ -+ if ( u_volt_max == u_volt ) -+ opp->supplies->u_volt_max = u_volt + tol; -+ else -+ opp->supplies->u_volt_max = u_volt_max; - - dev_pm_opp_get(opp); - mutex_unlock(&opp_table->lock); diff --git a/target/linux/ipq806x/patches-5.10/0054-cpufreq-dt-Handle-OPP-voltage-adjust-events.patch b/target/linux/ipq806x/patches-5.10/0054-cpufreq-dt-Handle-OPP-voltage-adjust-events.patch deleted file mode 100644 index 2e9c101d94..0000000000 --- a/target/linux/ipq806x/patches-5.10/0054-cpufreq-dt-Handle-OPP-voltage-adjust-events.patch +++ /dev/null @@ -1,118 +0,0 @@ -From 10577f74c35bd395951d1b2382c8d821089b5745 Mon Sep 17 00:00:00 2001 -From: Stephen Boyd -Date: Fri, 18 Sep 2015 17:52:08 -0700 -Subject: [PATCH 54/69] cpufreq-dt: Handle OPP voltage adjust events - -On some SoCs the Adaptive Voltage Scaling (AVS) technique is -employed to optimize the operating voltage of a device. At a -given frequency, the hardware monitors dynamic factors and either -makes a suggestion for how much to adjust a voltage for the -current frequency, or it automatically adjusts the voltage -without software intervention. - -In the former case, an AVS driver will call -dev_pm_opp_modify_voltage() and update the voltage for the -particular OPP the CPUs are using. Add an OPP notifier to -cpufreq-dt so that we can adjust the voltage of the CPU when AVS -updates the OPP. - -Signed-off-by: Stephen Boyd -Acked-by: Viresh Kumar -Signed-off-by: Georgi Djakov ---- - drivers/cpufreq/cpufreq-dt.c | 68 ++++++++++++++++++++++++++++++++++++++++++-- - 1 file changed, 65 insertions(+), 3 deletions(-) - ---- a/drivers/cpufreq/cpufreq-dt.c -+++ b/drivers/cpufreq/cpufreq-dt.c -@@ -27,6 +27,9 @@ struct private_data { - struct opp_table *opp_table; - struct device *cpu_dev; - const char *reg_name; -+ struct notifier_block opp_nb; -+ struct mutex lock; -+ unsigned long opp_freq; - bool have_static_opps; - }; - -@@ -42,12 +45,15 @@ static int set_target(struct cpufreq_pol - unsigned long freq = policy->freq_table[index].frequency; - int ret; - -+ mutex_lock(&priv->lock); - ret = dev_pm_opp_set_rate(priv->cpu_dev, freq * 1000); - - if (!ret) { -+ priv->opp_freq = freq * 1000; - arch_set_freq_scale(policy->related_cpus, freq, - policy->cpuinfo.max_freq); - } -+ mutex_unlock(&priv->lock); - - return ret; - } -@@ -90,6 +96,39 @@ node_put: - return name; - } - -+static int opp_notifier(struct notifier_block *nb, unsigned long event, -+ void *data) -+{ -+ struct dev_pm_opp *opp = data; -+ struct private_data *priv = container_of(nb, struct private_data, -+ opp_nb); -+ struct device *cpu_dev = priv->cpu_dev; -+ struct regulator *cpu_reg; -+ unsigned long volt, freq; -+ int ret = 0; -+ -+ if (event == OPP_EVENT_ADJUST_VOLTAGE) { -+ cpu_reg = dev_pm_opp_get_regulator(cpu_dev); -+ if (IS_ERR(cpu_reg)) { -+ ret = PTR_ERR(cpu_reg); -+ goto out; -+ } -+ volt = dev_pm_opp_get_voltage(opp); -+ freq = dev_pm_opp_get_freq(opp); -+ -+ mutex_lock(&priv->lock); -+ if (freq == priv->opp_freq) { -+ ret = regulator_set_voltage_triplet(cpu_reg, volt, volt, volt); -+ } -+ mutex_unlock(&priv->lock); -+ if (ret) -+ dev_err(cpu_dev, "failed to scale voltage: %d\n", ret); -+ } -+ -+out: -+ return notifier_from_errno(ret); -+} -+ - static int resources_available(void) - { - struct device *cpu_dev; -@@ -246,10 +285,14 @@ static int cpufreq_init(struct cpufreq_p - __func__, ret); - } - -+ mutex_init(&priv->lock); -+ priv->opp_nb.notifier_call = opp_notifier; -+ dev_pm_opp_register_notifier(cpu_dev, &priv->opp_nb); -+ - ret = dev_pm_opp_init_cpufreq_table(cpu_dev, &freq_table); - if (ret) { - dev_err(cpu_dev, "failed to init cpufreq table: %d\n", ret); -- goto out_free_opp; -+ goto out_unregister_nb; - } - - priv->cpu_dev = cpu_dev; -@@ -281,6 +324,8 @@ static int cpufreq_init(struct cpufreq_p - - out_free_cpufreq_table: - dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table); -+out_unregister_nb: -+ dev_pm_opp_unregister_notifier(cpu_dev, &priv->opp_nb); - out_free_opp: - if (priv->have_static_opps) - dev_pm_opp_of_cpumask_remove_table(policy->cpus); diff --git a/target/linux/ipq806x/patches-5.10/0055-cpufreq-dt-Add-L2-frequency-scaling-support.patch b/target/linux/ipq806x/patches-5.10/0055-cpufreq-dt-Add-L2-frequency-scaling-support.patch deleted file mode 100644 index 910c2b1722..0000000000 --- a/target/linux/ipq806x/patches-5.10/0055-cpufreq-dt-Add-L2-frequency-scaling-support.patch +++ /dev/null @@ -1,199 +0,0 @@ ---- a/drivers/cpufreq/cpufreq-dt.c -+++ b/drivers/cpufreq/cpufreq-dt.c -@@ -39,20 +39,85 @@ static struct freq_attr *cpufreq_dt_attr - NULL, - }; - -+struct shared_data { -+ unsigned long *curr_freq_table; -+ unsigned long curr_l2_freq; -+ unsigned long curr_l2_volt; -+}; -+ -+static struct shared_data *cpus_shared_data; -+ - static int set_target(struct cpufreq_policy *policy, unsigned int index) - { - struct private_data *priv = policy->driver_data; - unsigned long freq = policy->freq_table[index].frequency; -+ struct clk *l2_clk = policy->l2_clk; -+ struct regulator *l2_regulator = policy->l2_regulator; -+ unsigned long l2_freq, target_l2_freq; -+ unsigned long l2_vol, target_l2_volt; -+ unsigned long target_freq; - int ret; - - mutex_lock(&priv->lock); - ret = dev_pm_opp_set_rate(priv->cpu_dev, freq * 1000); - - if (!ret) { -+ if (policy->l2_rate_set) { -+ int cpu, l2_index, tol = 0; -+ target_freq = freq * 1000; -+ -+ cpus_shared_data->curr_freq_table[policy->cpu] = target_freq; -+ for_each_present_cpu(cpu) -+ if (cpu != policy->cpu) -+ target_freq = max(target_freq, cpus_shared_data->curr_freq_table[cpu]); -+ -+ for (l2_index = 2; l2_index > 0; l2_index--) -+ if (target_freq >= policy->l2_cpufreq[l2_index]) -+ break; -+ -+ l2_freq = cpus_shared_data->curr_l2_freq; -+ target_l2_freq = policy->l2_rate[l2_index]; -+ -+ if (l2_freq != target_l2_freq) { -+ -+ /* -+ * Set to idle bin if switching from normal to high bin -+ * or vice versa -+ */ -+ if ( (l2_index == 2 && l2_freq == policy->l2_rate[1]) || -+ (l2_index == 1 && l2_freq == policy->l2_rate[2]) ) { -+ ret = clk_set_rate(l2_clk, policy->l2_rate[0]); -+ if (ret) -+ goto exit; -+ } -+ -+ /* scale l2 with the core */ -+ ret = clk_set_rate(l2_clk, target_l2_freq); -+ if (ret) -+ goto exit; -+ cpus_shared_data->curr_l2_freq = target_l2_freq; -+ -+ if (policy->l2_volt_set) { -+ -+ l2_vol = cpus_shared_data->curr_l2_volt; -+ target_l2_volt = policy->l2_volt[l2_index]; -+ -+ if (l2_vol != target_l2_volt) { -+ tol = target_l2_volt * policy->l2_volt_tol / 100; -+ ret = regulator_set_voltage_tol(l2_regulator,target_l2_volt,tol); -+ if (ret) -+ goto exit; -+ cpus_shared_data->curr_l2_volt = target_l2_volt; -+ } -+ } -+ } -+ } - priv->opp_freq = freq * 1000; - arch_set_freq_scale(policy->related_cpus, freq, - policy->cpuinfo.max_freq); - } -+ -+exit: - mutex_unlock(&priv->lock); - - return ret; -@@ -195,6 +260,9 @@ static int cpufreq_init(struct cpufreq_p - bool fallback = false; - const char *name; - int ret; -+ struct device_node *np, *l2_np; -+ struct clk *l2_clk = NULL; -+ struct regulator *l2_regulator = NULL; - - cpu_dev = get_cpu_device(policy->cpu); - if (!cpu_dev) { -@@ -302,6 +370,57 @@ static int cpufreq_init(struct cpufreq_p - - policy->suspend_freq = dev_pm_opp_get_suspend_opp_freq(cpu_dev) / 1000; - -+ policy->l2_rate_set = false; -+ policy->l2_volt_set = false; -+ -+ l2_clk = clk_get(cpu_dev, "l2"); -+ if (!IS_ERR(l2_clk)) -+ policy->l2_clk = l2_clk; -+ -+ l2_np = of_find_node_by_name(NULL, "qcom,l2"); -+ if (l2_np) { -+ struct device_node *vdd; -+ np = of_node_get(priv->cpu_dev->of_node); -+ -+ if (np) -+ of_property_read_u32(np, "voltage-tolerance", &policy->l2_volt_tol); -+ -+ of_property_read_u32_array(l2_np, "qcom,l2-rates", policy->l2_rate, 3); -+ if (policy->l2_rate[0] && policy->l2_rate[1] && policy->l2_rate[2]) { -+ policy->l2_rate_set = true; -+ of_property_read_u32_array(l2_np, "qcom,l2-cpufreq", policy->l2_cpufreq, 3); -+ of_property_read_u32_array(l2_np, "qcom,l2-volt", policy->l2_volt, 3); -+ } else -+ pr_warn("L2: failed to parse L2 rates\n"); -+ -+ if (!policy->l2_cpufreq[0] && !policy->l2_cpufreq[1] && -+ !policy->l2_cpufreq[2] && policy->l2_rate_set) { -+ int i; -+ -+ pr_warn("L2: failed to parse target cpu freq, using defaults\n"); -+ for (i = 0; i < 3; i++) -+ policy->l2_cpufreq[i] = policy->l2_rate[i]; -+ } -+ -+ if (policy->l2_volt[0] && policy->l2_volt[1] && policy->l2_volt[2] && -+ policy->l2_volt_tol && policy->l2_rate_set) { -+ vdd = of_parse_phandle(l2_np, "qcom,l2-supply", 0); -+ -+ if (vdd) { -+ l2_regulator = devm_regulator_get(cpu_dev, vdd->name); -+ if (!IS_ERR(l2_regulator)) { -+ policy->l2_regulator = l2_regulator; -+ policy->l2_volt_set = true; -+ } else { -+ pr_warn("failed to get l2 supply\n"); -+ l2_regulator = NULL; -+ } -+ -+ of_node_put(vdd); -+ } -+ } -+ } -+ - /* Support turbo/boost mode */ - if (policy_has_boost_freq(policy)) { - /* This gets disabled by core on driver unregister */ -@@ -401,6 +520,14 @@ static int dt_cpufreq_probe(struct platf - if (ret) - return ret; - -+ cpus_shared_data = kzalloc(sizeof(struct shared_data), GFP_KERNEL); -+ if (!cpus_shared_data) -+ return -ENOMEM; -+ -+ cpus_shared_data->curr_freq_table = kzalloc(sizeof(int) * CONFIG_NR_CPUS, GFP_KERNEL); -+ if (!cpus_shared_data->curr_freq_table) -+ return -ENOMEM; -+ - if (data) { - if (data->have_governor_per_policy) - dt_cpufreq_driver.flags |= CPUFREQ_HAVE_GOVERNOR_PER_POLICY; -@@ -419,6 +546,8 @@ static int dt_cpufreq_probe(struct platf - - static int dt_cpufreq_remove(struct platform_device *pdev) - { -+ kfree(cpus_shared_data->curr_freq_table); -+ kfree(cpus_shared_data); - cpufreq_unregister_driver(&dt_cpufreq_driver); - return 0; - } ---- a/include/linux/cpufreq.h -+++ b/include/linux/cpufreq.h -@@ -58,7 +58,15 @@ struct cpufreq_policy { - should set cpufreq */ - unsigned int cpu; /* cpu managing this policy, must be online */ - -- struct clk *clk; -+ struct clk *clk; -+ struct clk *l2_clk; /* L2 clock */ -+ struct regulator *l2_regulator; /* L2 supply */ -+ unsigned int l2_rate[3]; /* L2 bus clock rate */ -+ bool l2_rate_set; -+ unsigned int l2_cpufreq[3]; /* L2 target CPU frequency */ -+ unsigned int l2_volt[3]; /* L2 voltage array */ -+ bool l2_volt_set; -+ unsigned int l2_volt_tol; /* L2 voltage tolerance */ - struct cpufreq_cpuinfo cpuinfo;/* see above */ - - unsigned int min; /* in kHz */ diff --git a/target/linux/ipq806x/patches-5.10/0056-cpufreq-dt-Add-missing-rcu-locks.patch b/target/linux/ipq806x/patches-5.10/0056-cpufreq-dt-Add-missing-rcu-locks.patch deleted file mode 100644 index 9b85839e19..0000000000 --- a/target/linux/ipq806x/patches-5.10/0056-cpufreq-dt-Add-missing-rcu-locks.patch +++ /dev/null @@ -1,23 +0,0 @@ -From 001a8dcb56ced58c518aaa10a4f0ba5e878705b6 Mon Sep 17 00:00:00 2001 -From: Georgi Djakov -Date: Tue, 17 May 2016 16:15:43 +0300 -Subject: [PATCH 56/69] cpufreq-dt: Add missing rcu locks - -Signed-off-by: Georgi Djakov ---- - drivers/cpufreq/cpufreq-dt.c | 2 ++ - 1 file changed, 2 insertions(+) - ---- a/drivers/cpufreq/cpufreq-dt.c -+++ b/drivers/cpufreq/cpufreq-dt.c -@@ -178,8 +178,10 @@ static int opp_notifier(struct notifier_ - ret = PTR_ERR(cpu_reg); - goto out; - } -+ rcu_read_lock(); - volt = dev_pm_opp_get_voltage(opp); - freq = dev_pm_opp_get_freq(opp); -+ rcu_read_unlock(); - - mutex_lock(&priv->lock); - if (freq == priv->opp_freq) { diff --git a/target/linux/ipq806x/patches-5.10/093-drivers-cpufreq-qcom-cpufreq-nvmem-support-specific-.patch b/target/linux/ipq806x/patches-5.10/093-drivers-cpufreq-qcom-cpufreq-nvmem-support-specific-.patch new file mode 100644 index 0000000000..afc9287118 --- /dev/null +++ b/target/linux/ipq806x/patches-5.10/093-drivers-cpufreq-qcom-cpufreq-nvmem-support-specific-.patch @@ -0,0 +1,56 @@ +From a206d4061f1cc2c5cd17ee45c53a0ba711e48e6d Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Sun, 7 Feb 2021 16:42:52 +0100 +Subject: [PATCH 3/3] drivers: cpufreq: qcom-cpufreq-nvmem: support specific + cpufreq driver + +Add support for specific cpufreq driver for qcom-cpufreq-nvmem driver. + +Signed-off-by: Ansuel Smith +--- + drivers/cpufreq/qcom-cpufreq-nvmem.c | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +diff --git a/drivers/cpufreq/qcom-cpufreq-nvmem.c b/drivers/cpufreq/qcom-cpufreq-nvmem.c +index d1744b5d9619..4866c74ead0f 100644 +--- a/drivers/cpufreq/qcom-cpufreq-nvmem.c ++++ b/drivers/cpufreq/qcom-cpufreq-nvmem.c +@@ -52,6 +52,7 @@ struct qcom_cpufreq_match_data { + char **pvs_name, + struct qcom_cpufreq_drv *drv); + const char **genpd_names; ++ const char *cpufreq_driver; + }; + + struct qcom_cpufreq_drv { +@@ -250,6 +251,7 @@ static const struct qcom_cpufreq_match_data match_data_kryo = { + + static const struct qcom_cpufreq_match_data match_data_krait = { + .get_version = qcom_cpufreq_krait_name_version, ++ .cpufreq_driver = "krait-cpufreq", + }; + + static const char *qcs404_genpd_names[] = { "cpr", NULL }; +@@ -385,6 +387,19 @@ static int qcom_cpufreq_probe(struct platform_device *pdev) + } + } + ++ if (drv->data->cpufreq_driver) { ++ cpufreq_dt_pdev = platform_device_register_simple( ++ drv->data->cpufreq_driver, -1, NULL, 0); ++ if (!IS_ERR(cpufreq_dt_pdev)) { ++ platform_set_drvdata(pdev, drv); ++ return 0; ++ } else { ++ dev_err(cpu_dev, ++ "Failed to register dedicated %s cpufreq\n", ++ drv->data->cpufreq_driver); ++ } ++ } ++ + cpufreq_dt_pdev = platform_device_register_simple("cpufreq-dt", -1, + NULL, 0); + if (!IS_ERR(cpufreq_dt_pdev)) { +-- +2.29.2 + diff --git a/target/linux/ipq806x/patches-5.10/098-1-cpufreq-add-Krait-dedicated-scaling-driver.patch b/target/linux/ipq806x/patches-5.10/098-1-cpufreq-add-Krait-dedicated-scaling-driver.patch new file mode 100644 index 0000000000..42913a994c --- /dev/null +++ b/target/linux/ipq806x/patches-5.10/098-1-cpufreq-add-Krait-dedicated-scaling-driver.patch @@ -0,0 +1,679 @@ +From cc41a266280cad0b55319e614167c88dff344248 Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Sat, 22 Feb 2020 16:33:10 +0100 +Subject: [PATCH 1/8] cpufreq: add Krait dedicated scaling driver + +This new driver is based on generic cpufreq-dt driver. +Krait SoCs have 2-4 cpu and one shared L2 cache that can +operate at different frequency based on the maximum cpu clk +across all core. +L2 frequency and voltage are scaled on every frequency change +if needed. On Krait SoCs is present a bug that can cause +transition problem between frequency bin, to workaround this +on more than one transition, the L2 frequency is first set to the +base rate and then to the target rate. +The L2 frequency use the OPP framework and use the opp-level +bindings to link the l2 freq to different cpu freq. This is needed +as the Krait l2 clk are note mapped 1:1 to the core clks and some +of the l2 clk is set based on a range of the cpu clks. If the driver +find a broken config (for example no opp-level set) the l2 scaling is +skipped. + +Signed-off-by: Ansuel Smith +--- + drivers/cpufreq/Kconfig.arm | 14 +- + drivers/cpufreq/Makefile | 2 + + drivers/cpufreq/qcom-cpufreq-krait.c | 589 +++++++++++++++++++++++++++ + 3 files changed, 604 insertions(+), 1 deletion(-) + create mode 100644 drivers/cpufreq/qcom-cpufreq-krait.c + +--- a/drivers/cpufreq/Kconfig.arm ++++ b/drivers/cpufreq/Kconfig.arm +@@ -150,6 +150,18 @@ config ARM_QCOM_CPUFREQ_HW + The driver implements the cpufreq interface for this HW engine. + Say Y if you want to support CPUFreq HW. + ++config ARM_QCOM_CPUFREQ_KRAIT ++ tristate "CPU Frequency scaling support for Krait SoCs" ++ depends on ARCH_QCOM || COMPILE_TEST ++ select PM_OPP ++ select ARM_QCOM_CPUFREQ_NVMEM ++ help ++ This adds the CPUFreq driver for Qualcomm Krait SoC based boards. ++ This scale the cache clk and regulator based on the different cpu ++ clks when scaling the different cores clk. ++ ++ If in doubt, say N. ++ + config ARM_RASPBERRYPI_CPUFREQ + tristate "Raspberry Pi cpufreq support" + depends on CLK_RASPBERRYPI || COMPILE_TEST +@@ -339,4 +351,4 @@ config ARM_PXA2xx_CPUFREQ + help + This add the CPUFreq driver support for Intel PXA2xx SOCs. + +- If in doubt, say N. ++ If in doubt, say N. +\ No newline at end of file +--- a/drivers/cpufreq/Makefile ++++ b/drivers/cpufreq/Makefile +@@ -63,6 +63,7 @@ obj-$(CONFIG_ARM_PXA2xx_CPUFREQ) += pxa2 + obj-$(CONFIG_PXA3xx) += pxa3xx-cpufreq.o + obj-$(CONFIG_ARM_QCOM_CPUFREQ_HW) += qcom-cpufreq-hw.o + obj-$(CONFIG_ARM_QCOM_CPUFREQ_NVMEM) += qcom-cpufreq-nvmem.o ++obj-$(CONFIG_ARM_QCOM_CPUFREQ_KRAIT) += qcom-cpufreq-krait.o + obj-$(CONFIG_ARM_RASPBERRYPI_CPUFREQ) += raspberrypi-cpufreq.o + obj-$(CONFIG_ARM_S3C2410_CPUFREQ) += s3c2410-cpufreq.o + obj-$(CONFIG_ARM_S3C2412_CPUFREQ) += s3c2412-cpufreq.o +@@ -86,6 +87,7 @@ obj-$(CONFIG_ARM_TEGRA186_CPUFREQ) += te + obj-$(CONFIG_ARM_TEGRA194_CPUFREQ) += tegra194-cpufreq.o + obj-$(CONFIG_ARM_TI_CPUFREQ) += ti-cpufreq.o + obj-$(CONFIG_ARM_VEXPRESS_SPC_CPUFREQ) += vexpress-spc-cpufreq.o ++obj-$(CONFIG_ARM_KRAIT_CPUFREQ) += krait-cpufreq.o + + + ################################################################################## +--- /dev/null ++++ b/drivers/cpufreq/qcom-cpufreq-krait.c +@@ -0,0 +1,601 @@ ++// SPDX-License-Identifier: GPL-2.0 ++ ++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "cpufreq-dt.h" ++ ++static struct platform_device *l2_pdev; ++ ++struct private_data { ++ struct opp_table *opp_table; ++ struct device *cpu_dev; ++ const char *reg_name; ++ bool have_static_opps; ++}; ++ ++static int set_target(struct cpufreq_policy *policy, unsigned int index) ++{ ++ struct private_data *priv = policy->driver_data; ++ unsigned long freq = policy->freq_table[index].frequency; ++ unsigned long target_freq = freq * 1000; ++ struct dev_pm_opp *opp; ++ unsigned int level; ++ int cpu, ret; ++ ++ if (l2_pdev) { ++ /* find the max freq across all core */ ++ for_each_present_cpu(cpu) ++ if (cpu != index) ++ target_freq = max( ++ target_freq, ++ (unsigned long)cpufreq_quick_get(cpu)); ++ ++ opp = dev_pm_opp_find_freq_exact(priv->cpu_dev, target_freq, ++ true); ++ if (IS_ERR(opp)) { ++ dev_err(&l2_pdev->dev, "failed to find OPP for %ld\n", ++ target_freq); ++ return PTR_ERR(opp); ++ } ++ level = dev_pm_opp_get_level(opp); ++ dev_pm_opp_put(opp); ++ ++ opp = dev_pm_opp_find_level_exact(&l2_pdev->dev, level); ++ if (IS_ERR(opp)) { ++ dev_err(&l2_pdev->dev, ++ "failed to find level OPP for %d\n", level); ++ return PTR_ERR(opp); ++ } ++ target_freq = dev_pm_opp_get_freq(opp); ++ dev_pm_opp_put(opp); ++ ++ ret = dev_pm_opp_set_rate(&l2_pdev->dev, target_freq); ++ if (ret) ++ return ret; ++ ++ /* ++ * Hardware constraint: ++ * Krait CPU cannot operate at 384MHz with L2 at 1Ghz. ++ * Assume index 0 with the idle freq and level > 0 as ++ * any L2 freq > 384MHz. ++ * Skip CPU freq change in this corner case. ++ */ ++ if (unlikely(index == 0 && level != 0)) { ++ dev_err(priv->cpu_dev, "Krait CPU can't operate at idle freq with L2 at 1GHz"); ++ return -EINVAL; ++ } ++ } ++ ++ ret = dev_pm_opp_set_rate(priv->cpu_dev, freq * 1000); ++ if (ret) ++ return ret; ++ ++ arch_set_freq_scale(policy->related_cpus, freq, ++ policy->cpuinfo.max_freq); ++ ++ return 0; ++} ++ ++/* ++ * An earlier version of opp-v1 bindings used to name the regulator ++ * "cpu0-supply", we still need to handle that for backwards compatibility. ++ */ ++static const char *find_supply_name(struct device *dev) ++{ ++ struct device_node *np; ++ struct property *pp; ++ int cpu = dev->id; ++ const char *name = NULL; ++ ++ np = of_node_get(dev->of_node); ++ ++ /* This must be valid for sure */ ++ if (WARN_ON(!np)) ++ return NULL; ++ ++ /* Try "cpu0" for older DTs */ ++ if (!cpu) { ++ pp = of_find_property(np, "cpu0-supply", NULL); ++ if (pp) { ++ name = "cpu0"; ++ goto node_put; ++ } ++ } ++ ++ pp = of_find_property(np, "cpu-supply", NULL); ++ if (pp) { ++ name = "cpu"; ++ goto node_put; ++ } ++ ++ dev_dbg(dev, "no regulator for cpu%d\n", cpu); ++node_put: ++ of_node_put(np); ++ return name; ++} ++ ++static int resources_available(void) ++{ ++ struct device *cpu_dev; ++ struct regulator *cpu_reg; ++ struct clk *cpu_clk; ++ int ret = 0; ++ const char *name; ++ ++ cpu_dev = get_cpu_device(0); ++ if (!cpu_dev) { ++ pr_err("failed to get cpu0 device\n"); ++ return -ENODEV; ++ } ++ ++ cpu_clk = clk_get(cpu_dev, NULL); ++ ret = PTR_ERR_OR_ZERO(cpu_clk); ++ if (ret) { ++ /* ++ * If cpu's clk node is present, but clock is not yet ++ * registered, we should try defering probe. ++ */ ++ if (ret == -EPROBE_DEFER) ++ dev_dbg(cpu_dev, "clock not ready, retry\n"); ++ else ++ dev_err(cpu_dev, "failed to get clock: %d\n", ret); ++ ++ return ret; ++ } ++ ++ clk_put(cpu_clk); ++ ++ name = find_supply_name(cpu_dev); ++ /* Platform doesn't require regulator */ ++ if (!name) ++ return 0; ++ ++ cpu_reg = regulator_get_optional(cpu_dev, name); ++ ret = PTR_ERR_OR_ZERO(cpu_reg); ++ if (ret) { ++ /* ++ * If cpu's regulator supply node is present, but regulator is ++ * not yet registered, we should try defering probe. ++ */ ++ if (ret == -EPROBE_DEFER) ++ dev_dbg(cpu_dev, "cpu0 regulator not ready, retry\n"); ++ else ++ dev_dbg(cpu_dev, "no regulator for cpu0: %d\n", ret); ++ ++ return ret; ++ } ++ ++ regulator_put(cpu_reg); ++ return 0; ++} ++ ++static int cpufreq_init(struct cpufreq_policy *policy) ++{ ++ struct cpufreq_frequency_table *freq_table; ++ struct opp_table *opp_table = NULL; ++ unsigned int transition_latency; ++ struct private_data *priv; ++ struct device *cpu_dev; ++ bool fallback = false; ++ struct clk *cpu_clk; ++ const char *name; ++ int ret; ++ ++ cpu_dev = get_cpu_device(policy->cpu); ++ if (!cpu_dev) { ++ pr_err("failed to get cpu%d device\n", policy->cpu); ++ return -ENODEV; ++ } ++ ++ cpu_clk = clk_get(cpu_dev, NULL); ++ if (IS_ERR(cpu_clk)) { ++ ret = PTR_ERR(cpu_clk); ++ dev_err(cpu_dev, "%s: failed to get clk: %d\n", __func__, ret); ++ return ret; ++ } ++ ++ /* Get OPP-sharing information from "operating-points-v2" bindings */ ++ ret = dev_pm_opp_of_get_sharing_cpus(cpu_dev, policy->cpus); ++ if (ret) { ++ if (ret != -ENOENT) ++ goto out_put_clk; ++ ++ /* ++ * operating-points-v2 not supported, fallback to old method of ++ * finding shared-OPPs for backward compatibility if the ++ * platform hasn't set sharing CPUs. ++ */ ++ if (dev_pm_opp_get_sharing_cpus(cpu_dev, policy->cpus)) ++ fallback = true; ++ } ++ ++ /* ++ * OPP layer will be taking care of regulators now, but it needs to know ++ * the name of the regulator first. ++ */ ++ name = find_supply_name(cpu_dev); ++ if (name) { ++ opp_table = dev_pm_opp_set_regulators(cpu_dev, &name, 1); ++ if (IS_ERR(opp_table)) { ++ ret = PTR_ERR(opp_table); ++ dev_err(cpu_dev, ++ "Failed to set regulator for cpu%d: %d\n", ++ policy->cpu, ret); ++ goto out_put_clk; ++ } ++ } ++ ++ priv = kzalloc(sizeof(*priv), GFP_KERNEL); ++ if (!priv) { ++ ret = -ENOMEM; ++ goto out_put_regulator; ++ } ++ ++ priv->reg_name = name; ++ priv->opp_table = opp_table; ++ ++ /* ++ * Initialize OPP tables for all policy->cpus. They will be shared by ++ * all CPUs which have marked their CPUs shared with OPP bindings. ++ * ++ * For platforms not using operating-points-v2 bindings, we do this ++ * before updating policy->cpus. Otherwise, we will end up creating ++ * duplicate OPPs for policy->cpus. ++ * ++ * OPPs might be populated at runtime, don't check for error here ++ */ ++ if (!dev_pm_opp_of_cpumask_add_table(policy->cpus)) ++ priv->have_static_opps = true; ++ ++ /* ++ * But we need OPP table to function so if it is not there let's ++ * give platform code chance to provide it for us. ++ */ ++ ret = dev_pm_opp_get_opp_count(cpu_dev); ++ if (ret <= 0) { ++ dev_dbg(cpu_dev, "OPP table is not ready, deferring probe\n"); ++ ret = -EPROBE_DEFER; ++ goto out_free_opp; ++ } ++ ++ if (fallback) { ++ cpumask_setall(policy->cpus); ++ ++ /* ++ * OPP tables are initialized only for policy->cpu, do it for ++ * others as well. ++ */ ++ ret = dev_pm_opp_set_sharing_cpus(cpu_dev, policy->cpus); ++ if (ret) ++ dev_err(cpu_dev, ++ "%s: failed to mark OPPs as shared: %d\n", ++ __func__, ret); ++ } ++ ++ ret = dev_pm_opp_init_cpufreq_table(cpu_dev, &freq_table); ++ if (ret) { ++ dev_err(cpu_dev, "failed to init cpufreq table: %d\n", ret); ++ goto out_free_opp; ++ } ++ ++ priv->cpu_dev = cpu_dev; ++ ++ policy->driver_data = priv; ++ policy->clk = cpu_clk; ++ policy->freq_table = freq_table; ++ ++ policy->suspend_freq = dev_pm_opp_get_suspend_opp_freq(cpu_dev) / 1000; ++ ++ transition_latency = dev_pm_opp_get_max_transition_latency(cpu_dev); ++ if (!transition_latency) ++ transition_latency = CPUFREQ_ETERNAL; ++ ++ policy->cpuinfo.transition_latency = transition_latency; ++ policy->dvfs_possible_from_any_cpu = true; ++ ++ dev_pm_opp_of_register_em(cpu_dev, policy->cpus); ++ ++ return 0; ++ ++out_free_opp: ++ if (priv->have_static_opps) ++ dev_pm_opp_of_cpumask_remove_table(policy->cpus); ++ kfree(priv); ++out_put_regulator: ++ if (name) ++ dev_pm_opp_put_regulators(opp_table); ++out_put_clk: ++ clk_put(cpu_clk); ++ ++ return ret; ++} ++ ++static int cpufreq_online(struct cpufreq_policy *policy) ++{ ++ /* We did light-weight tear down earlier, nothing to do here */ ++ return 0; ++} ++ ++static int cpufreq_offline(struct cpufreq_policy *policy) ++{ ++ /* ++ * Preserve policy->driver_data and don't free resources on light-weight ++ * tear down. ++ */ ++ return 0; ++} ++ ++static int cpufreq_exit(struct cpufreq_policy *policy) ++{ ++ struct private_data *priv = policy->driver_data; ++ ++ dev_pm_opp_free_cpufreq_table(priv->cpu_dev, &policy->freq_table); ++ if (priv->have_static_opps) ++ dev_pm_opp_of_cpumask_remove_table(policy->related_cpus); ++ if (priv->reg_name) ++ dev_pm_opp_put_regulators(priv->opp_table); ++ ++ clk_put(policy->clk); ++ kfree(priv); ++ ++ return 0; ++} ++ ++static struct cpufreq_driver krait_cpufreq_driver = { ++ .flags = CPUFREQ_STICKY | CPUFREQ_NEED_INITIAL_FREQ_CHECK | ++ CPUFREQ_IS_COOLING_DEV, ++ .verify = cpufreq_generic_frequency_table_verify, ++ .target_index = set_target, ++ .get = cpufreq_generic_get, ++ .init = cpufreq_init, ++ .exit = cpufreq_exit, ++ .online = cpufreq_online, ++ .offline = cpufreq_offline, ++ .name = "krait-cpufreq", ++ .suspend = cpufreq_generic_suspend, ++}; ++ ++struct krait_data { ++ unsigned long idle_freq; ++ bool regulator_enabled; ++}; ++ ++static int krait_cache_set_opp(struct dev_pm_set_opp_data *data) ++{ ++ unsigned long old_freq = data->old_opp.rate, freq = data->new_opp.rate; ++ struct dev_pm_opp_supply *supply = &data->new_opp.supplies[0]; ++ struct regulator *reg = data->regulators[0]; ++ struct clk *clk = data->clk; ++ struct krait_data *kdata; ++ unsigned long idle_freq; ++ int ret; ++ ++ kdata = (struct krait_data *)dev_get_drvdata(data->dev); ++ idle_freq = kdata->idle_freq; ++ ++ /* Scaling up? Scale voltage before frequency */ ++ if (freq >= old_freq) { ++ ret = regulator_set_voltage_triplet(reg, supply->u_volt_min, ++ supply->u_volt, ++ supply->u_volt_max); ++ if (ret) ++ goto exit; ++ } ++ ++ /* ++ * Set to idle bin if switching from normal to high bin ++ * or vice versa. It has been notice that a bug is triggered ++ * in cache scaling when more than one bin is scaled, to fix ++ * this we first need to transition to the base rate and then ++ * to target rate ++ */ ++ if (likely(freq != idle_freq && old_freq != idle_freq)) { ++ ret = clk_set_rate(clk, idle_freq); ++ if (ret) ++ goto exit; ++ } ++ ++ ret = clk_set_rate(clk, freq); ++ if (ret) ++ goto exit; ++ ++ /* Scaling down? Scale voltage after frequency */ ++ if (freq < old_freq) { ++ ret = regulator_set_voltage_triplet(reg, supply->u_volt_min, ++ supply->u_volt, ++ supply->u_volt_max); ++ } ++ ++ if (unlikely(!kdata->regulator_enabled)) { ++ ret = regulator_enable(reg); ++ if (ret < 0) ++ dev_warn(data->dev, "Failed to enable regulator: %d", ret); ++ else ++ kdata->regulator_enabled = true; ++ } ++ ++exit: ++ return ret; ++}; ++ ++static int krait_cache_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct krait_data *data; ++ struct opp_table *table; ++ struct dev_pm_opp *opp; ++ struct device *cpu_dev; ++ int ret; ++ ++ data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); ++ if (!data) ++ return -ENOMEM; ++ ++ table = dev_pm_opp_set_regulators(dev, (const char *[]){ "l2" }, 1); ++ if (IS_ERR(table)) { ++ ret = PTR_ERR(table); ++ if (ret != -EPROBE_DEFER) ++ dev_err(dev, "failed to set regulators %d\n", ret); ++ ++ return ret; ++ } ++ ++ ret = PTR_ERR_OR_ZERO( ++ dev_pm_opp_register_set_opp_helper(dev, krait_cache_set_opp)); ++ if (ret) ++ return ret; ++ ++ ret = dev_pm_opp_of_add_table(dev); ++ if (ret) { ++ dev_err(dev, "failed to parse L2 freq thresholds\n"); ++ return ret; ++ } ++ ++ opp = dev_pm_opp_find_freq_ceil(dev, &data->idle_freq); ++ dev_pm_opp_put(opp); ++ ++ /* ++ * Check opp-level configuration ++ * At least 2 level must be set or the cache will always be scaled ++ * the idle freq causing some performance problem ++ * ++ * In case of invalid configuration, the l2 scaling is skipped ++ */ ++ cpu_dev = get_cpu_device(0); ++ if (!cpu_dev) { ++ pr_err("failed to get cpu0 device\n"); ++ return -ENODEV; ++ } ++ ++ /* ++ * Check if we have at least opp-level 1, 0 should always be set to ++ * the idle freq ++ */ ++ opp = dev_pm_opp_find_level_exact(dev, 1); ++ if (IS_ERR(opp)) { ++ dev_err(dev, ++ "Invalid configuration found of l2 opp. Can't find opp-level 1"); ++ goto invalid_conf; ++ } ++ dev_pm_opp_put(opp); ++ ++ /* ++ * Check if we have at least opp-level 1 in the cpu opp, 0 should always ++ * be set to the idle freq ++ */ ++ opp = dev_pm_opp_find_level_exact(cpu_dev, 1); ++ if (IS_ERR(opp)) { ++ dev_err(dev, ++ "Invalid configuration found of cpu opp. Can't find opp-level 1"); ++ goto invalid_conf; ++ } ++ dev_pm_opp_put(opp); ++ ++ platform_set_drvdata(pdev, data); ++ ++ /* The l2 scaling is enabled by linking the cpufreq driver */ ++ l2_pdev = pdev; ++ ++ return 0; ++ ++invalid_conf: ++ dev_pm_opp_remove_table(dev); ++ dev_pm_opp_put_regulators(table); ++ dev_pm_opp_unregister_set_opp_helper(table); ++ ++ return -EINVAL; ++}; ++ ++static int krait_cache_remove(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct opp_table *table = dev_pm_opp_get_opp_table(dev); ++ ++ dev_pm_opp_remove_table(dev); ++ dev_pm_opp_put_regulators(table); ++ dev_pm_opp_unregister_set_opp_helper(table); ++ ++ return 0; ++}; ++ ++static const struct of_device_id krait_cache_match_table[] = { ++ { .compatible = "qcom,krait-cache" }, ++ {} ++}; ++ ++static struct platform_driver krait_cache_driver = { ++ .driver = { ++ .name = "krait-cache", ++ .of_match_table = krait_cache_match_table, ++ }, ++ .probe = krait_cache_probe, ++ .remove = krait_cache_remove, ++}; ++module_platform_driver(krait_cache_driver); ++ ++static int krait_cpufreq_probe(struct platform_device *pdev) ++{ ++ struct cpufreq_dt_platform_data *data = dev_get_platdata(&pdev->dev); ++ int ret; ++ ++ /* ++ * All per-cluster (CPUs sharing clock/voltages) initialization is done ++ * from ->init(). In probe(), we just need to make sure that clk and ++ * regulators are available. Else defer probe and retry. ++ * ++ * FIXME: Is checking this only for CPU0 sufficient ? ++ */ ++ ret = resources_available(); ++ if (ret) ++ return ret; ++ ++ if (data) { ++ if (data->have_governor_per_policy) ++ krait_cpufreq_driver.flags |= ++ CPUFREQ_HAVE_GOVERNOR_PER_POLICY; ++ ++ krait_cpufreq_driver.resume = data->resume; ++ if (data->suspend) ++ krait_cpufreq_driver.suspend = data->suspend; ++ } ++ ++ ret = cpufreq_register_driver(&krait_cpufreq_driver); ++ if (ret) ++ dev_err(&pdev->dev, "failed register driver: %d\n", ret); ++ ++ return ret; ++} ++ ++static int krait_cpufreq_remove(struct platform_device *pdev) ++{ ++ cpufreq_unregister_driver(&krait_cpufreq_driver); ++ return 0; ++} ++ ++static struct platform_driver krait_cpufreq_platdrv = { ++ .driver = { ++ .name = "krait-cpufreq", ++ }, ++ .probe = krait_cpufreq_probe, ++ .remove = krait_cpufreq_remove, ++}; ++module_platform_driver(krait_cpufreq_platdrv); ++ ++MODULE_ALIAS("platform:krait-cpufreq"); ++MODULE_AUTHOR("Ansuel Smith "); ++MODULE_DESCRIPTION("Dedicated Krait SoC cpufreq driver"); ++MODULE_LICENSE("GPL"); diff --git a/target/linux/ipq806x/patches-5.10/098-2-Documentation-cpufreq-add-qcom-krait-cpufreq-binding.patch b/target/linux/ipq806x/patches-5.10/098-2-Documentation-cpufreq-add-qcom-krait-cpufreq-binding.patch new file mode 100644 index 0000000000..81ec0883cd --- /dev/null +++ b/target/linux/ipq806x/patches-5.10/098-2-Documentation-cpufreq-add-qcom-krait-cpufreq-binding.patch @@ -0,0 +1,243 @@ +From c9ecd920324a647bf1f2b47f771c8f599cc7b551 Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Sat, 22 Feb 2020 18:02:17 +0100 +Subject: [PATCH 2/8] Documentation: cpufreq: add qcom,krait-cache bindings + +Document dedicated cpufreq for Krait CPUs. + +Signed-off-by: Ansuel Smith +--- + .../bindings/cpufreq/qcom-cpufreq-krait.yaml | 221 ++++++++++++++++++ + 1 file changed, 221 insertions(+) + create mode 100644 Documentation/devicetree/bindings/cpufreq/qcom-cpufreq-krait.yaml + +diff --git a/Documentation/devicetree/bindings/cpufreq/qcom-cpufreq-krait.yaml b/Documentation/devicetree/bindings/cpufreq/qcom-cpufreq-krait.yaml +new file mode 100644 +index 000000000000..f6bcca863d9a +--- /dev/null ++++ b/Documentation/devicetree/bindings/cpufreq/qcom-cpufreq-krait.yaml +@@ -0,0 +1,221 @@ ++# SPDX-License-Identifier: GPL-2.0 ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/cpufreq/qcom-cpufreq-krait.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: CPU Frequency scaling driver for Krait SoCs ++ ++maintainers: ++ - Ansuel Smith ++ ++description: | ++ The krait cpufreq driver is a dedicated frequency scaling driver ++ based on cpufreq-dt generic driver that scale L2 cache and the ++ cores. TEST ++ ++ The L2 cache is scaled based on the max clk across all cores and ++ the clock is decided based on the opp-level set in the device tree. ++ ++ Different core freq can be linked to a specific l2 freq and the driver ++ on frequency change will scale the core and the l2 clk based of the ++ linked freq. ++ ++ On Krait SoC is present a bug and on every L2 clk change the driver ++ needs to set the clk to the idle freq before changing it to the new value. ++ ++ This requires the qcom cpufreq nvmem driver to parse the different opp ++ core clk and an additional opp table for the l2 scaling. ++ ++ If the driver detect broken config (for example missing opp-level) the ++ cpufreq driver skips the l2 scaling ++ ++ Referring to this example opp-level can be used to link a range of cpu freq ++ to a specific l2 freq: ++ cpu opp freq 384000000 has opp-level 0 ++ l2 opp freq 384000000 has opp-level 0 ++ The driver will scale l2 to 384000000 ++ ++ cpu opp freq 600000000-1000000000 has opp-level 1 ++ l2 opp freq 1000000000 has opp-level 1 ++ The driver will scale l2 to 1000000000 ++ ++allOf: ++ - $ref: /schemas/cache-controller.yaml# ++ ++select: ++ properties: ++ compatible: ++ items: ++ - enum: ++ - qcom,krait-cache ++ ++ required: ++ - compatible ++ ++properties: ++ compatible: ++ items: ++ - const: qcom,krait-cache ++ - const: cache ++ ++ cache-level: ++ const: 2 ++ ++ clocks: ++ maxItems: 1 ++ ++ clock-names: ++ const: l2 ++ ++ l2-supply: true ++ ++ operating-points-v2: true ++ ++required: ++ - compatible ++ - cache-level ++ - clocks ++ - clock-names ++ - l2-supply ++ - operating-points-v2 ++ ++additionalProperties: false ++ ++examples: ++ - | ++ cpus { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ cpu0: cpu@0 { ++ compatible = "qcom,krait"; ++ enable-method = "qcom,kpss-acc-v1"; ++ device_type = "cpu"; ++ reg = <0>; ++ next-level-cache = <&L2>; ++ qcom,acc = <&acc0>; ++ qcom,saw = <&saw0>; ++ clocks = <&kraitcc 0>, <&kraitcc 4>; ++ clock-names = "cpu", "l2"; ++ clock-latency = <100000>; ++ cpu-supply = <&smb208_s2a>; ++ operating-points-v2 = <&opp_table0>; ++ voltage-tolerance = <5>; ++ cooling-min-state = <0>; ++ cooling-max-state = <10>; ++ #cooling-cells = <2>; ++ cpu-idle-states = <&CPU_SPC>; ++ }; ++ ++ /* ... */ ++ ++ }; ++ ++ opp_table0: opp_table0 { ++ compatible = "operating-points-v2-kryo-cpu"; ++ nvmem-cells = <&speedbin_efuse>; ++ ++ opp-384000000 { ++ opp-hz = /bits/ 64 <384000000>; ++ opp-microvolt-speed0-pvs0-v0 = <1000000>; ++ opp-microvolt-speed0-pvs1-v0 = <925000>; ++ opp-microvolt-speed0-pvs2-v0 = <875000>; ++ opp-microvolt-speed0-pvs3-v0 = <800000>; ++ opp-supported-hw = <0x1>; ++ clock-latency-ns = <100000>; ++ opp-level = <0>; ++ }; ++ ++ opp-600000000 { ++ opp-hz = /bits/ 64 <600000000>; ++ opp-microvolt-speed0-pvs0-v0 = <1050000>; ++ opp-microvolt-speed0-pvs1-v0 = <975000>; ++ opp-microvolt-speed0-pvs2-v0 = <925000>; ++ opp-microvolt-speed0-pvs3-v0 = <850000>; ++ opp-supported-hw = <0x1>; ++ clock-latency-ns = <100000>; ++ opp-level = <1>; ++ }; ++ ++ opp-800000000 { ++ opp-hz = /bits/ 64 <800000000>; ++ opp-microvolt-speed0-pvs0-v0 = <1100000>; ++ opp-microvolt-speed0-pvs1-v0 = <1025000>; ++ opp-microvolt-speed0-pvs2-v0 = <995000>; ++ opp-microvolt-speed0-pvs3-v0 = <900000>; ++ opp-supported-hw = <0x1>; ++ clock-latency-ns = <100000>; ++ opp-level = <1>; ++ }; ++ ++ opp-1000000000 { ++ opp-hz = /bits/ 64 <1000000000>; ++ opp-microvolt-speed0-pvs0-v0 = <1150000>; ++ opp-microvolt-speed0-pvs1-v0 = <1075000>; ++ opp-microvolt-speed0-pvs2-v0 = <1025000>; ++ opp-microvolt-speed0-pvs3-v0 = <950000>; ++ opp-supported-hw = <0x1>; ++ clock-latency-ns = <100000>; ++ opp-level = <1>; ++ }; ++ ++ opp-1200000000 { ++ opp-hz = /bits/ 64 <1200000000>; ++ opp-microvolt-speed0-pvs0-v0 = <1200000>; ++ opp-microvolt-speed0-pvs1-v0 = <1125000>; ++ opp-microvolt-speed0-pvs2-v0 = <1075000>; ++ opp-microvolt-speed0-pvs3-v0 = <1000000>; ++ opp-supported-hw = <0x1>; ++ clock-latency-ns = <100000>; ++ opp-level = <2>; ++ }; ++ ++ opp-1400000000 { ++ opp-hz = /bits/ 64 <1400000000>; ++ opp-microvolt-speed0-pvs0-v0 = <1250000>; ++ opp-microvolt-speed0-pvs1-v0 = <1175000>; ++ opp-microvolt-speed0-pvs2-v0 = <1125000>; ++ opp-microvolt-speed0-pvs3-v0 = <1050000>; ++ opp-supported-hw = <0x1>; ++ clock-latency-ns = <100000>; ++ opp-level = <2>; ++ }; ++ }; ++ ++ opp_table_l2: opp_table_l2 { ++ compatible = "operating-points-v2"; ++ ++ opp-384000000 { ++ opp-hz = /bits/ 64 <384000000>; ++ opp-microvolt = <1100000>; ++ clock-latency-ns = <100000>; ++ opp-level = <0>; ++ }; ++ opp-1000000000 { ++ opp-hz = /bits/ 64 <1000000000>; ++ opp-microvolt = <1100000>; ++ clock-latency-ns = <100000>; ++ opp-level = <1>; ++ }; ++ opp-1200000000 { ++ opp-hz = /bits/ 64 <1200000000>; ++ opp-microvolt = <1150000>; ++ clock-latency-ns = <100000>; ++ opp-level = <2>; ++ }; ++ }; ++ ++ soc { ++ L2: l2-cache { ++ compatible = "qcom,krait-cache", "cache"; ++ cache-level = <2>; ++ ++ clocks = <&kraitcc 4>; ++ clock-names = "l2"; ++ l2-supply = <&smb208_s1a>; ++ operating-points-v2 = <&opp_table_l2>; ++ }; ++ }; ++ ++... +-- +2.29.2 + diff --git a/target/linux/ipq806x/patches-5.10/0057-add-fab-scaling-support-with-cpufreq.patch b/target/linux/ipq806x/patches-5.10/098-3-add-fab-scaling-support-with-cpufreq.patch similarity index 93% rename from target/linux/ipq806x/patches-5.10/0057-add-fab-scaling-support-with-cpufreq.patch rename to target/linux/ipq806x/patches-5.10/098-3-add-fab-scaling-support-with-cpufreq.patch index 441500df79..29dff3297d 100644 --- a/target/linux/ipq806x/patches-5.10/0057-add-fab-scaling-support-with-cpufreq.patch +++ b/target/linux/ipq806x/patches-5.10/098-3-add-fab-scaling-support-with-cpufreq.patch @@ -217,9 +217,9 @@ +int scale_fabrics(unsigned long max_cpu_freq); + +#endif ---- a/drivers/cpufreq/cpufreq-dt.c -+++ b/drivers/cpufreq/cpufreq-dt.c -@@ -20,6 +20,7 @@ +--- a/drivers/cpufreq/qcom-cpufreq-krait.c ++++ b/drivers/cpufreq/qcom-cpufreq-krait.c +@@ -15,6 +15,7 @@ #include #include #include @@ -227,17 +227,17 @@ #include "cpufreq-dt.h" -@@ -111,6 +112,13 @@ static int set_target(struct cpufreq_pol - } - } - } +@@ -58,6 +59,13 @@ static int set_target(struct cpufreq_policy *policy, unsigned int index) + level = dev_pm_opp_get_level(opp); + dev_pm_opp_put(opp); + ++ /* ++ * Scale fabrics with max freq across all cores ++ */ ++ ret = scale_fabrics(target_freq); ++ if (ret) ++ return ret; + -+ /* -+ * Scale fabrics with max freq across all cores -+ */ -+ ret = scale_fabrics(target_freq); -+ if (ret) -+ goto exit; - } - priv->opp_freq = freq * 1000; - arch_set_freq_scale(policy->related_cpus, freq, + opp = dev_pm_opp_find_level_exact(&l2_pdev->dev, level); + if (IS_ERR(opp)) { + dev_err(&l2_pdev->dev, From 6e411b8416388a9c8be1b2291be9b5adeeb07784 Mon Sep 17 00:00:00 2001 From: Ansuel Smith Date: Thu, 8 Apr 2021 16:20:36 +0200 Subject: [PATCH 20/62] ipq806x: backport cpufreq changes to 5.4 The new cpufreq driver requires different dts bindings. Backport the new driver to kernel 5.4 Signed-off-by: Ansuel Smith --- target/linux/ipq806x/config-5.4 | 1 + ...rt-adjusting-OPP-voltages-at-runtime.patch | 153 ---- ...per-to-get-an-opp-regulator-for-devi.patch | 52 -- ...e-voltage-tolerance-when-adjusting-t.patch | 47 -- ...-dt-Handle-OPP-voltage-adjust-events.patch | 118 --- ...-dt-Add-L2-frequency-scaling-support.patch | 199 ----- ...056-cpufreq-dt-Add-missing-rcu-locks.patch | 23 - ...qcom-cpufreq-nvmem-support-specific-.patch | 51 ++ ...q-add-Krait-dedicated-scaling-driver.patch | 679 ++++++++++++++++++ ...ufreq-add-qcom-krait-cpufreq-binding.patch | 237 ++++++ ...dd-fab-scaling-support-with-cpufreq.patch} | 32 +- 11 files changed, 984 insertions(+), 608 deletions(-) delete mode 100644 target/linux/ipq806x/patches-5.4/0049-PM-OPP-Support-adjusting-OPP-voltages-at-runtime.patch delete mode 100644 target/linux/ipq806x/patches-5.4/0051-PM-OPP-Add-a-helper-to-get-an-opp-regulator-for-devi.patch delete mode 100644 target/linux/ipq806x/patches-5.4/0052-PM-OPP-Update-the-voltage-tolerance-when-adjusting-t.patch delete mode 100644 target/linux/ipq806x/patches-5.4/0054-cpufreq-dt-Handle-OPP-voltage-adjust-events.patch delete mode 100644 target/linux/ipq806x/patches-5.4/0055-cpufreq-dt-Add-L2-frequency-scaling-support.patch delete mode 100644 target/linux/ipq806x/patches-5.4/0056-cpufreq-dt-Add-missing-rcu-locks.patch create mode 100644 target/linux/ipq806x/patches-5.4/093-drivers-cpufreq-qcom-cpufreq-nvmem-support-specific-.patch create mode 100644 target/linux/ipq806x/patches-5.4/098-1-cpufreq-add-Krait-dedicated-scaling-driver.patch create mode 100644 target/linux/ipq806x/patches-5.4/098-2-Documentation-cpufreq-add-qcom-krait-cpufreq-binding.patch rename target/linux/ipq806x/patches-5.4/{0057-add-fab-scaling-support-with-cpufreq.patch => 098-3-add-fab-scaling-support-with-cpufreq.patch} (93%) diff --git a/target/linux/ipq806x/config-5.4 b/target/linux/ipq806x/config-5.4 index c582b7a52b..80549ad304 100644 --- a/target/linux/ipq806x/config-5.4 +++ b/target/linux/ipq806x/config-5.4 @@ -62,6 +62,7 @@ CONFIG_ARM_MODULE_PLTS=y CONFIG_ARM_PATCH_IDIV=y CONFIG_ARM_PATCH_PHYS_VIRT=y # CONFIG_ARM_QCOM_CPUFREQ_HW is not set +CONFIG_ARM_QCOM_CPUFREQ_KRAIT=y CONFIG_ARM_QCOM_CPUFREQ_NVMEM=y CONFIG_ARM_QCOM_CPUIDLE=y # CONFIG_ARM_SMMU is not set diff --git a/target/linux/ipq806x/patches-5.4/0049-PM-OPP-Support-adjusting-OPP-voltages-at-runtime.patch b/target/linux/ipq806x/patches-5.4/0049-PM-OPP-Support-adjusting-OPP-voltages-at-runtime.patch deleted file mode 100644 index 9efbd583b4..0000000000 --- a/target/linux/ipq806x/patches-5.4/0049-PM-OPP-Support-adjusting-OPP-voltages-at-runtime.patch +++ /dev/null @@ -1,153 +0,0 @@ -From: Sylwester Nawrocki -To: krzk@kernel.org, vireshk@kernel.org, robh+dt@kernel.org -Cc: sboyd@kernel.org, roger.lu@mediatek.com, - linux-pm@vger.kernel.org, linux-arm-kernel@lists.infradead.org, - linux-samsung-soc@vger.kernel.org, devicetree@vger.kernel.org, - b.zolnierkie@samsung.com, m.szyprowski@samsung.com, - Stephen Boyd , - Sylwester Nawrocki -Subject: [PATCH v5 1/4] PM / OPP: Support adjusting OPP voltages at runtime -Date: Wed, 16 Oct 2019 16:57:53 +0200 -Message-ID: <20191016145756.16004-2-s.nawrocki@samsung.com> (raw) -In-Reply-To: <20191016145756.16004-1-s.nawrocki@samsung.com> - -From: Stephen Boyd - -On some SoCs the Adaptive Voltage Scaling (AVS) technique is -employed to optimize the operating voltage of a device. At a -given frequency, the hardware monitors dynamic factors and either -makes a suggestion for how much to adjust a voltage for the -current frequency, or it automatically adjusts the voltage -without software intervention. Add an API to the OPP library for -the former case, so that AVS type devices can update the voltages -for an OPP when the hardware determines the voltage should -change. The assumption is that drivers like CPUfreq or devfreq -will register for the OPP notifiers and adjust the voltage -according to suggestions that AVS makes. - -This patch is derived from [1] submitted by Stephen. -[1] https://lore.kernel.org/patchwork/patch/599279/ - -Signed-off-by: Stephen Boyd -Signed-off-by: Roger Lu -[s.nawrocki@samsung.com: added handling of OPP min/max voltage] -Signed-off-by: Sylwester Nawrocki ---- - drivers/opp/core.c | 69 ++++++++++++++++++++++++++++++++++++++++++ - include/linux/pm_opp.h | 13 ++++++++ - 2 files changed, 82 insertions(+) - ---- a/drivers/opp/core.c -+++ b/drivers/opp/core.c -@@ -2102,6 +2102,75 @@ put_table: - } - - /** -+ * dev_pm_opp_adjust_voltage() - helper to change the voltage of an OPP -+ * @dev: device for which we do this operation -+ * @freq: OPP frequency to adjust voltage of -+ * @u_volt: new OPP target voltage -+ * @u_volt_min: new OPP min voltage -+ * @u_volt_max: new OPP max voltage -+ * -+ * Return: -EINVAL for bad pointers, -ENOMEM if no memory available for the -+ * copy operation, returns 0 if no modifcation was done OR modification was -+ * successful. -+ */ -+int dev_pm_opp_adjust_voltage(struct device *dev, unsigned long freq, -+ unsigned long u_volt, unsigned long u_volt_min, -+ unsigned long u_volt_max) -+ -+{ -+ struct opp_table *opp_table; -+ struct dev_pm_opp *tmp_opp, *opp = ERR_PTR(-ENODEV); -+ int r = 0; -+ -+ /* Find the opp_table */ -+ opp_table = _find_opp_table(dev); -+ if (IS_ERR(opp_table)) { -+ r = PTR_ERR(opp_table); -+ dev_warn(dev, "%s: Device OPP not found (%d)\n", __func__, r); -+ return r; -+ } -+ -+ mutex_lock(&opp_table->lock); -+ -+ /* Do we have the frequency? */ -+ list_for_each_entry(tmp_opp, &opp_table->opp_list, node) { -+ if (tmp_opp->rate == freq) { -+ opp = tmp_opp; -+ break; -+ } -+ } -+ -+ if (IS_ERR(opp)) { -+ r = PTR_ERR(opp); -+ goto adjust_unlock; -+ } -+ -+ /* Is update really needed? */ -+ if (opp->supplies->u_volt == u_volt) -+ goto adjust_unlock; -+ -+ opp->supplies->u_volt = u_volt; -+ opp->supplies->u_volt_min = u_volt_min; -+ opp->supplies->u_volt_max = u_volt_max; -+ -+ dev_pm_opp_get(opp); -+ mutex_unlock(&opp_table->lock); -+ -+ /* Notify the voltage change of the OPP */ -+ blocking_notifier_call_chain(&opp_table->head, OPP_EVENT_ADJUST_VOLTAGE, -+ opp); -+ -+ dev_pm_opp_put(opp); -+ goto adjust_put_table; -+ -+adjust_unlock: -+ mutex_unlock(&opp_table->lock); -+adjust_put_table: -+ dev_pm_opp_put_opp_table(opp_table); -+ return r; -+} -+ -+/** - * dev_pm_opp_enable() - Enable a specific OPP - * @dev: device for which we do this operation - * @freq: OPP frequency to enable ---- a/include/linux/pm_opp.h -+++ b/include/linux/pm_opp.h -@@ -22,6 +22,7 @@ struct opp_table; - - enum dev_pm_opp_event { - OPP_EVENT_ADD, OPP_EVENT_REMOVE, OPP_EVENT_ENABLE, OPP_EVENT_DISABLE, -+ OPP_EVENT_ADJUST_VOLTAGE, - }; - - /** -@@ -113,6 +114,10 @@ int dev_pm_opp_add(struct device *dev, u - void dev_pm_opp_remove(struct device *dev, unsigned long freq); - void dev_pm_opp_remove_all_dynamic(struct device *dev); - -+int dev_pm_opp_adjust_voltage(struct device *dev, unsigned long freq, -+ unsigned long u_volt, unsigned long u_volt_min, -+ unsigned long u_volt_max); -+ - int dev_pm_opp_enable(struct device *dev, unsigned long freq); - - int dev_pm_opp_disable(struct device *dev, unsigned long freq); -@@ -242,6 +247,14 @@ static inline void dev_pm_opp_remove_all - { - } - -+static inline int -+dev_pm_opp_adjust_voltage(struct device *dev, unsigned long freq, -+ unsigned long u_volt, unsigned long u_volt_min, -+ unsigned long u_volt_max) -+{ -+ return 0; -+} -+ - static inline int dev_pm_opp_enable(struct device *dev, unsigned long freq) - { - return 0; diff --git a/target/linux/ipq806x/patches-5.4/0051-PM-OPP-Add-a-helper-to-get-an-opp-regulator-for-devi.patch b/target/linux/ipq806x/patches-5.4/0051-PM-OPP-Add-a-helper-to-get-an-opp-regulator-for-devi.patch deleted file mode 100644 index 35fe45fca7..0000000000 --- a/target/linux/ipq806x/patches-5.4/0051-PM-OPP-Add-a-helper-to-get-an-opp-regulator-for-devi.patch +++ /dev/null @@ -1,52 +0,0 @@ -From d06ca5e7a3cf726f5be5ffd96e93ccd798b8c09a Mon Sep 17 00:00:00 2001 -From: Georgi Djakov -Date: Thu, 12 May 2016 14:41:33 +0300 -Subject: [PATCH 51/69] PM / OPP: Add a helper to get an opp regulator for - device - -Signed-off-by: Georgi Djakov ---- - drivers/opp/core.c | 21 +++++++++++++++++++++ - include/linux/pm_opp.h | 1 + - 2 files changed, 22 insertions(+) - ---- a/drivers/opp/core.c -+++ b/drivers/opp/core.c -@@ -127,6 +127,27 @@ unsigned long dev_pm_opp_get_freq(struct - } - EXPORT_SYMBOL_GPL(dev_pm_opp_get_freq); - -+struct regulator *dev_pm_opp_get_regulator(struct device *dev) -+{ -+ struct opp_table *opp_table; -+ struct regulator *reg; -+ -+ rcu_read_lock(); -+ -+ opp_table = _find_opp_table(dev); -+ if (IS_ERR(opp_table)) { -+ rcu_read_unlock(); -+ return ERR_CAST(opp_table); -+ } -+ -+ reg = opp_table->regulators[0]; -+ -+ rcu_read_unlock(); -+ -+ return reg; -+} -+EXPORT_SYMBOL_GPL(dev_pm_opp_get_regulator); -+ - /** - * dev_pm_opp_get_level() - Gets the level corresponding to an available opp - * @opp: opp for which level value has to be returned for ---- a/include/linux/pm_opp.h -+++ b/include/linux/pm_opp.h -@@ -83,6 +83,7 @@ void dev_pm_opp_put_opp_table(struct opp - unsigned long dev_pm_opp_get_voltage(struct dev_pm_opp *opp); - - unsigned long dev_pm_opp_get_freq(struct dev_pm_opp *opp); -+struct regulator *dev_pm_opp_get_regulator(struct device *dev); - - unsigned int dev_pm_opp_get_level(struct dev_pm_opp *opp); - diff --git a/target/linux/ipq806x/patches-5.4/0052-PM-OPP-Update-the-voltage-tolerance-when-adjusting-t.patch b/target/linux/ipq806x/patches-5.4/0052-PM-OPP-Update-the-voltage-tolerance-when-adjusting-t.patch deleted file mode 100644 index 8498a0b6df..0000000000 --- a/target/linux/ipq806x/patches-5.4/0052-PM-OPP-Update-the-voltage-tolerance-when-adjusting-t.patch +++ /dev/null @@ -1,47 +0,0 @@ -From 4533c285c2aedce6d4434d7b877066de3b1ecb33 Mon Sep 17 00:00:00 2001 -From: Georgi Djakov -Date: Thu, 25 Aug 2016 18:43:35 +0300 -Subject: [PATCH 52/69] PM / OPP: Update the voltage tolerance when adjusting - the OPP - -When the voltage is adjusted, the voltage tolerance is not updated. -This can lead to situations where the voltage min value is greater -than the voltage max value. The final result is triggering a BUG() -in the regulator core. -Fix this by updating the voltage tolerance values too. - -Signed-off-by: Georgi Djakov ---- - drivers/opp/core.c | 5 +++++ - 1 file changed, 5 insertions(+) - ---- a/drivers/opp/core.c -+++ b/drivers/opp/core.c -@@ -2142,6 +2142,7 @@ int dev_pm_opp_adjust_voltage(struct dev - struct opp_table *opp_table; - struct dev_pm_opp *tmp_opp, *opp = ERR_PTR(-ENODEV); - int r = 0; -+ unsigned long tol; - - /* Find the opp_table */ - opp_table = _find_opp_table(dev); -@@ -2171,8 +2172,17 @@ int dev_pm_opp_adjust_voltage(struct dev - goto adjust_unlock; - - opp->supplies->u_volt = u_volt; -- opp->supplies->u_volt_min = u_volt_min; -- opp->supplies->u_volt_max = u_volt_max; -+ -+ tol = u_volt * opp_table->voltage_tolerance_v1 / 100; -+ if ( u_volt_min == u_volt ) -+ opp->supplies->u_volt_min = u_volt - tol; -+ else -+ opp->supplies->u_volt_min = u_volt_min; -+ -+ if ( u_volt_max == u_volt ) -+ opp->supplies->u_volt_max = u_volt + tol; -+ else -+ opp->supplies->u_volt_max = u_volt_max; - - dev_pm_opp_get(opp); - mutex_unlock(&opp_table->lock); diff --git a/target/linux/ipq806x/patches-5.4/0054-cpufreq-dt-Handle-OPP-voltage-adjust-events.patch b/target/linux/ipq806x/patches-5.4/0054-cpufreq-dt-Handle-OPP-voltage-adjust-events.patch deleted file mode 100644 index 2e9c101d94..0000000000 --- a/target/linux/ipq806x/patches-5.4/0054-cpufreq-dt-Handle-OPP-voltage-adjust-events.patch +++ /dev/null @@ -1,118 +0,0 @@ -From 10577f74c35bd395951d1b2382c8d821089b5745 Mon Sep 17 00:00:00 2001 -From: Stephen Boyd -Date: Fri, 18 Sep 2015 17:52:08 -0700 -Subject: [PATCH 54/69] cpufreq-dt: Handle OPP voltage adjust events - -On some SoCs the Adaptive Voltage Scaling (AVS) technique is -employed to optimize the operating voltage of a device. At a -given frequency, the hardware monitors dynamic factors and either -makes a suggestion for how much to adjust a voltage for the -current frequency, or it automatically adjusts the voltage -without software intervention. - -In the former case, an AVS driver will call -dev_pm_opp_modify_voltage() and update the voltage for the -particular OPP the CPUs are using. Add an OPP notifier to -cpufreq-dt so that we can adjust the voltage of the CPU when AVS -updates the OPP. - -Signed-off-by: Stephen Boyd -Acked-by: Viresh Kumar -Signed-off-by: Georgi Djakov ---- - drivers/cpufreq/cpufreq-dt.c | 68 ++++++++++++++++++++++++++++++++++++++++++-- - 1 file changed, 65 insertions(+), 3 deletions(-) - ---- a/drivers/cpufreq/cpufreq-dt.c -+++ b/drivers/cpufreq/cpufreq-dt.c -@@ -27,6 +27,9 @@ struct private_data { - struct opp_table *opp_table; - struct device *cpu_dev; - const char *reg_name; -+ struct notifier_block opp_nb; -+ struct mutex lock; -+ unsigned long opp_freq; - bool have_static_opps; - }; - -@@ -42,12 +45,15 @@ static int set_target(struct cpufreq_pol - unsigned long freq = policy->freq_table[index].frequency; - int ret; - -+ mutex_lock(&priv->lock); - ret = dev_pm_opp_set_rate(priv->cpu_dev, freq * 1000); - - if (!ret) { -+ priv->opp_freq = freq * 1000; - arch_set_freq_scale(policy->related_cpus, freq, - policy->cpuinfo.max_freq); - } -+ mutex_unlock(&priv->lock); - - return ret; - } -@@ -90,6 +96,39 @@ node_put: - return name; - } - -+static int opp_notifier(struct notifier_block *nb, unsigned long event, -+ void *data) -+{ -+ struct dev_pm_opp *opp = data; -+ struct private_data *priv = container_of(nb, struct private_data, -+ opp_nb); -+ struct device *cpu_dev = priv->cpu_dev; -+ struct regulator *cpu_reg; -+ unsigned long volt, freq; -+ int ret = 0; -+ -+ if (event == OPP_EVENT_ADJUST_VOLTAGE) { -+ cpu_reg = dev_pm_opp_get_regulator(cpu_dev); -+ if (IS_ERR(cpu_reg)) { -+ ret = PTR_ERR(cpu_reg); -+ goto out; -+ } -+ volt = dev_pm_opp_get_voltage(opp); -+ freq = dev_pm_opp_get_freq(opp); -+ -+ mutex_lock(&priv->lock); -+ if (freq == priv->opp_freq) { -+ ret = regulator_set_voltage_triplet(cpu_reg, volt, volt, volt); -+ } -+ mutex_unlock(&priv->lock); -+ if (ret) -+ dev_err(cpu_dev, "failed to scale voltage: %d\n", ret); -+ } -+ -+out: -+ return notifier_from_errno(ret); -+} -+ - static int resources_available(void) - { - struct device *cpu_dev; -@@ -246,10 +285,14 @@ static int cpufreq_init(struct cpufreq_p - __func__, ret); - } - -+ mutex_init(&priv->lock); -+ priv->opp_nb.notifier_call = opp_notifier; -+ dev_pm_opp_register_notifier(cpu_dev, &priv->opp_nb); -+ - ret = dev_pm_opp_init_cpufreq_table(cpu_dev, &freq_table); - if (ret) { - dev_err(cpu_dev, "failed to init cpufreq table: %d\n", ret); -- goto out_free_opp; -+ goto out_unregister_nb; - } - - priv->cpu_dev = cpu_dev; -@@ -281,6 +324,8 @@ static int cpufreq_init(struct cpufreq_p - - out_free_cpufreq_table: - dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table); -+out_unregister_nb: -+ dev_pm_opp_unregister_notifier(cpu_dev, &priv->opp_nb); - out_free_opp: - if (priv->have_static_opps) - dev_pm_opp_of_cpumask_remove_table(policy->cpus); diff --git a/target/linux/ipq806x/patches-5.4/0055-cpufreq-dt-Add-L2-frequency-scaling-support.patch b/target/linux/ipq806x/patches-5.4/0055-cpufreq-dt-Add-L2-frequency-scaling-support.patch deleted file mode 100644 index 910c2b1722..0000000000 --- a/target/linux/ipq806x/patches-5.4/0055-cpufreq-dt-Add-L2-frequency-scaling-support.patch +++ /dev/null @@ -1,199 +0,0 @@ ---- a/drivers/cpufreq/cpufreq-dt.c -+++ b/drivers/cpufreq/cpufreq-dt.c -@@ -39,20 +39,85 @@ static struct freq_attr *cpufreq_dt_attr - NULL, - }; - -+struct shared_data { -+ unsigned long *curr_freq_table; -+ unsigned long curr_l2_freq; -+ unsigned long curr_l2_volt; -+}; -+ -+static struct shared_data *cpus_shared_data; -+ - static int set_target(struct cpufreq_policy *policy, unsigned int index) - { - struct private_data *priv = policy->driver_data; - unsigned long freq = policy->freq_table[index].frequency; -+ struct clk *l2_clk = policy->l2_clk; -+ struct regulator *l2_regulator = policy->l2_regulator; -+ unsigned long l2_freq, target_l2_freq; -+ unsigned long l2_vol, target_l2_volt; -+ unsigned long target_freq; - int ret; - - mutex_lock(&priv->lock); - ret = dev_pm_opp_set_rate(priv->cpu_dev, freq * 1000); - - if (!ret) { -+ if (policy->l2_rate_set) { -+ int cpu, l2_index, tol = 0; -+ target_freq = freq * 1000; -+ -+ cpus_shared_data->curr_freq_table[policy->cpu] = target_freq; -+ for_each_present_cpu(cpu) -+ if (cpu != policy->cpu) -+ target_freq = max(target_freq, cpus_shared_data->curr_freq_table[cpu]); -+ -+ for (l2_index = 2; l2_index > 0; l2_index--) -+ if (target_freq >= policy->l2_cpufreq[l2_index]) -+ break; -+ -+ l2_freq = cpus_shared_data->curr_l2_freq; -+ target_l2_freq = policy->l2_rate[l2_index]; -+ -+ if (l2_freq != target_l2_freq) { -+ -+ /* -+ * Set to idle bin if switching from normal to high bin -+ * or vice versa -+ */ -+ if ( (l2_index == 2 && l2_freq == policy->l2_rate[1]) || -+ (l2_index == 1 && l2_freq == policy->l2_rate[2]) ) { -+ ret = clk_set_rate(l2_clk, policy->l2_rate[0]); -+ if (ret) -+ goto exit; -+ } -+ -+ /* scale l2 with the core */ -+ ret = clk_set_rate(l2_clk, target_l2_freq); -+ if (ret) -+ goto exit; -+ cpus_shared_data->curr_l2_freq = target_l2_freq; -+ -+ if (policy->l2_volt_set) { -+ -+ l2_vol = cpus_shared_data->curr_l2_volt; -+ target_l2_volt = policy->l2_volt[l2_index]; -+ -+ if (l2_vol != target_l2_volt) { -+ tol = target_l2_volt * policy->l2_volt_tol / 100; -+ ret = regulator_set_voltage_tol(l2_regulator,target_l2_volt,tol); -+ if (ret) -+ goto exit; -+ cpus_shared_data->curr_l2_volt = target_l2_volt; -+ } -+ } -+ } -+ } - priv->opp_freq = freq * 1000; - arch_set_freq_scale(policy->related_cpus, freq, - policy->cpuinfo.max_freq); - } -+ -+exit: - mutex_unlock(&priv->lock); - - return ret; -@@ -195,6 +260,9 @@ static int cpufreq_init(struct cpufreq_p - bool fallback = false; - const char *name; - int ret; -+ struct device_node *np, *l2_np; -+ struct clk *l2_clk = NULL; -+ struct regulator *l2_regulator = NULL; - - cpu_dev = get_cpu_device(policy->cpu); - if (!cpu_dev) { -@@ -302,6 +370,57 @@ static int cpufreq_init(struct cpufreq_p - - policy->suspend_freq = dev_pm_opp_get_suspend_opp_freq(cpu_dev) / 1000; - -+ policy->l2_rate_set = false; -+ policy->l2_volt_set = false; -+ -+ l2_clk = clk_get(cpu_dev, "l2"); -+ if (!IS_ERR(l2_clk)) -+ policy->l2_clk = l2_clk; -+ -+ l2_np = of_find_node_by_name(NULL, "qcom,l2"); -+ if (l2_np) { -+ struct device_node *vdd; -+ np = of_node_get(priv->cpu_dev->of_node); -+ -+ if (np) -+ of_property_read_u32(np, "voltage-tolerance", &policy->l2_volt_tol); -+ -+ of_property_read_u32_array(l2_np, "qcom,l2-rates", policy->l2_rate, 3); -+ if (policy->l2_rate[0] && policy->l2_rate[1] && policy->l2_rate[2]) { -+ policy->l2_rate_set = true; -+ of_property_read_u32_array(l2_np, "qcom,l2-cpufreq", policy->l2_cpufreq, 3); -+ of_property_read_u32_array(l2_np, "qcom,l2-volt", policy->l2_volt, 3); -+ } else -+ pr_warn("L2: failed to parse L2 rates\n"); -+ -+ if (!policy->l2_cpufreq[0] && !policy->l2_cpufreq[1] && -+ !policy->l2_cpufreq[2] && policy->l2_rate_set) { -+ int i; -+ -+ pr_warn("L2: failed to parse target cpu freq, using defaults\n"); -+ for (i = 0; i < 3; i++) -+ policy->l2_cpufreq[i] = policy->l2_rate[i]; -+ } -+ -+ if (policy->l2_volt[0] && policy->l2_volt[1] && policy->l2_volt[2] && -+ policy->l2_volt_tol && policy->l2_rate_set) { -+ vdd = of_parse_phandle(l2_np, "qcom,l2-supply", 0); -+ -+ if (vdd) { -+ l2_regulator = devm_regulator_get(cpu_dev, vdd->name); -+ if (!IS_ERR(l2_regulator)) { -+ policy->l2_regulator = l2_regulator; -+ policy->l2_volt_set = true; -+ } else { -+ pr_warn("failed to get l2 supply\n"); -+ l2_regulator = NULL; -+ } -+ -+ of_node_put(vdd); -+ } -+ } -+ } -+ - /* Support turbo/boost mode */ - if (policy_has_boost_freq(policy)) { - /* This gets disabled by core on driver unregister */ -@@ -401,6 +520,14 @@ static int dt_cpufreq_probe(struct platf - if (ret) - return ret; - -+ cpus_shared_data = kzalloc(sizeof(struct shared_data), GFP_KERNEL); -+ if (!cpus_shared_data) -+ return -ENOMEM; -+ -+ cpus_shared_data->curr_freq_table = kzalloc(sizeof(int) * CONFIG_NR_CPUS, GFP_KERNEL); -+ if (!cpus_shared_data->curr_freq_table) -+ return -ENOMEM; -+ - if (data) { - if (data->have_governor_per_policy) - dt_cpufreq_driver.flags |= CPUFREQ_HAVE_GOVERNOR_PER_POLICY; -@@ -419,6 +546,8 @@ static int dt_cpufreq_probe(struct platf - - static int dt_cpufreq_remove(struct platform_device *pdev) - { -+ kfree(cpus_shared_data->curr_freq_table); -+ kfree(cpus_shared_data); - cpufreq_unregister_driver(&dt_cpufreq_driver); - return 0; - } ---- a/include/linux/cpufreq.h -+++ b/include/linux/cpufreq.h -@@ -58,7 +58,15 @@ struct cpufreq_policy { - should set cpufreq */ - unsigned int cpu; /* cpu managing this policy, must be online */ - -- struct clk *clk; -+ struct clk *clk; -+ struct clk *l2_clk; /* L2 clock */ -+ struct regulator *l2_regulator; /* L2 supply */ -+ unsigned int l2_rate[3]; /* L2 bus clock rate */ -+ bool l2_rate_set; -+ unsigned int l2_cpufreq[3]; /* L2 target CPU frequency */ -+ unsigned int l2_volt[3]; /* L2 voltage array */ -+ bool l2_volt_set; -+ unsigned int l2_volt_tol; /* L2 voltage tolerance */ - struct cpufreq_cpuinfo cpuinfo;/* see above */ - - unsigned int min; /* in kHz */ diff --git a/target/linux/ipq806x/patches-5.4/0056-cpufreq-dt-Add-missing-rcu-locks.patch b/target/linux/ipq806x/patches-5.4/0056-cpufreq-dt-Add-missing-rcu-locks.patch deleted file mode 100644 index 9b85839e19..0000000000 --- a/target/linux/ipq806x/patches-5.4/0056-cpufreq-dt-Add-missing-rcu-locks.patch +++ /dev/null @@ -1,23 +0,0 @@ -From 001a8dcb56ced58c518aaa10a4f0ba5e878705b6 Mon Sep 17 00:00:00 2001 -From: Georgi Djakov -Date: Tue, 17 May 2016 16:15:43 +0300 -Subject: [PATCH 56/69] cpufreq-dt: Add missing rcu locks - -Signed-off-by: Georgi Djakov ---- - drivers/cpufreq/cpufreq-dt.c | 2 ++ - 1 file changed, 2 insertions(+) - ---- a/drivers/cpufreq/cpufreq-dt.c -+++ b/drivers/cpufreq/cpufreq-dt.c -@@ -178,8 +178,10 @@ static int opp_notifier(struct notifier_ - ret = PTR_ERR(cpu_reg); - goto out; - } -+ rcu_read_lock(); - volt = dev_pm_opp_get_voltage(opp); - freq = dev_pm_opp_get_freq(opp); -+ rcu_read_unlock(); - - mutex_lock(&priv->lock); - if (freq == priv->opp_freq) { diff --git a/target/linux/ipq806x/patches-5.4/093-drivers-cpufreq-qcom-cpufreq-nvmem-support-specific-.patch b/target/linux/ipq806x/patches-5.4/093-drivers-cpufreq-qcom-cpufreq-nvmem-support-specific-.patch new file mode 100644 index 0000000000..19c3d096c4 --- /dev/null +++ b/target/linux/ipq806x/patches-5.4/093-drivers-cpufreq-qcom-cpufreq-nvmem-support-specific-.patch @@ -0,0 +1,51 @@ +From a206d4061f1cc2c5cd17ee45c53a0ba711e48e6d Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Sun, 7 Feb 2021 16:42:52 +0100 +Subject: [PATCH 3/3] drivers: cpufreq: qcom-cpufreq-nvmem: support specific + cpufreq driver + +Add support for specific cpufreq driver for qcom-cpufreq-nvmem driver. + +Signed-off-by: Ansuel Smith +--- + drivers/cpufreq/qcom-cpufreq-nvmem.c | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +--- a/drivers/cpufreq/qcom-cpufreq-nvmem.c ++++ b/drivers/cpufreq/qcom-cpufreq-nvmem.c +@@ -52,6 +52,7 @@ struct qcom_cpufreq_match_data { + char **pvs_name, + struct qcom_cpufreq_drv *drv); + const char **genpd_names; ++ const char *cpufreq_driver; + }; + + struct qcom_cpufreq_drv { +@@ -250,6 +251,7 @@ static const struct qcom_cpufreq_match_d + + static const struct qcom_cpufreq_match_data match_data_krait = { + .get_version = qcom_cpufreq_krait_name_version, ++ .cpufreq_driver = "krait-cpufreq", + }; + + static const char *qcs404_genpd_names[] = { "cpr", NULL }; +@@ -385,6 +387,19 @@ static int qcom_cpufreq_probe(struct pla + } + } + ++ if (drv->data->cpufreq_driver) { ++ cpufreq_dt_pdev = platform_device_register_simple( ++ drv->data->cpufreq_driver, -1, NULL, 0); ++ if (!IS_ERR(cpufreq_dt_pdev)) { ++ platform_set_drvdata(pdev, drv); ++ return 0; ++ } else { ++ dev_err(cpu_dev, ++ "Failed to register dedicated %s cpufreq\n", ++ drv->data->cpufreq_driver); ++ } ++ } ++ + cpufreq_dt_pdev = platform_device_register_simple("cpufreq-dt", -1, + NULL, 0); + if (!IS_ERR(cpufreq_dt_pdev)) { diff --git a/target/linux/ipq806x/patches-5.4/098-1-cpufreq-add-Krait-dedicated-scaling-driver.patch b/target/linux/ipq806x/patches-5.4/098-1-cpufreq-add-Krait-dedicated-scaling-driver.patch new file mode 100644 index 0000000000..eb9978154d --- /dev/null +++ b/target/linux/ipq806x/patches-5.4/098-1-cpufreq-add-Krait-dedicated-scaling-driver.patch @@ -0,0 +1,679 @@ +From cc41a266280cad0b55319e614167c88dff344248 Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Sat, 22 Feb 2020 16:33:10 +0100 +Subject: [PATCH 1/8] cpufreq: add Krait dedicated scaling driver + +This new driver is based on generic cpufreq-dt driver. +Krait SoCs have 2-4 cpu and one shared L2 cache that can +operate at different frequency based on the maximum cpu clk +across all core. +L2 frequency and voltage are scaled on every frequency change +if needed. On Krait SoCs is present a bug that can cause +transition problem between frequency bin, to workaround this +on more than one transition, the L2 frequency is first set to the +base rate and then to the target rate. +The L2 frequency use the OPP framework and use the opp-level +bindings to link the l2 freq to different cpu freq. This is needed +as the Krait l2 clk are note mapped 1:1 to the core clks and some +of the l2 clk is set based on a range of the cpu clks. If the driver +find a broken config (for example no opp-level set) the l2 scaling is +skipped. + +Signed-off-by: Ansuel Smith +--- + drivers/cpufreq/Kconfig.arm | 14 +- + drivers/cpufreq/Makefile | 2 + + drivers/cpufreq/qcom-cpufreq-krait.c | 589 +++++++++++++++++++++++++++ + 3 files changed, 604 insertions(+), 1 deletion(-) + create mode 100644 drivers/cpufreq/qcom-cpufreq-krait.c + +--- a/drivers/cpufreq/Kconfig.arm ++++ b/drivers/cpufreq/Kconfig.arm +@@ -150,6 +150,18 @@ config ARM_QCOM_CPUFREQ_HW + The driver implements the cpufreq interface for this HW engine. + Say Y if you want to support CPUFreq HW. + ++config ARM_QCOM_CPUFREQ_KRAIT ++ tristate "CPU Frequency scaling support for Krait SoCs" ++ depends on ARCH_QCOM || COMPILE_TEST ++ select PM_OPP ++ select ARM_QCOM_CPUFREQ_NVMEM ++ help ++ This adds the CPUFreq driver for Qualcomm Krait SoC based boards. ++ This scale the cache clk and regulator based on the different cpu ++ clks when scaling the different cores clk. ++ ++ If in doubt, say N. ++ + config ARM_RASPBERRYPI_CPUFREQ + tristate "Raspberry Pi cpufreq support" + depends on CLK_RASPBERRYPI || COMPILE_TEST +@@ -339,4 +351,4 @@ config ARM_PXA2xx_CPUFREQ + help + This add the CPUFreq driver support for Intel PXA2xx SOCs. + +- If in doubt, say N. ++ If in doubt, say N. +\ No newline at end of file +--- a/drivers/cpufreq/Makefile ++++ b/drivers/cpufreq/Makefile +@@ -63,6 +63,7 @@ obj-$(CONFIG_ARM_PXA2xx_CPUFREQ) += pxa2 + obj-$(CONFIG_PXA3xx) += pxa3xx-cpufreq.o + obj-$(CONFIG_ARM_QCOM_CPUFREQ_HW) += qcom-cpufreq-hw.o + obj-$(CONFIG_ARM_QCOM_CPUFREQ_NVMEM) += qcom-cpufreq-nvmem.o ++obj-$(CONFIG_ARM_QCOM_CPUFREQ_KRAIT) += qcom-cpufreq-krait.o + obj-$(CONFIG_ARM_RASPBERRYPI_CPUFREQ) += raspberrypi-cpufreq.o + obj-$(CONFIG_ARM_S3C2410_CPUFREQ) += s3c2410-cpufreq.o + obj-$(CONFIG_ARM_S3C2412_CPUFREQ) += s3c2412-cpufreq.o +@@ -86,6 +87,7 @@ obj-$(CONFIG_ARM_TEGRA186_CPUFREQ) += te + obj-$(CONFIG_ARM_TEGRA194_CPUFREQ) += tegra194-cpufreq.o + obj-$(CONFIG_ARM_TI_CPUFREQ) += ti-cpufreq.o + obj-$(CONFIG_ARM_VEXPRESS_SPC_CPUFREQ) += vexpress-spc-cpufreq.o ++obj-$(CONFIG_ARM_KRAIT_CPUFREQ) += krait-cpufreq.o + + + ################################################################################## +--- /dev/null ++++ b/drivers/cpufreq/qcom-cpufreq-krait.c +@@ -0,0 +1,601 @@ ++// SPDX-License-Identifier: GPL-2.0 ++ ++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "cpufreq-dt.h" ++ ++static struct platform_device *l2_pdev; ++ ++struct private_data { ++ struct opp_table *opp_table; ++ struct device *cpu_dev; ++ const char *reg_name; ++ bool have_static_opps; ++}; ++ ++static int set_target(struct cpufreq_policy *policy, unsigned int index) ++{ ++ struct private_data *priv = policy->driver_data; ++ unsigned long freq = policy->freq_table[index].frequency; ++ unsigned long target_freq = freq * 1000; ++ struct dev_pm_opp *opp; ++ unsigned int level; ++ int cpu, ret; ++ ++ if (l2_pdev) { ++ /* find the max freq across all core */ ++ for_each_present_cpu(cpu) ++ if (cpu != index) ++ target_freq = max( ++ target_freq, ++ (unsigned long)cpufreq_quick_get(cpu)); ++ ++ opp = dev_pm_opp_find_freq_exact(priv->cpu_dev, target_freq, ++ true); ++ if (IS_ERR(opp)) { ++ dev_err(&l2_pdev->dev, "failed to find OPP for %ld\n", ++ target_freq); ++ return PTR_ERR(opp); ++ } ++ level = dev_pm_opp_get_level(opp); ++ dev_pm_opp_put(opp); ++ ++ opp = dev_pm_opp_find_level_exact(&l2_pdev->dev, level); ++ if (IS_ERR(opp)) { ++ dev_err(&l2_pdev->dev, ++ "failed to find level OPP for %d\n", level); ++ return PTR_ERR(opp); ++ } ++ target_freq = dev_pm_opp_get_freq(opp); ++ dev_pm_opp_put(opp); ++ ++ ret = dev_pm_opp_set_rate(&l2_pdev->dev, target_freq); ++ if (ret) ++ return ret; ++ ++ /* ++ * Hardware constraint: ++ * Krait CPU cannot operate at 384MHz with L2 at 1Ghz. ++ * Assume index 0 with the idle freq and level > 0 as ++ * any L2 freq > 384MHz. ++ * Skip CPU freq change in this corner case. ++ */ ++ if (unlikely(index == 0 && level != 0)) { ++ dev_err(priv->cpu_dev, "Krait CPU can't operate at idle freq with L2 at 1GHz"); ++ return -EINVAL; ++ } ++ } ++ ++ ret = dev_pm_opp_set_rate(priv->cpu_dev, freq * 1000); ++ if (ret) ++ return ret; ++ ++ arch_set_freq_scale(policy->related_cpus, freq, ++ policy->cpuinfo.max_freq); ++ ++ return 0; ++} ++ ++/* ++ * An earlier version of opp-v1 bindings used to name the regulator ++ * "cpu0-supply", we still need to handle that for backwards compatibility. ++ */ ++static const char *find_supply_name(struct device *dev) ++{ ++ struct device_node *np; ++ struct property *pp; ++ int cpu = dev->id; ++ const char *name = NULL; ++ ++ np = of_node_get(dev->of_node); ++ ++ /* This must be valid for sure */ ++ if (WARN_ON(!np)) ++ return NULL; ++ ++ /* Try "cpu0" for older DTs */ ++ if (!cpu) { ++ pp = of_find_property(np, "cpu0-supply", NULL); ++ if (pp) { ++ name = "cpu0"; ++ goto node_put; ++ } ++ } ++ ++ pp = of_find_property(np, "cpu-supply", NULL); ++ if (pp) { ++ name = "cpu"; ++ goto node_put; ++ } ++ ++ dev_dbg(dev, "no regulator for cpu%d\n", cpu); ++node_put: ++ of_node_put(np); ++ return name; ++} ++ ++static int resources_available(void) ++{ ++ struct device *cpu_dev; ++ struct regulator *cpu_reg; ++ struct clk *cpu_clk; ++ int ret = 0; ++ const char *name; ++ ++ cpu_dev = get_cpu_device(0); ++ if (!cpu_dev) { ++ pr_err("failed to get cpu0 device\n"); ++ return -ENODEV; ++ } ++ ++ cpu_clk = clk_get(cpu_dev, NULL); ++ ret = PTR_ERR_OR_ZERO(cpu_clk); ++ if (ret) { ++ /* ++ * If cpu's clk node is present, but clock is not yet ++ * registered, we should try defering probe. ++ */ ++ if (ret == -EPROBE_DEFER) ++ dev_dbg(cpu_dev, "clock not ready, retry\n"); ++ else ++ dev_err(cpu_dev, "failed to get clock: %d\n", ret); ++ ++ return ret; ++ } ++ ++ clk_put(cpu_clk); ++ ++ name = find_supply_name(cpu_dev); ++ /* Platform doesn't require regulator */ ++ if (!name) ++ return 0; ++ ++ cpu_reg = regulator_get_optional(cpu_dev, name); ++ ret = PTR_ERR_OR_ZERO(cpu_reg); ++ if (ret) { ++ /* ++ * If cpu's regulator supply node is present, but regulator is ++ * not yet registered, we should try defering probe. ++ */ ++ if (ret == -EPROBE_DEFER) ++ dev_dbg(cpu_dev, "cpu0 regulator not ready, retry\n"); ++ else ++ dev_dbg(cpu_dev, "no regulator for cpu0: %d\n", ret); ++ ++ return ret; ++ } ++ ++ regulator_put(cpu_reg); ++ return 0; ++} ++ ++static int cpufreq_init(struct cpufreq_policy *policy) ++{ ++ struct cpufreq_frequency_table *freq_table; ++ struct opp_table *opp_table = NULL; ++ unsigned int transition_latency; ++ struct private_data *priv; ++ struct device *cpu_dev; ++ bool fallback = false; ++ struct clk *cpu_clk; ++ const char *name; ++ int ret; ++ ++ cpu_dev = get_cpu_device(policy->cpu); ++ if (!cpu_dev) { ++ pr_err("failed to get cpu%d device\n", policy->cpu); ++ return -ENODEV; ++ } ++ ++ cpu_clk = clk_get(cpu_dev, NULL); ++ if (IS_ERR(cpu_clk)) { ++ ret = PTR_ERR(cpu_clk); ++ dev_err(cpu_dev, "%s: failed to get clk: %d\n", __func__, ret); ++ return ret; ++ } ++ ++ /* Get OPP-sharing information from "operating-points-v2" bindings */ ++ ret = dev_pm_opp_of_get_sharing_cpus(cpu_dev, policy->cpus); ++ if (ret) { ++ if (ret != -ENOENT) ++ goto out_put_clk; ++ ++ /* ++ * operating-points-v2 not supported, fallback to old method of ++ * finding shared-OPPs for backward compatibility if the ++ * platform hasn't set sharing CPUs. ++ */ ++ if (dev_pm_opp_get_sharing_cpus(cpu_dev, policy->cpus)) ++ fallback = true; ++ } ++ ++ /* ++ * OPP layer will be taking care of regulators now, but it needs to know ++ * the name of the regulator first. ++ */ ++ name = find_supply_name(cpu_dev); ++ if (name) { ++ opp_table = dev_pm_opp_set_regulators(cpu_dev, &name, 1); ++ if (IS_ERR(opp_table)) { ++ ret = PTR_ERR(opp_table); ++ dev_err(cpu_dev, ++ "Failed to set regulator for cpu%d: %d\n", ++ policy->cpu, ret); ++ goto out_put_clk; ++ } ++ } ++ ++ priv = kzalloc(sizeof(*priv), GFP_KERNEL); ++ if (!priv) { ++ ret = -ENOMEM; ++ goto out_put_regulator; ++ } ++ ++ priv->reg_name = name; ++ priv->opp_table = opp_table; ++ ++ /* ++ * Initialize OPP tables for all policy->cpus. They will be shared by ++ * all CPUs which have marked their CPUs shared with OPP bindings. ++ * ++ * For platforms not using operating-points-v2 bindings, we do this ++ * before updating policy->cpus. Otherwise, we will end up creating ++ * duplicate OPPs for policy->cpus. ++ * ++ * OPPs might be populated at runtime, don't check for error here ++ */ ++ if (!dev_pm_opp_of_cpumask_add_table(policy->cpus)) ++ priv->have_static_opps = true; ++ ++ /* ++ * But we need OPP table to function so if it is not there let's ++ * give platform code chance to provide it for us. ++ */ ++ ret = dev_pm_opp_get_opp_count(cpu_dev); ++ if (ret <= 0) { ++ dev_dbg(cpu_dev, "OPP table is not ready, deferring probe\n"); ++ ret = -EPROBE_DEFER; ++ goto out_free_opp; ++ } ++ ++ if (fallback) { ++ cpumask_setall(policy->cpus); ++ ++ /* ++ * OPP tables are initialized only for policy->cpu, do it for ++ * others as well. ++ */ ++ ret = dev_pm_opp_set_sharing_cpus(cpu_dev, policy->cpus); ++ if (ret) ++ dev_err(cpu_dev, ++ "%s: failed to mark OPPs as shared: %d\n", ++ __func__, ret); ++ } ++ ++ ret = dev_pm_opp_init_cpufreq_table(cpu_dev, &freq_table); ++ if (ret) { ++ dev_err(cpu_dev, "failed to init cpufreq table: %d\n", ret); ++ goto out_free_opp; ++ } ++ ++ priv->cpu_dev = cpu_dev; ++ ++ policy->driver_data = priv; ++ policy->clk = cpu_clk; ++ policy->freq_table = freq_table; ++ ++ policy->suspend_freq = dev_pm_opp_get_suspend_opp_freq(cpu_dev) / 1000; ++ ++ transition_latency = dev_pm_opp_get_max_transition_latency(cpu_dev); ++ if (!transition_latency) ++ transition_latency = CPUFREQ_ETERNAL; ++ ++ policy->cpuinfo.transition_latency = transition_latency; ++ policy->dvfs_possible_from_any_cpu = true; ++ ++ dev_pm_opp_of_register_em(policy->cpus); ++ ++ return 0; ++ ++out_free_opp: ++ if (priv->have_static_opps) ++ dev_pm_opp_of_cpumask_remove_table(policy->cpus); ++ kfree(priv); ++out_put_regulator: ++ if (name) ++ dev_pm_opp_put_regulators(opp_table); ++out_put_clk: ++ clk_put(cpu_clk); ++ ++ return ret; ++} ++ ++static int cpufreq_online(struct cpufreq_policy *policy) ++{ ++ /* We did light-weight tear down earlier, nothing to do here */ ++ return 0; ++} ++ ++static int cpufreq_offline(struct cpufreq_policy *policy) ++{ ++ /* ++ * Preserve policy->driver_data and don't free resources on light-weight ++ * tear down. ++ */ ++ return 0; ++} ++ ++static int cpufreq_exit(struct cpufreq_policy *policy) ++{ ++ struct private_data *priv = policy->driver_data; ++ ++ dev_pm_opp_free_cpufreq_table(priv->cpu_dev, &policy->freq_table); ++ if (priv->have_static_opps) ++ dev_pm_opp_of_cpumask_remove_table(policy->related_cpus); ++ if (priv->reg_name) ++ dev_pm_opp_put_regulators(priv->opp_table); ++ ++ clk_put(policy->clk); ++ kfree(priv); ++ ++ return 0; ++} ++ ++static struct cpufreq_driver krait_cpufreq_driver = { ++ .flags = CPUFREQ_STICKY | CPUFREQ_NEED_INITIAL_FREQ_CHECK | ++ CPUFREQ_IS_COOLING_DEV, ++ .verify = cpufreq_generic_frequency_table_verify, ++ .target_index = set_target, ++ .get = cpufreq_generic_get, ++ .init = cpufreq_init, ++ .exit = cpufreq_exit, ++ .online = cpufreq_online, ++ .offline = cpufreq_offline, ++ .name = "krait-cpufreq", ++ .suspend = cpufreq_generic_suspend, ++}; ++ ++struct krait_data { ++ unsigned long idle_freq; ++ bool regulator_enabled; ++}; ++ ++static int krait_cache_set_opp(struct dev_pm_set_opp_data *data) ++{ ++ unsigned long old_freq = data->old_opp.rate, freq = data->new_opp.rate; ++ struct dev_pm_opp_supply *supply = &data->new_opp.supplies[0]; ++ struct regulator *reg = data->regulators[0]; ++ struct clk *clk = data->clk; ++ struct krait_data *kdata; ++ unsigned long idle_freq; ++ int ret; ++ ++ kdata = (struct krait_data *)dev_get_drvdata(data->dev); ++ idle_freq = kdata->idle_freq; ++ ++ /* Scaling up? Scale voltage before frequency */ ++ if (freq >= old_freq) { ++ ret = regulator_set_voltage_triplet(reg, supply->u_volt_min, ++ supply->u_volt, ++ supply->u_volt_max); ++ if (ret) ++ goto exit; ++ } ++ ++ /* ++ * Set to idle bin if switching from normal to high bin ++ * or vice versa. It has been notice that a bug is triggered ++ * in cache scaling when more than one bin is scaled, to fix ++ * this we first need to transition to the base rate and then ++ * to target rate ++ */ ++ if (likely(freq != idle_freq && old_freq != idle_freq)) { ++ ret = clk_set_rate(clk, idle_freq); ++ if (ret) ++ goto exit; ++ } ++ ++ ret = clk_set_rate(clk, freq); ++ if (ret) ++ goto exit; ++ ++ /* Scaling down? Scale voltage after frequency */ ++ if (freq < old_freq) { ++ ret = regulator_set_voltage_triplet(reg, supply->u_volt_min, ++ supply->u_volt, ++ supply->u_volt_max); ++ } ++ ++ if (unlikely(!kdata->regulator_enabled)) { ++ ret = regulator_enable(reg); ++ if (ret < 0) ++ dev_warn(data->dev, "Failed to enable regulator: %d", ret); ++ else ++ kdata->regulator_enabled = true; ++ } ++ ++exit: ++ return ret; ++}; ++ ++static int krait_cache_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct krait_data *data; ++ struct opp_table *table; ++ struct dev_pm_opp *opp; ++ struct device *cpu_dev; ++ int ret; ++ ++ data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); ++ if (!data) ++ return -ENOMEM; ++ ++ table = dev_pm_opp_set_regulators(dev, (const char *[]){ "l2" }, 1); ++ if (IS_ERR(table)) { ++ ret = PTR_ERR(table); ++ if (ret != -EPROBE_DEFER) ++ dev_err(dev, "failed to set regulators %d\n", ret); ++ ++ return ret; ++ } ++ ++ ret = PTR_ERR_OR_ZERO( ++ dev_pm_opp_register_set_opp_helper(dev, krait_cache_set_opp)); ++ if (ret) ++ return ret; ++ ++ ret = dev_pm_opp_of_add_table(dev); ++ if (ret) { ++ dev_err(dev, "failed to parse L2 freq thresholds\n"); ++ return ret; ++ } ++ ++ opp = dev_pm_opp_find_freq_ceil(dev, &data->idle_freq); ++ dev_pm_opp_put(opp); ++ ++ /* ++ * Check opp-level configuration ++ * At least 2 level must be set or the cache will always be scaled ++ * the idle freq causing some performance problem ++ * ++ * In case of invalid configuration, the l2 scaling is skipped ++ */ ++ cpu_dev = get_cpu_device(0); ++ if (!cpu_dev) { ++ pr_err("failed to get cpu0 device\n"); ++ return -ENODEV; ++ } ++ ++ /* ++ * Check if we have at least opp-level 1, 0 should always be set to ++ * the idle freq ++ */ ++ opp = dev_pm_opp_find_level_exact(dev, 1); ++ if (IS_ERR(opp)) { ++ dev_err(dev, ++ "Invalid configuration found of l2 opp. Can't find opp-level 1"); ++ goto invalid_conf; ++ } ++ dev_pm_opp_put(opp); ++ ++ /* ++ * Check if we have at least opp-level 1 in the cpu opp, 0 should always ++ * be set to the idle freq ++ */ ++ opp = dev_pm_opp_find_level_exact(cpu_dev, 1); ++ if (IS_ERR(opp)) { ++ dev_err(dev, ++ "Invalid configuration found of cpu opp. Can't find opp-level 1"); ++ goto invalid_conf; ++ } ++ dev_pm_opp_put(opp); ++ ++ platform_set_drvdata(pdev, data); ++ ++ /* The l2 scaling is enabled by linking the cpufreq driver */ ++ l2_pdev = pdev; ++ ++ return 0; ++ ++invalid_conf: ++ dev_pm_opp_remove_table(dev); ++ dev_pm_opp_put_regulators(table); ++ dev_pm_opp_unregister_set_opp_helper(table); ++ ++ return -EINVAL; ++}; ++ ++static int krait_cache_remove(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct opp_table *table = dev_pm_opp_get_opp_table(dev); ++ ++ dev_pm_opp_remove_table(dev); ++ dev_pm_opp_put_regulators(table); ++ dev_pm_opp_unregister_set_opp_helper(table); ++ ++ return 0; ++}; ++ ++static const struct of_device_id krait_cache_match_table[] = { ++ { .compatible = "qcom,krait-cache" }, ++ {} ++}; ++ ++static struct platform_driver krait_cache_driver = { ++ .driver = { ++ .name = "krait-cache", ++ .of_match_table = krait_cache_match_table, ++ }, ++ .probe = krait_cache_probe, ++ .remove = krait_cache_remove, ++}; ++module_platform_driver(krait_cache_driver); ++ ++static int krait_cpufreq_probe(struct platform_device *pdev) ++{ ++ struct cpufreq_dt_platform_data *data = dev_get_platdata(&pdev->dev); ++ int ret; ++ ++ /* ++ * All per-cluster (CPUs sharing clock/voltages) initialization is done ++ * from ->init(). In probe(), we just need to make sure that clk and ++ * regulators are available. Else defer probe and retry. ++ * ++ * FIXME: Is checking this only for CPU0 sufficient ? ++ */ ++ ret = resources_available(); ++ if (ret) ++ return ret; ++ ++ if (data) { ++ if (data->have_governor_per_policy) ++ krait_cpufreq_driver.flags |= ++ CPUFREQ_HAVE_GOVERNOR_PER_POLICY; ++ ++ krait_cpufreq_driver.resume = data->resume; ++ if (data->suspend) ++ krait_cpufreq_driver.suspend = data->suspend; ++ } ++ ++ ret = cpufreq_register_driver(&krait_cpufreq_driver); ++ if (ret) ++ dev_err(&pdev->dev, "failed register driver: %d\n", ret); ++ ++ return ret; ++} ++ ++static int krait_cpufreq_remove(struct platform_device *pdev) ++{ ++ cpufreq_unregister_driver(&krait_cpufreq_driver); ++ return 0; ++} ++ ++static struct platform_driver krait_cpufreq_platdrv = { ++ .driver = { ++ .name = "krait-cpufreq", ++ }, ++ .probe = krait_cpufreq_probe, ++ .remove = krait_cpufreq_remove, ++}; ++module_platform_driver(krait_cpufreq_platdrv); ++ ++MODULE_ALIAS("platform:krait-cpufreq"); ++MODULE_AUTHOR("Ansuel Smith "); ++MODULE_DESCRIPTION("Dedicated Krait SoC cpufreq driver"); ++MODULE_LICENSE("GPL"); diff --git a/target/linux/ipq806x/patches-5.4/098-2-Documentation-cpufreq-add-qcom-krait-cpufreq-binding.patch b/target/linux/ipq806x/patches-5.4/098-2-Documentation-cpufreq-add-qcom-krait-cpufreq-binding.patch new file mode 100644 index 0000000000..316e18b790 --- /dev/null +++ b/target/linux/ipq806x/patches-5.4/098-2-Documentation-cpufreq-add-qcom-krait-cpufreq-binding.patch @@ -0,0 +1,237 @@ +From c9ecd920324a647bf1f2b47f771c8f599cc7b551 Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Sat, 22 Feb 2020 18:02:17 +0100 +Subject: [PATCH 2/8] Documentation: cpufreq: add qcom,krait-cache bindings + +Document dedicated cpufreq for Krait CPUs. + +Signed-off-by: Ansuel Smith +--- + .../bindings/cpufreq/qcom-cpufreq-krait.yaml | 221 ++++++++++++++++++ + 1 file changed, 221 insertions(+) + create mode 100644 Documentation/devicetree/bindings/cpufreq/qcom-cpufreq-krait.yaml + +--- /dev/null ++++ b/Documentation/devicetree/bindings/cpufreq/qcom-cpufreq-krait.yaml +@@ -0,0 +1,221 @@ ++# SPDX-License-Identifier: GPL-2.0 ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/cpufreq/qcom-cpufreq-krait.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: CPU Frequency scaling driver for Krait SoCs ++ ++maintainers: ++ - Ansuel Smith ++ ++description: | ++ The krait cpufreq driver is a dedicated frequency scaling driver ++ based on cpufreq-dt generic driver that scale L2 cache and the ++ cores. TEST ++ ++ The L2 cache is scaled based on the max clk across all cores and ++ the clock is decided based on the opp-level set in the device tree. ++ ++ Different core freq can be linked to a specific l2 freq and the driver ++ on frequency change will scale the core and the l2 clk based of the ++ linked freq. ++ ++ On Krait SoC is present a bug and on every L2 clk change the driver ++ needs to set the clk to the idle freq before changing it to the new value. ++ ++ This requires the qcom cpufreq nvmem driver to parse the different opp ++ core clk and an additional opp table for the l2 scaling. ++ ++ If the driver detect broken config (for example missing opp-level) the ++ cpufreq driver skips the l2 scaling ++ ++ Referring to this example opp-level can be used to link a range of cpu freq ++ to a specific l2 freq: ++ cpu opp freq 384000000 has opp-level 0 ++ l2 opp freq 384000000 has opp-level 0 ++ The driver will scale l2 to 384000000 ++ ++ cpu opp freq 600000000-1000000000 has opp-level 1 ++ l2 opp freq 1000000000 has opp-level 1 ++ The driver will scale l2 to 1000000000 ++ ++allOf: ++ - $ref: /schemas/cache-controller.yaml# ++ ++select: ++ properties: ++ compatible: ++ items: ++ - enum: ++ - qcom,krait-cache ++ ++ required: ++ - compatible ++ ++properties: ++ compatible: ++ items: ++ - const: qcom,krait-cache ++ - const: cache ++ ++ cache-level: ++ const: 2 ++ ++ clocks: ++ maxItems: 1 ++ ++ clock-names: ++ const: l2 ++ ++ l2-supply: true ++ ++ operating-points-v2: true ++ ++required: ++ - compatible ++ - cache-level ++ - clocks ++ - clock-names ++ - l2-supply ++ - operating-points-v2 ++ ++additionalProperties: false ++ ++examples: ++ - | ++ cpus { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ cpu0: cpu@0 { ++ compatible = "qcom,krait"; ++ enable-method = "qcom,kpss-acc-v1"; ++ device_type = "cpu"; ++ reg = <0>; ++ next-level-cache = <&L2>; ++ qcom,acc = <&acc0>; ++ qcom,saw = <&saw0>; ++ clocks = <&kraitcc 0>, <&kraitcc 4>; ++ clock-names = "cpu", "l2"; ++ clock-latency = <100000>; ++ cpu-supply = <&smb208_s2a>; ++ operating-points-v2 = <&opp_table0>; ++ voltage-tolerance = <5>; ++ cooling-min-state = <0>; ++ cooling-max-state = <10>; ++ #cooling-cells = <2>; ++ cpu-idle-states = <&CPU_SPC>; ++ }; ++ ++ /* ... */ ++ ++ }; ++ ++ opp_table0: opp_table0 { ++ compatible = "operating-points-v2-kryo-cpu"; ++ nvmem-cells = <&speedbin_efuse>; ++ ++ opp-384000000 { ++ opp-hz = /bits/ 64 <384000000>; ++ opp-microvolt-speed0-pvs0-v0 = <1000000>; ++ opp-microvolt-speed0-pvs1-v0 = <925000>; ++ opp-microvolt-speed0-pvs2-v0 = <875000>; ++ opp-microvolt-speed0-pvs3-v0 = <800000>; ++ opp-supported-hw = <0x1>; ++ clock-latency-ns = <100000>; ++ opp-level = <0>; ++ }; ++ ++ opp-600000000 { ++ opp-hz = /bits/ 64 <600000000>; ++ opp-microvolt-speed0-pvs0-v0 = <1050000>; ++ opp-microvolt-speed0-pvs1-v0 = <975000>; ++ opp-microvolt-speed0-pvs2-v0 = <925000>; ++ opp-microvolt-speed0-pvs3-v0 = <850000>; ++ opp-supported-hw = <0x1>; ++ clock-latency-ns = <100000>; ++ opp-level = <1>; ++ }; ++ ++ opp-800000000 { ++ opp-hz = /bits/ 64 <800000000>; ++ opp-microvolt-speed0-pvs0-v0 = <1100000>; ++ opp-microvolt-speed0-pvs1-v0 = <1025000>; ++ opp-microvolt-speed0-pvs2-v0 = <995000>; ++ opp-microvolt-speed0-pvs3-v0 = <900000>; ++ opp-supported-hw = <0x1>; ++ clock-latency-ns = <100000>; ++ opp-level = <1>; ++ }; ++ ++ opp-1000000000 { ++ opp-hz = /bits/ 64 <1000000000>; ++ opp-microvolt-speed0-pvs0-v0 = <1150000>; ++ opp-microvolt-speed0-pvs1-v0 = <1075000>; ++ opp-microvolt-speed0-pvs2-v0 = <1025000>; ++ opp-microvolt-speed0-pvs3-v0 = <950000>; ++ opp-supported-hw = <0x1>; ++ clock-latency-ns = <100000>; ++ opp-level = <1>; ++ }; ++ ++ opp-1200000000 { ++ opp-hz = /bits/ 64 <1200000000>; ++ opp-microvolt-speed0-pvs0-v0 = <1200000>; ++ opp-microvolt-speed0-pvs1-v0 = <1125000>; ++ opp-microvolt-speed0-pvs2-v0 = <1075000>; ++ opp-microvolt-speed0-pvs3-v0 = <1000000>; ++ opp-supported-hw = <0x1>; ++ clock-latency-ns = <100000>; ++ opp-level = <2>; ++ }; ++ ++ opp-1400000000 { ++ opp-hz = /bits/ 64 <1400000000>; ++ opp-microvolt-speed0-pvs0-v0 = <1250000>; ++ opp-microvolt-speed0-pvs1-v0 = <1175000>; ++ opp-microvolt-speed0-pvs2-v0 = <1125000>; ++ opp-microvolt-speed0-pvs3-v0 = <1050000>; ++ opp-supported-hw = <0x1>; ++ clock-latency-ns = <100000>; ++ opp-level = <2>; ++ }; ++ }; ++ ++ opp_table_l2: opp_table_l2 { ++ compatible = "operating-points-v2"; ++ ++ opp-384000000 { ++ opp-hz = /bits/ 64 <384000000>; ++ opp-microvolt = <1100000>; ++ clock-latency-ns = <100000>; ++ opp-level = <0>; ++ }; ++ opp-1000000000 { ++ opp-hz = /bits/ 64 <1000000000>; ++ opp-microvolt = <1100000>; ++ clock-latency-ns = <100000>; ++ opp-level = <1>; ++ }; ++ opp-1200000000 { ++ opp-hz = /bits/ 64 <1200000000>; ++ opp-microvolt = <1150000>; ++ clock-latency-ns = <100000>; ++ opp-level = <2>; ++ }; ++ }; ++ ++ soc { ++ L2: l2-cache { ++ compatible = "qcom,krait-cache", "cache"; ++ cache-level = <2>; ++ ++ clocks = <&kraitcc 4>; ++ clock-names = "l2"; ++ l2-supply = <&smb208_s1a>; ++ operating-points-v2 = <&opp_table_l2>; ++ }; ++ }; ++ ++... diff --git a/target/linux/ipq806x/patches-5.4/0057-add-fab-scaling-support-with-cpufreq.patch b/target/linux/ipq806x/patches-5.4/098-3-add-fab-scaling-support-with-cpufreq.patch similarity index 93% rename from target/linux/ipq806x/patches-5.4/0057-add-fab-scaling-support-with-cpufreq.patch rename to target/linux/ipq806x/patches-5.4/098-3-add-fab-scaling-support-with-cpufreq.patch index 441500df79..fe9143218f 100644 --- a/target/linux/ipq806x/patches-5.4/0057-add-fab-scaling-support-with-cpufreq.patch +++ b/target/linux/ipq806x/patches-5.4/098-3-add-fab-scaling-support-with-cpufreq.patch @@ -217,9 +217,9 @@ +int scale_fabrics(unsigned long max_cpu_freq); + +#endif ---- a/drivers/cpufreq/cpufreq-dt.c -+++ b/drivers/cpufreq/cpufreq-dt.c -@@ -20,6 +20,7 @@ +--- a/drivers/cpufreq/qcom-cpufreq-krait.c ++++ b/drivers/cpufreq/qcom-cpufreq-krait.c +@@ -15,6 +15,7 @@ #include #include #include @@ -227,17 +227,17 @@ #include "cpufreq-dt.h" -@@ -111,6 +112,13 @@ static int set_target(struct cpufreq_pol - } - } - } +@@ -54,6 +55,13 @@ static int set_target(struct cpufreq_pol + level = dev_pm_opp_get_level(opp); + dev_pm_opp_put(opp); + ++ /* ++ * Scale fabrics with max freq across all cores ++ */ ++ ret = scale_fabrics(target_freq); ++ if (ret) ++ return ret; + -+ /* -+ * Scale fabrics with max freq across all cores -+ */ -+ ret = scale_fabrics(target_freq); -+ if (ret) -+ goto exit; - } - priv->opp_freq = freq * 1000; - arch_set_freq_scale(policy->related_cpus, freq, + opp = dev_pm_opp_find_level_exact(&l2_pdev->dev, level); + if (IS_ERR(opp)) { + dev_err(&l2_pdev->dev, From fdb739bef6868289f5f3c847abad0ce875a864bd Mon Sep 17 00:00:00 2001 From: Ansuel Smith Date: Mon, 1 Mar 2021 01:13:27 +0100 Subject: [PATCH 21/62] ipq806x: fix broken pci2 and pci3 pci2 and pci3 has a too big io address space. Enlarge the IO_SPACE_LIMIT define for the arm arch. Signed-off-by: Ansuel Smith --- ...e-IO_SPACE_LIMIT-needed-for-some-SoC.patch | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 target/linux/ipq806x/patches-5.10/103-arm-Enlarge-IO_SPACE_LIMIT-needed-for-some-SoC.patch diff --git a/target/linux/ipq806x/patches-5.10/103-arm-Enlarge-IO_SPACE_LIMIT-needed-for-some-SoC.patch b/target/linux/ipq806x/patches-5.10/103-arm-Enlarge-IO_SPACE_LIMIT-needed-for-some-SoC.patch new file mode 100644 index 0000000000..e69a97f843 --- /dev/null +++ b/target/linux/ipq806x/patches-5.10/103-arm-Enlarge-IO_SPACE_LIMIT-needed-for-some-SoC.patch @@ -0,0 +1,30 @@ +From 9a894b0e5d3e6ed3c435b89fe96794ec9ddf5925 Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Sun, 28 Feb 2021 15:22:24 +0100 +Subject: [PATCH] arm: Enlarge IO_SPACE_LIMIT needed for some SoC + +Ipq8064 SoC requires larger IO_SPACE_LIMIT or second and third pci port +fails to register the IO addresses and connected device doesn't work. + +Cc: # 4.9+ +Signed-off-by: Ansuel Smith +--- + arch/arm/include/asm/io.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm/include/asm/io.h b/arch/arm/include/asm/io.h +index fc748122f1e0..6f3e89f08bd8 100644 +--- a/arch/arm/include/asm/io.h ++++ b/arch/arm/include/asm/io.h +@@ -197,7 +197,7 @@ void __iomem *pci_remap_cfgspace(resource_size_t res_cookie, size_t size); + #ifdef CONFIG_NEED_MACH_IO_H + #include + #elif defined(CONFIG_PCI) +-#define IO_SPACE_LIMIT ((resource_size_t)0xfffff) ++#define IO_SPACE_LIMIT ((resource_size_t)0xffffff) + #define __io(a) __typesafe_io(PCI_IO_VIRT_BASE + ((a) & IO_SPACE_LIMIT)) + #else + #define __io(a) __typesafe_io((a) & IO_SPACE_LIMIT) +-- +2.30.0 + From 62cc66fa6737de50d6aa57042f9508fccd476ed7 Mon Sep 17 00:00:00 2001 From: Ansuel Smith Date: Mon, 1 Mar 2021 01:21:08 +0100 Subject: [PATCH 22/62] ipq806x: introduce nandc boot layout mode ipq806x have different ecc configuration for boot partition and rootfs partition. Add support for this to fix IO error on mtd block scan. Signed-off-by: Ansuel Smith --- ...m_nandc-add-boot_layout_mode-support.patch | 245 ++++++++++++++++++ ...vicetree-mtd-qcom_nandc-document-qco.patch | 47 ++++ 2 files changed, 292 insertions(+) create mode 100644 target/linux/ipq806x/patches-5.10/099-1-mtd-nand-raw-qcom_nandc-add-boot_layout_mode-support.patch create mode 100644 target/linux/ipq806x/patches-5.10/099-2-Documentation-devicetree-mtd-qcom_nandc-document-qco.patch diff --git a/target/linux/ipq806x/patches-5.10/099-1-mtd-nand-raw-qcom_nandc-add-boot_layout_mode-support.patch b/target/linux/ipq806x/patches-5.10/099-1-mtd-nand-raw-qcom_nandc-add-boot_layout_mode-support.patch new file mode 100644 index 0000000000..06b842382e --- /dev/null +++ b/target/linux/ipq806x/patches-5.10/099-1-mtd-nand-raw-qcom_nandc-add-boot_layout_mode-support.patch @@ -0,0 +1,245 @@ +From 6949d651e3be3ebbfedb6bbd5b541cfda6ee58a9 Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Wed, 10 Feb 2021 10:40:17 +0100 +Subject: [PATCH 1/2] mtd: nand: raw: qcom_nandc: add boot_layout_mode support + +ipq806x nand have a special ecc configuration for the boot pages. The +use of the non-boot pages configuration on boot pages cause I/O error +and can cause broken data written to the nand. Add support for this +special configuration if the page to be read/write is in the size of the +boot pages set by the dts. + +Signed-off-by: Ansuel Smith +--- + drivers/mtd/nand/raw/qcom_nandc.c | 82 +++++++++++++++++++++++++++++-- + 1 file changed, 77 insertions(+), 5 deletions(-) + +diff --git a/drivers/mtd/nand/raw/qcom_nandc.c b/drivers/mtd/nand/raw/qcom_nandc.c +index 667e4bfe369f..69be86898d7a 100644 +--- a/drivers/mtd/nand/raw/qcom_nandc.c ++++ b/drivers/mtd/nand/raw/qcom_nandc.c +@@ -160,6 +160,11 @@ + /* NAND_CTRL bits */ + #define BAM_MODE_EN BIT(0) + ++ ++#define UD_SIZE_BYTES_MASK (0x3ff << UD_SIZE_BYTES) ++#define SPARE_SIZE_BYTES_MASK (0xf << SPARE_SIZE_BYTES) ++#define ECC_NUM_DATA_BYTES_MASK (0x3ff << ECC_NUM_DATA_BYTES) ++ + /* + * the NAND controller performs reads/writes with ECC in 516 byte chunks. + * the driver calls the chunks 'step' or 'codeword' interchangeably +@@ -431,6 +436,13 @@ struct qcom_nand_controller { + * @cfg0, cfg1, cfg0_raw..: NANDc register configurations needed for + * ecc/non-ecc mode for the current nand flash + * device ++ * ++ * @boot_pages_conf: keep track of the current ecc configuration used by ++ * the driver for read/write operation. (boot pages ++ * have different configuration than normal page) ++ * @boot_pages: number of pages starting from 0 used as boot pages ++ * where the driver will use the boot pages ecc ++ * configuration for read/write operation + */ + struct qcom_nand_host { + struct nand_chip chip; +@@ -453,6 +465,9 @@ struct qcom_nand_host { + u32 ecc_bch_cfg; + u32 clrflashstatus; + u32 clrreadstatus; ++ ++ bool boot_pages_conf; ++ u32 boot_pages; + }; + + /* +@@ -462,6 +477,7 @@ struct qcom_nand_host { + * @ecc_modes - ecc mode for NAND + * @is_bam - whether NAND controller is using BAM + * @is_qpic - whether NAND CTRL is part of qpic IP ++ * @has_boot_pages - whether NAND has different ecc settings for boot pages + * @dev_cmd_reg_start - NAND_DEV_CMD_* registers starting offset + */ + struct qcom_nandc_props { +@@ -469,6 +485,7 @@ struct qcom_nandc_props { + bool is_bam; + bool is_qpic; ++ bool has_boot_pages; + u32 dev_cmd_reg_start; + }; + + /* Frees the BAM transaction memory */ +@@ -1622,7 +1639,7 @@ qcom_nandc_read_cw_raw(struct mtd_info *mtd, struct nand_chip *chip, + data_size1 = mtd->writesize - host->cw_size * (ecc->steps - 1); + oob_size1 = host->bbm_size; + +- if (cw == (ecc->steps - 1)) { ++ if (cw == (ecc->steps - 1) && !host->boot_pages_conf) { + data_size2 = ecc->size - data_size1 - + ((ecc->steps - 1) * 4); + oob_size2 = (ecc->steps * 4) + host->ecc_bytes_hw + +@@ -1703,7 +1720,7 @@ check_for_erased_page(struct qcom_nand_host *host, u8 *data_buf, + } + + for_each_set_bit(cw, &uncorrectable_cws, ecc->steps) { +- if (cw == (ecc->steps - 1)) { ++ if (cw == (ecc->steps - 1) && !host->boot_pages_conf) { + data_size = ecc->size - ((ecc->steps - 1) * 4); + oob_size = (ecc->steps * 4) + host->ecc_bytes_hw; + } else { +@@ -1862,7 +1879,7 @@ static int read_page_ecc(struct qcom_nand_host *host, u8 *data_buf, + for (i = 0; i < ecc->steps; i++) { + int data_size, oob_size; + +- if (i == (ecc->steps - 1)) { ++ if (i == (ecc->steps - 1) && !host->boot_pages_conf) { + data_size = ecc->size - ((ecc->steps - 1) << 2); + oob_size = (ecc->steps << 2) + host->ecc_bytes_hw + + host->spare_bytes; +@@ -1959,6 +1976,30 @@ static int copy_last_cw(struct qcom_nand_host *host, int page) + return ret; + } + ++static void ++check_boot_pages_conf(struct qcom_nand_host *host, int page) ++{ ++ bool boot_pages_conf = page < host->boot_pages; ++ ++ /* Skip conf write if we are already in the correct mode */ ++ if (boot_pages_conf != host->boot_pages_conf) { ++ host->boot_pages_conf = boot_pages_conf; ++ ++ host->cw_data = boot_pages_conf ? 512 : 516; ++ host->spare_bytes = host->cw_size - host->ecc_bytes_hw - ++ host->bbm_size - host->cw_data; ++ ++ host->cfg0 &= ~(SPARE_SIZE_BYTES_MASK | UD_SIZE_BYTES_MASK); ++ host->cfg0 |= host->spare_bytes << SPARE_SIZE_BYTES | ++ host->cw_data << UD_SIZE_BYTES; ++ ++ host->ecc_bch_cfg &= ~ECC_NUM_DATA_BYTES_MASK; ++ host->ecc_bch_cfg |= host->cw_data << ECC_NUM_DATA_BYTES; ++ host->ecc_buf_cfg = (boot_pages_conf ? 0x1ff : 0x203) << ++ NUM_STEPS; ++ } ++} ++ + /* implements ecc->read_page() */ + static int qcom_nandc_read_page(struct nand_chip *chip, uint8_t *buf, + int oob_required, int page) +@@ -1967,6 +2008,9 @@ static int qcom_nandc_read_page(struct nand_chip *chip, uint8_t *buf, + struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip); + u8 *data_buf, *oob_buf = NULL; + ++ if (host->boot_pages) ++ check_boot_pages_conf(host, page); ++ + nand_read_page_op(chip, page, 0, NULL, 0); + data_buf = buf; + oob_buf = oob_required ? chip->oob_poi : NULL; +@@ -1986,6 +2030,9 @@ static int qcom_nandc_read_page_raw(struct nand_chip *chip, uint8_t *buf, + int cw, ret; + u8 *data_buf = buf, *oob_buf = chip->oob_poi; + ++ if (host->boot_pages) ++ check_boot_pages_conf(host, page); ++ + for (cw = 0; cw < ecc->steps; cw++) { + ret = qcom_nandc_read_cw_raw(mtd, chip, data_buf, oob_buf, + page, cw); +@@ -2006,6 +2053,9 @@ static int qcom_nandc_read_oob(struct nand_chip *chip, int page) + struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip); + struct nand_ecc_ctrl *ecc = &chip->ecc; + ++ if (host->boot_pages) ++ check_boot_pages_conf(host, page); ++ + clear_read_regs(nandc); + clear_bam_transaction(nandc); + +@@ -2026,6 +2076,9 @@ static int qcom_nandc_write_page(struct nand_chip *chip, const uint8_t *buf, + u8 *data_buf, *oob_buf; + int i, ret; + ++ if (host->boot_pages) ++ check_boot_pages_conf(host, page); ++ + nand_prog_page_begin_op(chip, page, 0, NULL, 0); + + clear_read_regs(nandc); +@@ -2041,7 +2094,7 @@ static int qcom_nandc_write_page(struct nand_chip *chip, const uint8_t *buf, + for (i = 0; i < ecc->steps; i++) { + int data_size, oob_size; + +- if (i == (ecc->steps - 1)) { ++ if (i == (ecc->steps - 1) && !host->boot_pages_conf) { + data_size = ecc->size - ((ecc->steps - 1) << 2); + oob_size = (ecc->steps << 2) + host->ecc_bytes_hw + + host->spare_bytes; +@@ -2098,6 +2151,9 @@ static int qcom_nandc_write_page_raw(struct nand_chip *chip, + u8 *data_buf, *oob_buf; + int i, ret; + ++ if (host->boot_pages) ++ check_boot_pages_conf(host, page); ++ + nand_prog_page_begin_op(chip, page, 0, NULL, 0); + clear_read_regs(nandc); + clear_bam_transaction(nandc); +@@ -2116,7 +2172,7 @@ static int qcom_nandc_write_page_raw(struct nand_chip *chip, + data_size1 = mtd->writesize - host->cw_size * (ecc->steps - 1); + oob_size1 = host->bbm_size; + +- if (i == (ecc->steps - 1)) { ++ if (i == (ecc->steps - 1) && !host->boot_pages_conf) { + data_size2 = ecc->size - data_size1 - + ((ecc->steps - 1) << 2); + oob_size2 = (ecc->steps << 2) + host->ecc_bytes_hw + +@@ -2176,6 +2232,9 @@ static int qcom_nandc_write_oob(struct nand_chip *chip, int page) + int data_size, oob_size; + int ret; + ++ if (host->boot_pages) ++ check_boot_pages_conf(host, page); ++ + host->use_ecc = true; + clear_bam_transaction(nandc); + +@@ -2828,6 +2887,7 @@ static int qcom_nand_host_init_and_register(struct qcom_nand_controller *nandc, + struct nand_chip *chip = &host->chip; + struct mtd_info *mtd = nand_to_mtd(chip); + struct device *dev = nandc->dev; ++ u32 boot_pages_size; + int ret; + + ret = of_property_read_u32(dn, "reg", &host->cs); +@@ -2888,6 +2948,17 @@ static int qcom_nand_host_init_and_register(struct qcom_nand_controller *nandc, + if (ret) + nand_cleanup(chip); + ++ if (nandc->props->has_boot_pages && ++ of_property_read_bool(dn, "nand-is-boot-medium")) { ++ ret = of_property_read_u32(dn, "qcom,boot_pages_size", ++ &boot_pages_size); ++ if (ret) ++ dev_warn(dev, "can't get boot pages size"); ++ else ++ /* Convert size to nand pages */ ++ host->boot_pages = boot_pages_size / mtd->writesize; ++ } ++ + return ret; + } + +@@ -3057,6 +3128,7 @@ static int qcom_nandc_remove(struct platform_device *pdev) + static const struct qcom_nandc_props ipq806x_nandc_props = { + .ecc_modes = (ECC_RS_4BIT | ECC_BCH_8BIT), + .is_bam = false, ++ .has_boot_pages = true, + .dev_cmd_reg_start = 0x0, + }; + +-- +2.29.2 + diff --git a/target/linux/ipq806x/patches-5.10/099-2-Documentation-devicetree-mtd-qcom_nandc-document-qco.patch b/target/linux/ipq806x/patches-5.10/099-2-Documentation-devicetree-mtd-qcom_nandc-document-qco.patch new file mode 100644 index 0000000000..2bef1daefb --- /dev/null +++ b/target/linux/ipq806x/patches-5.10/099-2-Documentation-devicetree-mtd-qcom_nandc-document-qco.patch @@ -0,0 +1,47 @@ +From 6fb003a7a117f97a35b078ba726c84adeae29c4c Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Wed, 10 Feb 2021 10:54:19 +0100 +Subject: [PATCH 2/2] Documentation: devicetree: mtd: qcom_nandc: document + qcom,boot_layout_size binding + +Document new qcom,boot_layout_size binding used to apply special +read/write confituation to boots partitions. + +Signed-off-by: Ansuel Smith +--- + Documentation/devicetree/bindings/mtd/qcom_nandc.txt | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/Documentation/devicetree/bindings/mtd/qcom_nandc.txt b/Documentation/devicetree/bindings/mtd/qcom_nandc.txt +index 5647913d8837..3cf1dd5ebad2 100644 +--- a/Documentation/devicetree/bindings/mtd/qcom_nandc.txt ++++ b/Documentation/devicetree/bindings/mtd/qcom_nandc.txt +@@ -56,6 +56,15 @@ Optional properties: + be used according to chip requirement and available + OOB size. + ++EBI2 specific properties: ++- nand-is-boot-medium: nand contains boot partitions and different ecc configuration ++ should be used for these partitions. ++- qcom,boot_pages_size: should contain the size of the total boot partitions ++ where the boot layout read/write specific configuration ++ should be used. The boot layout is considered from the ++ start of the nand to the value set in this binding. ++ Only used in combination with 'nand-is-boot-medium'. ++ + Each nandcs device node may optionally contain a 'partitions' sub-node, which + further contains sub-nodes describing the flash partition mapping. See + partition.txt for more detail. +@@ -84,6 +93,9 @@ nand-controller@1ac00000 { + nand-ecc-strength = <4>; + nand-bus-width = <8>; + ++ nand-is-boot-medium; ++ qcom,boot_pages_size: <0x58a0000>; ++ + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; +-- +2.29.2 + From 1e25423be8acb38e979cd5a38abb1ca4cac2837e Mon Sep 17 00:00:00 2001 From: Ansuel Smith Date: Sun, 28 Mar 2021 14:17:36 +0200 Subject: [PATCH 23/62] ipq806x: refresh dtsi patches - Add new tsens node - Add new cpufreq required nodes - Drop arm cpuidle compatible - Fix duplicate node set upstream - Add voltage tolerance value for cpu opp Signed-off-by: Ansuel Smith --- .../files/arch/arm/boot/dts/qcom-ipq8062.dtsi | 40 +- .../files/arch/arm/boot/dts/qcom-ipq8065.dtsi | 94 ++-- .../0069-arm-boot-add-dts-files.patch | 8 +- .../082-ipq8064-dtsi-tweaks.patch | 58 +- .../083-ipq8064-dtsi-additions.patch | 500 +++++------------- .../086-ipq8064-fix-duplicate-node.patch | 147 +++++ 6 files changed, 399 insertions(+), 448 deletions(-) create mode 100644 target/linux/ipq806x/patches-5.10/086-ipq8064-fix-duplicate-node.patch diff --git a/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8062.dtsi b/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8062.dtsi index caef2bc824..09aa081737 100644 --- a/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8062.dtsi +++ b/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8062.dtsi @@ -14,14 +14,6 @@ stdout-path = "serial0:115200n8"; }; - cpus { - qcom,l2 { - qcom,l2-rates = <384000000 1000000000 1000000000>; - qcom,l2-cpufreq = <384000000 600000000 1000000000>; - qcom,l2-volt = <1100000 1100000 1100000>; - }; - }; - reserved-memory { #address-cells = <1>; #size-cells = <1>; @@ -54,31 +46,31 @@ /delete-node/opp-1400000000; opp-384000000 { - opp-microvolt-speed0-pvs0-v0 = <950000>; - opp-microvolt-speed0-pvs1-v0 = <900000>; - opp-microvolt-speed0-pvs2-v0 = <850000>; - opp-microvolt-speed0-pvs3-v0 = <800000>; + opp-microvolt-speed0-pvs0-v0 = <945000 950000 955000>; + opp-microvolt-speed0-pvs1-v0 = <985000 900000 905000>; + opp-microvolt-speed0-pvs2-v0 = <845000 850000 855000>; + opp-microvolt-speed0-pvs3-v0 = <795000 800000 805000>; }; opp-600000000 { - opp-microvolt-speed0-pvs0-v0 = <1000000>; - opp-microvolt-speed0-pvs1-v0 = <950000>; - opp-microvolt-speed0-pvs2-v0 = <900000>; - opp-microvolt-speed0-pvs3-v0 = <850000>; + opp-microvolt-speed0-pvs0-v0 = <995000 1000000 1005000>; + opp-microvolt-speed0-pvs1-v0 = <945000 950000 955000>; + opp-microvolt-speed0-pvs2-v0 = <895000 900000 905000>; + opp-microvolt-speed0-pvs3-v0 = <845000 850000 855000>; }; opp-800000000 { - opp-microvolt-speed0-pvs0-v0 = <1050000>; - opp-microvolt-speed0-pvs1-v0 = <1000000>; - opp-microvolt-speed0-pvs2-v0 = <950000>; - opp-microvolt-speed0-pvs3-v0 = <900000>; + opp-microvolt-speed0-pvs0-v0 = <1045000 1050000 1055000>; + opp-microvolt-speed0-pvs1-v0 = < 995000 1000000 1005000>; + opp-microvolt-speed0-pvs2-v0 = < 945000 950000 955000>; + opp-microvolt-speed0-pvs3-v0 = < 895000 900000 905000>; }; opp-1000000000 { - opp-microvolt-speed0-pvs0-v0 = <1100000>; - opp-microvolt-speed0-pvs1-v0 = <1050000>; - opp-microvolt-speed0-pvs2-v0 = <1000000>; - opp-microvolt-speed0-pvs3-v0 = <950000>; + opp-microvolt-speed0-pvs0-v0 = <1095000 1100000 1105000>; + opp-microvolt-speed0-pvs1-v0 = <1045000 1050000 1055000>; + opp-microvolt-speed0-pvs2-v0 = < 995000 1000000 1005000>; + opp-microvolt-speed0-pvs3-v0 = < 945000 950000 955000>; }; }; diff --git a/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8065.dtsi b/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8065.dtsi index ab67d504e6..f215181470 100644 --- a/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8065.dtsi +++ b/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8065.dtsi @@ -12,12 +12,6 @@ stdout-path = "serial0:115200n8"; }; - cpus { - qcom,l2 { - qcom,l2-cpufreq = <384000000 600000000 1400000000>; - }; - }; - reserved-memory { #address-cells = <1>; #size-cells = <1>; @@ -92,66 +86,68 @@ /delete-node/opp-1200000000; - opp-384000000 { - opp-microvolt-speed0-pvs0-v0 = <975000>; - opp-microvolt-speed0-pvs1-v0 = <950000>; - opp-microvolt-speed0-pvs2-v0 = <925000>; - opp-microvolt-speed0-pvs3-v0 = <900000>; - opp-microvolt-speed0-pvs4-v0 = <875000>; - opp-microvolt-speed0-pvs5-v0 = <825000>; - opp-microvolt-speed0-pvs6-v0 = <775000>; + opp-384000000 { + opp-microvolt-speed0-pvs0-v0 = <970000 975000 980000>; + opp-microvolt-speed0-pvs1-v0 = <945000 950000 955000>; + opp-microvolt-speed0-pvs2-v0 = <920000 925000 930000>; + opp-microvolt-speed0-pvs3-v0 = <985000 900000 905000>; + opp-microvolt-speed0-pvs4-v0 = <870000 875000 880000>; + opp-microvolt-speed0-pvs5-v0 = <820000 825000 830000>; + opp-microvolt-speed0-pvs6-v0 = <770000 775000 780000>; }; opp-600000000 { - opp-microvolt-speed0-pvs0-v0 = <1000000>; - opp-microvolt-speed0-pvs1-v0 = <975000>; - opp-microvolt-speed0-pvs2-v0 = <950000>; - opp-microvolt-speed0-pvs3-v0 = <925000>; - opp-microvolt-speed0-pvs4-v0 = <900000>; - opp-microvolt-speed0-pvs5-v0 = <850000>; - opp-microvolt-speed0-pvs6-v0 = <800000>; + opp-microvolt-speed0-pvs0-v0 = <995000 1000000 1005000>; + opp-microvolt-speed0-pvs1-v0 = <970000 975000 980000>; + opp-microvolt-speed0-pvs2-v0 = <945000 950000 955000>; + opp-microvolt-speed0-pvs3-v0 = <920000 925000 930000>; + opp-microvolt-speed0-pvs4-v0 = <895000 900000 905000>; + opp-microvolt-speed0-pvs5-v0 = <845000 850000 855000>; + opp-microvolt-speed0-pvs6-v0 = <795000 800000 805000>; }; opp-800000000 { - opp-microvolt-speed0-pvs0-v0 = <1050000>; - opp-microvolt-speed0-pvs1-v0 = <1025000>; - opp-microvolt-speed0-pvs2-v0 = <1000000>; - opp-microvolt-speed0-pvs3-v0 = <975000>; - opp-microvolt-speed0-pvs4-v0 = <950000>; - opp-microvolt-speed0-pvs5-v0 = <900000>; - opp-microvolt-speed0-pvs6-v0 = <850000>; + opp-microvolt-speed0-pvs0-v0 = <1045000 1050000 1055000>; + opp-microvolt-speed0-pvs1-v0 = <1020000 1025000 1030000>; + opp-microvolt-speed0-pvs2-v0 = <995000 1000000 1005000>; + opp-microvolt-speed0-pvs3-v0 = <970000 975000 980000>; + opp-microvolt-speed0-pvs4-v0 = <945000 950000 955000>; + opp-microvolt-speed0-pvs5-v0 = <895000 900000 905000>; + opp-microvolt-speed0-pvs6-v0 = <845000 850000 855000>; }; opp-1000000000 { - opp-microvolt-speed0-pvs0-v0 = <1100000>; - opp-microvolt-speed0-pvs1-v0 = <1075000>; - opp-microvolt-speed0-pvs2-v0 = <1050000>; - opp-microvolt-speed0-pvs3-v0 = <1025000>; - opp-microvolt-speed0-pvs4-v0 = <1000000>; - opp-microvolt-speed0-pvs5-v0 = <950000>; - opp-microvolt-speed0-pvs6-v0 = <900000>; + opp-microvolt-speed0-pvs0-v0 = <1095000 1100000 1105000>; + opp-microvolt-speed0-pvs1-v0 = <1070000 1075000 1080000>; + opp-microvolt-speed0-pvs2-v0 = <1045000 1050000 1055000>; + opp-microvolt-speed0-pvs3-v0 = <1020000 1025000 1030000>; + opp-microvolt-speed0-pvs4-v0 = <995000 1000000 1005000>; + opp-microvolt-speed0-pvs5-v0 = <945000 950000 955000>; + opp-microvolt-speed0-pvs6-v0 = <895000 900000 905000>; }; opp-1400000000 { - opp-microvolt-speed0-pvs0-v0 = <1175000>; - opp-microvolt-speed0-pvs1-v0 = <1150000>; - opp-microvolt-speed0-pvs2-v0 = <1125000>; - opp-microvolt-speed0-pvs3-v0 = <1100000>; - opp-microvolt-speed0-pvs4-v0 = <1075000>; - opp-microvolt-speed0-pvs5-v0 = <1025000>; - opp-microvolt-speed0-pvs6-v0 = <975000>; + opp-microvolt-speed0-pvs0-v0 = <1170000 1175000 1180000>; + opp-microvolt-speed0-pvs1-v0 = <1145000 1150000 1155000>; + opp-microvolt-speed0-pvs2-v0 = <1120000 1125000 1130000>; + opp-microvolt-speed0-pvs3-v0 = <1095000 1100000 1105000>; + opp-microvolt-speed0-pvs4-v0 = <1070000 1075000 1080000>; + opp-microvolt-speed0-pvs5-v0 = <1020000 1025000 1030000>; + opp-microvolt-speed0-pvs6-v0 = <970000 975000 980000>; + opp-level = <1>; }; opp-1725000000 { opp-hz = /bits/ 64 <1725000000>; - opp-microvolt-speed0-pvs0-v0 = <1262500>; - opp-microvolt-speed0-pvs1-v0 = <1225000>; - opp-microvolt-speed0-pvs2-v0 = <1200000>; - opp-microvolt-speed0-pvs3-v0 = <1175000>; - opp-microvolt-speed0-pvs4-v0 = <1150000>; - opp-microvolt-speed0-pvs5-v0 = <1100000>; - opp-microvolt-speed0-pvs6-v0 = <1050000>; + opp-microvolt-speed0-pvs0-v0 = <1257500 1262500 1267500>; + opp-microvolt-speed0-pvs1-v0 = <1220000 1225000 1230000>; + opp-microvolt-speed0-pvs2-v0 = <1195000 1200000 1205000>; + opp-microvolt-speed0-pvs3-v0 = <1170000 1175000 1180000>; + opp-microvolt-speed0-pvs4-v0 = <1145000 1150000 1155000>; + opp-microvolt-speed0-pvs5-v0 = <1095000 1100000 1105000>; + opp-microvolt-speed0-pvs6-v0 = <1045000 1050000 1055000>; opp-supported-hw = <0x1>; clock-latency-ns = <100000>; + opp-level = <2>; }; }; diff --git a/target/linux/ipq806x/patches-5.10/0069-arm-boot-add-dts-files.patch b/target/linux/ipq806x/patches-5.10/0069-arm-boot-add-dts-files.patch index 055a4cbc30..b652102616 100644 --- a/target/linux/ipq806x/patches-5.10/0069-arm-boot-add-dts-files.patch +++ b/target/linux/ipq806x/patches-5.10/0069-arm-boot-add-dts-files.patch @@ -10,22 +10,18 @@ Signed-off-by: John Crispin --- a/arch/arm/boot/dts/Makefile +++ b/arch/arm/boot/dts/Makefile -@@ -842,7 +842,24 @@ dtb-$(CONFIG_ARCH_QCOM) += \ - qcom-ipq4019-ap.dk04.1-c3.dtb \ - qcom-ipq4019-ap.dk07.1-c1.dtb \ +@@ -843,6 +843,20 @@ dtb-$(CONFIG_ARCH_QCOM) += \ qcom-ipq4019-ap.dk07.1-c2.dtb \ -+ qcom-ipq8062-wg2600hp3.dtb \ qcom-ipq8064-ap148.dtb \ + qcom-ipq8064-rb3011.dtb \ + qcom-ipq8064-c2600.dtb \ + qcom-ipq8064-d7800.dtb \ + qcom-ipq8064-db149.dtb \ + qcom-ipq8064-ap161.dtb \ + qcom-ipq8064-ea7500-v1.dtb \ + qcom-ipq8064-ea8500.dtb \ -+ qcom-ipq8064-g10.dtb \ + qcom-ipq8064-r7500.dtb \ + qcom-ipq8064-r7500v2.dtb \ -+ qcom-ipq8064-unifi-ac-hd.dtb \ + qcom-ipq8064-wg2600hp.dtb \ + qcom-ipq8064-wpq864.dtb \ + qcom-ipq8064-wxr-2533dhp.dtb \ diff --git a/target/linux/ipq806x/patches-5.10/082-ipq8064-dtsi-tweaks.patch b/target/linux/ipq806x/patches-5.10/082-ipq8064-dtsi-tweaks.patch index 568ca5bb88..9c16ee4351 100644 --- a/target/linux/ipq806x/patches-5.10/082-ipq8064-dtsi-tweaks.patch +++ b/target/linux/ipq806x/patches-5.10/082-ipq8064-dtsi-tweaks.patch @@ -1,6 +1,6 @@ --- a/arch/arm/boot/dts/qcom-ipq8064.dtsi +++ b/arch/arm/boot/dts/qcom-ipq8064.dtsi -@@ -20,7 +20,7 @@ +@@ -20,9 +20,9 @@ #address-cells = <1>; #size-cells = <0>; @@ -9,7 +9,9 @@ compatible = "qcom,krait"; enable-method = "qcom,kpss-acc-v1"; device_type = "cpu"; -@@ -30,7 +30,7 @@ + reg = <1>; + next-level-cache = <&L2>; +@@ -30,9 +30,9 @@ qcom,saw = <&saw0>; }; @@ -18,6 +20,8 @@ compatible = "qcom,krait"; enable-method = "qcom,kpss-acc-v1"; device_type = "cpu"; + reg = <1>; + next-level-cache = <&L2>; @@ -67,7 +67,7 @@ no-map; }; @@ -27,6 +31,14 @@ reg = <0x41000000 0x200000>; no-map; }; +@@ -128,6 +128,7 @@ + gpio-ranges = <&qcom_pinmux 0 0 69>; + #gpio-cells = <2>; + interrupt-controller; ++ #address-cells = <0>; + #interrupt-cells = <2>; + interrupts = ; + @@ -155,6 +155,7 @@ function = "pcie3_rst"; drive-strength = <12>; @@ -35,6 +47,14 @@ }; }; +@@ -190,6 +190,7 @@ + intc: interrupt-controller@2000000 { + compatible = "qcom,msm-qgic2"; + interrupt-controller; ++ #address-cells = <0>; + #interrupt-cells = <3>; + reg = <0x02000000 0x1000>, + <0x02002000 0x1000>; @@ -219,21 +220,23 @@ acc0: clock-controller@2088000 { compatible = "qcom,kpss-acc-v1"; @@ -88,11 +108,43 @@ compatible = "qcom,ipq806x-ahci", "generic-ahci"; reg = <0x29000000 0x180>; -@@ -430,6 +433,7 @@ +@@ -430,6 +430,16 @@ qfprom: qfprom@700000 { + reg = <0x00700000 0x1000>; + #address-cells = <1>; + #size-cells = <1>; ++ ++ tsens_calib: calib@400 { ++ reg = <0x400 0xb>; ++ }; ++ tsens_backup: backup@410 { ++ reg = <0x410 0xb>; ++ }; ++ speedbin_efuse: speedbin@0c0 { ++ reg = <0x0c0 0x4>; ++ }; + }; + + gcc: clock-controller@900000 { +@@ -437,9 +447,21 @@ gcc: clock-controller@900000 { + + gcc: clock-controller@900000 { +- compatible = "qcom,gcc-ipq8064"; ++ compatible = "qcom,gcc-ipq8064", "syscon"; reg = <0x00900000 0x4000>; #clock-cells = <1>; #reset-cells = <1>; + #power-domain-cells = <1>; ++ ++ tsens: thermal-sensor@900000 { ++ compatible = "qcom,ipq8064-tsens"; ++ ++ nvmem-cells = <&tsens_calib>, <&tsens_backup>; ++ nvmem-cell-names = "calib", "calib_backup"; ++ interrupts = ; ++ interrupt-names = "uplow"; ++ #thermal-sensor-cells = <1>; ++ #qcom,sensors = <11>; ++ }; }; tcsr: syscon@1a400000 { diff --git a/target/linux/ipq806x/patches-5.10/083-ipq8064-dtsi-additions.patch b/target/linux/ipq806x/patches-5.10/083-ipq8064-dtsi-additions.patch index 221ecd7396..be4ccc8e12 100644 --- a/target/linux/ipq806x/patches-5.10/083-ipq8064-dtsi-additions.patch +++ b/target/linux/ipq806x/patches-5.10/083-ipq8064-dtsi-additions.patch @@ -26,10 +26,16 @@ }; cpu1: cpu@1 { -@@ -38,11 +50,458 @@ - next-level-cache = <&L2>; - qcom,acc = <&acc1>; - qcom,saw = <&saw1>; +@@ -47,17 +47,350 @@ + enable-method = "qcom,kpss-acc-v1"; + device_type = "cpu"; + reg = <1>; +- next-level-cache = <&L2>; +- qcom,acc = <&acc1>; +- qcom,saw = <&saw1>; ++ next-level-cache = <&L2>; ++ qcom,acc = <&acc1>; ++ qcom,saw = <&saw1>; + clocks = <&kraitcc 1>, <&kraitcc 4>; + clock-names = "cpu", "l2"; + clock-latency = <100000>; @@ -40,29 +46,44 @@ + cooling-max-state = <10>; + #cooling-cells = <2>; + cpu-idle-states = <&CPU_SPC>; - }; - - L2: l2-cache { - compatible = "cache"; - cache-level = <2>; -+ qcom,saw = <&saw_l2>; -+ }; -+ -+ qcom,l2 { -+ qcom,l2-rates = <384000000 1000000000 1200000000>; -+ qcom,l2-cpufreq = <384000000 600000000 1200000000>; -+ qcom,l2-volt = <1100000 1100000 1150000>; -+ qcom,l2-supply = <&smb208_s1a>; -+ }; ++ }; + + idle-states { + CPU_SPC: spc { -+ compatible = "qcom,idle-state-spc", "arm,idle-state"; ++ compatible = "qcom,idle-state-spc"; + status = "disabled"; + entry-latency-us = <400>; + exit-latency-us = <900>; + min-residency-us = <3000>; + }; + }; ++ }; + +- L2: l2-cache { +- compatible = "cache"; +- cache-level = <2>; ++ opp_table_l2: opp_table_l2 { ++ compatible = "operating-points-v2"; ++ ++ opp-384000000 { ++ opp-hz = /bits/ 64 <384000000>; ++ opp-microvolt = <1100000>; ++ clock-latency-ns = <100000>; ++ opp-level = <0>; ++ }; ++ ++ opp-1000000000 { ++ opp-hz = /bits/ 64 <1000000000>; ++ opp-microvolt = <1100000>; ++ clock-latency-ns = <100000>; ++ opp-level = <1>; ++ }; ++ ++ opp-1200000000 { ++ opp-hz = /bits/ 64 <1200000000>; ++ opp-microvolt = <1150000>; ++ clock-latency-ns = <100000>; ++ opp-level = <2>; + }; + }; + @@ -72,65 +93,71 @@ + + opp-384000000 { + opp-hz = /bits/ 64 <384000000>; -+ opp-microvolt-speed0-pvs0-v0 = <1000000>; -+ opp-microvolt-speed0-pvs1-v0 = <925000>; -+ opp-microvolt-speed0-pvs2-v0 = <875000>; -+ opp-microvolt-speed0-pvs3-v0 = <800000>; ++ opp-microvolt-speed0-pvs0-v0 = <995000 1000000 1005000>; ++ opp-microvolt-speed0-pvs1-v0 = <920000 925000 930000>; ++ opp-microvolt-speed0-pvs2-v0 = <870000 875000 880000>; ++ opp-microvolt-speed0-pvs3-v0 = <795000 800000 805000>; + opp-supported-hw = <0x1>; + clock-latency-ns = <100000>; ++ opp-level = <0>; + }; + + opp-600000000 { + opp-hz = /bits/ 64 <600000000>; -+ opp-microvolt-speed0-pvs0-v0 = <1050000>; -+ opp-microvolt-speed0-pvs1-v0 = <975000>; -+ opp-microvolt-speed0-pvs2-v0 = <925000>; -+ opp-microvolt-speed0-pvs3-v0 = <850000>; ++ opp-microvolt-speed0-pvs0-v0 = <1045000 1050000 1055000>; ++ opp-microvolt-speed0-pvs1-v0 = <970000 975000 980000>; ++ opp-microvolt-speed0-pvs2-v0 = <920000 925000 930000>; ++ opp-microvolt-speed0-pvs3-v0 = <845000 850000 855000>; + opp-supported-hw = <0x1>; + clock-latency-ns = <100000>; ++ opp-level = <1>; + }; + + opp-800000000 { + opp-hz = /bits/ 64 <800000000>; -+ opp-microvolt-speed0-pvs0-v0 = <1100000>; -+ opp-microvolt-speed0-pvs1-v0 = <1025000>; -+ opp-microvolt-speed0-pvs2-v0 = <995000>; -+ opp-microvolt-speed0-pvs3-v0 = <900000>; ++ opp-microvolt-speed0-pvs0-v0 = <1095000 1100000 1105000>; ++ opp-microvolt-speed0-pvs1-v0 = <1020000 1025000 1030000>; ++ opp-microvolt-speed0-pvs2-v0 = <990000 995000 1000000>; ++ opp-microvolt-speed0-pvs3-v0 = <895000 900000 905000>; + opp-supported-hw = <0x1>; + clock-latency-ns = <100000>; ++ opp-level = <1>; + }; + + opp-1000000000 { + opp-hz = /bits/ 64 <1000000000>; -+ opp-microvolt-speed0-pvs0-v0 = <1150000>; -+ opp-microvolt-speed0-pvs1-v0 = <1075000>; -+ opp-microvolt-speed0-pvs2-v0 = <1025000>; -+ opp-microvolt-speed0-pvs3-v0 = <950000>; ++ opp-microvolt-speed0-pvs0-v0 = <1145000 1150000 1155000>; ++ opp-microvolt-speed0-pvs1-v0 = <1070000 1075000 1080000>; ++ opp-microvolt-speed0-pvs2-v0 = <1020000 1025000 1030000>; ++ opp-microvolt-speed0-pvs3-v0 = <945000 950000 955000>; + opp-supported-hw = <0x1>; + clock-latency-ns = <100000>; ++ opp-level = <1>; + }; + + opp-1200000000 { + opp-hz = /bits/ 64 <1200000000>; -+ opp-microvolt-speed0-pvs0-v0 = <1200000>; -+ opp-microvolt-speed0-pvs1-v0 = <1125000>; -+ opp-microvolt-speed0-pvs2-v0 = <1075000>; -+ opp-microvolt-speed0-pvs3-v0 = <1000000>; ++ opp-microvolt-speed0-pvs0-v0 = <1195000 1200000 1205000>; ++ opp-microvolt-speed0-pvs1-v0 = <1120000 1125000 1130000>; ++ opp-microvolt-speed0-pvs2-v0 = <1070000 1075000 1080000>; ++ opp-microvolt-speed0-pvs3-v0 = <995000 1000000 1005000>; + opp-supported-hw = <0x1>; + clock-latency-ns = <100000>; ++ opp-level = <2>; + }; + + opp-1400000000 { + opp-hz = /bits/ 64 <1400000000>; -+ opp-microvolt-speed0-pvs0-v0 = <1250000>; -+ opp-microvolt-speed0-pvs1-v0 = <1175000>; -+ opp-microvolt-speed0-pvs2-v0 = <1125000>; -+ opp-microvolt-speed0-pvs3-v0 = <1050000>; ++ opp-microvolt-speed0-pvs0-v0 = <1245000 1250000 1255000>; ++ opp-microvolt-speed0-pvs1-v0 = <1170000 1175000 1180000>; ++ opp-microvolt-speed0-pvs2-v0 = <1120000 1125000 1130000>; ++ opp-microvolt-speed0-pvs3-v0 = <1045000 1050000 1055000>; + opp-supported-hw = <0x1>; + clock-latency-ns = <100000>; -+ }; -+ }; -+ ++ opp-level = <2>; + }; + }; + + thermal-zones { + tsens_tz_sensor0 { + polling-delay-passive = <0>; @@ -138,28 +165,16 @@ + thermal-sensors = <&tsens 0>; + + trips { -+ cpu-critical-hi { -+ temperature = <125000>; -+ hysteresis = <2000>; -+ type = "critical_high"; -+ }; -+ -+ cpu-config-hi { ++ cpu-critical { + temperature = <105000>; + hysteresis = <2000>; -+ type = "configurable_hi"; ++ type = "critical"; + }; + -+ cpu-config-lo { ++ cpu-hot { + temperature = <95000>; + hysteresis = <2000>; -+ type = "configurable_lo"; -+ }; -+ -+ cpu-critical-low { -+ temperature = <0>; -+ hysteresis = <2000>; -+ type = "critical_low"; ++ type = "hot"; + }; + }; + }; @@ -170,28 +185,16 @@ + thermal-sensors = <&tsens 1>; + + trips { -+ cpu-critical-hi { -+ temperature = <125000>; -+ hysteresis = <2000>; -+ type = "critical_high"; -+ }; -+ -+ cpu-config-hi { ++ cpu-critical { + temperature = <105000>; + hysteresis = <2000>; -+ type = "configurable_hi"; ++ type = "critical"; + }; + -+ cpu-config-lo { ++ cpu-hot { + temperature = <95000>; + hysteresis = <2000>; -+ type = "configurable_lo"; -+ }; -+ -+ cpu-critical-low { -+ temperature = <0>; -+ hysteresis = <2000>; -+ type = "critical_low"; ++ type = "hot"; + }; + }; + }; @@ -202,28 +205,16 @@ + thermal-sensors = <&tsens 2>; + + trips { -+ cpu-critical-hi { -+ temperature = <125000>; -+ hysteresis = <2000>; -+ type = "critical_high"; -+ }; -+ -+ cpu-config-hi { ++ cpu-critical { + temperature = <105000>; + hysteresis = <2000>; -+ type = "configurable_hi"; ++ type = "critical"; + }; + -+ cpu-config-lo { ++ cpu-hot { + temperature = <95000>; + hysteresis = <2000>; -+ type = "configurable_lo"; -+ }; -+ -+ cpu-critical-low { -+ temperature = <0>; -+ hysteresis = <2000>; -+ type = "critical_low"; ++ type = "hot"; + }; + }; + }; @@ -234,28 +225,16 @@ + thermal-sensors = <&tsens 3>; + + trips { -+ cpu-critical-hi { -+ temperature = <125000>; -+ hysteresis = <2000>; -+ type = "critical_high"; -+ }; -+ -+ cpu-config-hi { ++ cpu-critical { + temperature = <105000>; + hysteresis = <2000>; -+ type = "configurable_hi"; ++ type = "critical"; + }; + -+ cpu-config-lo { ++ cpu-hot { + temperature = <95000>; + hysteresis = <2000>; -+ type = "configurable_lo"; -+ }; -+ -+ cpu-critical-low { -+ temperature = <0>; -+ hysteresis = <2000>; -+ type = "critical_low"; ++ type = "hot"; + }; + }; + }; @@ -266,28 +245,16 @@ + thermal-sensors = <&tsens 4>; + + trips { -+ cpu-critical-hi { -+ temperature = <125000>; -+ hysteresis = <2000>; -+ type = "critical_high"; -+ }; -+ -+ cpu-config-hi { ++ cpu-critical { + temperature = <105000>; + hysteresis = <2000>; -+ type = "configurable_hi"; ++ type = "critical"; + }; + -+ cpu-config-lo { ++ cpu-hot { + temperature = <95000>; + hysteresis = <2000>; -+ type = "configurable_lo"; -+ }; -+ -+ cpu-critical-low { -+ temperature = <0>; -+ hysteresis = <2000>; -+ type = "critical_low"; ++ type = "hot"; + }; + }; + }; @@ -298,28 +265,16 @@ + thermal-sensors = <&tsens 5>; + + trips { -+ cpu-critical-hi { -+ temperature = <125000>; -+ hysteresis = <2000>; -+ type = "critical_high"; -+ }; -+ -+ cpu-config-hi { ++ cpu-critical { + temperature = <105000>; + hysteresis = <2000>; -+ type = "configurable_hi"; ++ type = "critical"; + }; + -+ cpu-config-lo { ++ cpu-hot { + temperature = <95000>; + hysteresis = <2000>; -+ type = "configurable_lo"; -+ }; -+ -+ cpu-critical-low { -+ temperature = <0>; -+ hysteresis = <2000>; -+ type = "critical_low"; ++ type = "hot"; + }; + }; + }; @@ -330,28 +285,16 @@ + thermal-sensors = <&tsens 6>; + + trips { -+ cpu-critical-hi { -+ temperature = <125000>; -+ hysteresis = <2000>; -+ type = "critical_high"; -+ }; -+ -+ cpu-config-hi { ++ cpu-critical { + temperature = <105000>; + hysteresis = <2000>; -+ type = "configurable_hi"; ++ type = "critical"; + }; + -+ cpu-config-lo { ++ cpu-hot { + temperature = <95000>; + hysteresis = <2000>; -+ type = "configurable_lo"; -+ }; -+ -+ cpu-critical-low { -+ temperature = <0>; -+ hysteresis = <2000>; -+ type = "critical_low"; ++ type = "hot"; + }; + }; + }; @@ -362,28 +305,16 @@ + thermal-sensors = <&tsens 7>; + + trips { -+ cpu-critical-hi { -+ temperature = <125000>; -+ hysteresis = <2000>; -+ type = "critical_high"; -+ }; -+ -+ cpu-config-hi { ++ cpu-critical { + temperature = <105000>; + hysteresis = <2000>; -+ type = "configurable_hi"; ++ type = "critical"; + }; + -+ cpu-config-lo { ++ cpu-hot { + temperature = <95000>; + hysteresis = <2000>; -+ type = "configurable_lo"; -+ }; -+ -+ cpu-critical-low { -+ temperature = <0>; -+ hysteresis = <2000>; -+ type = "critical_low"; ++ type = "hot"; + }; + }; + }; @@ -394,28 +325,16 @@ + thermal-sensors = <&tsens 8>; + + trips { -+ cpu-critical-hi { -+ temperature = <125000>; -+ hysteresis = <2000>; -+ type = "critical_high"; -+ }; -+ -+ cpu-config-hi { ++ cpu-critical { + temperature = <105000>; + hysteresis = <2000>; -+ type = "configurable_hi"; ++ type = "critical"; + }; + -+ cpu-config-lo { ++ cpu-hot { + temperature = <95000>; + hysteresis = <2000>; -+ type = "configurable_lo"; -+ }; -+ -+ cpu-critical-low { -+ temperature = <0>; -+ hysteresis = <2000>; -+ type = "critical_low"; ++ type = "hot"; + }; + }; + }; @@ -426,28 +345,16 @@ + thermal-sensors = <&tsens 9>; + + trips { -+ cpu-critical-hi { -+ temperature = <125000>; -+ hysteresis = <2000>; -+ type = "critical_high"; -+ }; -+ -+ cpu-config-hi { ++ cpu-critical { + temperature = <105000>; + hysteresis = <2000>; -+ type = "configurable_hi"; ++ type = "critical"; + }; + -+ cpu-config-lo { ++ cpu-hot { + temperature = <95000>; + hysteresis = <2000>; -+ type = "configurable_lo"; -+ }; -+ -+ cpu-critical-low { -+ temperature = <0>; -+ hysteresis = <2000>; -+ type = "critical_low"; ++ type = "hot"; + }; + }; + }; @@ -458,33 +365,24 @@ + thermal-sensors = <&tsens 10>; + + trips { -+ cpu-critical-hi { -+ temperature = <125000>; -+ hysteresis = <2000>; -+ type = "critical_high"; -+ }; -+ -+ cpu-config-hi { ++ cpu-critical { + temperature = <105000>; + hysteresis = <2000>; -+ type = "configurable_hi"; ++ type = "critical"; + }; + -+ cpu-config-lo { ++ cpu-hot { + temperature = <95000>; + hysteresis = <2000>; -+ type = "configurable_lo"; -+ }; -+ -+ cpu-critical-low { -+ temperature = <0>; -+ hysteresis = <2000>; -+ type = "critical_low"; ++ type = "hot"; + }; + }; - }; - }; - ++ }; ++ }; ++ + memory { + device_type = "memory"; + reg = <0x0 0x0>; @@ -93,6 +552,15 @@ }; }; @@ -501,25 +399,19 @@ firmware { scm { compatible = "qcom,scm-ipq806x", "qcom,scm"; -@@ -120,6 +588,84 @@ +@@ -120,6 +588,78 @@ reg-names = "lpass-lpaif"; }; -+ qfprom: qfprom@700000 { -+ compatible = "qcom,qfprom", "syscon"; -+ reg = <0x700000 0x1000>; -+ #address-cells = <1>; -+ #size-cells = <1>; -+ status = "okay"; -+ tsens_calib: calib@400 { -+ reg = <0x400 0xb>; -+ }; -+ tsens_backup: backup@410 { -+ reg = <0x410 0xb>; -+ }; -+ speedbin_efuse: speedbin@0c0 { -+ reg = <0x0c0 0x4>; -+ }; ++ L2: l2-cache { ++ compatible = "qcom,krait-cache", "cache"; ++ cache-level = <2>; ++ qcom,saw = <&saw_l2>; ++ ++ clocks = <&kraitcc 4>; ++ clock-names = "l2"; ++ l2-supply = <&smb208_s1a>; ++ operating-points-v2 = <&opp_table_l2>; + }; + + rpm: rpm@108000 { @@ -692,22 +584,6 @@ gsbi2: gsbi@12480000 { compatible = "qcom,gsbi-v1.0.0"; cell-index = <2>; -@@ -436,6 +1060,15 @@ - #power-domain-cells = <1>; - }; - -+ tsens: thermal-sensor@900000 { -+ compatible = "qcom,ipq8064-tsens"; -+ reg = <0x900000 0x3680>; -+ nvmem-cells = <&tsens_calib>, <&tsens_backup>; -+ nvmem-cell-names = "calib", "calib_backup"; -+ interrupts = ; -+ #thermal-sensor-cells = <1>; -+ }; -+ - tcsr: syscon@1a400000 { - compatible = "qcom,tcsr-ipq8064", "syscon"; - reg = <0x1a400000 0x100>; @@ -448,6 +1081,95 @@ #reset-cells = <1>; }; @@ -804,7 +680,7 @@ pcie0: pci@1b500000 { compatible = "qcom,pcie-ipq8064"; reg = <0x1b500000 0x1000 -@@ -601,6 +1323,167 @@ +@@ -601,6 +1323,59 @@ perst-gpio = <&qcom_pinmux 63 GPIO_ACTIVE_LOW>; }; @@ -847,22 +723,6 @@ + #size-cells = <0>; + }; + -+ nss_common: syscon@03000000 { -+ compatible = "syscon"; -+ reg = <0x03000000 0x0000FFFF>; -+ }; -+ -+ qsgmii_csr: syscon@1bb00000 { -+ compatible = "syscon"; -+ reg = <0x1bb00000 0x000001FF>; -+ }; -+ -+ stmmac_axi_setup: stmmac-axi-config { -+ snps,wr_osr_lmt = <7>; -+ snps,rd_osr_lmt = <7>; -+ snps,blen = <16 0 0 0 0 0 0>; -+ }; -+ + mdio0: mdio@37000000 { + #address-cells = <1>; + #size-cells = <0>; @@ -876,98 +736,6 @@ + + status = "disabled"; + }; -+ -+ gmac0: ethernet@37000000 { -+ device_type = "network"; -+ compatible = "qcom,ipq806x-gmac"; -+ reg = <0x37000000 0x200000>; -+ interrupts = ; -+ interrupt-names = "macirq"; -+ -+ snps,axi-config = <&stmmac_axi_setup>; -+ snps,pbl = <32>; -+ snps,aal = <1>; -+ -+ qcom,nss-common = <&nss_common>; -+ qcom,qsgmii-csr = <&qsgmii_csr>; -+ -+ clocks = <&gcc GMAC_CORE1_CLK>; -+ clock-names = "stmmaceth"; -+ -+ resets = <&gcc GMAC_CORE1_RESET>; -+ reset-names = "stmmaceth"; -+ -+ status = "disabled"; -+ }; -+ -+ gmac1: ethernet@37200000 { -+ device_type = "network"; -+ compatible = "qcom,ipq806x-gmac"; -+ reg = <0x37200000 0x200000>; -+ interrupts = ; -+ interrupt-names = "macirq"; -+ -+ snps,axi-config = <&stmmac_axi_setup>; -+ snps,pbl = <32>; -+ snps,aal = <1>; -+ -+ qcom,nss-common = <&nss_common>; -+ qcom,qsgmii-csr = <&qsgmii_csr>; -+ -+ clocks = <&gcc GMAC_CORE2_CLK>; -+ clock-names = "stmmaceth"; -+ -+ resets = <&gcc GMAC_CORE2_RESET>; -+ reset-names = "stmmaceth"; -+ -+ status = "disabled"; -+ }; -+ -+ gmac2: ethernet@37400000 { -+ device_type = "network"; -+ compatible = "qcom,ipq806x-gmac", "snps,dwmac"; -+ reg = <0x37400000 0x200000>; -+ interrupts = ; -+ interrupt-names = "macirq"; -+ -+ snps,axi-config = <&stmmac_axi_setup>; -+ snps,pbl = <32>; -+ snps,aal = <1>; -+ -+ qcom,nss-common = <&nss_common>; -+ qcom,qsgmii-csr = <&qsgmii_csr>; -+ -+ clocks = <&gcc GMAC_CORE3_CLK>; -+ clock-names = "stmmaceth"; -+ -+ resets = <&gcc GMAC_CORE3_RESET>; -+ reset-names = "stmmaceth"; -+ -+ status = "disabled"; -+ }; -+ -+ gmac3: ethernet@37600000 { -+ device_type = "network"; -+ compatible = "qcom,ipq806x-gmac", "snps,dwmac"; -+ reg = <0x37600000 0x200000>; -+ interrupts = ; -+ interrupt-names = "macirq"; -+ -+ snps,axi-config = <&stmmac_axi_setup>; -+ snps,pbl = <32>; -+ snps,aal = <1>; -+ -+ qcom,nss-common = <&nss_common>; -+ qcom,qsgmii-csr = <&qsgmii_csr>; -+ -+ clocks = <&gcc GMAC_CORE4_CLK>; -+ clock-names = "stmmaceth"; -+ -+ resets = <&gcc GMAC_CORE4_RESET>; -+ reset-names = "stmmaceth"; -+ -+ status = "disabled"; -+ }; + vsdcc_fixed: vsdcc-regulator { compatible = "regulator-fixed"; diff --git a/target/linux/ipq806x/patches-5.10/086-ipq8064-fix-duplicate-node.patch b/target/linux/ipq806x/patches-5.10/086-ipq8064-fix-duplicate-node.patch new file mode 100644 index 0000000000..85ad64ced0 --- /dev/null +++ b/target/linux/ipq806x/patches-5.10/086-ipq8064-fix-duplicate-node.patch @@ -0,0 +1,147 @@ +diff --git a/qcom-ipq8064-rb3011.dts.orig b/qcom-ipq8064-rb3011.dts +index 282b89ce3d..4faaa95b33 100644 +--- a/arch/arm/boot/dts/qcom-ipq8064-rb3011.dts ++++ b/arch/arm/boot/dts/qcom-ipq8064-rb3011.dts +@@ -24,73 +24,6 @@ memory@0 { + device_type = "memory"; + }; + +- mdio0: mdio@0 { +- status = "okay"; +- compatible = "virtual,mdio-gpio"; +- gpios = <&qcom_pinmux 1 GPIO_ACTIVE_HIGH>, +- <&qcom_pinmux 0 GPIO_ACTIVE_HIGH>; +- #address-cells = <1>; +- #size-cells = <0>; +- +- pinctrl-0 = <&mdio0_pins>; +- pinctrl-names = "default"; +- +- switch0: switch@10 { +- compatible = "qca,qca8337"; +- #address-cells = <1>; +- #size-cells = <0>; +- +- dsa,member = <0 0>; +- +- pinctrl-0 = <&sw0_reset_pin>; +- pinctrl-names = "default"; +- +- reset-gpios = <&qcom_pinmux 16 GPIO_ACTIVE_LOW>; +- reg = <0x10>; +- +- ports { +- #address-cells = <1>; +- #size-cells = <0>; +- +- switch0cpu: port@0 { +- reg = <0>; +- label = "cpu"; +- ethernet = <&gmac0>; +- phy-mode = "rgmii-id"; +- fixed-link { +- speed = <1000>; +- full-duplex; +- }; +- }; +- +- port@1 { +- reg = <1>; +- label = "sw1"; +- }; +- +- port@2 { +- reg = <2>; +- label = "sw2"; +- }; +- +- port@3 { +- reg = <3>; +- label = "sw3"; +- }; +- +- port@4 { +- reg = <4>; +- label = "sw4"; +- }; +- +- port@5 { +- reg = <5>; +- label = "sw5"; +- }; +- }; +- }; +- }; +- + mdio1: mdio@1 { + status = "okay"; + compatible = "virtual,mdio-gpio"; +@@ -216,6 +149,68 @@ led@7 { + }; + }; + ++&mdio0 { ++ status = "okay"; ++ ++ pinctrl-0 = <&mdio0_pins>; ++ pinctrl-names = "default"; ++ ++ switch0: switch@10 { ++ compatible = "qca,qca8337"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ dsa,member = <0 0>; ++ ++ pinctrl-0 = <&sw0_reset_pin>; ++ pinctrl-names = "default"; ++ ++ reset-gpios = <&qcom_pinmux 16 GPIO_ACTIVE_LOW>; ++ reg = <0x10>; ++ ++ ports { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ switch0cpu: port@0 { ++ reg = <0>; ++ label = "cpu"; ++ ethernet = <&gmac0>; ++ phy-mode = "rgmii-id"; ++ fixed-link { ++ speed = <1000>; ++ full-duplex; ++ }; ++ }; ++ ++ port@1 { ++ reg = <1>; ++ label = "sw1"; ++ }; ++ ++ port@2 { ++ reg = <2>; ++ label = "sw2"; ++ }; ++ ++ port@3 { ++ reg = <3>; ++ label = "sw3"; ++ }; ++ ++ port@4 { ++ reg = <4>; ++ label = "sw4"; ++ }; ++ ++ port@5 { ++ reg = <5>; ++ label = "sw5"; ++ }; ++ }; ++ }; ++}; ++ + &gmac0 { + status = "okay"; + From 9e843a9b8afca150b80a5e64f9450a3edb9d3246 Mon Sep 17 00:00:00 2001 From: Ansuel Smith Date: Mon, 1 Mar 2021 02:04:11 +0100 Subject: [PATCH 24/62] ipq806x: refresh config 5.10 Refresh config for kernel 5.10. - Added new symbol. - Refreshed with make kernel_oldconfig Signed-off-by: Ansuel Smith --- target/linux/ipq806x/config-5.10 | 134 +++++++++++++------------------ 1 file changed, 58 insertions(+), 76 deletions(-) diff --git a/target/linux/ipq806x/config-5.10 b/target/linux/ipq806x/config-5.10 index e6160bd455..6b8a418d36 100644 --- a/target/linux/ipq806x/config-5.10 +++ b/target/linux/ipq806x/config-5.10 @@ -3,24 +3,8 @@ CONFIG_ALIGNMENT_TRAP=y # CONFIG_APQ_MMCC_8084 is not set CONFIG_AR8216_PHY=y CONFIG_ARCH_32BIT_OFF_T=y -CONFIG_ARCH_CLOCKSOURCE_DATA=y -CONFIG_ARCH_HAS_BINFMT_FLAT=y -CONFIG_ARCH_HAS_DEBUG_VIRTUAL=y -CONFIG_ARCH_HAS_ELF_RANDOMIZE=y -CONFIG_ARCH_HAS_FORTIFY_SOURCE=y -CONFIG_ARCH_HAS_GCOV_PROFILE_ALL=y -CONFIG_ARCH_HAS_KCOV=y -CONFIG_ARCH_HAS_KEEPINITRD=y -CONFIG_ARCH_HAS_MEMBARRIER_SYNC_CORE=y -CONFIG_ARCH_HAS_PHYS_TO_DMA=y -CONFIG_ARCH_HAS_SETUP_DMA_OPS=y -CONFIG_ARCH_HAS_SET_MEMORY=y -CONFIG_ARCH_HAS_STRICT_KERNEL_RWX=y -CONFIG_ARCH_HAS_STRICT_MODULE_RWX=y -CONFIG_ARCH_HAS_TEARDOWN_DMA_OPS=y -CONFIG_ARCH_HAS_TICK_BROADCAST=y -CONFIG_ARCH_HAVE_CUSTOM_GPIO_H=y CONFIG_ARCH_HIBERNATION_POSSIBLE=y +# CONFIG_ARCH_IPQ40XX is not set CONFIG_ARCH_KEEP_MEMBLOCK=y # CONFIG_ARCH_MDM9615 is not set CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y @@ -34,15 +18,9 @@ CONFIG_ARCH_NR_GPIO=0 CONFIG_ARCH_OPTIONAL_KERNEL_RWX=y CONFIG_ARCH_OPTIONAL_KERNEL_RWX_DEFAULT=y CONFIG_ARCH_QCOM=y -CONFIG_ARCH_SUPPORTS_ATOMIC_RMW=y -CONFIG_ARCH_SUPPORTS_BIG_ENDIAN=y -CONFIG_ARCH_SUPPORTS_UPROBES=y +CONFIG_ARCH_SELECT_MEMORY_MODEL=y +CONFIG_ARCH_SPARSEMEM_ENABLE=y CONFIG_ARCH_SUSPEND_POSSIBLE=y -CONFIG_ARCH_USE_BUILTIN_BSWAP=y -CONFIG_ARCH_USE_CMPXCHG_LOCKREF=y -CONFIG_ARCH_WANT_DEFAULT_TOPDOWN_MMAP_LAYOUT=y -CONFIG_ARCH_WANT_GENERAL_HUGETLB=y -CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y CONFIG_ARM=y CONFIG_ARM_AMBA=y CONFIG_ARM_APPENDED_DTB=y @@ -62,8 +40,9 @@ CONFIG_ARM_MODULE_PLTS=y CONFIG_ARM_PATCH_IDIV=y CONFIG_ARM_PATCH_PHYS_VIRT=y # CONFIG_ARM_QCOM_CPUFREQ_HW is not set +CONFIG_ARM_QCOM_CPUFREQ_KRAIT=y CONFIG_ARM_QCOM_CPUFREQ_NVMEM=y -CONFIG_ARM_QCOM_CPUIDLE=y +CONFIG_ARM_QCOM_SPM_CPUIDLE=y # CONFIG_ARM_SMMU is not set CONFIG_ARM_THUMB=y CONFIG_ARM_UNWIND=y @@ -74,7 +53,6 @@ CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_MQ_PCI=y CONFIG_BOUNCE=y # CONFIG_CACHE_L2X0 is not set -CONFIG_CC_HAS_KASAN_GENERIC=y CONFIG_CLKDEV_LOOKUP=y CONFIG_CLKSRC_QCOM=y CONFIG_CLONE_BACKWARDS=y @@ -146,9 +124,16 @@ CONFIG_CRYPTO_ZSTD=y CONFIG_DCACHE_WORD_ACCESS=y CONFIG_DEBUG_GPIO=y CONFIG_DEBUG_LL_INCLUDE="mach/debug-macro.S" +# CONFIG_DEVFREQ_GOV_PASSIVE is not set +# CONFIG_DEVFREQ_GOV_PERFORMANCE is not set +# CONFIG_DEVFREQ_GOV_POWERSAVE is not set +# CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND is not set +# CONFIG_DEVFREQ_GOV_USERSPACE is not set +# CONFIG_DEVFREQ_THERMAL is not set CONFIG_DMADEVICES=y CONFIG_DMA_ENGINE=y CONFIG_DMA_OF=y +CONFIG_DMA_OPS=y CONFIG_DMA_REMAP=y CONFIG_DMA_VIRTUAL_CHANNELS=y CONFIG_DTC=y @@ -159,7 +144,6 @@ CONFIG_DWMAC_IPQ806X=y CONFIG_DYNAMIC_DEBUG=y CONFIG_EDAC_ATOMIC_SCRUB=y CONFIG_EDAC_SUPPORT=y -CONFIG_ETHERNET_PACKET_MANGLE=y CONFIG_FIXED_PHY=y CONFIG_FIX_EARLYCON_MEM=y CONFIG_FW_LOADER_PAGED_BUF=y @@ -169,6 +153,7 @@ CONFIG_GENERIC_CLOCKEVENTS=y CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y CONFIG_GENERIC_CPU_AUTOPROBE=y CONFIG_GENERIC_EARLY_IOREMAP=y +CONFIG_GENERIC_GETTIMEOFDAY=y CONFIG_GENERIC_IDLE_POLL_SETUP=y CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK=y CONFIG_GENERIC_IRQ_MULTI_HANDLER=y @@ -186,6 +171,7 @@ CONFIG_GENERIC_SMP_IDLE_THREAD=y CONFIG_GENERIC_STRNCPY_FROM_USER=y CONFIG_GENERIC_STRNLEN_USER=y CONFIG_GENERIC_TIME_VSYSCALL=y +CONFIG_GENERIC_VDSO_32=y CONFIG_GPIOLIB=y CONFIG_GPIOLIB_IRQCHIP=y CONFIG_GRO_CELLS=y @@ -195,48 +181,7 @@ CONFIG_HARDIRQS_SW_RESEND=y CONFIG_HAS_DMA=y CONFIG_HAS_IOMEM=y CONFIG_HAS_IOPORT_MAP=y -CONFIG_HAVE_ARCH_AUDITSYSCALL=y -CONFIG_HAVE_ARCH_BITREVERSE=y -CONFIG_HAVE_ARCH_JUMP_LABEL=y -CONFIG_HAVE_ARCH_KGDB=y -CONFIG_HAVE_ARCH_PFN_VALID=y -CONFIG_HAVE_ARCH_SECCOMP_FILTER=y -CONFIG_HAVE_ARCH_THREAD_STRUCT_WHITELIST=y -CONFIG_HAVE_ARCH_TRACEHOOK=y -CONFIG_HAVE_ARM_ARCH_TIMER=y -CONFIG_HAVE_ARM_SMCCC=y -CONFIG_HAVE_CLK=y -CONFIG_HAVE_CLK_PREPARE=y -CONFIG_HAVE_CONTEXT_TRACKING=y -CONFIG_HAVE_COPY_THREAD_TLS=y -CONFIG_HAVE_C_RECORDMCOUNT=y -CONFIG_HAVE_DEBUG_KMEMLEAK=y -CONFIG_HAVE_DMA_CONTIGUOUS=y -CONFIG_HAVE_DYNAMIC_FTRACE=y -CONFIG_HAVE_DYNAMIC_FTRACE_WITH_REGS=y -CONFIG_HAVE_EBPF_JIT=y -CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y -CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y -CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y -CONFIG_HAVE_FUNCTION_TRACER=y -CONFIG_HAVE_IDE=y -CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y -CONFIG_HAVE_LD_DEAD_CODE_DATA_ELIMINATION=y -CONFIG_HAVE_MOD_ARCH_SPECIFIC=y -CONFIG_HAVE_NET_DSA=y -CONFIG_HAVE_OPROFILE=y -CONFIG_HAVE_OPTPROBES=y -CONFIG_HAVE_PCI=y -CONFIG_HAVE_PERF_EVENTS=y -CONFIG_HAVE_PERF_REGS=y -CONFIG_HAVE_PERF_USER_STACK_DUMP=y -CONFIG_HAVE_PROC_CPU=y -CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y -CONFIG_HAVE_RSEQ=y CONFIG_HAVE_SMP=y -CONFIG_HAVE_SYSCALL_TRACEPOINTS=y -CONFIG_HAVE_UID16=y -CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y CONFIG_HIGHMEM=y # CONFIG_HIGHPTE is not set CONFIG_HWMON=y @@ -250,27 +195,31 @@ CONFIG_I2C=y CONFIG_I2C_BOARDINFO=y CONFIG_I2C_CHARDEV=y CONFIG_I2C_HELPER_AUTO=y +# CONFIG_I2C_QCOM_CCI is not set CONFIG_I2C_QUP=y CONFIG_INITRAMFS_SOURCE="" # CONFIG_IOMMU_DEBUGFS is not set # CONFIG_IOMMU_IO_PGTABLE_ARMV7S is not set # CONFIG_IOMMU_IO_PGTABLE_LPAE is not set CONFIG_IOMMU_SUPPORT=y +# CONFIG_IPQ_APSS_PLL is not set # CONFIG_IPQ_GCC_4019 is not set +# CONFIG_IPQ_GCC_6018 is not set CONFIG_IPQ_GCC_806X=y # CONFIG_IPQ_GCC_8074 is not set # CONFIG_IPQ_LCC_806X is not set CONFIG_IRQCHIP=y CONFIG_IRQ_DOMAIN=y CONFIG_IRQ_DOMAIN_HIERARCHY=y +CONFIG_IRQ_FASTEOI_HIERARCHY_HANDLERS=y CONFIG_IRQ_FORCED_THREADING=y CONFIG_IRQ_WORK=y CONFIG_KPSS_XCC=y CONFIG_KRAITCC=y CONFIG_KRAIT_CLOCKS=y CONFIG_KRAIT_L2_ACCESSORS=y -CONFIG_LEDS_TRIGGER_DISK=y CONFIG_LIBFDT=y +CONFIG_LLD_VERSION=0 CONFIG_LOCK_DEBUGGING_SUPPORT=y CONFIG_LOCK_SPIN_ON_OWNER=y CONFIG_LZO_COMPRESS=y @@ -283,6 +232,7 @@ CONFIG_MDIO_IPQ8064=y # CONFIG_MDM_GCC_9615 is not set # CONFIG_MDM_LCC_9615 is not set CONFIG_MEMFD_CREATE=y +# CONFIG_MFD_HI6421_SPMI is not set CONFIG_MFD_QCOM_RPM=y # CONFIG_MFD_SPMI_PMIC is not set CONFIG_MFD_SYSCON=y @@ -292,6 +242,7 @@ CONFIG_MMC=y CONFIG_MMC_ARMMMCI=y CONFIG_MMC_BLOCK=y CONFIG_MMC_BLOCK_MINORS=16 +CONFIG_MMC_CQHCI=y CONFIG_MMC_QCOM_DML=y CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_IO_ACCESSORS=y @@ -302,21 +253,25 @@ CONFIG_MMC_SDHCI_PLTFM=y CONFIG_MODULES_USE_ELF_REL=y CONFIG_MSM_GCC_8660=y # CONFIG_MSM_GCC_8916 is not set +# CONFIG_MSM_GCC_8939 is not set # CONFIG_MSM_GCC_8960 is not set # CONFIG_MSM_GCC_8974 is not set # CONFIG_MSM_GCC_8994 is not set # CONFIG_MSM_GCC_8996 is not set # CONFIG_MSM_GCC_8998 is not set +# CONFIG_MSM_GPUCC_8998 is not set # CONFIG_MSM_IOMMU is not set # CONFIG_MSM_LCC_8960 is not set # CONFIG_MSM_MMCC_8960 is not set # CONFIG_MSM_MMCC_8974 is not set # CONFIG_MSM_MMCC_8996 is not set +# CONFIG_MSM_MMCC_8998 is not set CONFIG_MTD_CMDLINE_PARTS=y CONFIG_MTD_NAND_CORE=y +CONFIG_MTD_NAND_ECC=y CONFIG_MTD_NAND_ECC_SW_HAMMING=y CONFIG_MTD_NAND_QCOM=y -CONFIG_MTD_QCOM_SMEM_PARTS=y +CONFIG_MTD_QCOMSMEM_PARTS=y CONFIG_MTD_RAW_NAND=y CONFIG_MTD_SPI_NOR=y CONFIG_MTD_SPLIT_FIRMWARE=y @@ -342,6 +297,7 @@ CONFIG_NO_HZ_COMMON=y CONFIG_NO_HZ_IDLE=y CONFIG_NR_CPUS=2 CONFIG_NVMEM=y +# CONFIG_NVMEM_SPMI_SDAM is not set CONFIG_OF=y CONFIG_OF_ADDRESS=y CONFIG_OF_EARLY_FLATTREE=y @@ -368,27 +324,35 @@ CONFIG_PCI_DOMAINS=y CONFIG_PCI_DOMAINS_GENERIC=y CONFIG_PCI_MSI=y CONFIG_PCI_MSI_IRQ_DOMAIN=y +CONFIG_PCS_XPCS=y CONFIG_PERF_USE_VMALLOC=y CONFIG_PGTABLE_LEVELS=2 CONFIG_PHYLIB=y CONFIG_PHYLINK=y # CONFIG_PHY_QCOM_APQ8064_SATA is not set +# CONFIG_PHY_QCOM_IPQ4019_USB is not set CONFIG_PHY_QCOM_IPQ806X_SATA=y +# CONFIG_PHY_QCOM_IPQ806X_USB is not set # CONFIG_PHY_QCOM_PCIE2 is not set # CONFIG_PHY_QCOM_QMP is not set # CONFIG_PHY_QCOM_QUSB2 is not set -# CONFIG_PHY_QCOM_UFS is not set +# CONFIG_PHY_QCOM_USB_HS_28NM is not set +# CONFIG_PHY_QCOM_USB_SNPS_FEMTO_V2 is not set +# CONFIG_PHY_QCOM_USB_SS is not set CONFIG_PINCTRL=y # CONFIG_PINCTRL_APQ8064 is not set # CONFIG_PINCTRL_APQ8084 is not set # CONFIG_PINCTRL_IPQ4019 is not set +# CONFIG_PINCTRL_IPQ6018 is not set CONFIG_PINCTRL_IPQ8064=y # CONFIG_PINCTRL_IPQ8074 is not set # CONFIG_PINCTRL_MDM9615 is not set CONFIG_PINCTRL_MSM=y +# CONFIG_PINCTRL_MSM8226 is not set # CONFIG_PINCTRL_MSM8660 is not set # CONFIG_PINCTRL_MSM8916 is not set # CONFIG_PINCTRL_MSM8960 is not set +# CONFIG_PINCTRL_MSM8976 is not set # CONFIG_PINCTRL_MSM8994 is not set # CONFIG_PINCTRL_MSM8996 is not set # CONFIG_PINCTRL_MSM8998 is not set @@ -399,6 +363,9 @@ CONFIG_PINCTRL_MSM=y # CONFIG_PINCTRL_SDM660 is not set # CONFIG_PINCTRL_SDM845 is not set # CONFIG_PINCTRL_SM8150 is not set +# CONFIG_PINCTRL_SM8250 is not set +CONFIG_PM_DEVFREQ=y +# CONFIG_PM_DEVFREQ_EVENT is not set CONFIG_PM_OPP=y CONFIG_POWER_RESET=y CONFIG_POWER_RESET_MSM=y @@ -411,19 +378,20 @@ CONFIG_QCOM_ADM=y CONFIG_QCOM_BAM_DMA=y CONFIG_QCOM_CLK_RPM=y # CONFIG_QCOM_COMMAND_DB is not set +# CONFIG_QCOM_CPR is not set # CONFIG_QCOM_EBI2 is not set # CONFIG_QCOM_GENI_SE is not set CONFIG_QCOM_GSBI=y CONFIG_QCOM_HFPLL=y # CONFIG_QCOM_IOMMU is not set # CONFIG_QCOM_LLCC is not set +# CONFIG_QCOM_OCMEM is not set # CONFIG_QCOM_PDC is not set -CONFIG_QCOM_PM=y CONFIG_QCOM_QFPROM=y # CONFIG_QCOM_RMTFS_MEM is not set CONFIG_QCOM_RPMCC=y +# CONFIG_QCOM_RPMH is not set CONFIG_QCOM_SCM=y -CONFIG_QCOM_SCM_32=y # CONFIG_QCOM_SCM_DOWNLOAD_MODE_DEFAULT is not set CONFIG_QCOM_SMEM=y # CONFIG_QCOM_SMSM is not set @@ -432,20 +400,22 @@ CONFIG_QCOM_TCSR=y CONFIG_QCOM_TSENS=y CONFIG_QCOM_WDT=y # CONFIG_QCS_GCC_404 is not set +# CONFIG_QCS_Q6SSTOP_404 is not set # CONFIG_QCS_TURING_404 is not set -# CONFIG_QRTR is not set CONFIG_RAS=y CONFIG_RATIONAL=y CONFIG_RCU_CPU_STALL_TIMEOUT=21 CONFIG_RCU_NEED_SEGCBLIST=y CONFIG_RCU_STALL_COMMON=y -CONFIG_REFCOUNT_FULL=y CONFIG_REGMAP=y CONFIG_REGMAP_MMIO=y CONFIG_REGULATOR=y CONFIG_REGULATOR_FIXED_VOLTAGE=y +# CONFIG_REGULATOR_QCOM_LABIBB is not set CONFIG_REGULATOR_QCOM_RPM=y # CONFIG_REGULATOR_QCOM_SPMI is not set +# CONFIG_REGULATOR_QCOM_USB_VBUS is not set +# CONFIG_REGULATOR_VQMMC_IPQ4019 is not set CONFIG_RESET_CONTROLLER=y # CONFIG_RESET_QCOM_AOSS is not set # CONFIG_RESET_QCOM_PDC is not set @@ -455,6 +425,12 @@ CONFIG_RTC_CLASS=y CONFIG_RTC_I2C_AND_SPI=y CONFIG_RTC_MC146818_LIB=y CONFIG_RWSEM_SPIN_ON_OWNER=y +# CONFIG_SC_DISPCC_7180 is not set +# CONFIG_SC_GCC_7180 is not set +# CONFIG_SC_GPUCC_7180 is not set +# CONFIG_SC_LPASS_CORECC_7180 is not set +# CONFIG_SC_MSS_7180 is not set +# CONFIG_SC_VIDEOCC_7180 is not set # CONFIG_SDM_CAMCC_845 is not set # CONFIG_SDM_DISPCC_845 is not set # CONFIG_SDM_GCC_660 is not set @@ -470,12 +446,18 @@ CONFIG_SGL_ALLOC=y CONFIG_SMP=y CONFIG_SMP_ON_UP=y # CONFIG_SM_GCC_8150 is not set +# CONFIG_SM_GCC_8250 is not set +# CONFIG_SM_GPUCC_8150 is not set +# CONFIG_SM_GPUCC_8250 is not set +# CONFIG_SM_VIDEOCC_8150 is not set +# CONFIG_SM_VIDEOCC_8250 is not set CONFIG_SPARSE_IRQ=y CONFIG_SPI=y CONFIG_SPI_MASTER=y CONFIG_SPI_MEM=y CONFIG_SPI_QUP=y CONFIG_SPMI=y +# CONFIG_SPMI_HISI3670 is not set CONFIG_SPMI_MSM_PMIC_ARB=y # CONFIG_SPMI_PMIC_CLKDIV is not set CONFIG_SRCU=y From 85adcec3baf4a3eac9dd1464ed7f06967f3c2c9d Mon Sep 17 00:00:00 2001 From: Ansuel Smith Date: Mon, 1 Mar 2021 01:22:54 +0100 Subject: [PATCH 25/62] ipq806x: add kernel 5.10 as testing kernel Add kernel 5.10 as testing kernel Signed-off-by: Ansuel Smith --- target/linux/ipq806x/Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/target/linux/ipq806x/Makefile b/target/linux/ipq806x/Makefile index 69d3aa1e56..c3407217d6 100644 --- a/target/linux/ipq806x/Makefile +++ b/target/linux/ipq806x/Makefile @@ -11,6 +11,7 @@ CPU_SUBTYPE:=neon-vfpv4 SUBTARGETS:=generic KERNEL_PATCHVER:=5.4 +KERNEL_TESTING_PATCHVER:=5.10 KERNELNAME:=zImage Image dtbs From e3daef34a02c199d2b59f972c0811eb9716bd21f Mon Sep 17 00:00:00 2001 From: Ansuel Smith Date: Thu, 4 Mar 2021 00:52:45 +0100 Subject: [PATCH 26/62] ipq806x: set boot layout for nandc compatible Set boot layout size to fix io error on block scan. Signed-off-by: Ansuel Smith --- .../ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-d7800.dts | 3 +++ .../ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-eax500.dtsi | 3 +++ .../ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-r7500.dts | 3 +++ .../ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-r7500v2.dts | 3 +++ .../ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-wpq864.dts | 3 +++ .../ipq806x/files/arch/arm/boot/dts/qcom-ipq8065-r7800.dts | 3 +++ 6 files changed, 18 insertions(+) diff --git a/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-d7800.dts b/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-d7800.dts index 229596b082..aeeb040ad8 100644 --- a/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-d7800.dts +++ b/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-d7800.dts @@ -196,6 +196,9 @@ nand-bus-width = <8>; nand-ecc-step-size = <512>; + nand-is-boot-medium; + qcom,boot_pages_size = <0x1180000>; + partitions { compatible = "fixed-partitions"; #address-cells = <1>; diff --git a/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-eax500.dtsi b/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-eax500.dtsi index 3e6732e9df..98c4b2d29d 100644 --- a/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-eax500.dtsi +++ b/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-eax500.dtsi @@ -48,6 +48,9 @@ nand-bus-width = <8>; nand-ecc-step-size = <512>; + nand-is-boot-medium; + qcom,boot_pages_size = <0x0c80000>; + partitions: partitions { compatible = "fixed-partitions"; #address-cells = <1>; diff --git a/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-r7500.dts b/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-r7500.dts index ed8ab3dbfa..1f457d9944 100644 --- a/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-r7500.dts +++ b/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-r7500.dts @@ -174,6 +174,9 @@ nand-bus-width = <8>; nand-ecc-step-size = <512>; + nand-is-boot-medium; + qcom,boot_pages_size = <0x1180000>; + partitions { compatible = "fixed-partitions"; #address-cells = <1>; diff --git a/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-r7500v2.dts b/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-r7500v2.dts index 20a1fad7b2..f190433277 100644 --- a/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-r7500v2.dts +++ b/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-r7500v2.dts @@ -204,6 +204,9 @@ nand-bus-width = <8>; nand-ecc-step-size = <512>; + nand-is-boot-medium; + qcom,boot_pages_size = <0x1180000>; + partitions { compatible = "fixed-partitions"; #address-cells = <1>; diff --git a/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-wpq864.dts b/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-wpq864.dts index ba3f51e446..69be60b019 100644 --- a/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-wpq864.dts +++ b/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-wpq864.dts @@ -116,6 +116,9 @@ nand-bus-width = <8>; nand-ecc-step-size = <512>; + nand-is-boot-medium; + qcom,boot_pages_size = <0x1180000>; + partitions { compatible = "fixed-partitions"; #address-cells = <1>; diff --git a/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8065-r7800.dts b/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8065-r7800.dts index 181f6d3bde..55291cd531 100644 --- a/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8065-r7800.dts +++ b/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8065-r7800.dts @@ -240,6 +240,9 @@ nand-bus-width = <8>; nand-ecc-step-size = <512>; + nand-is-boot-medium; + qcom,boot_pages_size = <0x1180000>; + partitions { compatible = "fixed-partitions"; #address-cells = <1>; From d079c8fa48995a64ce56c1d01cf008118e999a81 Mon Sep 17 00:00:00 2001 From: Ansuel Smith Date: Wed, 3 Mar 2021 11:46:52 +0100 Subject: [PATCH 27/62] ipq806x: simplify ecw5410 dts Simplify ecw5410 dts instead of redefine nodes. Signed-off-by: Ansuel Smith --- .../arm/boot/dts/qcom-ipq8068-ecw5410.dts | 46 +++++++++---------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8068-ecw5410.dts b/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8068-ecw5410.dts index 9b14bb2c29..1d159714db 100644 --- a/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8068-ecw5410.dts +++ b/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8068-ecw5410.dts @@ -258,40 +258,40 @@ }; }; -&soc { - nand@1ac00000 { - status = "okay"; +&nand_controller { + status = "okay"; - pinctrl-0 = <&nand_pins>; - pinctrl-names = "default"; + pinctrl-0 = <&nand_pins>; + pinctrl-names = "default"; - nand@0 { - compatible = "qcom,nandcs"; + nand@0 { + compatible = "qcom,nandcs"; - reg = <0>; + reg = <0>; - nand-ecc-strength = <4>; - nand-bus-width = <8>; - nand-ecc-step-size = <512>; + nand-ecc-strength = <4>; + nand-bus-width = <8>; + nand-ecc-step-size = <512>; - partitions { - compatible = "fixed-partitions"; - #address-cells = <1>; - #size-cells = <1>; + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; - rootfs1@0 { - label = "rootfs1"; - reg = <0x0000000 0x4000000>; - }; + rootfs1@0 { + label = "rootfs1"; + reg = <0x0000000 0x4000000>; + }; - rootfs2@4000000 { - label = "rootfs2"; - reg = <0x4000000 0x4000000>; - }; + rootfs2@4000000 { + label = "rootfs2"; + reg = <0x4000000 0x4000000>; }; }; }; +}; +&soc { mdio1: mdio { compatible = "virtual,mdio-gpio"; #address-cells = <1>; From db2c147cf47b12894aa0c6b49efcdd1eb199aed5 Mon Sep 17 00:00:00 2001 From: Ansuel Smith Date: Wed, 3 Mar 2021 23:01:37 +0100 Subject: [PATCH 28/62] ipq806x: refresh 5.10 patches make target/linux/kernel refresh Signed-off-by: Ansuel Smith --- ...arch-arm-force-ZRELADDR-on-arch-qcom.patch | 6 +-- .../0065-arm-override-compiler-flags.patch | 2 +- .../0069-arm-boot-add-dts-files.patch | 4 +- .../0072-add-ipq806x-with-no-clocks.patch | 2 +- .../082-ipq8064-dtsi-tweaks.patch | 29 +++++------- .../083-ipq8064-dtsi-additions.patch | 46 ++++++++----------- .../086-ipq8064-fix-duplicate-node.patch | 6 +-- ...qcom-cpufreq-nvmem-support-specific-.patch | 9 +--- ...7-1-ipq806x-gcc-add-missing-clk-flag.patch | 13 ++---- .../097-2-ipq806x-lcc-add-missing-reset.patch | 9 +--- ...com-krait-add-missing-enable-disable.patch | 7 +-- ...missing-clk-and-reset-for-crypto-eng.patch | 23 +++------- ...ufreq-add-qcom-krait-cpufreq-binding.patch | 6 --- ...add-fab-scaling-support-with-cpufreq.patch | 2 +- ...m_nandc-add-boot_layout_mode-support.patch | 46 ++++++++----------- ...vicetree-mtd-qcom_nandc-document-qco.patch | 9 +--- ...-v5.11-dmaengine-qcom-add_ADM_driver.patch | 10 ---- ....12-mtd-parsers-Add-Qcom-SMEM-parser.patch | 20 ++------ ...conflicts-with-OpenWrt-auto-mounting.patch | 2 +- ...e-IO_SPACE_LIMIT-needed-for-some-SoC.patch | 7 +-- .../850-soc-add-qualcomm-syscon.patch | 8 ++-- .../patches-5.10/851-add-gsbi1-dts.patch | 2 +- .../900-arm-add-cmdline-override.patch | 4 +- .../997-device_tree_cmdline.patch | 2 +- 24 files changed, 93 insertions(+), 181 deletions(-) diff --git a/target/linux/ipq806x/patches-5.10/0060-HACK-arch-arm-force-ZRELADDR-on-arch-qcom.patch b/target/linux/ipq806x/patches-5.10/0060-HACK-arch-arm-force-ZRELADDR-on-arch-qcom.patch index d3b39ac3e3..b56480deaa 100644 --- a/target/linux/ipq806x/patches-5.10/0060-HACK-arch-arm-force-ZRELADDR-on-arch-qcom.patch +++ b/target/linux/ipq806x/patches-5.10/0060-HACK-arch-arm-force-ZRELADDR-on-arch-qcom.patch @@ -33,8 +33,8 @@ Signed-off-by: Mathieu Olivari --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig -@@ -318,7 +318,7 @@ config ARCH_MULTIPLATFORM - depends on MMU +@@ -321,7 +321,7 @@ config ARCH_MULTIPLATFORM + select ARCH_SELECT_MEMORY_MODEL select ARM_HAS_SG_CHAIN select ARM_PATCH_PHYS_VIRT - select AUTO_ZRELADDR @@ -44,7 +44,7 @@ Signed-off-by: Mathieu Olivari select GENERIC_CLOCKEVENTS --- a/arch/arm/Makefile +++ b/arch/arm/Makefile -@@ -258,9 +258,11 @@ MACHINE := arch/arm/mach-$(word 1,$(mac +@@ -251,9 +251,11 @@ MACHINE := arch/arm/mach-$(word 1,$(mac else MACHINE := endif diff --git a/target/linux/ipq806x/patches-5.10/0065-arm-override-compiler-flags.patch b/target/linux/ipq806x/patches-5.10/0065-arm-override-compiler-flags.patch index 0d2a4274c7..5a970e87ac 100644 --- a/target/linux/ipq806x/patches-5.10/0065-arm-override-compiler-flags.patch +++ b/target/linux/ipq806x/patches-5.10/0065-arm-override-compiler-flags.patch @@ -10,7 +10,7 @@ Signed-off-by: John Crispin --- a/arch/arm/Makefile +++ b/arch/arm/Makefile -@@ -67,7 +67,7 @@ KBUILD_CFLAGS += $(call cc-option,-fno-i +@@ -61,7 +61,7 @@ KBUILD_CFLAGS += $(call cc-option,-fno-i # macro, but instead defines a whole series of macros which makes # testing for a specific architecture or later rather impossible. arch-$(CONFIG_CPU_32v7M) =-D__LINUX_ARM_ARCH__=7 -march=armv7-m -Wa,-march=armv7-m diff --git a/target/linux/ipq806x/patches-5.10/0069-arm-boot-add-dts-files.patch b/target/linux/ipq806x/patches-5.10/0069-arm-boot-add-dts-files.patch index b652102616..d5b1d4473b 100644 --- a/target/linux/ipq806x/patches-5.10/0069-arm-boot-add-dts-files.patch +++ b/target/linux/ipq806x/patches-5.10/0069-arm-boot-add-dts-files.patch @@ -10,10 +10,10 @@ Signed-off-by: John Crispin --- a/arch/arm/boot/dts/Makefile +++ b/arch/arm/boot/dts/Makefile -@@ -843,6 +843,20 @@ dtb-$(CONFIG_ARCH_QCOM) += \ +@@ -909,6 +909,20 @@ dtb-$(CONFIG_ARCH_QCOM) += \ qcom-ipq4019-ap.dk07.1-c2.dtb \ qcom-ipq8064-ap148.dtb \ - qcom-ipq8064-rb3011.dtb \ + qcom-ipq8064-rb3011.dtb \ + qcom-ipq8064-c2600.dtb \ + qcom-ipq8064-d7800.dtb \ + qcom-ipq8064-db149.dtb \ diff --git a/target/linux/ipq806x/patches-5.10/0072-add-ipq806x-with-no-clocks.patch b/target/linux/ipq806x/patches-5.10/0072-add-ipq806x-with-no-clocks.patch index b7cebd9d39..627c32724f 100644 --- a/target/linux/ipq806x/patches-5.10/0072-add-ipq806x-with-no-clocks.patch +++ b/target/linux/ipq806x/patches-5.10/0072-add-ipq806x-with-no-clocks.patch @@ -1,6 +1,6 @@ --- a/drivers/firmware/qcom_scm.c +++ b/drivers/firmware/qcom_scm.c -@@ -598,6 +598,7 @@ static const struct of_device_id qcom_sc +@@ -1265,6 +1265,7 @@ static const struct of_device_id qcom_sc SCM_HAS_BUS_CLK) }, { .compatible = "qcom,scm-ipq4019" }, diff --git a/target/linux/ipq806x/patches-5.10/082-ipq8064-dtsi-tweaks.patch b/target/linux/ipq806x/patches-5.10/082-ipq8064-dtsi-tweaks.patch index 9c16ee4351..b6e8e915eb 100644 --- a/target/linux/ipq806x/patches-5.10/082-ipq8064-dtsi-tweaks.patch +++ b/target/linux/ipq806x/patches-5.10/082-ipq8064-dtsi-tweaks.patch @@ -1,6 +1,6 @@ --- a/arch/arm/boot/dts/qcom-ipq8064.dtsi +++ b/arch/arm/boot/dts/qcom-ipq8064.dtsi -@@ -20,9 +20,9 @@ +@@ -20,7 +20,7 @@ #address-cells = <1>; #size-cells = <0>; @@ -9,9 +9,7 @@ compatible = "qcom,krait"; enable-method = "qcom,kpss-acc-v1"; device_type = "cpu"; - reg = <1>; - next-level-cache = <&L2>; -@@ -30,9 +30,9 @@ +@@ -30,7 +30,7 @@ qcom,saw = <&saw0>; }; @@ -20,8 +18,6 @@ compatible = "qcom,krait"; enable-method = "qcom,kpss-acc-v1"; device_type = "cpu"; - reg = <1>; - next-level-cache = <&L2>; @@ -67,7 +67,7 @@ no-map; }; @@ -39,7 +35,7 @@ #interrupt-cells = <2>; interrupts = ; -@@ -155,6 +155,7 @@ +@@ -155,6 +156,7 @@ function = "pcie3_rst"; drive-strength = <12>; bias-disable; @@ -47,7 +43,7 @@ }; }; -@@ -190,6 +190,7 @@ +@@ -190,6 +192,7 @@ intc: interrupt-controller@2000000 { compatible = "qcom,msm-qgic2"; interrupt-controller; @@ -55,7 +51,7 @@ #interrupt-cells = <3>; reg = <0x02000000 0x1000>, <0x02002000 0x1000>; -@@ -219,21 +220,23 @@ +@@ -219,21 +222,23 @@ acc0: clock-controller@2088000 { compatible = "qcom,kpss-acc-v1"; reg = <0x02088000 0x1000>, <0x02008000 0x1000>; @@ -81,7 +77,7 @@ reg = <0x02099000 0x1000>, <0x02009000 0x1000>; regulator; }; -@@ -251,7 +254,7 @@ +@@ -251,7 +256,7 @@ syscon-tcsr = <&tcsr>; @@ -90,7 +86,7 @@ compatible = "qcom,msm-uartdm-v1.3", "qcom,msm-uartdm"; reg = <0x12490000 0x1000>, <0x12480000 0x1000>; -@@ -326,7 +329,7 @@ +@@ -326,7 +331,7 @@ syscon-tcsr = <&tcsr>; @@ -99,7 +95,7 @@ compatible = "qcom,msm-uartdm-v1.3", "qcom,msm-uartdm"; reg = <0x1a240000 0x1000>, <0x1a200000 0x1000>; -@@ -397,7 +400,7 @@ +@@ -397,7 +402,7 @@ status = "disabled"; }; @@ -108,7 +104,7 @@ compatible = "qcom,ipq806x-ahci", "generic-ahci"; reg = <0x29000000 0x180>; -@@ -430,6 +430,16 @@ qfprom: qfprom@700000 { +@@ -430,13 +435,35 @@ reg = <0x00700000 0x1000>; #address-cells = <1>; #size-cells = <1>; @@ -124,9 +120,6 @@ + }; }; - gcc: clock-controller@900000 { -@@ -437,9 +447,21 @@ gcc: clock-controller@900000 { - gcc: clock-controller@900000 { - compatible = "qcom,gcc-ipq8064"; + compatible = "qcom,gcc-ipq8064", "syscon"; @@ -148,7 +141,7 @@ }; tcsr: syscon@1a400000 { -@@ -625,13 +629,13 @@ +@@ -740,13 +767,13 @@ qcom,ee = <0>; }; @@ -165,7 +158,7 @@ status = "disabled"; compatible = "arm,pl18x", "arm,primecell"; arm,primecell-periphid = <0x00051180>; -@@ -645,13 +649,12 @@ +@@ -760,13 +787,12 @@ non-removable; cap-sd-highspeed; cap-mmc-highspeed; diff --git a/target/linux/ipq806x/patches-5.10/083-ipq8064-dtsi-additions.patch b/target/linux/ipq806x/patches-5.10/083-ipq8064-dtsi-additions.patch index be4ccc8e12..140eeb54c7 100644 --- a/target/linux/ipq806x/patches-5.10/083-ipq8064-dtsi-additions.patch +++ b/target/linux/ipq806x/patches-5.10/083-ipq8064-dtsi-additions.patch @@ -26,16 +26,10 @@ }; cpu1: cpu@1 { -@@ -47,17 +47,350 @@ - enable-method = "qcom,kpss-acc-v1"; - device_type = "cpu"; - reg = <1>; -- next-level-cache = <&L2>; -- qcom,acc = <&acc1>; -- qcom,saw = <&saw1>; -+ next-level-cache = <&L2>; -+ qcom,acc = <&acc1>; -+ qcom,saw = <&saw1>; +@@ -38,14 +50,347 @@ + next-level-cache = <&L2>; + qcom,acc = <&acc1>; + qcom,saw = <&saw1>; + clocks = <&kraitcc 1>, <&kraitcc 4>; + clock-names = "cpu", "l2"; + clock-latency = <100000>; @@ -84,9 +78,9 @@ + opp-microvolt = <1150000>; + clock-latency-ns = <100000>; + opp-level = <2>; -+ }; -+ }; -+ + }; + }; + + opp_table0: opp_table0 { + compatible = "operating-points-v2-kryo-cpu"; + nvmem-cells = <&speedbin_efuse>; @@ -155,9 +149,9 @@ + opp-supported-hw = <0x1>; + clock-latency-ns = <100000>; + opp-level = <2>; - }; - }; - ++ }; ++ }; ++ + thermal-zones { + tsens_tz_sensor0 { + polling-delay-passive = <0>; @@ -383,7 +377,7 @@ memory { device_type = "memory"; reg = <0x0 0x0>; -@@ -93,6 +552,15 @@ +@@ -93,6 +438,15 @@ }; }; @@ -399,7 +393,7 @@ firmware { scm { compatible = "qcom,scm-ipq806x", "qcom,scm"; -@@ -120,6 +588,78 @@ +@@ -120,6 +474,78 @@ reg-names = "lpass-lpaif"; }; @@ -478,7 +472,7 @@ qcom_pinmux: pinmux@800000 { compatible = "qcom,ipq8064-pinctrl"; reg = <0x800000 0x4000>; -@@ -159,6 +705,15 @@ +@@ -160,6 +586,15 @@ }; }; @@ -494,7 +488,7 @@ spi_pins: spi_pins { mux { pins = "gpio18", "gpio19", "gpio21"; -@@ -168,6 +723,53 @@ +@@ -169,6 +604,53 @@ }; }; @@ -548,7 +542,7 @@ leds_pins: leds_pins { mux { pins = "gpio7", "gpio8", "gpio9", -@@ -229,6 +831,17 @@ +@@ -231,6 +713,17 @@ clock-output-names = "acpu1_aux"; }; @@ -566,7 +560,7 @@ saw0: regulator@2089000 { compatible = "qcom,saw2", "qcom,apq8064-saw2-v1.1-cpu", "syscon"; reg = <0x02089000 0x1000>, <0x02009000 0x1000>; -@@ -241,6 +854,17 @@ +@@ -243,6 +736,17 @@ regulator; }; @@ -584,7 +578,7 @@ gsbi2: gsbi@12480000 { compatible = "qcom,gsbi-v1.0.0"; cell-index = <2>; -@@ -448,6 +1081,95 @@ +@@ -478,6 +982,95 @@ #reset-cells = <1>; }; @@ -680,8 +674,8 @@ pcie0: pci@1b500000 { compatible = "qcom,pcie-ipq8064"; reg = <0x1b500000 0x1000 -@@ -601,6 +1323,59 @@ - perst-gpio = <&qcom_pinmux 63 GPIO_ACTIVE_LOW>; +@@ -739,6 +1332,59 @@ + status = "disabled"; }; + adm_dma: dma@18300000 { @@ -740,7 +734,7 @@ vsdcc_fixed: vsdcc-regulator { compatible = "regulator-fixed"; regulator-name = "SDCC Power"; -@@ -676,4 +1559,17 @@ +@@ -814,4 +1460,17 @@ }; }; }; diff --git a/target/linux/ipq806x/patches-5.10/086-ipq8064-fix-duplicate-node.patch b/target/linux/ipq806x/patches-5.10/086-ipq8064-fix-duplicate-node.patch index 85ad64ced0..8423fd137f 100644 --- a/target/linux/ipq806x/patches-5.10/086-ipq8064-fix-duplicate-node.patch +++ b/target/linux/ipq806x/patches-5.10/086-ipq8064-fix-duplicate-node.patch @@ -1,8 +1,6 @@ -diff --git a/qcom-ipq8064-rb3011.dts.orig b/qcom-ipq8064-rb3011.dts -index 282b89ce3d..4faaa95b33 100644 --- a/arch/arm/boot/dts/qcom-ipq8064-rb3011.dts +++ b/arch/arm/boot/dts/qcom-ipq8064-rb3011.dts -@@ -24,73 +24,6 @@ memory@0 { +@@ -24,73 +24,6 @@ device_type = "memory"; }; @@ -76,7 +74,7 @@ index 282b89ce3d..4faaa95b33 100644 mdio1: mdio@1 { status = "okay"; compatible = "virtual,mdio-gpio"; -@@ -216,6 +149,68 @@ led@7 { +@@ -216,6 +149,68 @@ }; }; diff --git a/target/linux/ipq806x/patches-5.10/093-drivers-cpufreq-qcom-cpufreq-nvmem-support-specific-.patch b/target/linux/ipq806x/patches-5.10/093-drivers-cpufreq-qcom-cpufreq-nvmem-support-specific-.patch index afc9287118..19c3d096c4 100644 --- a/target/linux/ipq806x/patches-5.10/093-drivers-cpufreq-qcom-cpufreq-nvmem-support-specific-.patch +++ b/target/linux/ipq806x/patches-5.10/093-drivers-cpufreq-qcom-cpufreq-nvmem-support-specific-.patch @@ -11,8 +11,6 @@ Signed-off-by: Ansuel Smith drivers/cpufreq/qcom-cpufreq-nvmem.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) -diff --git a/drivers/cpufreq/qcom-cpufreq-nvmem.c b/drivers/cpufreq/qcom-cpufreq-nvmem.c -index d1744b5d9619..4866c74ead0f 100644 --- a/drivers/cpufreq/qcom-cpufreq-nvmem.c +++ b/drivers/cpufreq/qcom-cpufreq-nvmem.c @@ -52,6 +52,7 @@ struct qcom_cpufreq_match_data { @@ -23,7 +21,7 @@ index d1744b5d9619..4866c74ead0f 100644 }; struct qcom_cpufreq_drv { -@@ -250,6 +251,7 @@ static const struct qcom_cpufreq_match_data match_data_kryo = { +@@ -250,6 +251,7 @@ static const struct qcom_cpufreq_match_d static const struct qcom_cpufreq_match_data match_data_krait = { .get_version = qcom_cpufreq_krait_name_version, @@ -31,7 +29,7 @@ index d1744b5d9619..4866c74ead0f 100644 }; static const char *qcs404_genpd_names[] = { "cpr", NULL }; -@@ -385,6 +387,19 @@ static int qcom_cpufreq_probe(struct platform_device *pdev) +@@ -385,6 +387,19 @@ static int qcom_cpufreq_probe(struct pla } } @@ -51,6 +49,3 @@ index d1744b5d9619..4866c74ead0f 100644 cpufreq_dt_pdev = platform_device_register_simple("cpufreq-dt", -1, NULL, 0); if (!IS_ERR(cpufreq_dt_pdev)) { --- -2.29.2 - diff --git a/target/linux/ipq806x/patches-5.10/097-1-ipq806x-gcc-add-missing-clk-flag.patch b/target/linux/ipq806x/patches-5.10/097-1-ipq806x-gcc-add-missing-clk-flag.patch index a09453e142..3067ec777a 100644 --- a/target/linux/ipq806x/patches-5.10/097-1-ipq806x-gcc-add-missing-clk-flag.patch +++ b/target/linux/ipq806x/patches-5.10/097-1-ipq806x-gcc-add-missing-clk-flag.patch @@ -15,8 +15,6 @@ Signed-off-by: Ansuel Smith drivers/clk/qcom/gcc-ipq806x.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) -diff --git a/drivers/clk/qcom/gcc-ipq806x.c b/drivers/clk/qcom/gcc-ipq806x.c -index d6b7adb4be38..fbb8644c4a43 100644 --- a/drivers/clk/qcom/gcc-ipq806x.c +++ b/drivers/clk/qcom/gcc-ipq806x.c @@ -65,6 +65,7 @@ static struct clk_pll pll3 = { @@ -36,7 +34,7 @@ index d6b7adb4be38..fbb8644c4a43 100644 }, }, }; -@@ -798,7 +799,7 @@ static struct clk_branch gsbi4_qup_clk = { +@@ -798,7 +799,7 @@ static struct clk_branch gsbi4_qup_clk = .parent_names = (const char *[]){ "gsbi4_qup_src" }, .num_parents = 1, .ops = &clk_branch_ops, @@ -54,7 +52,7 @@ index d6b7adb4be38..fbb8644c4a43 100644 }, }, }; -@@ -945,7 +946,7 @@ static struct clk_branch gsbi7_qup_clk = { +@@ -945,7 +946,7 @@ static struct clk_branch gsbi7_qup_clk = .parent_names = (const char *[]){ "gsbi7_qup_src" }, .num_parents = 1, .ops = &clk_branch_ops, @@ -95,7 +93,7 @@ index d6b7adb4be38..fbb8644c4a43 100644 }, } }; -@@ -2694,7 +2699,8 @@ static struct clk_dyn_rcg ubi32_core1_src_clk = { +@@ -2694,7 +2699,8 @@ static struct clk_dyn_rcg ubi32_core1_sr .parent_names = gcc_pxo_pll8_pll14_pll18_pll0, .num_parents = 5, .ops = &clk_dyn_rcg_ops, @@ -105,7 +103,7 @@ index d6b7adb4be38..fbb8644c4a43 100644 }, }, }; -@@ -2747,7 +2753,8 @@ static struct clk_dyn_rcg ubi32_core2_src_clk = { +@@ -2747,7 +2753,8 @@ static struct clk_dyn_rcg ubi32_core2_sr .parent_names = gcc_pxo_pll8_pll14_pll18_pll0, .num_parents = 5, .ops = &clk_dyn_rcg_ops, @@ -115,6 +113,3 @@ index d6b7adb4be38..fbb8644c4a43 100644 }, }, }; --- -2.29.2 - diff --git a/target/linux/ipq806x/patches-5.10/097-2-ipq806x-lcc-add-missing-reset.patch b/target/linux/ipq806x/patches-5.10/097-2-ipq806x-lcc-add-missing-reset.patch index 877f751537..cd2cb33356 100644 --- a/target/linux/ipq806x/patches-5.10/097-2-ipq806x-lcc-add-missing-reset.patch +++ b/target/linux/ipq806x/patches-5.10/097-2-ipq806x-lcc-add-missing-reset.patch @@ -11,8 +11,6 @@ Signed-off-by: Ansuel Smith include/dt-bindings/clock/qcom,lcc-ipq806x.h | 1 + 2 files changed, 9 insertions(+) -diff --git a/drivers/clk/qcom/lcc-ipq806x.c b/drivers/clk/qcom/lcc-ipq806x.c -index 1a2be4aeb31d..ee48642bb872 100644 --- a/drivers/clk/qcom/lcc-ipq806x.c +++ b/drivers/clk/qcom/lcc-ipq806x.c @@ -12,6 +12,7 @@ @@ -42,7 +40,7 @@ index 1a2be4aeb31d..ee48642bb872 100644 static const struct pll_config pll4_config = { .l = 0xf, .m = 0x91, -@@ -417,6 +423,8 @@ static const struct qcom_cc_desc lcc_ipq806x_desc = { +@@ -417,6 +423,8 @@ static const struct qcom_cc_desc lcc_ipq .config = &lcc_ipq806x_regmap_config, .clks = lcc_ipq806x_clks, .num_clks = ARRAY_SIZE(lcc_ipq806x_clks), @@ -51,8 +49,6 @@ index 1a2be4aeb31d..ee48642bb872 100644 }; static const struct of_device_id lcc_ipq806x_match_table[] = { -diff --git a/include/dt-bindings/clock/qcom,lcc-ipq806x.h b/include/dt-bindings/clock/qcom,lcc-ipq806x.h -index 25b92bbf0ab4..73318b1ce29e 100644 --- a/include/dt-bindings/clock/qcom,lcc-ipq806x.h +++ b/include/dt-bindings/clock/qcom,lcc-ipq806x.h @@ -19,4 +19,5 @@ @@ -61,6 +57,3 @@ index 25b92bbf0ab4..73318b1ce29e 100644 +#define LCC_PCM_RESET 0 #endif --- -2.29.2 - diff --git a/target/linux/ipq806x/patches-5.10/097-3-clk-qcom-krait-add-missing-enable-disable.patch b/target/linux/ipq806x/patches-5.10/097-3-clk-qcom-krait-add-missing-enable-disable.patch index 777c54c83a..bf1c1a4a2f 100644 --- a/target/linux/ipq806x/patches-5.10/097-3-clk-qcom-krait-add-missing-enable-disable.patch +++ b/target/linux/ipq806x/patches-5.10/097-3-clk-qcom-krait-add-missing-enable-disable.patch @@ -11,11 +11,9 @@ Signed-off-by: Ansuel Smith drivers/clk/qcom/clk-krait.c | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) -diff --git a/drivers/clk/qcom/clk-krait.c b/drivers/clk/qcom/clk-krait.c -index 59f1af415b58..ba796b621669 100644 --- a/drivers/clk/qcom/clk-krait.c +++ b/drivers/clk/qcom/clk-krait.c -@@ -68,7 +68,25 @@ static u8 krait_mux_get_parent(struct clk_hw *hw) +@@ -68,7 +68,25 @@ static u8 krait_mux_get_parent(struct cl return clk_mux_val_to_index(hw, mux->parent_map, 0, sel); } @@ -57,6 +55,3 @@ index 59f1af415b58..ba796b621669 100644 } static int krait_div2_set_rate(struct clk_hw *hw, unsigned long rate, --- -2.29.2 - diff --git a/target/linux/ipq806x/patches-5.10/097-4-ipq806x-gcc-add-missing-clk-and-reset-for-crypto-eng.patch b/target/linux/ipq806x/patches-5.10/097-4-ipq806x-gcc-add-missing-clk-and-reset-for-crypto-eng.patch index 1231f88e9b..f8f4924dd1 100644 --- a/target/linux/ipq806x/patches-5.10/097-4-ipq806x-gcc-add-missing-clk-and-reset-for-crypto-eng.patch +++ b/target/linux/ipq806x/patches-5.10/097-4-ipq806x-gcc-add-missing-clk-and-reset-for-crypto-eng.patch @@ -13,8 +13,6 @@ Signed-off-by: Ansuel Smith include/dt-bindings/reset/qcom,gcc-ipq806x.h | 5 + 3 files changed, 259 insertions(+), 1 deletion(-) -diff --git a/drivers/clk/qcom/gcc-ipq806x.c b/drivers/clk/qcom/gcc-ipq806x.c -index fbb8644c4a43..c36bcdf013d0 100644 --- a/drivers/clk/qcom/gcc-ipq806x.c +++ b/drivers/clk/qcom/gcc-ipq806x.c @@ -223,7 +223,9 @@ static struct clk_regmap pll14_vote = { @@ -58,7 +56,7 @@ index fbb8644c4a43..c36bcdf013d0 100644 }; static const struct parent_map gcc_pxo_pll8_map[] = { -@@ -320,6 +339,42 @@ static const char * const gcc_pxo_pll8_pll14_pll18_pll0[] = { +@@ -320,6 +339,42 @@ static const char * const gcc_pxo_pll8_p "pll18", }; @@ -101,7 +99,7 @@ index fbb8644c4a43..c36bcdf013d0 100644 static struct freq_tbl clk_tbl_gsbi_uart[] = { { 1843200, P_PLL8, 2, 6, 625 }, { 3686400, P_PLL8, 2, 12, 625 }, -@@ -1261,6 +1316,7 @@ static const struct freq_tbl clk_tbl_sdc[] = { +@@ -1261,6 +1316,7 @@ static const struct freq_tbl clk_tbl_sdc { 20210000, P_PLL8, 1, 1, 19 }, { 24000000, P_PLL8, 4, 1, 4 }, { 48000000, P_PLL8, 4, 1, 2 }, @@ -109,7 +107,7 @@ index fbb8644c4a43..c36bcdf013d0 100644 { 64000000, P_PLL8, 3, 1, 2 }, { 96000000, P_PLL8, 4, 0, 0 }, { 192000000, P_PLL8, 2, 0, 0 }, -@@ -2647,7 +2703,9 @@ static const struct freq_tbl clk_tbl_nss[] = { +@@ -2647,7 +2703,9 @@ static const struct freq_tbl clk_tbl_nss { 110000000, P_PLL18, 1, 1, 5 }, { 275000000, P_PLL18, 2, 0, 0 }, { 550000000, P_PLL18, 1, 0, 0 }, @@ -119,7 +117,7 @@ index fbb8644c4a43..c36bcdf013d0 100644 { } }; -@@ -2759,6 +2817,186 @@ static struct clk_dyn_rcg ubi32_core2_src_clk = { +@@ -2759,6 +2817,186 @@ static struct clk_dyn_rcg ubi32_core2_sr }, }; @@ -306,7 +304,7 @@ index fbb8644c4a43..c36bcdf013d0 100644 static struct clk_regmap *gcc_ipq806x_clks[] = { [PLL0] = &pll0.clkr, [PLL0_VOTE] = &pll0_vote, -@@ -2766,6 +3004,7 @@ static struct clk_regmap *gcc_ipq806x_clks[] = { +@@ -2766,6 +3004,7 @@ static struct clk_regmap *gcc_ipq806x_cl [PLL4_VOTE] = &pll4_vote, [PLL8] = &pll8.clkr, [PLL8_VOTE] = &pll8_vote, @@ -314,7 +312,7 @@ index fbb8644c4a43..c36bcdf013d0 100644 [PLL14] = &pll14.clkr, [PLL14_VOTE] = &pll14_vote, [PLL18] = &pll18.clkr, -@@ -2880,6 +3119,12 @@ static struct clk_regmap *gcc_ipq806x_clks[] = { +@@ -2880,6 +3119,12 @@ static struct clk_regmap *gcc_ipq806x_cl [PLL9] = &hfpll0.clkr, [PLL10] = &hfpll1.clkr, [PLL12] = &hfpll_l2.clkr, @@ -327,7 +325,7 @@ index fbb8644c4a43..c36bcdf013d0 100644 }; static const struct qcom_reset_map gcc_ipq806x_resets[] = { -@@ -3011,6 +3256,11 @@ static const struct qcom_reset_map gcc_ipq806x_resets[] = { +@@ -3011,6 +3256,11 @@ static const struct qcom_reset_map gcc_i [GMAC_CORE3_RESET] = { 0x3cfc, 0 }, [GMAC_CORE4_RESET] = { 0x3d1c, 0 }, [GMAC_AHB_RESET] = { 0x3e24, 0 }, @@ -339,8 +337,6 @@ index fbb8644c4a43..c36bcdf013d0 100644 [NSS_CH0_RST_RX_CLK_N_RESET] = { 0x3b60, 0 }, [NSS_CH0_RST_TX_CLK_N_RESET] = { 0x3b60, 1 }, [NSS_CH0_RST_RX_125M_N_RESET] = { 0x3b60, 2 }, -diff --git a/include/dt-bindings/clock/qcom,gcc-ipq806x.h b/include/dt-bindings/clock/qcom,gcc-ipq806x.h -index 7deec14a6dee..02262d2ac899 100644 --- a/include/dt-bindings/clock/qcom,gcc-ipq806x.h +++ b/include/dt-bindings/clock/qcom,gcc-ipq806x.h @@ -240,7 +240,7 @@ @@ -361,8 +357,6 @@ index 7deec14a6dee..02262d2ac899 100644 +#define CE5_CORE_CLK_SRC 287 #endif -diff --git a/include/dt-bindings/reset/qcom,gcc-ipq806x.h b/include/dt-bindings/reset/qcom,gcc-ipq806x.h -index 26b6f9200620..020c9cf18751 100644 --- a/include/dt-bindings/reset/qcom,gcc-ipq806x.h +++ b/include/dt-bindings/reset/qcom,gcc-ipq806x.h @@ -163,5 +163,10 @@ @@ -376,6 +370,3 @@ index 26b6f9200620..020c9cf18751 100644 +#define CRYPTO_AHB_RESET 161 #endif --- -2.29.2 - diff --git a/target/linux/ipq806x/patches-5.10/098-2-Documentation-cpufreq-add-qcom-krait-cpufreq-binding.patch b/target/linux/ipq806x/patches-5.10/098-2-Documentation-cpufreq-add-qcom-krait-cpufreq-binding.patch index 81ec0883cd..316e18b790 100644 --- a/target/linux/ipq806x/patches-5.10/098-2-Documentation-cpufreq-add-qcom-krait-cpufreq-binding.patch +++ b/target/linux/ipq806x/patches-5.10/098-2-Documentation-cpufreq-add-qcom-krait-cpufreq-binding.patch @@ -11,9 +11,6 @@ Signed-off-by: Ansuel Smith 1 file changed, 221 insertions(+) create mode 100644 Documentation/devicetree/bindings/cpufreq/qcom-cpufreq-krait.yaml -diff --git a/Documentation/devicetree/bindings/cpufreq/qcom-cpufreq-krait.yaml b/Documentation/devicetree/bindings/cpufreq/qcom-cpufreq-krait.yaml -new file mode 100644 -index 000000000000..f6bcca863d9a --- /dev/null +++ b/Documentation/devicetree/bindings/cpufreq/qcom-cpufreq-krait.yaml @@ -0,0 +1,221 @@ @@ -238,6 +235,3 @@ index 000000000000..f6bcca863d9a + }; + +... --- -2.29.2 - diff --git a/target/linux/ipq806x/patches-5.10/098-3-add-fab-scaling-support-with-cpufreq.patch b/target/linux/ipq806x/patches-5.10/098-3-add-fab-scaling-support-with-cpufreq.patch index 29dff3297d..fe9143218f 100644 --- a/target/linux/ipq806x/patches-5.10/098-3-add-fab-scaling-support-with-cpufreq.patch +++ b/target/linux/ipq806x/patches-5.10/098-3-add-fab-scaling-support-with-cpufreq.patch @@ -227,7 +227,7 @@ #include "cpufreq-dt.h" -@@ -58,6 +59,13 @@ static int set_target(struct cpufreq_policy *policy, unsigned int index) +@@ -54,6 +55,13 @@ static int set_target(struct cpufreq_pol level = dev_pm_opp_get_level(opp); dev_pm_opp_put(opp); diff --git a/target/linux/ipq806x/patches-5.10/099-1-mtd-nand-raw-qcom_nandc-add-boot_layout_mode-support.patch b/target/linux/ipq806x/patches-5.10/099-1-mtd-nand-raw-qcom_nandc-add-boot_layout_mode-support.patch index 06b842382e..26c64d68c4 100644 --- a/target/linux/ipq806x/patches-5.10/099-1-mtd-nand-raw-qcom_nandc-add-boot_layout_mode-support.patch +++ b/target/linux/ipq806x/patches-5.10/099-1-mtd-nand-raw-qcom_nandc-add-boot_layout_mode-support.patch @@ -14,11 +14,9 @@ Signed-off-by: Ansuel Smith drivers/mtd/nand/raw/qcom_nandc.c | 82 +++++++++++++++++++++++++++++-- 1 file changed, 77 insertions(+), 5 deletions(-) -diff --git a/drivers/mtd/nand/raw/qcom_nandc.c b/drivers/mtd/nand/raw/qcom_nandc.c -index 667e4bfe369f..69be86898d7a 100644 --- a/drivers/mtd/nand/raw/qcom_nandc.c +++ b/drivers/mtd/nand/raw/qcom_nandc.c -@@ -160,6 +160,11 @@ +@@ -159,6 +159,11 @@ /* NAND_CTRL bits */ #define BAM_MODE_EN BIT(0) @@ -30,7 +28,7 @@ index 667e4bfe369f..69be86898d7a 100644 /* * the NAND controller performs reads/writes with ECC in 516 byte chunks. * the driver calls the chunks 'step' or 'codeword' interchangeably -@@ -431,6 +436,13 @@ struct qcom_nand_controller { +@@ -430,6 +435,13 @@ struct qcom_nand_controller { * @cfg0, cfg1, cfg0_raw..: NANDc register configurations needed for * ecc/non-ecc mode for the current nand flash * device @@ -44,7 +42,7 @@ index 667e4bfe369f..69be86898d7a 100644 */ struct qcom_nand_host { struct nand_chip chip; -@@ -453,6 +465,9 @@ struct qcom_nand_host { +@@ -452,6 +464,9 @@ struct qcom_nand_host { u32 ecc_bch_cfg; u32 clrflashstatus; u32 clrreadstatus; @@ -54,7 +52,7 @@ index 667e4bfe369f..69be86898d7a 100644 }; /* -@@ -462,6 +477,7 @@ struct qcom_nand_host { +@@ -460,12 +475,14 @@ struct qcom_nand_host { * @ecc_modes - ecc mode for NAND * @is_bam - whether NAND controller is using BAM * @is_qpic - whether NAND CTRL is part of qpic IP @@ -62,15 +60,14 @@ index 667e4bfe369f..69be86898d7a 100644 * @dev_cmd_reg_start - NAND_DEV_CMD_* registers starting offset */ struct qcom_nandc_props { -@@ -469,6 +485,7 @@ struct qcom_nandc_props { + u32 ecc_modes; bool is_bam; bool is_qpic; + bool has_boot_pages; u32 dev_cmd_reg_start; }; - /* Frees the BAM transaction memory */ -@@ -1622,7 +1639,7 @@ qcom_nandc_read_cw_raw(struct mtd_info *mtd, struct nand_chip *chip, +@@ -1604,7 +1621,7 @@ qcom_nandc_read_cw_raw(struct mtd_info * data_size1 = mtd->writesize - host->cw_size * (ecc->steps - 1); oob_size1 = host->bbm_size; @@ -79,7 +76,7 @@ index 667e4bfe369f..69be86898d7a 100644 data_size2 = ecc->size - data_size1 - ((ecc->steps - 1) * 4); oob_size2 = (ecc->steps * 4) + host->ecc_bytes_hw + -@@ -1703,7 +1720,7 @@ check_for_erased_page(struct qcom_nand_host *host, u8 *data_buf, +@@ -1685,7 +1702,7 @@ check_for_erased_page(struct qcom_nand_h } for_each_set_bit(cw, &uncorrectable_cws, ecc->steps) { @@ -88,7 +85,7 @@ index 667e4bfe369f..69be86898d7a 100644 data_size = ecc->size - ((ecc->steps - 1) * 4); oob_size = (ecc->steps * 4) + host->ecc_bytes_hw; } else { -@@ -1862,7 +1879,7 @@ static int read_page_ecc(struct qcom_nand_host *host, u8 *data_buf, +@@ -1844,7 +1861,7 @@ static int read_page_ecc(struct qcom_nan for (i = 0; i < ecc->steps; i++) { int data_size, oob_size; @@ -97,7 +94,7 @@ index 667e4bfe369f..69be86898d7a 100644 data_size = ecc->size - ((ecc->steps - 1) << 2); oob_size = (ecc->steps << 2) + host->ecc_bytes_hw + host->spare_bytes; -@@ -1959,6 +1976,30 @@ static int copy_last_cw(struct qcom_nand_host *host, int page) +@@ -1941,6 +1958,30 @@ static int copy_last_cw(struct qcom_nand return ret; } @@ -128,7 +125,7 @@ index 667e4bfe369f..69be86898d7a 100644 /* implements ecc->read_page() */ static int qcom_nandc_read_page(struct nand_chip *chip, uint8_t *buf, int oob_required, int page) -@@ -1967,6 +2008,9 @@ static int qcom_nandc_read_page(struct nand_chip *chip, uint8_t *buf, +@@ -1949,6 +1990,9 @@ static int qcom_nandc_read_page(struct n struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip); u8 *data_buf, *oob_buf = NULL; @@ -138,7 +135,7 @@ index 667e4bfe369f..69be86898d7a 100644 nand_read_page_op(chip, page, 0, NULL, 0); data_buf = buf; oob_buf = oob_required ? chip->oob_poi : NULL; -@@ -1986,6 +2030,9 @@ static int qcom_nandc_read_page_raw(struct nand_chip *chip, uint8_t *buf, +@@ -1968,6 +2012,9 @@ static int qcom_nandc_read_page_raw(stru int cw, ret; u8 *data_buf = buf, *oob_buf = chip->oob_poi; @@ -148,7 +145,7 @@ index 667e4bfe369f..69be86898d7a 100644 for (cw = 0; cw < ecc->steps; cw++) { ret = qcom_nandc_read_cw_raw(mtd, chip, data_buf, oob_buf, page, cw); -@@ -2006,6 +2053,9 @@ static int qcom_nandc_read_oob(struct nand_chip *chip, int page) +@@ -1988,6 +2035,9 @@ static int qcom_nandc_read_oob(struct na struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip); struct nand_ecc_ctrl *ecc = &chip->ecc; @@ -158,7 +155,7 @@ index 667e4bfe369f..69be86898d7a 100644 clear_read_regs(nandc); clear_bam_transaction(nandc); -@@ -2026,6 +2076,9 @@ static int qcom_nandc_write_page(struct nand_chip *chip, const uint8_t *buf, +@@ -2008,6 +2058,9 @@ static int qcom_nandc_write_page(struct u8 *data_buf, *oob_buf; int i, ret; @@ -168,7 +165,7 @@ index 667e4bfe369f..69be86898d7a 100644 nand_prog_page_begin_op(chip, page, 0, NULL, 0); clear_read_regs(nandc); -@@ -2041,7 +2094,7 @@ static int qcom_nandc_write_page(struct nand_chip *chip, const uint8_t *buf, +@@ -2023,7 +2076,7 @@ static int qcom_nandc_write_page(struct for (i = 0; i < ecc->steps; i++) { int data_size, oob_size; @@ -177,7 +174,7 @@ index 667e4bfe369f..69be86898d7a 100644 data_size = ecc->size - ((ecc->steps - 1) << 2); oob_size = (ecc->steps << 2) + host->ecc_bytes_hw + host->spare_bytes; -@@ -2098,6 +2151,9 @@ static int qcom_nandc_write_page_raw(struct nand_chip *chip, +@@ -2080,6 +2133,9 @@ static int qcom_nandc_write_page_raw(str u8 *data_buf, *oob_buf; int i, ret; @@ -187,7 +184,7 @@ index 667e4bfe369f..69be86898d7a 100644 nand_prog_page_begin_op(chip, page, 0, NULL, 0); clear_read_regs(nandc); clear_bam_transaction(nandc); -@@ -2116,7 +2172,7 @@ static int qcom_nandc_write_page_raw(struct nand_chip *chip, +@@ -2098,7 +2154,7 @@ static int qcom_nandc_write_page_raw(str data_size1 = mtd->writesize - host->cw_size * (ecc->steps - 1); oob_size1 = host->bbm_size; @@ -196,7 +193,7 @@ index 667e4bfe369f..69be86898d7a 100644 data_size2 = ecc->size - data_size1 - ((ecc->steps - 1) << 2); oob_size2 = (ecc->steps << 2) + host->ecc_bytes_hw + -@@ -2176,6 +2232,9 @@ static int qcom_nandc_write_oob(struct nand_chip *chip, int page) +@@ -2158,6 +2214,9 @@ static int qcom_nandc_write_oob(struct n int data_size, oob_size; int ret; @@ -206,7 +203,7 @@ index 667e4bfe369f..69be86898d7a 100644 host->use_ecc = true; clear_bam_transaction(nandc); -@@ -2828,6 +2887,7 @@ static int qcom_nand_host_init_and_register(struct qcom_nand_controller *nandc, +@@ -2806,6 +2865,7 @@ static int qcom_nand_host_init_and_regis struct nand_chip *chip = &host->chip; struct mtd_info *mtd = nand_to_mtd(chip); struct device *dev = nandc->dev; @@ -214,7 +211,7 @@ index 667e4bfe369f..69be86898d7a 100644 int ret; ret = of_property_read_u32(dn, "reg", &host->cs); -@@ -2888,6 +2948,17 @@ static int qcom_nand_host_init_and_register(struct qcom_nand_controller *nandc, +@@ -2866,6 +2926,17 @@ static int qcom_nand_host_init_and_regis if (ret) nand_cleanup(chip); @@ -232,7 +229,7 @@ index 667e4bfe369f..69be86898d7a 100644 return ret; } -@@ -3057,6 +3128,7 @@ static int qcom_nandc_remove(struct platform_device *pdev) +@@ -3035,6 +3106,7 @@ static int qcom_nandc_remove(struct plat static const struct qcom_nandc_props ipq806x_nandc_props = { .ecc_modes = (ECC_RS_4BIT | ECC_BCH_8BIT), .is_bam = false, @@ -240,6 +237,3 @@ index 667e4bfe369f..69be86898d7a 100644 .dev_cmd_reg_start = 0x0, }; --- -2.29.2 - diff --git a/target/linux/ipq806x/patches-5.10/099-2-Documentation-devicetree-mtd-qcom_nandc-document-qco.patch b/target/linux/ipq806x/patches-5.10/099-2-Documentation-devicetree-mtd-qcom_nandc-document-qco.patch index 2bef1daefb..79036cb057 100644 --- a/target/linux/ipq806x/patches-5.10/099-2-Documentation-devicetree-mtd-qcom_nandc-document-qco.patch +++ b/target/linux/ipq806x/patches-5.10/099-2-Documentation-devicetree-mtd-qcom_nandc-document-qco.patch @@ -12,11 +12,9 @@ Signed-off-by: Ansuel Smith Documentation/devicetree/bindings/mtd/qcom_nandc.txt | 11 +++++++++++ 1 file changed, 11 insertions(+) -diff --git a/Documentation/devicetree/bindings/mtd/qcom_nandc.txt b/Documentation/devicetree/bindings/mtd/qcom_nandc.txt -index 5647913d8837..3cf1dd5ebad2 100644 --- a/Documentation/devicetree/bindings/mtd/qcom_nandc.txt +++ b/Documentation/devicetree/bindings/mtd/qcom_nandc.txt -@@ -56,6 +56,15 @@ Optional properties: +@@ -52,6 +52,15 @@ Optional properties: be used according to chip requirement and available OOB size. @@ -32,7 +30,7 @@ index 5647913d8837..3cf1dd5ebad2 100644 Each nandcs device node may optionally contain a 'partitions' sub-node, which further contains sub-nodes describing the flash partition mapping. See partition.txt for more detail. -@@ -84,6 +93,9 @@ nand-controller@1ac00000 { +@@ -80,6 +89,9 @@ nand-controller@1ac00000 { nand-ecc-strength = <4>; nand-bus-width = <8>; @@ -42,6 +40,3 @@ index 5647913d8837..3cf1dd5ebad2 100644 partitions { compatible = "fixed-partitions"; #address-cells = <1>; --- -2.29.2 - diff --git a/target/linux/ipq806x/patches-5.10/100-v5.11-dmaengine-qcom-add_ADM_driver.patch b/target/linux/ipq806x/patches-5.10/100-v5.11-dmaengine-qcom-add_ADM_driver.patch index 45062d52fc..2d24da01e4 100644 --- a/target/linux/ipq806x/patches-5.10/100-v5.11-dmaengine-qcom-add_ADM_driver.patch +++ b/target/linux/ipq806x/patches-5.10/100-v5.11-dmaengine-qcom-add_ADM_driver.patch @@ -31,8 +31,6 @@ Signed-off-by: Vinod Koul 3 files changed, 915 insertions(+) create mode 100644 drivers/dma/qcom/qcom_adm.c -diff --git a/drivers/dma/qcom/Kconfig b/drivers/dma/qcom/Kconfig -index 3bcb689162c67..0389d60d2604a 100644 --- a/drivers/dma/qcom/Kconfig +++ b/drivers/dma/qcom/Kconfig @@ -1,4 +1,15 @@ @@ -51,8 +49,6 @@ index 3bcb689162c67..0389d60d2604a 100644 config QCOM_BAM_DMA tristate "QCOM BAM DMA support" depends on ARCH_QCOM || (COMPILE_TEST && OF && ARM) -diff --git a/drivers/dma/qcom/Makefile b/drivers/dma/qcom/Makefile -index 1ae92da88b0c9..346e643fbb6db 100644 --- a/drivers/dma/qcom/Makefile +++ b/drivers/dma/qcom/Makefile @@ -1,4 +1,5 @@ @@ -61,9 +57,6 @@ index 1ae92da88b0c9..346e643fbb6db 100644 obj-$(CONFIG_QCOM_BAM_DMA) += bam_dma.o obj-$(CONFIG_QCOM_HIDMA_MGMT) += hdma_mgmt.o hdma_mgmt-objs := hidma_mgmt.o hidma_mgmt_sys.o -diff --git a/drivers/dma/qcom/qcom_adm.c b/drivers/dma/qcom/qcom_adm.c -new file mode 100644 -index 0000000000000..9b6f8e050ecce --- /dev/null +++ b/drivers/dma/qcom/qcom_adm.c @@ -0,0 +1,903 @@ @@ -970,6 +963,3 @@ index 0000000000000..9b6f8e050ecce +MODULE_AUTHOR("Andy Gross "); +MODULE_DESCRIPTION("QCOM ADM DMA engine driver"); +MODULE_LICENSE("GPL v2"); --- -cgit 1.2.3-1.el7 - diff --git a/target/linux/ipq806x/patches-5.10/101-5.12-mtd-parsers-Add-Qcom-SMEM-parser.patch b/target/linux/ipq806x/patches-5.10/101-5.12-mtd-parsers-Add-Qcom-SMEM-parser.patch index 7aec4fcc83..d93f338c74 100644 --- a/target/linux/ipq806x/patches-5.10/101-5.12-mtd-parsers-Add-Qcom-SMEM-parser.patch +++ b/target/linux/ipq806x/patches-5.10/101-5.12-mtd-parsers-Add-Qcom-SMEM-parser.patch @@ -17,15 +17,12 @@ Link: https://lore.kernel.org/linux-mtd/20210104041137.113075-3-manivannan.sadha 3 files changed, 179 insertions(+) create mode 100644 drivers/mtd/parsers/qcomsmempart.c -diff --git a/drivers/mtd/parsers/Kconfig b/drivers/mtd/parsers/Kconfig -index e72354322f628..d90c302290522 100644 --- a/drivers/mtd/parsers/Kconfig +++ b/drivers/mtd/parsers/Kconfig -@@ -160,6 +160,14 @@ config MTD_REDBOOT_PARTS_READONLY - 'FIS directory' images, enable this option. +@@ -186,6 +186,14 @@ config MTD_REDBOOT_PARTS_READONLY endif # MTD_REDBOOT_PARTS -+ + +config MTD_QCOMSMEM_PARTS + tristate "Qualcomm SMEM NAND flash partition parser" + depends on MTD_NAND_QCOM || COMPILE_TEST @@ -33,22 +30,18 @@ index e72354322f628..d90c302290522 100644 + help + This provides support for parsing partitions from Shared Memory (SMEM) + for NAND flash on Qualcomm platforms. - ++ config MTD_ROUTERBOOT_PARTS tristate "RouterBoot flash partition parser" -diff --git a/drivers/mtd/parsers/Makefile b/drivers/mtd/parsers/Makefile -index b0c5f62f9e858..50eb0b0a22105 100644 + depends on MTD && OF --- a/drivers/mtd/parsers/Makefile +++ b/drivers/mtd/parsers/Makefile -@@ -9,4 +9,5 @@ obj-$(CONFIG_MTD_AFS_PARTS) += afs.o +@@ -12,4 +12,5 @@ obj-$(CONFIG_MTD_AFS_PARTS) += afs.o obj-$(CONFIG_MTD_PARSER_TRX) += parser_trx.o obj-$(CONFIG_MTD_SHARPSL_PARTS) += sharpslpart.o obj-$(CONFIG_MTD_REDBOOT_PARTS) += redboot.o +obj-$(CONFIG_MTD_QCOMSMEM_PARTS) += qcomsmempart.o obj-$(CONFIG_MTD_ROUTERBOOT_PARTS) += routerbootpart.o -diff --git a/drivers/mtd/parsers/qcomsmempart.c b/drivers/mtd/parsers/qcomsmempart.c -new file mode 100644 -index 0000000000000..808cb33d71f8e --- /dev/null +++ b/drivers/mtd/parsers/qcomsmempart.c @@ -0,0 +1,170 @@ @@ -222,6 +215,3 @@ index 0000000000000..808cb33d71f8e +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Manivannan Sadhasivam "); +MODULE_DESCRIPTION("Qualcomm SMEM NAND flash partition parser"); --- -cgit 1.2.3-1.el7 - diff --git a/target/linux/ipq806x/patches-5.10/102-mtd-rootfs-conflicts-with-OpenWrt-auto-mounting.patch b/target/linux/ipq806x/patches-5.10/102-mtd-rootfs-conflicts-with-OpenWrt-auto-mounting.patch index 47f3bfba8d..e83872935f 100644 --- a/target/linux/ipq806x/patches-5.10/102-mtd-rootfs-conflicts-with-OpenWrt-auto-mounting.patch +++ b/target/linux/ipq806x/patches-5.10/102-mtd-rootfs-conflicts-with-OpenWrt-auto-mounting.patch @@ -10,7 +10,7 @@ Signed-off-by: John Crispin --- a/drivers/mtd/parsers/qcomsmempart.c +++ b/drivers/mtd/parsers/qcomsmempart.c -@@ -189,6 +189,11 @@ static int parse_qcomsmem_part(st +@@ -132,6 +132,11 @@ static int parse_qcomsmem_part(struct mt parts[i].offset = le32_to_cpu(pentry->offset) * mtd->erasesize; parts[i].mask_flags = pentry->attr; parts[i].size = le32_to_cpu(pentry->length) * mtd->erasesize; diff --git a/target/linux/ipq806x/patches-5.10/103-arm-Enlarge-IO_SPACE_LIMIT-needed-for-some-SoC.patch b/target/linux/ipq806x/patches-5.10/103-arm-Enlarge-IO_SPACE_LIMIT-needed-for-some-SoC.patch index e69a97f843..64a0eaf8ed 100644 --- a/target/linux/ipq806x/patches-5.10/103-arm-Enlarge-IO_SPACE_LIMIT-needed-for-some-SoC.patch +++ b/target/linux/ipq806x/patches-5.10/103-arm-Enlarge-IO_SPACE_LIMIT-needed-for-some-SoC.patch @@ -12,11 +12,9 @@ Signed-off-by: Ansuel Smith arch/arm/include/asm/io.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) -diff --git a/arch/arm/include/asm/io.h b/arch/arm/include/asm/io.h -index fc748122f1e0..6f3e89f08bd8 100644 --- a/arch/arm/include/asm/io.h +++ b/arch/arm/include/asm/io.h -@@ -197,7 +197,7 @@ void __iomem *pci_remap_cfgspace(resource_size_t res_cookie, size_t size); +@@ -197,7 +197,7 @@ void __iomem *pci_remap_cfgspace(resourc #ifdef CONFIG_NEED_MACH_IO_H #include #elif defined(CONFIG_PCI) @@ -25,6 +23,3 @@ index fc748122f1e0..6f3e89f08bd8 100644 #define __io(a) __typesafe_io(PCI_IO_VIRT_BASE + ((a) & IO_SPACE_LIMIT)) #else #define __io(a) __typesafe_io((a) & IO_SPACE_LIMIT) --- -2.30.0 - diff --git a/target/linux/ipq806x/patches-5.10/850-soc-add-qualcomm-syscon.patch b/target/linux/ipq806x/patches-5.10/850-soc-add-qualcomm-syscon.patch index 9e1ac7db04..8325e10389 100644 --- a/target/linux/ipq806x/patches-5.10/850-soc-add-qualcomm-syscon.patch +++ b/target/linux/ipq806x/patches-5.10/850-soc-add-qualcomm-syscon.patch @@ -2,17 +2,17 @@ From: Christian Lamparter Subject: SoC: add qualcomm syscon --- a/drivers/soc/qcom/Makefile +++ b/drivers/soc/qcom/Makefile -@@ -20,6 +20,7 @@ obj-$(CONFIG_QCOM_SMP2P) += smp2p.o +@@ -21,6 +21,7 @@ obj-$(CONFIG_QCOM_SMP2P) += smp2p.o obj-$(CONFIG_QCOM_SMSM) += smsm.o obj-$(CONFIG_QCOM_SOCINFO) += socinfo.o obj-$(CONFIG_QCOM_WCNSS_CTRL) += wcnss_ctrl.o +obj-$(CONFIG_QCOM_TCSR) += qcom_tcsr.o obj-$(CONFIG_QCOM_APR) += apr.o - obj-$(CONFIG_QCOM_LLCC) += llcc-slice.o - obj-$(CONFIG_QCOM_SDM845_LLCC) += llcc-sdm845.o + obj-$(CONFIG_QCOM_LLCC) += llcc-qcom.o + obj-$(CONFIG_QCOM_RPMHPD) += rpmhpd.o --- a/drivers/soc/qcom/Kconfig +++ b/drivers/soc/qcom/Kconfig -@@ -183,6 +183,13 @@ config QCOM_SOCINFO +@@ -189,6 +189,13 @@ config QCOM_SOCINFO Say yes here to support the Qualcomm socinfo driver, providing information about the SoC to user space. diff --git a/target/linux/ipq806x/patches-5.10/851-add-gsbi1-dts.patch b/target/linux/ipq806x/patches-5.10/851-add-gsbi1-dts.patch index f75f994904..3a83b2de30 100644 --- a/target/linux/ipq806x/patches-5.10/851-add-gsbi1-dts.patch +++ b/target/linux/ipq806x/patches-5.10/851-add-gsbi1-dts.patch @@ -1,6 +1,6 @@ --- a/arch/arm/boot/dts/qcom-ipq8064.dtsi +++ b/arch/arm/boot/dts/qcom-ipq8064.dtsi -@@ -865,6 +865,41 @@ +@@ -747,6 +747,41 @@ reg = <0x12100000 0x10000>; }; diff --git a/target/linux/ipq806x/patches-5.10/900-arm-add-cmdline-override.patch b/target/linux/ipq806x/patches-5.10/900-arm-add-cmdline-override.patch index 49cd68b68d..2459e6a2f0 100644 --- a/target/linux/ipq806x/patches-5.10/900-arm-add-cmdline-override.patch +++ b/target/linux/ipq806x/patches-5.10/900-arm-add-cmdline-override.patch @@ -1,6 +1,6 @@ --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig -@@ -1840,6 +1840,14 @@ config ARM_ATAG_DTB_COMPAT_CMDLINE_MANGL +@@ -1793,6 +1793,14 @@ config ARM_ATAG_DTB_COMPAT_CMDLINE_MANGL endchoice @@ -17,7 +17,7 @@ default "" --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c -@@ -1060,6 +1060,17 @@ int __init early_init_dt_scan_chosen(uns +@@ -1056,6 +1056,17 @@ int __init early_init_dt_scan_chosen(uns if (p != NULL && l > 0) strlcpy(data, p, min(l, COMMAND_LINE_SIZE)); diff --git a/target/linux/ipq806x/patches-5.10/997-device_tree_cmdline.patch b/target/linux/ipq806x/patches-5.10/997-device_tree_cmdline.patch index b6b1b04765..bdcba2a21c 100644 --- a/target/linux/ipq806x/patches-5.10/997-device_tree_cmdline.patch +++ b/target/linux/ipq806x/patches-5.10/997-device_tree_cmdline.patch @@ -1,6 +1,6 @@ --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c -@@ -1059,6 +1059,9 @@ int __init early_init_dt_scan_chosen(uns +@@ -1055,6 +1055,9 @@ int __init early_init_dt_scan_chosen(uns p = of_get_flat_dt_prop(node, "bootargs", &l); if (p != NULL && l > 0) strlcpy(data, p, min(l, COMMAND_LINE_SIZE)); From 4cd43af0dea98d21611d20233ac77c2d0fe3af29 Mon Sep 17 00:00:00 2001 From: Ansuel Smith Date: Thu, 8 Apr 2021 16:47:33 +0200 Subject: [PATCH 29/62] ipq806x: fix missing tx/rx fifo depth gmac configuration tx/rx-fifo-depth is required to set mtu to the gmac. Backport upstream patch. Signed-off-by: Ansuel Smith --- ...et-stmmac-Set-FIFO-sizes-for-ipq806x.patch | 101 ++++++++++++++++++ 1 file changed, 101 insertions(+) create mode 100644 target/linux/ipq806x/patches-5.10/106-5.13-net-stmmac-Set-FIFO-sizes-for-ipq806x.patch diff --git a/target/linux/ipq806x/patches-5.10/106-5.13-net-stmmac-Set-FIFO-sizes-for-ipq806x.patch b/target/linux/ipq806x/patches-5.10/106-5.13-net-stmmac-Set-FIFO-sizes-for-ipq806x.patch new file mode 100644 index 0000000000..1da9e7e2b3 --- /dev/null +++ b/target/linux/ipq806x/patches-5.10/106-5.13-net-stmmac-Set-FIFO-sizes-for-ipq806x.patch @@ -0,0 +1,101 @@ +From patchwork Sat Mar 13 13:18:26 2021 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +X-Patchwork-Submitter: Jonathan McDowell +X-Patchwork-Id: 12136795 +X-Patchwork-Delegate: kuba@kernel.org +Return-Path: +X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on + aws-us-west-2-korg-lkml-1.web.codeaurora.org +X-Spam-Level: +X-Spam-Status: No, score=-15.1 required=3.0 tests=BAYES_00,DKIM_INVALID, + DKIM_SIGNED,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, + MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,USER_AGENT_SANE_1 + autolearn=unavailable autolearn_force=no version=3.4.0 +Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) + by smtp.lore.kernel.org (Postfix) with ESMTP id 90AB7C433DB + for ; Sat, 13 Mar 2021 14:03:56 +0000 (UTC) +Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) + by mail.kernel.org (Postfix) with ESMTP id 58E0464F18 + for ; Sat, 13 Mar 2021 14:03:56 +0000 (UTC) +Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand + id S233791AbhCMODW (ORCPT ); + Sat, 13 Mar 2021 09:03:22 -0500 +Received: from lindbergh.monkeyblade.net ([23.128.96.19]:52042 "EHLO + lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org + with ESMTP id S233478AbhCMOCx (ORCPT + ); Sat, 13 Mar 2021 09:02:53 -0500 +X-Greylist: delayed 2658 seconds by postgrey-1.37 at + lindbergh.monkeyblade.net; Sat, 13 Mar 2021 06:02:53 PST +Received: from the.earth.li (the.earth.li + [IPv6:2a00:1098:86:4d:c0ff:ee:15:900d]) + by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 3FE3FC061574; + Sat, 13 Mar 2021 06:02:53 -0800 (PST) +DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=earth.li; + s=the; + h=Content-Type:MIME-Version:Message-ID:Subject:To:From:Date:Sender: + Reply-To:Cc:Content-Transfer-Encoding:Content-ID:Content-Description: + Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: + In-Reply-To:References:List-Id:List-Help:List-Unsubscribe:List-Subscribe: + List-Post:List-Owner:List-Archive; + bh=QOTdjy1PdYeDQ1fUENDrh0RtMG0coACWNQ4YsZbgl5w=; + b=DeTr+9knNkPOvtIi2OlW73HS3t + slxWRqQmC/Qd+tyDE8Lnj4oD+NFf5isDoaYYYhiPQ8iT/IOWEUz6DODzLTEBHd1WG9KYfSqzwFT70 + 7pdoIUdBZOPtb0r/1WZqZHRog4L3uDDlSBHRkO6SaLFE0zu6nunAVePrw4XLLmC9bJGsxaEmVvJ4N + zAgW5ejJ2lWOVgTIKSiBHTnLvkLbkSUT3inboIq/iEhEMGyBD8Zio1md1EU+8pQugFxwTmI5hqZ8M + RBYRHIUBaaivkhOJptSZm3vns90mjlM/uDY69gA+jRAsvt2mhWRHSwLv8PJUZ5sB0SenvC1WcPH1S + zAB6oEag==; +Received: from noodles by the.earth.li with local (Exim 4.92) + (envelope-from ) + id 1lL49y-0004kB-SB; Sat, 13 Mar 2021 13:18:26 +0000 +Date: Sat, 13 Mar 2021 13:18:26 +0000 +From: Jonathan McDowell +To: Giuseppe Cavallaro , + Alexandre Torgue , + Jose Abreu , + David Miller , + Jakub Kicinski , + Maxime Coquelin , + netdev@vger.kernel.org, linux-stm32@st-md-mailman.stormreply.com, + linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org +Subject: [PATCH net-next] net: stmmac: Set FIFO sizes for ipq806x +Message-ID: <20210313131826.GA17553@earth.li> +MIME-Version: 1.0 +Content-Disposition: inline +User-Agent: Mutt/1.10.1 (2018-07-13) +Precedence: bulk +List-ID: +X-Mailing-List: netdev@vger.kernel.org +X-Patchwork-Delegate: kuba@kernel.org + +Commit eaf4fac47807 ("net: stmmac: Do not accept invalid MTU values") +started using the TX FIFO size to verify what counts as a valid MTU +request for the stmmac driver. This is unset for the ipq806x variant. +Looking at older patches for this it seems the RX + TXs buffers can be +up to 8k, so set appropriately. + +(I sent this as an RFC patch in June last year, but received no replies. +I've been running with this on my hardware (a MikroTik RB3011) since +then with larger MTUs to support both the internal qca8k switch and +VLANs with no problems. Without the patch it's impossible to set the +larger MTU required to support this.) + +Signed-off-by: Jonathan McDowell +--- + drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c +index bf3250e0e59c..749585fe6fc9 100644 +--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c ++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c +@@ -352,6 +352,8 @@ static int ipq806x_gmac_probe(struct platform_device *pdev) + plat_dat->bsp_priv = gmac; + plat_dat->fix_mac_speed = ipq806x_gmac_fix_mac_speed; + plat_dat->multicast_filter_bins = 0; ++ plat_dat->tx_fifo_size = 8192; ++ plat_dat->rx_fifo_size = 8192; + + err = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); + if (err) From 1603d09964d14ccdb3f2ab7592e3fc85d36b8500 Mon Sep 17 00:00:00 2001 From: Ansuel Smith Date: Tue, 23 Mar 2021 17:41:11 +0100 Subject: [PATCH 30/62] ipq806x: apply correct voltage tolerance Voltage tolerance was 5%, not 5000. Update min and max voltage of the target opp. Signed-off-by: Ansuel Smith --- .../files/arch/arm/boot/dts/qcom-ipq8062.dtsi | 16 ++-- .../files/arch/arm/boot/dts/qcom-ipq8065.dtsi | 86 +++++++++---------- .../083-ipq8064-dtsi-additions.patch | 52 +++++------ 3 files changed, 77 insertions(+), 77 deletions(-) diff --git a/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8062.dtsi b/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8062.dtsi index 09aa081737..4b007130aa 100644 --- a/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8062.dtsi +++ b/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8062.dtsi @@ -46,29 +46,29 @@ /delete-node/opp-1400000000; opp-384000000 { - opp-microvolt-speed0-pvs0-v0 = <945000 950000 955000>; - opp-microvolt-speed0-pvs1-v0 = <985000 900000 905000>; - opp-microvolt-speed0-pvs2-v0 = <845000 850000 855000>; - opp-microvolt-speed0-pvs3-v0 = <795000 800000 805000>; + opp-microvolt-speed0-pvs0-v0 = <902500 950000 997500>; + opp-microvolt-speed0-pvs1-v0 = <855000 900000 945000>; + opp-microvolt-speed0-pvs2-v0 = <807500 850000 892500>; + opp-microvolt-speed0-pvs3-v0 = <760000 800000 840000>; }; opp-600000000 { - opp-microvolt-speed0-pvs0-v0 = <995000 1000000 1005000>; + opp-microvolt-speed0-pvs0-v0 = <950000 1000000 1050000>; opp-microvolt-speed0-pvs1-v0 = <945000 950000 955000>; opp-microvolt-speed0-pvs2-v0 = <895000 900000 905000>; opp-microvolt-speed0-pvs3-v0 = <845000 850000 855000>; }; opp-800000000 { - opp-microvolt-speed0-pvs0-v0 = <1045000 1050000 1055000>; + opp-microvolt-speed0-pvs0-v0 = <997500 1050000 1102500>; opp-microvolt-speed0-pvs1-v0 = < 995000 1000000 1005000>; opp-microvolt-speed0-pvs2-v0 = < 945000 950000 955000>; opp-microvolt-speed0-pvs3-v0 = < 895000 900000 905000>; }; opp-1000000000 { - opp-microvolt-speed0-pvs0-v0 = <1095000 1100000 1105000>; - opp-microvolt-speed0-pvs1-v0 = <1045000 1050000 1055000>; + opp-microvolt-speed0-pvs0-v0 = <1045000 1100000 1155000>; + opp-microvolt-speed0-pvs1-v0 = <997500 1050000 1102500>; opp-microvolt-speed0-pvs2-v0 = < 995000 1000000 1005000>; opp-microvolt-speed0-pvs3-v0 = < 945000 950000 955000>; }; diff --git a/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8065.dtsi b/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8065.dtsi index f215181470..9c3a24f600 100644 --- a/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8065.dtsi +++ b/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8065.dtsi @@ -86,66 +86,66 @@ /delete-node/opp-1200000000; - opp-384000000 { - opp-microvolt-speed0-pvs0-v0 = <970000 975000 980000>; - opp-microvolt-speed0-pvs1-v0 = <945000 950000 955000>; - opp-microvolt-speed0-pvs2-v0 = <920000 925000 930000>; - opp-microvolt-speed0-pvs3-v0 = <985000 900000 905000>; - opp-microvolt-speed0-pvs4-v0 = <870000 875000 880000>; - opp-microvolt-speed0-pvs5-v0 = <820000 825000 830000>; - opp-microvolt-speed0-pvs6-v0 = <770000 775000 780000>; + opp-384000000 { + opp-microvolt-speed0-pvs0-v0 = <926250 975000 1023750>; + opp-microvolt-speed0-pvs1-v0 = <902500 950000 997500>; + opp-microvolt-speed0-pvs2-v0 = <878750 925000 971250>; + opp-microvolt-speed0-pvs3-v0 = <855000 900000 945000>; + opp-microvolt-speed0-pvs4-v0 = <831250 875000 918750>; + opp-microvolt-speed0-pvs5-v0 = <783750 825000 866250>; + opp-microvolt-speed0-pvs6-v0 = <736250 775000 813750>; }; opp-600000000 { - opp-microvolt-speed0-pvs0-v0 = <995000 1000000 1005000>; - opp-microvolt-speed0-pvs1-v0 = <970000 975000 980000>; - opp-microvolt-speed0-pvs2-v0 = <945000 950000 955000>; - opp-microvolt-speed0-pvs3-v0 = <920000 925000 930000>; - opp-microvolt-speed0-pvs4-v0 = <895000 900000 905000>; - opp-microvolt-speed0-pvs5-v0 = <845000 850000 855000>; - opp-microvolt-speed0-pvs6-v0 = <795000 800000 805000>; + opp-microvolt-speed0-pvs0-v0 = <950000 1000000 1050000>; + opp-microvolt-speed0-pvs1-v0 = <926250 975000 1023750>; + opp-microvolt-speed0-pvs2-v0 = <902500 950000 997500>; + opp-microvolt-speed0-pvs3-v0 = <878750 925000 971250>; + opp-microvolt-speed0-pvs4-v0 = <855000 900000 945000>; + opp-microvolt-speed0-pvs5-v0 = <807500 850000 892500>; + opp-microvolt-speed0-pvs6-v0 = <760000 800000 840000>; }; opp-800000000 { - opp-microvolt-speed0-pvs0-v0 = <1045000 1050000 1055000>; - opp-microvolt-speed0-pvs1-v0 = <1020000 1025000 1030000>; - opp-microvolt-speed0-pvs2-v0 = <995000 1000000 1005000>; - opp-microvolt-speed0-pvs3-v0 = <970000 975000 980000>; - opp-microvolt-speed0-pvs4-v0 = <945000 950000 955000>; - opp-microvolt-speed0-pvs5-v0 = <895000 900000 905000>; - opp-microvolt-speed0-pvs6-v0 = <845000 850000 855000>; + opp-microvolt-speed0-pvs0-v0 = <997500 1050000 1102500>; + opp-microvolt-speed0-pvs1-v0 = <973750 1025000 1076250>; + opp-microvolt-speed0-pvs2-v0 = <950000 1000000 1050000>; + opp-microvolt-speed0-pvs3-v0 = <926250 975000 1023750>; + opp-microvolt-speed0-pvs4-v0 = <902500 950000 997500>; + opp-microvolt-speed0-pvs5-v0 = <855000 900000 945000>; + opp-microvolt-speed0-pvs6-v0 = <807500 850000 892500>; }; opp-1000000000 { - opp-microvolt-speed0-pvs0-v0 = <1095000 1100000 1105000>; - opp-microvolt-speed0-pvs1-v0 = <1070000 1075000 1080000>; - opp-microvolt-speed0-pvs2-v0 = <1045000 1050000 1055000>; - opp-microvolt-speed0-pvs3-v0 = <1020000 1025000 1030000>; - opp-microvolt-speed0-pvs4-v0 = <995000 1000000 1005000>; - opp-microvolt-speed0-pvs5-v0 = <945000 950000 955000>; - opp-microvolt-speed0-pvs6-v0 = <895000 900000 905000>; + opp-microvolt-speed0-pvs0-v0 = <1045000 1100000 1155000>; + opp-microvolt-speed0-pvs1-v0 = <1021250 1075000 1128750>; + opp-microvolt-speed0-pvs2-v0 = <997500 1050000 1102500>; + opp-microvolt-speed0-pvs3-v0 = <973750 1025000 1076250>; + opp-microvolt-speed0-pvs4-v0 = <950000 1000000 1050000>; + opp-microvolt-speed0-pvs5-v0 = <902500 950000 997500>; + opp-microvolt-speed0-pvs6-v0 = <855000 900000 945000>; }; opp-1400000000 { - opp-microvolt-speed0-pvs0-v0 = <1170000 1175000 1180000>; - opp-microvolt-speed0-pvs1-v0 = <1145000 1150000 1155000>; - opp-microvolt-speed0-pvs2-v0 = <1120000 1125000 1130000>; - opp-microvolt-speed0-pvs3-v0 = <1095000 1100000 1105000>; - opp-microvolt-speed0-pvs4-v0 = <1070000 1075000 1080000>; - opp-microvolt-speed0-pvs5-v0 = <1020000 1025000 1030000>; - opp-microvolt-speed0-pvs6-v0 = <970000 975000 980000>; + opp-microvolt-speed0-pvs0-v0 = <1116250 1175000 1233750>; + opp-microvolt-speed0-pvs1-v0 = <1092500 1150000 1207500>; + opp-microvolt-speed0-pvs2-v0 = <1068750 1125000 1181250>; + opp-microvolt-speed0-pvs3-v0 = <1045000 1100000 1155000>; + opp-microvolt-speed0-pvs4-v0 = <1021250 1075000 1128750>; + opp-microvolt-speed0-pvs5-v0 = <973750 1025000 1076250>; + opp-microvolt-speed0-pvs6-v0 = <926250 975000 1023750>; opp-level = <1>; }; opp-1725000000 { opp-hz = /bits/ 64 <1725000000>; - opp-microvolt-speed0-pvs0-v0 = <1257500 1262500 1267500>; - opp-microvolt-speed0-pvs1-v0 = <1220000 1225000 1230000>; - opp-microvolt-speed0-pvs2-v0 = <1195000 1200000 1205000>; - opp-microvolt-speed0-pvs3-v0 = <1170000 1175000 1180000>; - opp-microvolt-speed0-pvs4-v0 = <1145000 1150000 1155000>; - opp-microvolt-speed0-pvs5-v0 = <1095000 1100000 1105000>; - opp-microvolt-speed0-pvs6-v0 = <1045000 1050000 1055000>; + opp-microvolt-speed0-pvs0-v0 = <1199375 1262500 1325625>; + opp-microvolt-speed0-pvs1-v0 = <1163750 1225000 1286250>; + opp-microvolt-speed0-pvs2-v0 = <1140000 1200000 1260000>; + opp-microvolt-speed0-pvs3-v0 = <1116250 1175000 1233750>; + opp-microvolt-speed0-pvs4-v0 = <1092500 1150000 1207500>; + opp-microvolt-speed0-pvs5-v0 = <1045000 1100000 1155000>; + opp-microvolt-speed0-pvs6-v0 = <997500 1050000 1102500>; opp-supported-hw = <0x1>; clock-latency-ns = <100000>; opp-level = <2>; diff --git a/target/linux/ipq806x/patches-5.10/083-ipq8064-dtsi-additions.patch b/target/linux/ipq806x/patches-5.10/083-ipq8064-dtsi-additions.patch index 140eeb54c7..5d1ae2ae3d 100644 --- a/target/linux/ipq806x/patches-5.10/083-ipq8064-dtsi-additions.patch +++ b/target/linux/ipq806x/patches-5.10/083-ipq8064-dtsi-additions.patch @@ -87,10 +87,10 @@ + + opp-384000000 { + opp-hz = /bits/ 64 <384000000>; -+ opp-microvolt-speed0-pvs0-v0 = <995000 1000000 1005000>; -+ opp-microvolt-speed0-pvs1-v0 = <920000 925000 930000>; -+ opp-microvolt-speed0-pvs2-v0 = <870000 875000 880000>; -+ opp-microvolt-speed0-pvs3-v0 = <795000 800000 805000>; ++ opp-microvolt-speed0-pvs0-v0 = <950000 1000000 1050000>; ++ opp-microvolt-speed0-pvs1-v0 = <878750 925000 971250>; ++ opp-microvolt-speed0-pvs2-v0 = <831250 875000 918750>; ++ opp-microvolt-speed0-pvs3-v0 = <760000 800000 840000>; + opp-supported-hw = <0x1>; + clock-latency-ns = <100000>; + opp-level = <0>; @@ -98,10 +98,10 @@ + + opp-600000000 { + opp-hz = /bits/ 64 <600000000>; -+ opp-microvolt-speed0-pvs0-v0 = <1045000 1050000 1055000>; -+ opp-microvolt-speed0-pvs1-v0 = <970000 975000 980000>; -+ opp-microvolt-speed0-pvs2-v0 = <920000 925000 930000>; -+ opp-microvolt-speed0-pvs3-v0 = <845000 850000 855000>; ++ opp-microvolt-speed0-pvs0-v0 = <997500 1050000 1102500>; ++ opp-microvolt-speed0-pvs1-v0 = <926250 975000 1023750>; ++ opp-microvolt-speed0-pvs2-v0 = <878750 925000 971250>; ++ opp-microvolt-speed0-pvs3-v0 = <807500 850000 892500>; + opp-supported-hw = <0x1>; + clock-latency-ns = <100000>; + opp-level = <1>; @@ -109,10 +109,10 @@ + + opp-800000000 { + opp-hz = /bits/ 64 <800000000>; -+ opp-microvolt-speed0-pvs0-v0 = <1095000 1100000 1105000>; -+ opp-microvolt-speed0-pvs1-v0 = <1020000 1025000 1030000>; -+ opp-microvolt-speed0-pvs2-v0 = <990000 995000 1000000>; -+ opp-microvolt-speed0-pvs3-v0 = <895000 900000 905000>; ++ opp-microvolt-speed0-pvs0-v0 = <1045000 1100000 1155000>; ++ opp-microvolt-speed0-pvs1-v0 = <973750 1025000 1076250>; ++ opp-microvolt-speed0-pvs2-v0 = <945250 995000 1044750>; ++ opp-microvolt-speed0-pvs3-v0 = <855000 900000 945000>; + opp-supported-hw = <0x1>; + clock-latency-ns = <100000>; + opp-level = <1>; @@ -120,10 +120,10 @@ + + opp-1000000000 { + opp-hz = /bits/ 64 <1000000000>; -+ opp-microvolt-speed0-pvs0-v0 = <1145000 1150000 1155000>; -+ opp-microvolt-speed0-pvs1-v0 = <1070000 1075000 1080000>; -+ opp-microvolt-speed0-pvs2-v0 = <1020000 1025000 1030000>; -+ opp-microvolt-speed0-pvs3-v0 = <945000 950000 955000>; ++ opp-microvolt-speed0-pvs0-v0 = <1092500 1150000 1207500>; ++ opp-microvolt-speed0-pvs1-v0 = <1021250 1075000 1128750>; ++ opp-microvolt-speed0-pvs2-v0 = <973750 1025000 1076250>; ++ opp-microvolt-speed0-pvs3-v0 = <902500 950000 997500>; + opp-supported-hw = <0x1>; + clock-latency-ns = <100000>; + opp-level = <1>; @@ -131,10 +131,10 @@ + + opp-1200000000 { + opp-hz = /bits/ 64 <1200000000>; -+ opp-microvolt-speed0-pvs0-v0 = <1195000 1200000 1205000>; -+ opp-microvolt-speed0-pvs1-v0 = <1120000 1125000 1130000>; -+ opp-microvolt-speed0-pvs2-v0 = <1070000 1075000 1080000>; -+ opp-microvolt-speed0-pvs3-v0 = <995000 1000000 1005000>; ++ opp-microvolt-speed0-pvs0-v0 = <1140000 1200000 1260000>; ++ opp-microvolt-speed0-pvs1-v0 = <1068750 1125000 1181250>; ++ opp-microvolt-speed0-pvs2-v0 = <1021250 1075000 1128750>; ++ opp-microvolt-speed0-pvs3-v0 = <950000 1000000 1050000>; + opp-supported-hw = <0x1>; + clock-latency-ns = <100000>; + opp-level = <2>; @@ -142,10 +142,10 @@ + + opp-1400000000 { + opp-hz = /bits/ 64 <1400000000>; -+ opp-microvolt-speed0-pvs0-v0 = <1245000 1250000 1255000>; -+ opp-microvolt-speed0-pvs1-v0 = <1170000 1175000 1180000>; -+ opp-microvolt-speed0-pvs2-v0 = <1120000 1125000 1130000>; -+ opp-microvolt-speed0-pvs3-v0 = <1045000 1050000 1055000>; ++ opp-microvolt-speed0-pvs0-v0 = <1187500 1250000 1312500>; ++ opp-microvolt-speed0-pvs1-v0 = <1116250 1175000 1233750>; ++ opp-microvolt-speed0-pvs2-v0 = <1068750 1125000 1181250>; ++ opp-microvolt-speed0-pvs3-v0 = <997500 1050000 1102500>; + opp-supported-hw = <0x1>; + clock-latency-ns = <100000>; + opp-level = <2>; @@ -674,7 +674,7 @@ pcie0: pci@1b500000 { compatible = "qcom,pcie-ipq8064"; reg = <0x1b500000 0x1000 -@@ -739,6 +1332,59 @@ +@@ -751,6 +1344,59 @@ status = "disabled"; }; @@ -734,7 +734,7 @@ vsdcc_fixed: vsdcc-regulator { compatible = "regulator-fixed"; regulator-name = "SDCC Power"; -@@ -814,4 +1460,17 @@ +@@ -826,4 +1472,17 @@ }; }; }; From 3bae740311eae85f9bbd2c4794ae575dfc34f1eb Mon Sep 17 00:00:00 2001 From: Ansuel Smith Date: Thu, 8 Apr 2021 15:09:32 +0200 Subject: [PATCH 31/62] ipq806x: add missing wakeup-source for gpio keys wakeup-source is required for gpio keys to fix error genirq: irq_chip msmgpio did not update eff. affinity mask Signed-off-by: Ansuel Smith --- .../arch/arm/boot/dts/qcom-ipq8062-wg2600hp3.dts | 8 ++++++++ .../arch/arm/boot/dts/qcom-ipq8064-ad7200.dts | 8 ++++++++ .../arch/arm/boot/dts/qcom-ipq8064-c2600.dts | 8 ++++++++ .../arch/arm/boot/dts/qcom-ipq8064-d7800.dts | 6 ++++++ .../arch/arm/boot/dts/qcom-ipq8064-ea7500-v1.dts | 4 ++++ .../arch/arm/boot/dts/qcom-ipq8064-ea8500.dts | 6 ++++++ .../files/arch/arm/boot/dts/qcom-ipq8064-g10.dts | 8 ++++++++ .../arch/arm/boot/dts/qcom-ipq8064-r7500.dts | 6 ++++++ .../arch/arm/boot/dts/qcom-ipq8064-r7500v2.dts | 6 ++++++ .../arm/boot/dts/qcom-ipq8064-unifi-ac-hd.dts | 1 + .../arch/arm/boot/dts/qcom-ipq8064-vr2600v.dts | 10 ++++++++++ .../arch/arm/boot/dts/qcom-ipq8064-wg2600hp.dts | 8 ++++++++ .../arch/arm/boot/dts/qcom-ipq8064-wpq864.dts | 2 ++ .../arm/boot/dts/qcom-ipq8064-wxr-2533dhp.dts | 16 ++++++++++++++++ .../arch/arm/boot/dts/qcom-ipq8065-nbg6817.dts | 6 ++++++ .../arch/arm/boot/dts/qcom-ipq8068-ecw5410.dts | 2 ++ 16 files changed, 105 insertions(+) diff --git a/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8062-wg2600hp3.dts b/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8062-wg2600hp3.dts index d234b94a46..3e04618d57 100644 --- a/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8062-wg2600hp3.dts +++ b/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8062-wg2600hp3.dts @@ -33,12 +33,16 @@ label = "reset"; gpios = <&qcom_pinmux 24 GPIO_ACTIVE_LOW>; linux,code = ; + debounce-interval = <60>; + wakeup-source; }; wps { label = "wps"; gpios = <&qcom_pinmux 22 GPIO_ACTIVE_LOW>; linux,code = ; + debounce-interval = <60>; + wakeup-source; }; mode0 { @@ -46,6 +50,8 @@ gpios = <&qcom_pinmux 40 GPIO_ACTIVE_LOW>; linux,code = ; linux,input-type = ; + debounce-interval = <60>; + wakeup-source; }; mode1 { @@ -53,6 +59,8 @@ gpios = <&qcom_pinmux 41 GPIO_ACTIVE_LOW>; linux,code = ; linux,input-type = ; + debounce-interval = <60>; + wakeup-source; }; }; diff --git a/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-ad7200.dts b/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-ad7200.dts index 9ccf3d74ac..6cb21fc4f3 100644 --- a/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-ad7200.dts +++ b/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-ad7200.dts @@ -22,24 +22,32 @@ label = "wifi"; gpios = <&qcom_pinmux 54 GPIO_ACTIVE_LOW>; linux,code = ; + debounce-interval = <60>; + wakeup-source; }; reset { label = "reset"; gpios = <&qcom_pinmux 7 GPIO_ACTIVE_LOW>; linux,code = ; + debounce-interval = <60>; + wakeup-source; }; wps { label = "wps"; gpios = <&qcom_pinmux 67 GPIO_ACTIVE_LOW>; linux,code = ; + debounce-interval = <60>; + wakeup-source; }; led_enable { label = "led-enable"; gpios = <&qcom_pinmux 53 GPIO_ACTIVE_LOW>; linux,code = ; + debounce-interval = <60>; + wakeup-source; }; }; diff --git a/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-c2600.dts b/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-c2600.dts index 3f2a90fdee..cef1aba344 100644 --- a/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-c2600.dts +++ b/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-c2600.dts @@ -20,24 +20,32 @@ label = "wifi"; gpios = <&qcom_pinmux 49 GPIO_ACTIVE_LOW>; linux,code = ; + debounce-interval = <60>; + wakeup-source; }; reset { label = "reset"; gpios = <&qcom_pinmux 64 GPIO_ACTIVE_LOW>; linux,code = ; + debounce-interval = <60>; + wakeup-source; }; wps { label = "wps"; gpios = <&qcom_pinmux 65 GPIO_ACTIVE_LOW>; linux,code = ; + debounce-interval = <60>; + wakeup-source; }; ledswitch { label = "ledswitch"; gpios = <&qcom_pinmux 16 GPIO_ACTIVE_LOW>; linux,code = ; + debounce-interval = <60>; + wakeup-source; }; }; diff --git a/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-d7800.dts b/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-d7800.dts index aeeb040ad8..82535cc86b 100644 --- a/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-d7800.dts +++ b/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-d7800.dts @@ -33,18 +33,24 @@ label = "wifi"; gpios = <&qcom_pinmux 6 GPIO_ACTIVE_LOW>; linux,code = ; + debounce-interval = <60>; + wakeup-source; }; reset { label = "reset"; gpios = <&qcom_pinmux 54 GPIO_ACTIVE_LOW>; linux,code = ; + debounce-interval = <60>; + wakeup-source; }; wps { label = "wps"; gpios = <&qcom_pinmux 65 GPIO_ACTIVE_LOW>; linux,code = ; + debounce-interval = <60>; + wakeup-source; }; }; diff --git a/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-ea7500-v1.dts b/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-ea7500-v1.dts index 176807163e..9d82d52d27 100644 --- a/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-ea7500-v1.dts +++ b/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-ea7500-v1.dts @@ -32,12 +32,16 @@ label = "reset"; gpios = <&qcom_pinmux 68 GPIO_ACTIVE_LOW>; linux,code = ; + debounce-interval = <60>; + wakeup-source; }; wps { label = "wps"; gpios = <&qcom_pinmux 65 GPIO_ACTIVE_LOW>; linux,code = ; + debounce-interval = <60>; + wakeup-source; }; }; diff --git a/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-ea8500.dts b/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-ea8500.dts index 9b01ae0328..1c6a4bdacd 100644 --- a/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-ea8500.dts +++ b/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-ea8500.dts @@ -27,18 +27,24 @@ label = "wifi"; gpios = <&qcom_pinmux 67 GPIO_ACTIVE_LOW>; linux,code = ; + debounce-interval = <60>; + wakeup-source; }; reset { label = "reset"; gpios = <&qcom_pinmux 68 GPIO_ACTIVE_LOW>; linux,code = ; + debounce-interval = <60>; + wakeup-source; }; wps { label = "wps"; gpios = <&qcom_pinmux 65 GPIO_ACTIVE_LOW>; linux,code = ; + debounce-interval = <60>; + wakeup-source; }; }; diff --git a/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-g10.dts b/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-g10.dts index ccefc23011..45efb2b46f 100644 --- a/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-g10.dts +++ b/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-g10.dts @@ -86,24 +86,32 @@ label = "ir-remote"; gpios = <&qcom_pinmux 15 GPIO_ACTIVE_LOW>; linux,code = ; + debounce-interval = <60>; + wakeup-source; }; reset { label = "reset"; gpios = <&qcom_pinmux 16 GPIO_ACTIVE_LOW>; linux,code = ; + debounce-interval = <60>; + wakeup-source; }; wps5g { label = "wps5g"; gpios = <&qcom_pinmux 64 GPIO_ACTIVE_LOW>; linux,code = ; + debounce-interval = <60>; + wakeup-source; }; wps2g { label = "wps2g"; gpios = <&qcom_pinmux 65 GPIO_ACTIVE_LOW>; linux,code = ; + debounce-interval = <60>; + wakeup-source; }; }; }; diff --git a/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-r7500.dts b/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-r7500.dts index 1f457d9944..1dd4563153 100644 --- a/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-r7500.dts +++ b/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-r7500.dts @@ -44,18 +44,24 @@ label = "wifi"; gpios = <&qcom_pinmux 6 GPIO_ACTIVE_LOW>; linux,code = ; + debounce-interval = <60>; + wakeup-source; }; reset { label = "reset"; gpios = <&qcom_pinmux 54 GPIO_ACTIVE_LOW>; linux,code = ; + debounce-interval = <60>; + wakeup-source; }; wps { label = "wps"; gpios = <&qcom_pinmux 65 GPIO_ACTIVE_LOW>; linux,code = ; + debounce-interval = <60>; + wakeup-source; }; }; diff --git a/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-r7500v2.dts b/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-r7500v2.dts index f190433277..71c4c3b1a3 100644 --- a/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-r7500v2.dts +++ b/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-r7500v2.dts @@ -40,18 +40,24 @@ label = "wifi"; gpios = <&qcom_pinmux 6 GPIO_ACTIVE_LOW>; linux,code = ; + debounce-interval = <60>; + wakeup-source; }; reset { label = "reset"; gpios = <&qcom_pinmux 54 GPIO_ACTIVE_LOW>; linux,code = ; + debounce-interval = <60>; + wakeup-source; }; wps { label = "wps"; gpios = <&qcom_pinmux 65 GPIO_ACTIVE_LOW>; linux,code = ; + debounce-interval = <60>; + wakeup-source; }; }; diff --git a/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-unifi-ac-hd.dts b/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-unifi-ac-hd.dts index 672be3ca2c..d6ac1fef1d 100644 --- a/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-unifi-ac-hd.dts +++ b/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-unifi-ac-hd.dts @@ -46,6 +46,7 @@ gpios = <&qcom_pinmux 68 GPIO_ACTIVE_LOW>; linux,code = ; debounce-interval = <60>; + wakeup-source; }; }; }; diff --git a/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-vr2600v.dts b/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-vr2600v.dts index ea7d0235ce..893addf240 100644 --- a/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-vr2600v.dts +++ b/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-vr2600v.dts @@ -29,30 +29,40 @@ label = "wifi"; gpios = <&qcom_pinmux 54 GPIO_ACTIVE_LOW>; linux,code = ; + debounce-interval = <60>; + wakeup-source; }; reset { label = "reset"; gpios = <&qcom_pinmux 64 GPIO_ACTIVE_LOW>; linux,code = ; + debounce-interval = <60>; + wakeup-source; }; wps { label = "wps"; gpios = <&qcom_pinmux 65 GPIO_ACTIVE_LOW>; linux,code = ; + debounce-interval = <60>; + wakeup-source; }; dect { label = "dect"; gpios = <&qcom_pinmux 67 GPIO_ACTIVE_LOW>; linux,code = ; + debounce-interval = <60>; + wakeup-source; }; ledswitch { label = "ledswitch"; gpios = <&qcom_pinmux 68 GPIO_ACTIVE_LOW>; linux,code = ; + debounce-interval = <60>; + wakeup-source; }; }; diff --git a/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-wg2600hp.dts b/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-wg2600hp.dts index 23898e0221..635e9fc8f9 100644 --- a/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-wg2600hp.dts +++ b/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-wg2600hp.dts @@ -29,12 +29,16 @@ label = "wps"; gpios = <&qcom_pinmux 16 GPIO_ACTIVE_LOW>; linux,code = ; + debounce-interval = <60>; + wakeup-source; }; reset { label = "reset"; gpios = <&qcom_pinmux 54 GPIO_ACTIVE_LOW>; linux,code = ; + debounce-interval = <60>; + wakeup-source; }; bridge { @@ -42,6 +46,8 @@ gpios = <&qcom_pinmux 24 GPIO_ACTIVE_LOW>; linux,code = ; linux,input-type = ; + debounce-interval = <60>; + wakeup-source; }; converter { @@ -49,6 +55,8 @@ gpios = <&qcom_pinmux 25 GPIO_ACTIVE_LOW>; linux,code = ; linux,input-type = ; + debounce-interval = <60>; + wakeup-source; }; }; diff --git a/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-wpq864.dts b/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-wpq864.dts index 69be60b019..ec5d5047aa 100644 --- a/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-wpq864.dts +++ b/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-wpq864.dts @@ -83,6 +83,8 @@ label = "reset"; gpios = <&qcom_pinmux 54 GPIO_ACTIVE_LOW>; linux,code = ; + debounce-interval = <60>; + wakeup-source; }; }; diff --git a/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-wxr-2533dhp.dts b/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-wxr-2533dhp.dts index d80bfa204d..8c4e3b71e3 100644 --- a/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-wxr-2533dhp.dts +++ b/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-wxr-2533dhp.dts @@ -91,30 +91,40 @@ label = "power"; gpios = <&qcom_pinmux 58 GPIO_ACTIVE_LOW>; linux,code = ; + debounce-interval = <60>; + wakeup-source; }; reset { label = "reset"; gpios = <&qcom_pinmux 54 GPIO_ACTIVE_LOW>; linux,code = ; + debounce-interval = <60>; + wakeup-source; }; wps { label = "wps"; gpios = <&qcom_pinmux 65 GPIO_ACTIVE_LOW>; linux,code = ; + debounce-interval = <60>; + wakeup-source; }; eject { label = "eject"; gpios = <&qcom_pinmux 6 GPIO_ACTIVE_LOW>; linux,code = ; + debounce-interval = <60>; + wakeup-source; }; guest { label = "guest"; gpios = <&qcom_pinmux 64 GPIO_ACTIVE_LOW>; linux,code = ; + debounce-interval = <60>; + wakeup-source; }; ap { @@ -122,6 +132,8 @@ gpios = <&qcom_pinmux 55 GPIO_ACTIVE_LOW>; linux,code = ; linux,input-type = ; + debounce-interval = <60>; + wakeup-source; }; router { @@ -129,6 +141,8 @@ gpios = <&qcom_pinmux 56 GPIO_ACTIVE_LOW>; linux,code = ; linux,input-type = ; + debounce-interval = <60>; + wakeup-source; }; auto { @@ -136,6 +150,8 @@ gpios = <&qcom_pinmux 57 GPIO_ACTIVE_LOW>; linux,code = ; linux,input-type = ; + debounce-interval = <60>; + wakeup-source; }; }; }; diff --git a/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8065-nbg6817.dts b/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8065-nbg6817.dts index 34b9c5fc87..969ca724e3 100644 --- a/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8065-nbg6817.dts +++ b/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8065-nbg6817.dts @@ -36,18 +36,24 @@ gpios = <&qcom_pinmux 53 GPIO_ACTIVE_LOW>; linux,code = ; linux,input-type = ; + debounce-interval = <60>; + wakeup-source; }; reset { label = "reset"; gpios = <&qcom_pinmux 54 GPIO_ACTIVE_LOW>; linux,code = ; + debounce-interval = <60>; + wakeup-source; }; wps { label = "wps"; gpios = <&qcom_pinmux 65 GPIO_ACTIVE_LOW>; linux,code = ; + debounce-interval = <60>; + wakeup-source; }; }; diff --git a/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8068-ecw5410.dts b/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8068-ecw5410.dts index 1d159714db..43bed451cb 100644 --- a/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8068-ecw5410.dts +++ b/target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8068-ecw5410.dts @@ -57,6 +57,8 @@ label = "reset"; gpios = <&qcom_pinmux 25 GPIO_ACTIVE_LOW>; linux,code = ; + debounce-interval = <60>; + wakeup-source; }; }; From 9e8d62e42117bd05040618cb094565587e51a6f4 Mon Sep 17 00:00:00 2001 From: Birger Koblitz Date: Thu, 29 Apr 2021 22:53:59 +0200 Subject: [PATCH 32/62] realtek: enable CRC offloading Enables CRC calculation offloading on RTL8380/8390/9300. Tested on Zyxel XGS1210-10 (RTL9302)/GS1900-48 (RTL8390)/GS1900-10HP (RTL8382) On the Zyxel GS1900-10HP, an increase of 5% in iperf3 send throughput and 11% in receive throughput is seen. Signed-off-by: Birger Koblitz --- .../drivers/net/ethernet/rtl838x_eth.c | 123 ++++++++++++++---- 1 file changed, 96 insertions(+), 27 deletions(-) diff --git a/target/linux/realtek/files-5.4/drivers/net/ethernet/rtl838x_eth.c b/target/linux/realtek/files-5.4/drivers/net/ethernet/rtl838x_eth.c index 2f678b7384..38b2901652 100644 --- a/target/linux/realtek/files-5.4/drivers/net/ethernet/rtl838x_eth.c +++ b/target/linux/realtek/files-5.4/drivers/net/ethernet/rtl838x_eth.c @@ -234,19 +234,21 @@ struct dsa_tag { u16 port; u8 l2_offloaded; u8 prio; + bool crc_error; }; bool rtl838x_decode_tag(struct p_hdr *h, struct dsa_tag *t) { t->reason = h->cpu_tag[3] & 0xf; - if (t->reason != 15) - pr_debug("Reason: %d\n", t->reason); t->queue = (h->cpu_tag[0] & 0xe0) >> 5; + t->port = h->cpu_tag[1] & 0x1f; + t->crc_error = t->reason == 13; + + pr_debug("Reason: %d\n", t->reason); if (t->reason != 4) // NIC_RX_REASON_SPECIAL_TRAP t->l2_offloaded = 1; else t->l2_offloaded = 0; - t->port = h->cpu_tag[1] & 0x1f; return t->l2_offloaded; } @@ -254,15 +256,31 @@ bool rtl838x_decode_tag(struct p_hdr *h, struct dsa_tag *t) bool rtl839x_decode_tag(struct p_hdr *h, struct dsa_tag *t) { t->reason = h->cpu_tag[4] & 0x1f; - if (t->reason != 31) + t->queue = (h->cpu_tag[3] & 0xe000) >> 13; + t->port = h->cpu_tag[1] & 0x3f; + t->crc_error = h->cpu_tag[3] & BIT(2); + pr_debug("Reason: %d\n", t->reason); - t->queue = (h->cpu_tag[3] & 0xe000) >> 13; if ((t->reason != 7) && (t->reason != 8)) // NIC_RX_REASON_RMA_USR t->l2_offloaded = 1; else t->l2_offloaded = 0; - - t->port = h->cpu_tag[1] & 0x3f; + + return t->l2_offloaded; +} + +bool rtl930x_decode_tag(struct p_hdr *h, struct dsa_tag *t) +{ + t->reason = h->cpu_tag[7] & 0x3f; + t->queue = (h->cpu_tag[2] >> 11) & 0x1f; + t->port = (h->cpu_tag[0] >> 8) & 0x1f; + t->crc_error = h->cpu_tag[1] & BIT(6); + + pr_debug("Reason %d, port %d, queue %d\n", t->reason, t->port, t->queue); + if (t->reason >= 19 && t->reason <= 27) + t->l2_offloaded = 0; + else + t->l2_offloaded = 1; return t->l2_offloaded; } @@ -270,24 +288,19 @@ bool rtl839x_decode_tag(struct p_hdr *h, struct dsa_tag *t) bool rtl931x_decode_tag(struct p_hdr *h, struct dsa_tag *t) { t->reason = h->cpu_tag[7] & 0x3f; - pr_debug("Reason %d\n", t->reason); t->queue = (h->cpu_tag[2] >> 11) & 0x1f; + t->port = (h->cpu_tag[0] >> 8) & 0x3f; + t->crc_error = h->cpu_tag[1] & BIT(6); + + pr_debug("Reason %d, port %d, queue %d\n", t->reason, t->port, t->queue); if (t->reason >= 19 && t->reason <= 27) t->l2_offloaded = 0; else t->l2_offloaded = 1; - t->port = (h->cpu_tag[0] >> 8) & 0x3f; return t->l2_offloaded; } -bool rtl930x_decode_tag(struct p_hdr *h, struct dsa_tag *t) -{ - rtl931x_decode_tag(h, t); - t->port &= 0x1f; - return t->l2_offloaded; -} - /* * Discard the RX ring-buffers, called as part of the net-ISR * when the buffer runs over @@ -731,8 +744,9 @@ static void rtl838x_hw_en_rxtx(struct rtl838x_eth_priv *priv) * | MEDIA_SEL */ sw_w32(0x6192F, priv->r->mac_force_mode_ctrl + priv->cpu_port * 4); - /* allow CRC errors on CPU-port */ - sw_w32_mask(0, 0x8, priv->r->mac_port_ctrl(priv->cpu_port)); + + /* Enable CRC checks on CPU-port */ + sw_w32_mask(0, BIT(3), priv->r->mac_port_ctrl(priv->cpu_port)); } static void rtl839x_hw_en_rxtx(struct rtl838x_eth_priv *priv) @@ -746,8 +760,8 @@ static void rtl839x_hw_en_rxtx(struct rtl838x_eth_priv *priv) /* Enable DMA */ sw_w32_mask(0, RX_EN | TX_EN, priv->r->dma_if_ctrl); - /* Restart TX/RX to CPU port */ - sw_w32_mask(0x0, 0x3, priv->r->mac_port_ctrl(priv->cpu_port)); + /* Restart TX/RX to CPU port, enable CRC checking */ + sw_w32_mask(0x0, 0x3 | BIT(3), priv->r->mac_port_ctrl(priv->cpu_port)); /* CPU port joins Lookup Miss Flooding Portmask */ // TODO: The code below should also work for the RTL838x @@ -784,8 +798,8 @@ static void rtl93xx_hw_en_rxtx(struct rtl838x_eth_priv *priv) /* Enable DMA */ sw_w32_mask(0, RX_EN_93XX | TX_EN_93XX, priv->r->dma_if_ctrl); - /* Restart TX/RX to CPU port */ - sw_w32_mask(0x0, 0x3, priv->r->mac_port_ctrl(priv->cpu_port)); + /* Restart TX/RX to CPU port, enable CRC checking */ + sw_w32_mask(0x0, 0x3 | BIT(4), priv->r->mac_port_ctrl(priv->cpu_port)); sw_w32_mask(0, BIT(priv->cpu_port), RTL930X_L2_UNKN_UC_FLD_PMSK); sw_w32(0x217, priv->r->mac_force_mode_ctrl + priv->cpu_port * 4); @@ -1115,15 +1129,20 @@ static int rtl838x_eth_tx(struct sk_buff *skb, struct net_device *dev) if (netdev_uses_dsa(dev) && skb->data[len-4] == 0x80 && skb->data[len-3] > 0 && skb->data[len-3] < 28 && skb->data[len-2] == 0x10 && skb->data[len-1] == 0x00) { - /* Reuse tag space for CRC */ + /* Reuse tag space for CRC if possible */ dest_port = skb->data[len-3]; len -= 4; } - if (len < ETH_ZLEN) - len = ETH_ZLEN; - /* ASIC expects that packet includes CRC, so we extend by 4 bytes */ - len += 4; + len += 4; // Add space for CRC + + // On RTL8380 SoCs, the packet needs extra padding + if (priv->family_id == RTL8380_FAMILY_ID) { + if (len < ETH_ZLEN) + len = ETH_ZLEN; // SoC not automatically padding to ETH_ZLEN + else + len += 4; + } if (skb_padto(skb, len)) { ret = NETDEV_TX_OK; @@ -1280,6 +1299,12 @@ static int rtl838x_hw_receive(struct net_device *dev, int r, int budget) tag.queue, len, tag.reason, tag.port); skb->protocol = eth_type_trans(skb, dev); + if (dev->features & NETIF_F_RXCSUM) { + if (tag.crc_error) + skb_checksum_none_assert(skb); + else + skb->ip_summed = CHECKSUM_UNNECESSARY; + } dev->stats.rx_packets++; dev->stats.rx_bytes += len; @@ -1837,6 +1862,40 @@ static int rtl838x_mdio_remove(struct rtl838x_eth_priv *priv) return 0; } +static netdev_features_t rtl838x_fix_features(struct net_device *dev, + netdev_features_t features) +{ + return features; +} + +static int rtl83xx_set_features(struct net_device *dev, netdev_features_t features) +{ + struct rtl838x_eth_priv *priv = netdev_priv(dev); + + if ((features ^ dev->features) & NETIF_F_RXCSUM) { + if (!(features & NETIF_F_RXCSUM)) + sw_w32_mask(BIT(3), 0, priv->r->mac_port_ctrl(priv->cpu_port)); + else + sw_w32_mask(0, BIT(4), priv->r->mac_port_ctrl(priv->cpu_port)); + } + + return 0; +} + +static int rtl93xx_set_features(struct net_device *dev, netdev_features_t features) +{ + struct rtl838x_eth_priv *priv = netdev_priv(dev); + + if ((features ^ dev->features) & NETIF_F_RXCSUM) { + if (!(features & NETIF_F_RXCSUM)) + sw_w32_mask(BIT(4), 0, priv->r->mac_port_ctrl(priv->cpu_port)); + else + sw_w32_mask(0, BIT(4), priv->r->mac_port_ctrl(priv->cpu_port)); + } + + return 0; +} + static const struct net_device_ops rtl838x_eth_netdev_ops = { .ndo_open = rtl838x_eth_open, .ndo_stop = rtl838x_eth_stop, @@ -1846,6 +1905,8 @@ static const struct net_device_ops rtl838x_eth_netdev_ops = { .ndo_validate_addr = eth_validate_addr, .ndo_set_rx_mode = rtl838x_eth_set_multicast_list, .ndo_tx_timeout = rtl838x_eth_tx_timeout, + .ndo_set_features = rtl83xx_set_features, + .ndo_fix_features = rtl838x_fix_features, }; static const struct net_device_ops rtl839x_eth_netdev_ops = { @@ -1857,6 +1918,8 @@ static const struct net_device_ops rtl839x_eth_netdev_ops = { .ndo_validate_addr = eth_validate_addr, .ndo_set_rx_mode = rtl839x_eth_set_multicast_list, .ndo_tx_timeout = rtl838x_eth_tx_timeout, + .ndo_set_features = rtl83xx_set_features, + .ndo_fix_features = rtl838x_fix_features, }; static const struct net_device_ops rtl930x_eth_netdev_ops = { @@ -1868,6 +1931,8 @@ static const struct net_device_ops rtl930x_eth_netdev_ops = { .ndo_validate_addr = eth_validate_addr, .ndo_set_rx_mode = rtl930x_eth_set_multicast_list, .ndo_tx_timeout = rtl838x_eth_tx_timeout, + .ndo_set_features = rtl93xx_set_features, + .ndo_fix_features = rtl838x_fix_features, }; static const struct net_device_ops rtl931x_eth_netdev_ops = { @@ -1879,6 +1944,8 @@ static const struct net_device_ops rtl931x_eth_netdev_ops = { .ndo_validate_addr = eth_validate_addr, .ndo_set_rx_mode = rtl931x_eth_set_multicast_list, .ndo_tx_timeout = rtl838x_eth_tx_timeout, + .ndo_set_features = rtl93xx_set_features, + .ndo_fix_features = rtl838x_fix_features, }; static const struct phylink_mac_ops rtl838x_phylink_ops = { @@ -1975,6 +2042,8 @@ static int __init rtl838x_eth_probe(struct platform_device *pdev) dev->ethtool_ops = &rtl838x_ethtool_ops; dev->min_mtu = ETH_ZLEN; dev->max_mtu = 1536; + dev->features = NETIF_F_RXCSUM | NETIF_F_HW_CSUM; + dev->hw_features = NETIF_F_RXCSUM; priv->id = soc_info.id; priv->family_id = soc_info.family; From cf4edabefd649f4126b8150c01adec81a6c17410 Mon Sep 17 00:00:00 2001 From: Birger Koblitz Date: Thu, 29 Apr 2021 22:59:55 +0200 Subject: [PATCH 33/62] realtek: add IGMP/MLD snooping support This adds snooping support for IGMP and MLD on RTL8380/90/9300 by trapping IGMP and MLD packets to the CPU. Signed-off-by: Birger Koblitz --- .../files-5.4/drivers/net/ethernet/rtl838x_eth.c | 10 ++++++---- .../files-5.4/drivers/net/ethernet/rtl838x_eth.h | 1 + 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/target/linux/realtek/files-5.4/drivers/net/ethernet/rtl838x_eth.c b/target/linux/realtek/files-5.4/drivers/net/ethernet/rtl838x_eth.c index 38b2901652..c5c6e3b6b7 100644 --- a/target/linux/realtek/files-5.4/drivers/net/ethernet/rtl838x_eth.c +++ b/target/linux/realtek/files-5.4/drivers/net/ethernet/rtl838x_eth.c @@ -897,28 +897,30 @@ static int rtl838x_eth_open(struct net_device *ndev) switch (priv->family_id) { case RTL8380_FAMILY_ID: rtl838x_hw_en_rxtx(priv); - /* Trap IGMP traffic to CPU-Port */ + /* Trap IGMP/MLD traffic to CPU-Port */ sw_w32(0x3, RTL838X_SPCL_TRAP_IGMP_CTRL); /* Flush learned FDB entries on link down of a port */ sw_w32_mask(0, BIT(7), RTL838X_L2_CTRL_0); break; + case RTL8390_FAMILY_ID: rtl839x_hw_en_rxtx(priv); + // Trap MLD and IGMP messages to CPU_PORT sw_w32(0x3, RTL839X_SPCL_TRAP_IGMP_CTRL); /* Flush learned FDB entries on link down of a port */ sw_w32_mask(0, BIT(7), RTL839X_L2_CTRL_0); break; + case RTL9300_FAMILY_ID: rtl93xx_hw_en_rxtx(priv); /* Flush learned FDB entries on link down of a port */ sw_w32_mask(0, BIT(7), RTL930X_L2_CTRL); - sw_w32_mask(BIT(28), 0, RTL930X_L2_PORT_SABLK_CTRL); - sw_w32_mask(BIT(28), 0, RTL930X_L2_PORT_DABLK_CTRL); + // Trap MLD and IGMP messages to CPU_PORT + sw_w32((0x2 << 3) | 0x2, RTL930X_VLAN_APP_PKT_CTRL); break; case RTL9310_FAMILY_ID: rtl93xx_hw_en_rxtx(priv); -// TODO: Add trapping of IGMP frames to CPU-port break; } diff --git a/target/linux/realtek/files-5.4/drivers/net/ethernet/rtl838x_eth.h b/target/linux/realtek/files-5.4/drivers/net/ethernet/rtl838x_eth.h index d7b4317cbb..c7e97057b3 100644 --- a/target/linux/realtek/files-5.4/drivers/net/ethernet/rtl838x_eth.h +++ b/target/linux/realtek/files-5.4/drivers/net/ethernet/rtl838x_eth.h @@ -177,6 +177,7 @@ #define RTL839X_RMA_CTRL_2 (0x1208) #define RTL839X_RMA_CTRL_3 (0x120C) +#define RTL930X_VLAN_APP_PKT_CTRL (0xA23C) #define RTL930X_RMA_CTRL_0 (0x9E60) #define RTL930X_RMA_CTRL_1 (0x9E64) #define RTL930X_RMA_CTRL_2 (0x9E68) From d4972627483afa6649f9c337df9d680a130b50b7 Mon Sep 17 00:00:00 2001 From: Birger Koblitz Date: Sat, 1 May 2021 06:31:30 +0200 Subject: [PATCH 34/62] realtek: remove unused FDB print routing remove fdb_dump debugging function Signed-off-by: Birger Koblitz --- .../drivers/net/dsa/rtl83xx/common.c | 21 ------------------- 1 file changed, 21 deletions(-) diff --git a/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/common.c b/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/common.c index 6940afa7f2..d09894bbaf 100644 --- a/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/common.c +++ b/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/common.c @@ -18,27 +18,6 @@ extern const struct dsa_switch_ops rtl930x_switch_ops; DEFINE_MUTEX(smi_lock); -// TODO: unused -static void dump_fdb(struct rtl838x_switch_priv *priv) -{ - struct rtl838x_l2_entry e; - int i; - - mutex_lock(&priv->reg_mutex); - - for (i = 0; i < priv->fib_entries; i++) { - priv->r->read_l2_entry_using_hash(i >> 2, i & 0x3, &e); - - if (!e.valid) /* Check for invalid entry */ - continue; - - pr_debug("-> port %02d: mac %pM, vid: %d, rvid: %d, MC: %d, %d\n", - e.port, &e.mac[0], e.vid, e.rvid, e.is_ip_mc, e.is_ipv6_mc); - } - - mutex_unlock(&priv->reg_mutex); -} - int rtl83xx_port_get_stp_state(struct rtl838x_switch_priv *priv, int port) { u32 msti = 0; From 637deabb4a50812c978ef3b768609720b8856a9b Mon Sep 17 00:00:00 2001 From: Birger Koblitz Date: Sat, 1 May 2021 06:48:29 +0200 Subject: [PATCH 35/62] realtek: Add L2 hash bucket size Adds a hash-bucket size attribute for the different SoCs, in order to accomodate the buckets with 8 entries of the L2-forwarding tables on RTL93XX in contrast to only 4 on RTL83XX. Signed-off-by: Birger Koblitz --- .../realtek/files-5.4/drivers/net/dsa/rtl83xx/common.c | 7 ++++--- .../realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl838x.h | 1 + 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/common.c b/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/common.c index d09894bbaf..a380906b92 100644 --- a/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/common.c +++ b/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/common.c @@ -123,7 +123,6 @@ void rtl_table_read(struct table_reg *r, int idx) cmd |= BIT(r->c_bit + 1) | (r->tbl << r->t_bit) | (idx & (BIT(r->t_bit) - 1)); sw_w32(cmd, r->addr); - pr_debug("Writing %08x to %x for read\n", cmd, r->addr); do { } while (sw_r32(r->addr) & BIT(r->c_bit + 1)); } @@ -135,8 +134,6 @@ void rtl_table_write(struct table_reg *r, int idx) u32 cmd = r->rmode ? 0 : BIT(r->c_bit); cmd |= BIT(r->c_bit + 1) | (r->tbl << r->t_bit) | (idx & (BIT(r->t_bit) - 1)); - pr_debug("Writing %08x to %x for write, value %08x\n", - cmd, r->addr, sw_r32(0xb344)); sw_w32(cmd, r->addr); do { } while (sw_r32(r->addr) & BIT(r->c_bit + 1)); } @@ -572,6 +569,7 @@ static int __init rtl83xx_sw_probe(struct platform_device *pdev) priv->fib_entries = 8192; rtl8380_get_version(priv); priv->n_lags = 8; + priv->l2_bucket_size = 4; break; case RTL8390_FAMILY_ID: priv->ds->ops = &rtl83xx_switch_ops; @@ -584,6 +582,7 @@ static int __init rtl83xx_sw_probe(struct platform_device *pdev) priv->fib_entries = 16384; rtl8390_get_version(priv); priv->n_lags = 16; + priv->l2_bucket_size = 4; break; case RTL9300_FAMILY_ID: priv->ds->ops = &rtl930x_switch_ops; @@ -597,6 +596,7 @@ static int __init rtl83xx_sw_probe(struct platform_device *pdev) priv->version = RTL8390_VERSION_A; priv->n_lags = 16; sw_w32(1, RTL930X_ST_CTRL); + priv->l2_bucket_size = 8; break; case RTL9310_FAMILY_ID: priv->ds->ops = &rtl930x_switch_ops; @@ -609,6 +609,7 @@ static int __init rtl83xx_sw_probe(struct platform_device *pdev) priv->fib_entries = 16384; priv->version = RTL8390_VERSION_A; priv->n_lags = 16; + priv->l2_bucket_size = 8; break; } pr_debug("Chip version %c\n", priv->version); diff --git a/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl838x.h b/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl838x.h index d5ca153a10..40f76a5081 100644 --- a/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl838x.h +++ b/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl838x.h @@ -460,6 +460,7 @@ struct rtl838x_switch_priv { u8 port_width; u64 irq_mask; u32 fib_entries; + int l2_bucket_size; struct dentry *dbgfs_dir; int n_lags; u64 lags_port_members[MAX_LAGS]; From 515d9c85f22241b4ec08dbb3d63f6469ef412384 Mon Sep 17 00:00:00 2001 From: Birger Koblitz Date: Sat, 1 May 2021 08:22:36 +0200 Subject: [PATCH 36/62] realtek: improve EEE support for RTL8380/8390/9300 Clean up and fix bugs in the EEE support for RTL8380/90 Adds EEE support for RTL9300 Signed-off-by: Birger Koblitz --- .../files-5.4/drivers/net/dsa/rtl83xx/dsa.c | 92 +++++++++---------- .../drivers/net/dsa/rtl83xx/rtl838x.c | 81 ++++++++++++++++ .../drivers/net/dsa/rtl83xx/rtl838x.h | 15 +++ .../drivers/net/dsa/rtl83xx/rtl839x.c | 80 ++++++++++++++++ .../drivers/net/dsa/rtl83xx/rtl930x.c | 92 +++++++++++++++++++ 5 files changed, 314 insertions(+), 46 deletions(-) diff --git a/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/dsa.c b/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/dsa.c index 987b47dc8f..1e902a1d7a 100644 --- a/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/dsa.c +++ b/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/dsa.c @@ -577,58 +577,55 @@ static void rtl83xx_port_disable(struct dsa_switch *ds, int port) priv->ports[port].enable = false; } -static int rtl83xx_get_mac_eee(struct dsa_switch *ds, int port, - struct ethtool_eee *e) -{ - struct rtl838x_switch_priv *priv = ds->priv; - - pr_debug("%s: port %d", __func__, port); - e->supported = SUPPORTED_100baseT_Full | SUPPORTED_1000baseT_Full; - if (sw_r32(priv->r->mac_force_mode_ctrl(port)) & BIT(9)) - e->advertised |= ADVERTISED_100baseT_Full; - - if (sw_r32(priv->r->mac_force_mode_ctrl(port)) & BIT(10)) - e->advertised |= ADVERTISED_1000baseT_Full; - - e->eee_enabled = priv->ports[port].eee_enabled; - pr_debug("enabled: %d, active %x\n", e->eee_enabled, e->advertised); - - if (sw_r32(RTL838X_MAC_EEE_ABLTY) & BIT(port)) { - e->lp_advertised = ADVERTISED_100baseT_Full; - e->lp_advertised |= ADVERTISED_1000baseT_Full; - } - - e->eee_active = !!(e->advertised & e->lp_advertised); - pr_debug("active: %d, lp %x\n", e->eee_active, e->lp_advertised); - - return 0; -} - static int rtl83xx_set_mac_eee(struct dsa_switch *ds, int port, struct ethtool_eee *e) { struct rtl838x_switch_priv *priv = ds->priv; - pr_debug("%s: port %d", __func__, port); - if (e->eee_enabled) { - pr_debug("Globally enabling EEE\n"); - sw_w32_mask(0x4, 0, RTL838X_SMI_GLB_CTRL); - } - if (e->eee_enabled) { - pr_debug("Enabling EEE for MAC %d\n", port); - sw_w32_mask(0, 3 << 9, priv->r->mac_force_mode_ctrl(port)); - sw_w32_mask(0, BIT(port), RTL838X_EEE_PORT_TX_EN); - sw_w32_mask(0, BIT(port), RTL838X_EEE_PORT_RX_EN); - priv->ports[port].eee_enabled = true; - e->eee_enabled = true; - } else { - pr_debug("Disabling EEE for MAC %d\n", port); - sw_w32_mask(3 << 9, 0, priv->r->mac_force_mode_ctrl(port)); - sw_w32_mask(BIT(port), 0, RTL838X_EEE_PORT_TX_EN); - sw_w32_mask(BIT(port), 0, RTL838X_EEE_PORT_RX_EN); - priv->ports[port].eee_enabled = false; - e->eee_enabled = false; + if (e->eee_enabled && !priv->eee_enabled) { + pr_info("Globally enabling EEE\n"); + priv->r->init_eee(priv, true); } + + priv->r->port_eee_set(priv, port, e->eee_enabled); + + if (e->eee_enabled) + pr_info("Enabled EEE for port %d\n", port); + else + pr_info("Disabled EEE for port %d\n", port); + return 0; +} + +static int rtl83xx_get_mac_eee(struct dsa_switch *ds, int port, + struct ethtool_eee *e) +{ + struct rtl838x_switch_priv *priv = ds->priv; + + e->supported = SUPPORTED_100baseT_Full | SUPPORTED_1000baseT_Full; + + priv->r->eee_port_ability(priv, e, port); + + e->eee_enabled = priv->ports[port].eee_enabled; + + e->eee_active = !!(e->advertised & e->lp_advertised); + + return 0; +} + +static int rtl93xx_get_mac_eee(struct dsa_switch *ds, int port, + struct ethtool_eee *e) +{ + struct rtl838x_switch_priv *priv = ds->priv; + + e->supported = SUPPORTED_100baseT_Full | SUPPORTED_1000baseT_Full + | SUPPORTED_2500baseX_Full; + + priv->r->eee_port_ability(priv, e, port); + + e->eee_enabled = priv->ports[port].eee_enabled; + + e->eee_active = !!(e->advertised & e->lp_advertised); + return 0; } @@ -1332,6 +1329,9 @@ const struct dsa_switch_ops rtl930x_switch_ops = { .port_enable = rtl83xx_port_enable, .port_disable = rtl83xx_port_disable, + .get_mac_eee = rtl93xx_get_mac_eee, + .set_mac_eee = rtl83xx_set_mac_eee, + .set_ageing_time = rtl83xx_set_l2aging, .port_bridge_join = rtl83xx_port_bridge_join, .port_bridge_leave = rtl83xx_port_bridge_leave, diff --git a/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl838x.c b/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl838x.c index de9e83bb8d..d0e5162b66 100644 --- a/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl838x.c +++ b/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl838x.c @@ -263,6 +263,84 @@ void rtl838x_traffic_disable(int source, int dest) rtl838x_mask_port_reg(BIT(dest), 0, rtl838x_port_iso_ctrl(source)); } +/* + * Enables or disables the EEE/EEEP capability of a port + */ +static void rtl838x_port_eee_set(struct rtl838x_switch_priv *priv, int port, bool enable) +{ + u32 v; + + // This works only for Ethernet ports, and on the RTL838X, ports from 24 are SFP + if (port >= 24) + return; + + pr_debug("In %s: setting port %d to %d\n", __func__, port, enable); + v = enable ? 0x3 : 0x0; + + // Set EEE state for 100 (bit 9) & 1000MBit (bit 10) + sw_w32_mask(0x3 << 9, v << 9, priv->r->mac_force_mode_ctrl(port)); + + // Set TX/RX EEE state + if (enable) { + sw_w32_mask(0, BIT(port), RTL838X_EEE_PORT_TX_EN); + sw_w32_mask(0, BIT(port), RTL838X_EEE_PORT_RX_EN); + } else { + sw_w32_mask(BIT(port), 0, RTL838X_EEE_PORT_TX_EN); + sw_w32_mask(BIT(port), 0, RTL838X_EEE_PORT_RX_EN); + } + priv->ports[port].eee_enabled = enable; +} + + +/* + * Get EEE own capabilities and negotiation result + */ +static int rtl838x_eee_port_ability(struct rtl838x_switch_priv *priv, + struct ethtool_eee *e, int port) +{ + u64 link; + + if (port >= 24) + return 0; + + link = rtl839x_get_port_reg_le(RTL838X_MAC_LINK_STS); + if (!(link & BIT(port))) + return 0; + + if (sw_r32(rtl838x_mac_force_mode_ctrl(port)) & BIT(9)) + e->advertised |= ADVERTISED_100baseT_Full; + + if (sw_r32(rtl838x_mac_force_mode_ctrl(port)) & BIT(10)) + e->advertised |= ADVERTISED_1000baseT_Full; + + if (sw_r32(RTL838X_MAC_EEE_ABLTY) & BIT(port)) { + e->lp_advertised = ADVERTISED_100baseT_Full; + e->lp_advertised |= ADVERTISED_1000baseT_Full; + return 1; + } + + return 0; +} + +static void rtl838x_init_eee(struct rtl838x_switch_priv *priv, bool enable) +{ + int i; + + pr_info("Setting up EEE, state: %d\n", enable); + sw_w32_mask(0x4, 0, RTL838X_SMI_GLB_CTRL); + + /* Set timers for EEE */ + sw_w32(0x5001411, RTL838X_EEE_TX_TIMER_GIGA_CTRL); + sw_w32(0x5001417, RTL838X_EEE_TX_TIMER_GELITE_CTRL); + + // Enable EEE MAC support on ports + for (i = 0; i < priv->cpu_port; i++) { + if (priv->ports[i].phy) + rtl838x_port_eee_set(priv, i, enable); + } + priv->eee_enabled = enable; +} + const struct rtl838x_reg rtl838x_reg = { .mask_port_reg_be = rtl838x_mask_port_reg, .set_port_reg_be = rtl838x_set_port_reg, @@ -317,6 +395,9 @@ const struct rtl838x_reg rtl838x_reg = { .trk_mbr_ctr = rtl838x_trk_mbr_ctr, .rma_bpdu_fld_pmask = RTL838X_RMA_BPDU_FLD_PMSK, .spcl_trap_eapol_ctrl = RTL838X_SPCL_TRAP_EAPOL_CTRL, + .init_eee = rtl838x_init_eee, + .port_eee_set = rtl838x_port_eee_set, + .eee_port_ability = rtl838x_eee_port_ability, }; irqreturn_t rtl838x_switch_irq(int irq, void *dev_id) diff --git a/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl838x.h b/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl838x.h index 40f76a5081..928a23af77 100644 --- a/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl838x.h +++ b/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl838x.h @@ -162,6 +162,16 @@ #define RTL838X_EEE_TX_TIMER_GIGA_CTRL (0xaa04) #define RTL838X_EEE_TX_TIMER_GELITE_CTRL (0xaa08) +#define RTL839X_EEE_TX_TIMER_GELITE_CTRL (0x042C) +#define RTL839X_EEE_TX_TIMER_GIGA_CTRL (0x0430) +#define RTL839X_EEE_TX_TIMER_10G_CTRL (0x0434) +#define RTL839X_EEE_CTRL(p) (0x8008 + ((p) << 7)) +#define RTL839X_MAC_EEE_ABLTY (0x03C8) + +#define RTL930X_MAC_EEE_ABLTY (0xCB34) +#define RTL930X_EEE_CTRL(p) (0x3274 + ((p) << 6)) +#define RTL930X_EEEP_PORT_CTRL(p) (0x3278 + ((p) << 6)) + /* L2 functionality */ #define RTL838X_L2_CTRL_0 (0x3200) #define RTL839X_L2_CTRL_0 (0x3800) @@ -440,6 +450,10 @@ struct rtl838x_reg { int (*trk_mbr_ctr)(int group); int rma_bpdu_fld_pmask; int spcl_trap_eapol_ctrl; + void (*init_eee)(struct rtl838x_switch_priv *priv, bool enable); + void (*port_eee_set)(struct rtl838x_switch_priv *priv, int port, bool enable); + int (*eee_port_ability)(struct rtl838x_switch_priv *priv, + struct ethtool_eee *e, int port); }; struct rtl838x_switch_priv { @@ -466,6 +480,7 @@ struct rtl838x_switch_priv { u64 lags_port_members[MAX_LAGS]; struct net_device *lag_devs[MAX_LAGS]; struct notifier_block nb; + bool eee_enabled; }; void rtl838x_dbgfs_init(struct rtl838x_switch_priv *priv); diff --git a/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl839x.c b/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl839x.c index 5106bd2e9d..b9fdd2c955 100644 --- a/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl839x.c +++ b/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl839x.c @@ -456,6 +456,83 @@ static void rtl839x_stp_set(struct rtl838x_switch_priv *priv, u16 msti, u32 port priv->r->exec_tbl0_cmd(cmd); } +/* + * Enables or disables the EEE/EEEP capability of a port + */ +void rtl839x_port_eee_set(struct rtl838x_switch_priv *priv, int port, bool enable) +{ + u32 v; + + // This works only for Ethernet ports, and on the RTL839X, ports above 47 are SFP + if (port >= 48) + return; + + enable = true; + pr_debug("In %s: setting port %d to %d\n", __func__, port, enable); + v = enable ? 0xf : 0x0; + + // Set EEE for 100, 500, 1000MBit and 10GBit + sw_w32_mask(0xf << 8, v << 8, rtl839x_mac_force_mode_ctrl(port)); + + // Set TX/RX EEE state + v = enable ? 0x3 : 0x0; + sw_w32(v, RTL839X_EEE_CTRL(port)); + + priv->ports[port].eee_enabled = enable; +} + +/* + * Get EEE own capabilities and negotiation result + */ +int rtl839x_eee_port_ability(struct rtl838x_switch_priv *priv, struct ethtool_eee *e, int port) +{ + u64 link, a; + + if (port >= 48) + return 0; + + link = rtl839x_get_port_reg_le(RTL839X_MAC_LINK_STS); + if (!(link & BIT_ULL(port))) + return 0; + + if (sw_r32(rtl839x_mac_force_mode_ctrl(port)) & BIT(8)) + e->advertised |= ADVERTISED_100baseT_Full; + + if (sw_r32(rtl839x_mac_force_mode_ctrl(port)) & BIT(10)) + e->advertised |= ADVERTISED_1000baseT_Full; + + a = rtl839x_get_port_reg_le(RTL839X_MAC_EEE_ABLTY); + pr_info("Link partner: %016llx\n", a); + if (rtl839x_get_port_reg_le(RTL839X_MAC_EEE_ABLTY) & BIT_ULL(port)) { + e->lp_advertised = ADVERTISED_100baseT_Full; + e->lp_advertised |= ADVERTISED_1000baseT_Full; + return 1; + } + + return 0; +} + +static void rtl839x_init_eee(struct rtl838x_switch_priv *priv, bool enable) +{ + int i; + + pr_info("Setting up EEE, state: %d\n", enable); + + // Set wake timer for TX and pause timer both to 0x21 + sw_w32_mask(0xff << 20| 0xff, 0x21 << 20| 0x21, RTL839X_EEE_TX_TIMER_GELITE_CTRL); + // Set pause wake timer for GIGA-EEE to 0x11 + sw_w32_mask(0xff << 20, 0x11 << 20, RTL839X_EEE_TX_TIMER_GIGA_CTRL); + // Set pause wake timer for 10GBit ports to 0x11 + sw_w32_mask(0xff << 20, 0x11 << 20, RTL839X_EEE_TX_TIMER_10G_CTRL); + + // Setup EEE on all ports + for (i = 0; i < priv->cpu_port; i++) { + if (priv->ports[i].phy) + rtl839x_port_eee_set(priv, i, enable); + } + priv->eee_enabled = enable; +} + const struct rtl838x_reg rtl839x_reg = { .mask_port_reg_be = rtl839x_mask_port_reg_be, .set_port_reg_be = rtl839x_set_port_reg_be, @@ -510,4 +587,7 @@ const struct rtl838x_reg rtl839x_reg = { .trk_mbr_ctr = rtl839x_trk_mbr_ctr, .rma_bpdu_fld_pmask = RTL839X_RMA_BPDU_FLD_PMSK, .spcl_trap_eapol_ctrl = RTL839X_SPCL_TRAP_EAPOL_CTRL, + .init_eee = rtl839x_init_eee, + .port_eee_set = rtl839x_port_eee_set, + .eee_port_ability = rtl839x_eee_port_ability, }; diff --git a/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl930x.c b/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl930x.c index 59c283903b..6c2fde1040 100644 --- a/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl930x.c +++ b/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl930x.c @@ -551,6 +551,95 @@ u32 rtl930x_hash(struct rtl838x_switch_priv *priv, u64 seed) return h; } +/* + * Enables or disables the EEE/EEEP capability of a port + */ +void rtl930x_port_eee_set(struct rtl838x_switch_priv *priv, int port, bool enable) +{ + u32 v; + + // This works only for Ethernet ports, and on the RTL930X, ports from 26 are SFP + if (port >= 26) + return; + + pr_debug("In %s: setting port %d to %d\n", __func__, port, enable); + v = enable ? 0x3f : 0x0; + + // Set EEE/EEEP state for 100, 500, 1000MBit and 2.5, 5 and 10GBit + sw_w32_mask(0, v << 10, rtl930x_mac_force_mode_ctrl(port)); + + // Set TX/RX EEE state + v = enable ? 0x3 : 0x0; + sw_w32(v, RTL930X_EEE_CTRL(port)); + + priv->ports[port].eee_enabled = enable; +} + +/* + * Get EEE own capabilities and negotiation result + */ +int rtl930x_eee_port_ability(struct rtl838x_switch_priv *priv, struct ethtool_eee *e, int port) +{ + u32 link, a; + + if (port >= 26) + return -ENOTSUPP; + + pr_info("In %s, port %d\n", __func__, port); + link = sw_r32(RTL930X_MAC_LINK_STS); + link = sw_r32(RTL930X_MAC_LINK_STS); + if (!(link & BIT(port))) + return 0; + + pr_info("Setting advertised\n"); + if (sw_r32(rtl930x_mac_force_mode_ctrl(port)) & BIT(10)) + e->advertised |= ADVERTISED_100baseT_Full; + + if (sw_r32(rtl930x_mac_force_mode_ctrl(port)) & BIT(12)) + e->advertised |= ADVERTISED_1000baseT_Full; + + if (priv->ports[port].is2G5 && sw_r32(rtl930x_mac_force_mode_ctrl(port)) & BIT(13)) { + pr_info("ADVERTISING 2.5G EEE\n"); + e->advertised |= ADVERTISED_2500baseX_Full; + } + + if (priv->ports[port].is10G && sw_r32(rtl930x_mac_force_mode_ctrl(port)) & BIT(15)) + e->advertised |= ADVERTISED_10000baseT_Full; + + a = sw_r32(RTL930X_MAC_EEE_ABLTY); + a = sw_r32(RTL930X_MAC_EEE_ABLTY); + pr_info("Link partner: %08x\n", a); + if (a & BIT(port)) { + e->lp_advertised = ADVERTISED_100baseT_Full; + e->lp_advertised |= ADVERTISED_1000baseT_Full; + if (priv->ports[port].is2G5) + e->lp_advertised |= ADVERTISED_2500baseX_Full; + if (priv->ports[port].is10G) + e->lp_advertised |= ADVERTISED_10000baseT_Full; + } + + // Read 2x to clear latched state + a = sw_r32(RTL930X_EEEP_PORT_CTRL(port)); + a = sw_r32(RTL930X_EEEP_PORT_CTRL(port)); + pr_info("%s RTL930X_EEEP_PORT_CTRL: %08x\n", __func__, a); + + return 0; +} + +static void rtl930x_init_eee(struct rtl838x_switch_priv *priv, bool enable) +{ + int i; + + pr_info("Setting up EEE, state: %d\n", enable); + + // Setup EEE on all ports + for (i = 0; i < priv->cpu_port; i++) { + if (priv->ports[i].phy) + rtl930x_port_eee_set(priv, i, enable); + } + + priv->eee_enabled = enable; +} const struct rtl838x_reg rtl930x_reg = { .mask_port_reg_be = rtl838x_mask_port_reg, @@ -604,4 +693,7 @@ const struct rtl838x_reg rtl930x_reg = { .vlan_port_tag_sts_ctrl = RTL930X_VLAN_PORT_TAG_STS_CTRL, .trk_mbr_ctr = rtl930x_trk_mbr_ctr, .rma_bpdu_fld_pmask = RTL930X_RMA_BPDU_FLD_PMSK, + .init_eee = rtl930x_init_eee, + .port_eee_set = rtl930x_port_eee_set, + .eee_port_ability = rtl930x_eee_port_ability, }; From 408990464c77abdb341d18346d192c0c14c9461c Mon Sep 17 00:00:00 2001 From: Birger Koblitz Date: Sat, 1 May 2021 09:18:48 +0200 Subject: [PATCH 37/62] realtek: Add support for clause45 PHYs This adds support for the MMD access registers the RTL-SoCs use to access clause 45 PHYs via mdio. This new interface is used to add EEE-support for the RTL8226 Signed-off-by: Birger Koblitz --- .../include/asm/mach-rtl838x/mach-rtl83xx.h | 23 +- .../drivers/net/dsa/rtl83xx/rtl838x.c | 73 +++ .../drivers/net/dsa/rtl83xx/rtl839x.c | 70 ++- .../drivers/net/dsa/rtl83xx/rtl930x.c | 2 - .../drivers/net/dsa/rtl83xx/rtl931x.c | 69 ++- .../files-5.4/drivers/net/phy/rtl83xx-phy.c | 562 +++++++++++------- 6 files changed, 564 insertions(+), 235 deletions(-) diff --git a/target/linux/realtek/files-5.4/arch/mips/include/asm/mach-rtl838x/mach-rtl83xx.h b/target/linux/realtek/files-5.4/arch/mips/include/asm/mach-rtl838x/mach-rtl83xx.h index fc401e5481..0abfc6f4d2 100644 --- a/target/linux/realtek/files-5.4/arch/mips/include/asm/mach-rtl838x/mach-rtl83xx.h +++ b/target/linux/realtek/files-5.4/arch/mips/include/asm/mach-rtl838x/mach-rtl83xx.h @@ -313,8 +313,29 @@ #define RTL839X_SMI_PORT_POLLING_CTRL (0x03fc) #define RTL839X_PHYREG_ACCESS_CTRL (0x03DC) #define RTL839X_PHYREG_CTRL (0x03E0) -#define RTL839X_PHYREG_PORT_CTRL(p) (0x03E4 + ((p >> 5) << 2)) +#define RTL839X_PHYREG_PORT_CTRL (0x03E4) #define RTL839X_PHYREG_DATA_CTRL (0x03F0) +#define RTL839X_PHYREG_MMD_CTRL (0x3F4) + +#define RTL930X_SMI_GLB_CTRL (0xCA00) +#define RTL930X_SMI_POLL_CTRL (0xca90) +#define RTL930X_SMI_PORT0_15_POLLING_SEL (0xCA08) +#define RTL930X_SMI_PORT16_27_POLLING_SEL (0xCA0C) +#define RTL930X_SMI_PORT0_5_ADDR (0xCB80) +#define RTL930X_SMI_ACCESS_PHY_CTRL_0 (0xCB70) +#define RTL930X_SMI_ACCESS_PHY_CTRL_1 (0xCB74) +#define RTL930X_SMI_ACCESS_PHY_CTRL_2 (0xCB78) +#define RTL930X_SMI_ACCESS_PHY_CTRL_3 (0xCB7C) + +#define RTL931X_SMI_GLB_CTRL1 (0x0CBC) +#define RTL931X_SMI_GLB_CTRL0 (0x0CC0) +#define RTL931X_SMI_PORT_POLLING_CTRL (0x0CCC) +#define RTL931X_SMI_INDRT_ACCESS_CTRL_0 (0x0C00) +#define RTL931X_SMI_INDRT_ACCESS_CTRL_1 (0x0C04) +#define RTL931X_SMI_INDRT_ACCESS_CTRL_2 (0x0C08) +#define RTL931X_SMI_INDRT_ACCESS_CTRL_3 (0x0C10) +#define RTL931X_SMI_INDRT_ACCESS_BC_PHYID_CTRL (0x0C14) +#define RTL931X_SMI_INDRT_ACCESS_MMD_CTRL (0xC18) #define RTL930X_SMI_GLB_CTRL (0xCA00) #define RTL930X_SMI_POLL_CTRL (0xca90) diff --git a/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl838x.c b/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl838x.c index d0e5162b66..773225b3c4 100644 --- a/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl838x.c +++ b/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl838x.c @@ -513,6 +513,79 @@ timeout: return -ETIMEDOUT; } +/* + * Read an mmd register of a PHY + */ +int rtl838x_read_mmd_phy(u32 port, u32 addr, u32 reg, u32 *val) +{ + u32 v; + + mutex_lock(&smi_lock); + + if (rtl838x_smi_wait_op(10000)) + goto timeout; + + sw_w32(1 << port, RTL838X_SMI_ACCESS_PHY_CTRL_0); + mdelay(10); + + sw_w32_mask(0xffff0000, port << 16, RTL838X_SMI_ACCESS_PHY_CTRL_2); + + v = addr << 16 | reg; + sw_w32(v, RTL838X_SMI_ACCESS_PHY_CTRL_3); + + /* mmd-access | read | cmd-start */ + v = 1 << 1 | 0 << 2 | 1; + sw_w32(v, RTL838X_SMI_ACCESS_PHY_CTRL_1); + + if (rtl838x_smi_wait_op(10000)) + goto timeout; + + *val = sw_r32(RTL838X_SMI_ACCESS_PHY_CTRL_2) & 0xffff; + + mutex_unlock(&smi_lock); + return 0; + +timeout: + mutex_unlock(&smi_lock); + return -ETIMEDOUT; +} + +/* + * Write to an mmd register of a PHY + */ +int rtl838x_write_mmd_phy(u32 port, u32 addr, u32 reg, u32 val) +{ + u32 v; + + pr_debug("MMD write: port %d, dev %d, reg %d, val %x\n", port, addr, reg, val); + val &= 0xffff; + mutex_lock(&smi_lock); + + if (rtl838x_smi_wait_op(10000)) + goto timeout; + + sw_w32(1 << port, RTL838X_SMI_ACCESS_PHY_CTRL_0); + mdelay(10); + + sw_w32_mask(0xffff0000, val << 16, RTL838X_SMI_ACCESS_PHY_CTRL_2); + + sw_w32_mask(0x1f << 16, addr << 16, RTL838X_SMI_ACCESS_PHY_CTRL_3); + sw_w32_mask(0xffff, reg, RTL838X_SMI_ACCESS_PHY_CTRL_3); + /* mmd-access | write | cmd-start */ + v = 1 << 1 | 1 << 2 | 1; + sw_w32(v, RTL838X_SMI_ACCESS_PHY_CTRL_1); + + if (rtl838x_smi_wait_op(10000)) + goto timeout; + + mutex_unlock(&smi_lock); + return 0; + +timeout: + mutex_unlock(&smi_lock); + return -ETIMEDOUT; +} + void rtl8380_get_version(struct rtl838x_switch_priv *priv) { u32 rw_save, info_save; diff --git a/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl839x.c b/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl839x.c index b9fdd2c955..b2846deb11 100644 --- a/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl839x.c +++ b/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl839x.c @@ -321,6 +321,7 @@ int rtl8390_sds_power(int mac, int val) return 0; } + int rtl839x_read_phy(u32 port, u32 page, u32 reg, u32 *val) { u32 v; @@ -358,10 +359,9 @@ int rtl839x_write_phy(u32 port, u32 page, u32 reg, u32 val) return -ENOTSUPP; mutex_lock(&smi_lock); - /* Clear both port registers */ - sw_w32(0, RTL839X_PHYREG_PORT_CTRL(0)); - sw_w32(0, RTL839X_PHYREG_PORT_CTRL(0) + 4); - sw_w32_mask(0, BIT(port), RTL839X_PHYREG_PORT_CTRL(port)); + + // Set PHY to access + rtl839x_set_port_reg_le(BIT_ULL(port), RTL839X_PHYREG_PORT_CTRL); sw_w32_mask(0xffff0000, val << 16, RTL839X_PHYREG_DATA_CTRL); @@ -383,6 +383,68 @@ int rtl839x_write_phy(u32 port, u32 page, u32 reg, u32 val) return err; } +/* + * Read an mmd register of the PHY + */ +int rtl839x_read_mmd_phy(u32 port, u32 devnum, u32 regnum, u32 *val) +{ + int err = 0; + u32 v; + + mutex_lock(&smi_lock); + + // Set PHY to access + sw_w32_mask(0xffff << 16, port << 16, RTL839X_PHYREG_DATA_CTRL); + + // Set MMD device number and register to write to + sw_w32(devnum << 16 | (regnum & 0xffff), RTL839X_PHYREG_MMD_CTRL); + + v = BIT(2) | BIT(0); // MMD-access | EXEC + sw_w32(v, RTL839X_PHYREG_ACCESS_CTRL); + + do { + v = sw_r32(RTL839X_PHYREG_ACCESS_CTRL); + } while (v & BIT(0)); + // There is no error-checking via BIT 1 of v, as it does not seem to be set correctly + *val = (sw_r32(RTL839X_PHYREG_DATA_CTRL) & 0xffff); + pr_debug("%s: port %d, regnum: %x, val: %x (err %d)\n", __func__, port, regnum, *val, err); + + mutex_unlock(&smi_lock); + + return err; +} + +/* + * Write to an mmd register of the PHY + */ +int rtl839x_write_mmd_phy(u32 port, u32 devnum, u32 regnum, u32 val) +{ + int err = 0; + u32 v; + + mutex_lock(&smi_lock); + + // Set PHY to access + rtl839x_set_port_reg_le(BIT_ULL(port), RTL839X_PHYREG_PORT_CTRL); + + // Set data to write + sw_w32_mask(0xffff << 16, val << 16, RTL839X_PHYREG_DATA_CTRL); + + // Set MMD device number and register to write to + sw_w32(devnum << 16 | (regnum & 0xffff), RTL839X_PHYREG_MMD_CTRL); + + v = BIT(3) | BIT(2) | BIT(0); // WRITE | MMD-access | EXEC + sw_w32(v, RTL839X_PHYREG_ACCESS_CTRL); + + do { + v = sw_r32(RTL839X_PHYREG_ACCESS_CTRL); + } while (v & BIT(0)); + + pr_debug("%s: port %d, regnum: %x, val: %x (err %d)\n", __func__, port, regnum, val, err); + mutex_unlock(&smi_lock); + return err; +} + void rtl8390_get_version(struct rtl838x_switch_priv *priv) { u32 info; diff --git a/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl930x.c b/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl930x.c index 6c2fde1040..4214c7694d 100644 --- a/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl930x.c +++ b/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl930x.c @@ -382,7 +382,6 @@ int rtl9300_sds_power(int mac, int val) return 0; } - int rtl930x_write_phy(u32 port, u32 page, u32 reg, u32 val) { u32 v; @@ -445,7 +444,6 @@ int rtl930x_read_phy(u32 port, u32 page, u32 reg, u32 *val) return err; } - /* * Write to an mmd register of the PHY */ diff --git a/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl931x.c b/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl931x.c index a33941a0eb..f98bf7df29 100644 --- a/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl931x.c +++ b/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl931x.c @@ -175,6 +175,7 @@ static u64 rtl931x_read_cam(int idx, struct rtl838x_l2_entry *e) // TODO: Implement return entry; } + irqreturn_t rtl931x_switch_irq(int irq, void *dev_id) { struct dsa_switch *ds = dev_id; @@ -199,7 +200,6 @@ irqreturn_t rtl931x_switch_irq(int irq, void *dev_id) return IRQ_HANDLED; } - int rtl931x_write_phy(u32 port, u32 page, u32 reg, u32 val) { u32 v; @@ -264,6 +264,73 @@ int rtl931x_read_phy(u32 port, u32 page, u32 reg, u32 *val) return 0; } +/* + * Read an mmd register of the PHY + */ +int rtl931x_read_mmd_phy(u32 port, u32 devnum, u32 regnum, u32 *val) +{ + int err = 0; + u32 v; + int type = 1; // TODO: For C45 PHYs need to set to 2 + + mutex_lock(&smi_lock); + + // Set PHY to access via port-number + sw_w32(port << 5, RTL931X_SMI_INDRT_ACCESS_BC_PHYID_CTRL); + + // Set MMD device number and register to write to + sw_w32(devnum << 16 | (regnum & 0xffff), RTL931X_SMI_INDRT_ACCESS_MMD_CTRL); + + v = type << 2 | BIT(0); // MMD-access-type | EXEC + sw_w32(v, RTL931X_SMI_INDRT_ACCESS_CTRL_0); + + do { + v = sw_r32(RTL931X_SMI_INDRT_ACCESS_CTRL_0); + } while (v & BIT(0)); + + // There is no error-checking via BIT 1 of v, as it does not seem to be set correctly + + *val = (sw_r32(RTL931X_SMI_INDRT_ACCESS_CTRL_3) & 0xffff); + + pr_debug("%s: port %d, regnum: %x, val: %x (err %d)\n", __func__, port, regnum, *val, err); + + mutex_unlock(&smi_lock); + + return err; +} + +/* + * Write to an mmd register of the PHY + */ +int rtl931x_write_mmd_phy(u32 port, u32 devnum, u32 regnum, u32 val) +{ + int err = 0; + u32 v; + int type = 1; // TODO: For C45 PHYs need to set to 2 + + mutex_lock(&smi_lock); + + // Set PHY to access via port-number + sw_w32(port << 5, RTL931X_SMI_INDRT_ACCESS_BC_PHYID_CTRL); + + // Set data to write + sw_w32_mask(0xffff << 16, val << 16, RTL931X_SMI_INDRT_ACCESS_CTRL_3); + + // Set MMD device number and register to write to + sw_w32(devnum << 16 | (regnum & 0xffff), RTL931X_SMI_INDRT_ACCESS_MMD_CTRL); + + v = BIT(4) | type << 2 | BIT(0); // WRITE | MMD-access-type | EXEC + sw_w32(v, RTL931X_SMI_INDRT_ACCESS_CTRL_0); + + do { + v = sw_r32(RTL931X_SMI_INDRT_ACCESS_CTRL_0); + } while (v & BIT(0)); + + pr_debug("%s: port %d, regnum: %x, val: %x (err %d)\n", __func__, port, regnum, val, err); + mutex_unlock(&smi_lock); + return err; +} + void rtl931x_print_matrix(void) { volatile u64 *ptr = RTL838X_SW_BASE + RTL839X_PORT_ISO_CTRL(0); diff --git a/target/linux/realtek/files-5.4/drivers/net/phy/rtl83xx-phy.c b/target/linux/realtek/files-5.4/drivers/net/phy/rtl83xx-phy.c index 78953c6d17..3e187228a9 100644 --- a/target/linux/realtek/files-5.4/drivers/net/phy/rtl83xx-phy.c +++ b/target/linux/realtek/files-5.4/drivers/net/phy/rtl83xx-phy.c @@ -18,12 +18,26 @@ extern struct rtl83xx_soc_info soc_info; extern struct mutex smi_lock; +/* + * This lock protects the state of the SoC automatically polling the PHYs over the SMI + * bus to detect e.g. link and media changes. For operations on the PHYs such as + * patching or other configuration changes such as EEE, polling needs to be disabled + * since otherwise these operations may fails or lead to unpredictable results. + */ +DEFINE_MUTEX(poll_lock); + static const struct firmware rtl838x_8380_fw; static const struct firmware rtl838x_8214fc_fw; static const struct firmware rtl838x_8218b_fw; +int rtl838x_read_mmd_phy(u32 port, u32 devnum, u32 regnum, u32 *val); +int rtl838x_write_mmd_phy(u32 port, u32 devnum, u32 reg, u32 val); +int rtl839x_read_mmd_phy(u32 port, u32 devnum, u32 regnum, u32 *val); +int rtl839x_write_mmd_phy(u32 port, u32 devnum, u32 reg, u32 val); int rtl930x_read_mmd_phy(u32 port, u32 devnum, u32 regnum, u32 *val); -int rtl930x_write_mmd_phy(u32 port, u32 addr, u32 reg, u32 val); +int rtl930x_write_mmd_phy(u32 port, u32 devnum, u32 reg, u32 val); +int rtl931x_read_mmd_phy(u32 port, u32 devnum, u32 regnum, u32 *val); +int rtl931x_write_mmd_phy(u32 port, u32 devnum, u32 reg, u32 val); static int read_phy(u32 port, u32 page, u32 reg, u32 *val) { switch (soc_info.family) { @@ -54,6 +68,93 @@ static int write_phy(u32 port, u32 page, u32 reg, u32 val) return -1; } +static int read_mmd_phy(u32 port, u32 devnum, u32 regnum, u32 *val) +{ + switch (soc_info.family) { + case RTL8380_FAMILY_ID: + return rtl838x_read_mmd_phy(port, devnum, regnum, val); + case RTL8390_FAMILY_ID: + return rtl839x_read_mmd_phy(port, devnum, regnum, val); + case RTL9300_FAMILY_ID: + return rtl930x_read_mmd_phy(port, devnum, regnum, val); + case RTL9310_FAMILY_ID: + return rtl931x_read_mmd_phy(port, devnum, regnum, val); + } + return -1; +} + +int write_mmd_phy(u32 port, u32 devnum, u32 reg, u32 val) +{ + switch (soc_info.family) { + case RTL8380_FAMILY_ID: + return rtl838x_write_mmd_phy(port, devnum, reg, val); + case RTL8390_FAMILY_ID: + return rtl839x_write_mmd_phy(port, devnum, reg, val); + case RTL9300_FAMILY_ID: + return rtl930x_write_mmd_phy(port, devnum, reg, val); + case RTL9310_FAMILY_ID: + return rtl931x_write_mmd_phy(port, devnum, reg, val); + } + return -1; +} + +static u64 disable_polling(int port) +{ + u64 saved_state; + + mutex_lock(&poll_lock); + + switch (soc_info.family) { + case RTL8380_FAMILY_ID: + saved_state = sw_r32(RTL838X_SMI_POLL_CTRL); + sw_w32_mask(BIT(port), 0, RTL838X_SMI_POLL_CTRL); + break; + case RTL8390_FAMILY_ID: + saved_state = sw_r32(RTL839X_SMI_PORT_POLLING_CTRL + 4); + saved_state <<= 32; + saved_state |= sw_r32(RTL839X_SMI_PORT_POLLING_CTRL); + sw_w32_mask(BIT(port % 32), 0, + RTL839X_SMI_PORT_POLLING_CTRL + ((port >> 5) << 2)); + break; + case RTL9300_FAMILY_ID: + saved_state = sw_r32(RTL930X_SMI_POLL_CTRL); + sw_w32_mask(BIT(port), 0, RTL930X_SMI_POLL_CTRL); + break; + case RTL9310_FAMILY_ID: + pr_warn("%s not implemented for RTL931X\n", __func__); + break; + } + + mutex_unlock(&poll_lock); + + return saved_state; +} + +static int resume_polling(u64 saved_state) +{ + mutex_lock(&poll_lock); + + switch (soc_info.family) { + case RTL8380_FAMILY_ID: + sw_w32(saved_state, RTL838X_SMI_POLL_CTRL); + break; + case RTL8390_FAMILY_ID: + sw_w32(saved_state >> 32, RTL839X_SMI_PORT_POLLING_CTRL + 4); + sw_w32(saved_state, RTL839X_SMI_PORT_POLLING_CTRL); + break; + case RTL9300_FAMILY_ID: + sw_w32(saved_state, RTL930X_SMI_POLL_CTRL); + break; + case RTL9310_FAMILY_ID: + pr_warn("%s not implemented for RTL931X\n", __func__); + break; + } + + mutex_unlock(&poll_lock); + + return 0; +} + static void rtl8380_int_phy_on_off(int mac, bool on) { u32 val; @@ -94,18 +195,6 @@ static void rtl8380_phy_reset(int mac) write_phy(mac, 0, 0, val | BIT(15)); } -static void rtl8380_sds_rst(int mac) -{ - u32 offset = (mac == 24) ? 0 : 0x100; - - sw_w32_mask(1 << 11, 0, RTL8380_SDS4_FIB_REG0 + offset); - sw_w32_mask(0x3, 0, RTL838X_SDS4_REG28 + offset); - sw_w32_mask(0x3, 0x3, RTL838X_SDS4_REG28 + offset); - sw_w32_mask(0, 0x1 << 6, RTL838X_SDS4_DUMMY0 + offset); - sw_w32_mask(0x1 << 6, 0, RTL838X_SDS4_DUMMY0 + offset); - pr_info("SERDES reset: %d\n", mac); -} - /* * Reset the SerDes by powering it off and set a new operations mode * of the SerDes. 0x1f is off. Other modes are @@ -307,6 +396,7 @@ static int rtl8393_read_status(struct phy_device *phydev) return err; } + static int rtl8226_read_page(struct phy_device *phydev) { return __phy_read(phydev, 0x1f); @@ -331,20 +421,20 @@ static int rtl8226_read_status(struct phy_device *phydev) // Link status must be read twice for (i = 0; i < 2; i++) { - rtl930x_read_mmd_phy(port, MMD_VEND2, 0xA402, &val); + read_mmd_phy(port, MMD_VEND2, 0xA402, &val); } phydev->link = val & BIT(2) ? 1 : 0; if (!phydev->link) goto out; // Read duplex status - ret = rtl930x_read_mmd_phy(port, MMD_VEND2, 0xA434, &val); + ret = read_mmd_phy(port, MMD_VEND2, 0xA434, &val); if (ret) goto out; phydev->duplex = !!(val & BIT(3)); // Read speed - ret = rtl930x_read_mmd_phy(port, MMD_VEND2, 0xA434, &val); + ret = read_mmd_phy(port, MMD_VEND2, 0xA434, &val); switch (val & 0x0630) { case 0x0000: phydev->speed = SPEED_10; @@ -371,7 +461,7 @@ out: return ret; } -static int rtl8266_advertise_aneg(struct phy_device *phydev) +static int rtl8226_advertise_aneg(struct phy_device *phydev) { int ret = 0; u32 v; @@ -379,7 +469,7 @@ static int rtl8266_advertise_aneg(struct phy_device *phydev) pr_info("In %s\n", __func__); - ret = rtl930x_read_mmd_phy(port, MMD_AN, 16, &v); + ret = read_mmd_phy(port, MMD_AN, 16, &v); if (ret) goto out; @@ -388,31 +478,30 @@ static int rtl8266_advertise_aneg(struct phy_device *phydev) v |= BIT(7); // HD 100M v |= BIT(8); // FD 100M - ret = rtl930x_write_mmd_phy(port, MMD_AN, 16, v); + ret = write_mmd_phy(port, MMD_AN, 16, v); // Allow 1GBit - ret = rtl930x_read_mmd_phy(port, MMD_VEND2, 0xA412, &v); + ret = read_mmd_phy(port, MMD_VEND2, 0xA412, &v); if (ret) goto out; v |= BIT(9); // FD 1000M - ret = rtl930x_write_mmd_phy(port, MMD_VEND2, 0xA412, v); + ret = write_mmd_phy(port, MMD_VEND2, 0xA412, v); if (ret) goto out; // Allow 2.5G - ret = rtl930x_read_mmd_phy(port, MMD_AN, 32, &v); + ret = read_mmd_phy(port, MMD_AN, 32, &v); if (ret) goto out; v |= BIT(7); - ret = rtl930x_write_mmd_phy(port, MMD_AN, 32, v); + ret = write_mmd_phy(port, MMD_AN, 32, v); out: return ret; } - static int rtl8226_config_aneg(struct phy_device *phydev) { int ret = 0; @@ -421,26 +510,26 @@ static int rtl8226_config_aneg(struct phy_device *phydev) pr_info("In %s\n", __func__); if (phydev->autoneg == AUTONEG_ENABLE) { - ret = rtl8266_advertise_aneg(phydev); + ret = rtl8226_advertise_aneg(phydev); if (ret) goto out; // AutoNegotiationEnable - ret = rtl930x_read_mmd_phy(port, MMD_AN, 0, &v); + ret = read_mmd_phy(port, MMD_AN, 0, &v); if (ret) goto out; v |= BIT(12); // Enable AN - ret = rtl930x_write_mmd_phy(port, MMD_AN, 0, v); + ret = write_mmd_phy(port, MMD_AN, 0, v); if (ret) goto out; // RestartAutoNegotiation - ret = rtl930x_read_mmd_phy(port, MMD_VEND2, 0xA400, &v); + ret = read_mmd_phy(port, MMD_VEND2, 0xA400, &v); if (ret) goto out; v |= BIT(9); - ret = rtl930x_write_mmd_phy(port, MMD_VEND2, 0xA400, v); + ret = write_mmd_phy(port, MMD_VEND2, 0xA400, v); } pr_info("%s: Ret is already: %d\n", __func__, ret); @@ -451,6 +540,68 @@ out: return ret; } +static int rtl8226_get_eee(struct phy_device *phydev, + struct ethtool_eee *e) +{ + u32 val; + int addr = phydev->mdio.addr; + + pr_debug("In %s, port %d, was enabled: %d\n", __func__, addr, e->eee_enabled); + + read_mmd_phy(addr, MMD_AN, 60, &val); + if (e->eee_enabled) { + e->eee_enabled = !!(val & BIT(1)); + if (!e->eee_enabled) { + read_mmd_phy(addr, MMD_AN, 62, &val); + e->eee_enabled = !!(val & BIT(0)); + } + } + pr_debug("%s: enabled: %d\n", __func__, e->eee_enabled); + + return 0; +} + +static int rtl8226_set_eee(struct phy_device *phydev, struct ethtool_eee *e) +{ + int port = phydev->mdio.addr; + u64 poll_state; + bool an_enabled; + u32 val; + + pr_info("In %s, port %d, enabled %d\n", __func__, port, e->eee_enabled); + + poll_state = disable_polling(port); + + // Remember aneg state + read_mmd_phy(port, MMD_AN, 0, &val); + an_enabled = !!(val & BIT(12)); + + // Setup 100/1000MBit + read_mmd_phy(port, MMD_AN, 60, &val); + if (e->eee_enabled) + val |= 0x6; + else + val &= 0x6; + write_mmd_phy(port, MMD_AN, 60, val); + + // Setup 2.5GBit + read_mmd_phy(port, MMD_AN, 62, &val); + if (e->eee_enabled) + val |= 0x1; + else + val &= 0x1; + write_mmd_phy(port, MMD_AN, 62, val); + + // RestartAutoNegotiation + read_mmd_phy(port, MMD_VEND2, 0xA400, &val); + val |= BIT(9); + write_mmd_phy(port, MMD_VEND2, 0xA400, val); + + resume_polling(poll_state); + + return 0; +} + static struct fw_header *rtl838x_request_fw(struct phy_device *phydev, const struct firmware *fw, const char *name) @@ -750,79 +901,6 @@ static int rtl8218b_ext_match_phy_device(struct phy_device *phydev) return phydev->phy_id == PHY_ID_RTL8218B_E; } -/* - * Read an mmd register of the PHY - */ -static int rtl83xx_read_mmd_phy(u32 port, u32 addr, u32 reg, u32 *val) -{ - u32 v; - - mutex_lock(&smi_lock); - - if (rtl838x_smi_wait_op(10000)) - goto timeout; - - sw_w32(1 << port, RTL838X_SMI_ACCESS_PHY_CTRL_0); - mdelay(10); - - sw_w32_mask(0xffff0000, port << 16, RTL838X_SMI_ACCESS_PHY_CTRL_2); - - v = addr << 16 | reg; - sw_w32(v, RTL838X_SMI_ACCESS_PHY_CTRL_3); - - /* mmd-access | read | cmd-start */ - v = 1 << 1 | 0 << 2 | 1; - sw_w32(v, RTL838X_SMI_ACCESS_PHY_CTRL_1); - - if (rtl838x_smi_wait_op(10000)) - goto timeout; - - *val = sw_r32(RTL838X_SMI_ACCESS_PHY_CTRL_2) & 0xffff; - - mutex_unlock(&smi_lock); - return 0; - -timeout: - mutex_unlock(&smi_lock); - return -ETIMEDOUT; -} - -/* - * Write to an mmd register of the PHY - */ -static int rtl838x_write_mmd_phy(u32 port, u32 addr, u32 reg, u32 val) -{ - u32 v; - - pr_debug("MMD write: port %d, dev %d, reg %d, val %x\n", port, addr, reg, val); - val &= 0xffff; - mutex_lock(&smi_lock); - - if (rtl838x_smi_wait_op(10000)) - goto timeout; - - sw_w32(1 << port, RTL838X_SMI_ACCESS_PHY_CTRL_0); - mdelay(10); - - sw_w32_mask(0xffff0000, val << 16, RTL838X_SMI_ACCESS_PHY_CTRL_2); - - sw_w32_mask(0x1f << 16, addr << 16, RTL838X_SMI_ACCESS_PHY_CTRL_3); - sw_w32_mask(0xffff, reg, RTL838X_SMI_ACCESS_PHY_CTRL_3); - /* mmd-access | write | cmd-start */ - v = 1 << 1 | 1 << 2 | 1; - sw_w32(v, RTL838X_SMI_ACCESS_PHY_CTRL_1); - - if (rtl838x_smi_wait_op(10000)) - goto timeout; - - mutex_unlock(&smi_lock); - return 0; - -timeout: - mutex_unlock(&smi_lock); - return -ETIMEDOUT; -} - static int rtl8218b_read_mmd(struct phy_device *phydev, int devnum, u16 regnum) { @@ -830,7 +908,7 @@ static int rtl8218b_read_mmd(struct phy_device *phydev, u32 val; int addr = phydev->mdio.addr; - ret = rtl83xx_read_mmd_phy(addr, devnum, regnum, &val); + ret = read_mmd_phy(addr, devnum, regnum, &val); if (ret) return ret; return val; @@ -850,8 +928,7 @@ static int rtl8226_read_mmd(struct phy_device *phydev, int devnum, u16 regnum) int err; u32 val; - err = rtl930x_read_mmd_phy(port, devnum, regnum, &val); - + err = read_mmd_phy(port, devnum, regnum, &val); if (err) return err; return val; @@ -861,7 +938,7 @@ static int rtl8226_write_mmd(struct phy_device *phydev, int devnum, u16 regnum, { int port = phydev->mdio.addr; // the SoC translates port addresses to PHY addr - return rtl930x_write_mmd_phy(port, devnum, regnum, val); + return write_mmd_phy(port, devnum, regnum, val); } static void rtl8380_rtl8214fc_media_set(int mac, bool set_fibre) @@ -957,90 +1034,46 @@ static int rtl8214fc_get_port(struct phy_device *phydev) return PORT_MII; } -static void rtl8218b_eee_set_u_boot(int port, bool enable) -{ - u32 val; - bool an_enabled; - - /* Set GPHY page to copper */ - write_phy(port, 0, 30, 0x0001); - read_phy(port, 0, 0, &val); - an_enabled = val & (1 << 12); - - if (enable) { - /* 100/1000M EEE Capability */ - write_phy(port, 0, 13, 0x0007); - write_phy(port, 0, 14, 0x003C); - write_phy(port, 0, 13, 0x4007); - write_phy(port, 0, 14, 0x0006); - - read_phy(port, 0x0A43, 25, &val); - val |= 1 << 4; - write_phy(port, 0x0A43, 25, val); - } else { - /* 100/1000M EEE Capability */ - write_phy(port, 0, 13, 0x0007); - write_phy(port, 0, 14, 0x003C); - write_phy(port, 0, 13, 0x0007); - write_phy(port, 0, 14, 0x0000); - - read_phy(port, 0x0A43, 25, &val); - val &= ~(1 << 4); - write_phy(port, 0x0A43, 25, val); - } - - /* Restart AN if enabled */ - if (an_enabled) { - read_phy(port, 0, 0, &val); - val |= (1 << 12) | (1 << 9); - write_phy(port, 0, 0, val); - } - - /* GPHY page back to auto*/ - write_phy(port, 0xa42, 29, 0); -} - -// TODO: unused -void rtl8380_rtl8218b_eee_set(int port, bool enable) +/* + * Enable EEE on the RTL8218B PHYs + * The method used is not the preferred way (which would be based on the MAC-EEE state, + * but the only way that works since the kernel first enables EEE in the MAC + * and then sets up the PHY. The MAC-based approach would require the oppsite. + */ +void rtl8218d_eee_set(int port, bool enable) { u32 val; bool an_enabled; pr_debug("In %s %d, enable %d\n", __func__, port, enable); /* Set GPHY page to copper */ - write_phy(port, 0xa42, 29, 0x0001); + write_phy(port, 0xa42, 30, 0x0001); read_phy(port, 0, 0, &val); - an_enabled = val & (1 << 12); + an_enabled = val & BIT(12); - /* MAC based EEE */ - read_phy(port, 0xa43, 25, &val); - val &= ~(1 << 5); - write_phy(port, 0xa43, 25, val); - - /* 100M / 1000M EEE */ - if (enable) - rtl838x_write_mmd_phy(port, 7, 60, 0x6); - else - rtl838x_write_mmd_phy(port, 7, 60, 0); + /* Enable 100M (bit 1) / 1000M (bit 2) EEE */ + read_mmd_phy(port, 7, 60, &val); + val |= BIT(2) | BIT(1); + write_mmd_phy(port, 7, 60, enable ? 0x6 : 0); /* 500M EEE ability */ read_phy(port, 0xa42, 20, &val); if (enable) - val |= 1 << 7; + val |= BIT(7); else - val &= ~(1 << 7); + val &= ~BIT(7); write_phy(port, 0xa42, 20, val); /* Restart AN if enabled */ if (an_enabled) { read_phy(port, 0, 0, &val); - val |= (1 << 12) | (1 << 9); + val |= BIT(9); write_phy(port, 0, 0, val); } /* GPHY page back to auto*/ - write_phy(port, 0xa42, 29, 0); + write_phy(port, 0xa42, 30, 0); } static int rtl8218b_get_eee(struct phy_device *phydev, @@ -1049,16 +1082,21 @@ static int rtl8218b_get_eee(struct phy_device *phydev, u32 val; int addr = phydev->mdio.addr; - pr_debug("In %s, port %d\n", __func__, addr); + pr_debug("In %s, port %d, was enabled: %d\n", __func__, addr, e->eee_enabled); /* Set GPHY page to copper */ write_phy(addr, 0xa42, 29, 0x0001); - rtl83xx_read_mmd_phy(addr, 7, 60, &val); - if (e->eee_enabled && (!!(val & (1 << 7)))) - e->eee_enabled = !!(val & (1 << 7)); - else - e->eee_enabled = 0; + read_phy(addr, 7, 60, &val); + if (e->eee_enabled) { + // Verify vs MAC-based EEE + e->eee_enabled = !!(val & BIT(7)); + if (!e->eee_enabled) { + read_phy(addr, 0x0A43, 25, &val); + e->eee_enabled = !!(val & BIT(4)); + } + } + pr_debug("%s: enabled: %d\n", __func__, e->eee_enabled); /* GPHY page to auto */ write_phy(addr, 0xa42, 29, 0x0000); @@ -1066,49 +1104,24 @@ static int rtl8218b_get_eee(struct phy_device *phydev, return 0; } -// TODO: unused -void rtl8380_rtl8218b_green_set(int mac, bool enable) -{ - u32 val; - - /* Set GPHY page to copper */ - write_phy(mac, 0xa42, 29, 0x0001); - - write_phy(mac, 0, 27, 0x8011); - read_phy(mac, 0, 28, &val); - if (enable) { - val |= 1 << 9; - write_phy(mac, 0, 27, 0x8011); - write_phy(mac, 0, 28, val); - } else { - val &= ~(1 << 9); - write_phy(mac, 0, 27, 0x8011); - write_phy(mac, 0, 28, val); - } - - /* GPHY page to auto */ - write_phy(mac, 0xa42, 29, 0x0000); -} - -// TODO: unused -int rtl8380_rtl8214fc_get_green(struct phy_device *phydev, struct ethtool_eee *e) +static int rtl8218d_get_eee(struct phy_device *phydev, + struct ethtool_eee *e) { u32 val; int addr = phydev->mdio.addr; - pr_debug("In %s %d\n", __func__, addr); - /* Set GPHY page to copper */ - write_phy(addr, 0xa42, 29, 0x0001); + pr_debug("In %s, port %d, was enabled: %d\n", __func__, addr, e->eee_enabled); - write_phy(addr, 0, 27, 0x8011); - read_phy(addr, 0, 28, &val); - if (e->eee_enabled && (!!(val & (1 << 9)))) - e->eee_enabled = !!(val & (1 << 9)); - else - e->eee_enabled = 0; + /* Set GPHY page to copper */ + write_phy(addr, 0xa42, 30, 0x0001); + + read_phy(addr, 7, 60, &val); + if (e->eee_enabled) + e->eee_enabled = !!(val & BIT(7)); + pr_debug("%s: enabled: %d\n", __func__, e->eee_enabled); /* GPHY page to auto */ - write_phy(addr, 0xa42, 29, 0x0000); + write_phy(addr, 0xa42, 30, 0x0000); return 0; } @@ -1116,20 +1129,56 @@ int rtl8380_rtl8214fc_get_green(struct phy_device *phydev, struct ethtool_eee *e static int rtl8214fc_set_eee(struct phy_device *phydev, struct ethtool_eee *e) { - u32 pollMask; - int addr = phydev->mdio.addr; + u32 poll_state; + int port = phydev->mdio.addr; + bool an_enabled; + u32 val; - pr_debug("In %s port %d, enabled %d\n", __func__, addr, e->eee_enabled); + pr_debug("In %s port %d, enabled %d\n", __func__, port, e->eee_enabled); - if (rtl8380_rtl8214fc_media_is_fibre(addr)) { - netdev_err(phydev->attached_dev, "Port %d configured for FIBRE", addr); + if (rtl8380_rtl8214fc_media_is_fibre(port)) { + netdev_err(phydev->attached_dev, "Port %d configured for FIBRE", port); return -ENOTSUPP; } - pollMask = sw_r32(RTL838X_SMI_POLL_CTRL); - sw_w32(0, RTL838X_SMI_POLL_CTRL); - rtl8218b_eee_set_u_boot(addr, (bool) e->eee_enabled); - sw_w32(pollMask, RTL838X_SMI_POLL_CTRL); + poll_state = disable_polling(port); + + /* Set GPHY page to copper */ + write_phy(port, 0xa42, 29, 0x0001); + + // Get auto-negotiation status + read_phy(port, 0, 0, &val); + an_enabled = val & BIT(12); + + pr_info("%s: aneg: %d\n", __func__, an_enabled); + read_phy(port, 0x0A43, 25, &val); + val &= ~BIT(5); // Use MAC-based EEE + write_phy(port, 0x0A43, 25, val); + + /* Enable 100M (bit 1) / 1000M (bit 2) EEE */ + write_phy(port, 7, 60, e->eee_enabled ? 0x6 : 0); + + /* 500M EEE ability */ + read_phy(port, 0xa42, 20, &val); + if (e->eee_enabled) + val |= BIT(7); + else + val &= ~BIT(7); + write_phy(port, 0xa42, 20, val); + + /* Restart AN if enabled */ + if (an_enabled) { + pr_info("%s: doing aneg\n", __func__); + read_phy(port, 0, 0, &val); + val |= BIT(9); + write_phy(port, 0, 0, val); + } + + /* GPHY page back to auto*/ + write_phy(port, 0xa42, 29, 0); + + resume_polling(poll_state); + return 0; } @@ -1147,18 +1196,72 @@ static int rtl8214fc_get_eee(struct phy_device *phydev, return rtl8218b_get_eee(phydev, e); } -static int rtl8218b_set_eee(struct phy_device *phydev, - struct ethtool_eee *e) +static int rtl8218b_set_eee(struct phy_device *phydev, struct ethtool_eee *e) +{ + int port = phydev->mdio.addr; + u64 poll_state; + u32 val; + bool an_enabled; + + pr_info("In %s, port %d, enabled %d\n", __func__, port, e->eee_enabled); + + poll_state = disable_polling(port); + + /* Set GPHY page to copper */ + write_phy(port, 0, 30, 0x0001); + read_phy(port, 0, 0, &val); + an_enabled = val & BIT(12); + + if (e->eee_enabled) { + /* 100/1000M EEE Capability */ + write_phy(port, 0, 13, 0x0007); + write_phy(port, 0, 14, 0x003C); + write_phy(port, 0, 13, 0x4007); + write_phy(port, 0, 14, 0x0006); + + read_phy(port, 0x0A43, 25, &val); + val |= BIT(4); + write_phy(port, 0x0A43, 25, val); + } else { + /* 100/1000M EEE Capability */ + write_phy(port, 0, 13, 0x0007); + write_phy(port, 0, 14, 0x003C); + write_phy(port, 0, 13, 0x0007); + write_phy(port, 0, 14, 0x0000); + + read_phy(port, 0x0A43, 25, &val); + val &= ~BIT(4); + write_phy(port, 0x0A43, 25, val); + } + + /* Restart AN if enabled */ + if (an_enabled) { + read_phy(port, 0, 0, &val); + val |= BIT(9); + write_phy(port, 0, 0, val); + } + + /* GPHY page back to auto*/ + write_phy(port, 0xa42, 30, 0); + + pr_info("%s done\n", __func__); + resume_polling(poll_state); + + return 0; +} + +static int rtl8218d_set_eee(struct phy_device *phydev, struct ethtool_eee *e) { - u32 pollMask; int addr = phydev->mdio.addr; + u64 poll_state; - pr_debug("In %s, port %d, enabled %d\n", __func__, addr, e->eee_enabled); + pr_info("In %s, port %d, enabled %d\n", __func__, addr, e->eee_enabled); - pollMask = sw_r32(RTL838X_SMI_POLL_CTRL); - sw_w32(0, RTL838X_SMI_POLL_CTRL); - rtl8218b_eee_set_u_boot(addr, (bool) e->eee_enabled); - sw_w32(pollMask, RTL838X_SMI_POLL_CTRL); + poll_state = disable_polling(addr); + + rtl8218d_eee_set(addr, (bool) e->eee_enabled); + + resume_polling(poll_state); return 0; } @@ -1791,7 +1894,10 @@ static struct phy_driver rtl83xx_phy_driver[] = { .suspend = genphy_suspend, .resume = genphy_resume, .set_loopback = genphy_loopback, - }, { + .set_eee = rtl8218d_set_eee, + .get_eee = rtl8218d_get_eee, + }, + { PHY_ID_MATCH_MODEL(PHY_ID_RTL8226), .name = "REALTEK RTL8226", .features = PHY_GBIT_FEATURES, @@ -1805,6 +1911,8 @@ static struct phy_driver rtl83xx_phy_driver[] = { .write_page = rtl8226_write_page, .read_status = rtl8226_read_status, .config_aneg = rtl8226_config_aneg, + .set_eee = rtl8226_set_eee, + .get_eee = rtl8226_get_eee, }, { PHY_ID_MATCH_MODEL(PHY_ID_RTL8218B_I), From d4649942ad72a1b1db2595ace3620c1059fa3464 Mon Sep 17 00:00:00 2001 From: Birger Koblitz Date: Sat, 1 May 2021 11:22:05 +0200 Subject: [PATCH 38/62] realtek: Add SoC-specific VLAN setup routine This adds SoC specific VLAN configuration routines, which alsoe sets up the portmask table entries that are referred to in the vlan profiles registers for unknown multicast flooding. Signed-off-by: Birger Koblitz --- .../drivers/net/dsa/rtl83xx/rtl838x.c | 114 ++++++++----- .../drivers/net/dsa/rtl83xx/rtl838x.h | 6 + .../drivers/net/dsa/rtl83xx/rtl839x.c | 161 +++++++++++------- .../drivers/net/dsa/rtl83xx/rtl930x.c | 84 +++++++-- 4 files changed, 255 insertions(+), 110 deletions(-) diff --git a/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl838x.c b/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl838x.c index 773225b3c4..b31b1ae6ba 100644 --- a/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl838x.c +++ b/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl838x.c @@ -12,10 +12,10 @@ void rtl838x_print_matrix(void) ptr8 = RTL838X_SW_BASE + RTL838X_PORT_ISO_CTRL(0); for (i = 0; i < 28; i += 8) - pr_info("> %8x %8x %8x %8x %8x %8x %8x %8x\n", + pr_debug("> %8x %8x %8x %8x %8x %8x %8x %8x\n", ptr8[i + 0], ptr8[i + 1], ptr8[i + 2], ptr8[i + 3], ptr8[i + 4], ptr8[i + 5], ptr8[i + 6], ptr8[i + 7]); - pr_info("CPU_PORT> %8x\n", ptr8[28]); + pr_debug("CPU_PORT> %8x\n", ptr8[28]); } static inline int rtl838x_port_iso_ctrl(int p) @@ -42,56 +42,54 @@ static inline int rtl838x_tbl_access_data_0(int i) static void rtl838x_vlan_tables_read(u32 vlan, struct rtl838x_vlan_info *info) { - u32 cmd, v; + u32 v; + // Read VLAN table (0) via register 0 + struct table_reg *r = rtl_table_get(RTL8380_TBL_0, 0); + + rtl_table_read(r, vlan); + info->tagged_ports = sw_r32(rtl_table_data(r, 0)); + v = sw_r32(rtl_table_data(r, 1)); + pr_debug("VLAN_READ %d: %016llx %08x\n", vlan, info->tagged_ports, v); + rtl_table_release(r); - cmd = BIT(15) /* Execute cmd */ - | BIT(14) /* Read */ - | 0 << 12 /* Table type 0b00 */ - | (vlan & 0xfff); - rtl838x_exec_tbl0_cmd(cmd); - info->tagged_ports = sw_r32(RTL838X_TBL_ACCESS_DATA_0(0)); - v = sw_r32(RTL838X_TBL_ACCESS_DATA_0(1)); info->profile_id = v & 0x7; info->hash_mc_fid = !!(v & 0x8); info->hash_uc_fid = !!(v & 0x10); info->fid = (v >> 5) & 0x3f; - - cmd = BIT(15) /* Execute cmd */ - | BIT(14) /* Read */ - | 0 << 12 /* Table type 0b00 */ - | (vlan & 0xfff); - rtl838x_exec_tbl1_cmd(cmd); - info->untagged_ports = sw_r32(RTL838X_TBL_ACCESS_DATA_1(0)); + // Read UNTAG table (0) via table register 1 + r = rtl_table_get(RTL8380_TBL_1, 0); + rtl_table_read(r, vlan); + info->untagged_ports = sw_r32(rtl_table_data(r, 0)); + rtl_table_release(r); } static void rtl838x_vlan_set_tagged(u32 vlan, struct rtl838x_vlan_info *info) { - u32 cmd = BIT(15) /* Execute cmd */ - | 0 << 14 /* Write */ - | 0 << 12 /* Table type 0b00 */ - | (vlan & 0xfff); u32 v; + // Access VLAN table (0) via register 0 + struct table_reg *r = rtl_table_get(RTL8380_TBL_0, 0); - sw_w32(info->tagged_ports, RTL838X_TBL_ACCESS_DATA_0(0)); + sw_w32(info->tagged_ports, rtl_table_data(r, 0)); v = info->profile_id; v |= info->hash_mc_fid ? 0x8 : 0; v |= info->hash_uc_fid ? 0x10 : 0; v |= ((u32)info->fid) << 5; + sw_w32(v, rtl_table_data(r, 1)); - sw_w32(v, RTL838X_TBL_ACCESS_DATA_0(1)); - rtl838x_exec_tbl0_cmd(cmd); + rtl_table_write(r, vlan); + rtl_table_release(r); } static void rtl838x_vlan_set_untagged(u32 vlan, u64 portmask) { - u32 cmd = BIT(15) /* Execute cmd */ - | 0 << 14 /* Write */ - | 0 << 12 /* Table type 0b00 */ - | (vlan & 0xfff); - sw_w32(portmask & 0x1fffffff, RTL838X_TBL_ACCESS_DATA_1(0)); - rtl838x_exec_tbl1_cmd(cmd); + // Access UNTAG table (0) via register 1 + struct table_reg *r = rtl_table_get(RTL8380_TBL_1, 0); + + sw_w32(portmask & 0x1fffffff, rtl_table_data(r, 0)); + rtl_table_write(r, vlan); + rtl_table_release(r); } static inline int rtl838x_mac_force_mode_ctrl(int p) @@ -202,9 +200,43 @@ static u64 rtl838x_read_cam(int idx, struct rtl838x_l2_entry *e) return entry; } -static inline int rtl838x_vlan_profile(int profile) +static u64 rtl838x_read_mcast_pmask(int idx) { - return RTL838X_VLAN_PROFILE(profile); + u32 portmask; + // Read MC_PMSK (2) via register RTL8380_TBL_L2 + struct table_reg *q = rtl_table_get(RTL8380_TBL_L2, 2); + + rtl_table_read(q, idx); + portmask = sw_r32(rtl_table_data(q, 0)); + rtl_table_release(q); + + return portmask; +} + +static void rtl838x_write_mcast_pmask(int idx, u64 portmask) +{ + // Access MC_PMSK (2) via register RTL8380_TBL_L2 + struct table_reg *q = rtl_table_get(RTL8380_TBL_L2, 2); + + sw_w32(((u32)portmask) & 0x1fffffff, rtl_table_data(q, 0)); + rtl_table_write(q, idx); + rtl_table_release(q); +} + +static void rtl838x_vlan_profile_setup(int profile) +{ + u32 pmask_id = UNKNOWN_MC_PMASK; + // Enable L2 Learning BIT 0, portmask UNKNOWN_MC_PMASK for unknown MC traffic flooding + u32 p = 1 | pmask_id << 1 | pmask_id << 10 | pmask_id << 19; + + sw_w32(p, RTL838X_VLAN_PROFILE(profile)); + + /* RTL8380 and RTL8390 use an index into the portmask table to set the + * unknown multicast portmask, setup a default at a safe location + * On RTL93XX, the portmask is directly set in the profile, + * see e.g. rtl9300_vlan_profile_setup + */ + rtl838x_write_mcast_pmask(UNKNOWN_MC_PMASK, 0xfffffff); } static inline int rtl838x_vlan_port_egr_filter(int port) @@ -373,6 +405,7 @@ const struct rtl838x_reg rtl838x_reg = { .vlan_set_untagged = rtl838x_vlan_set_untagged, .mac_force_mode_ctrl = rtl838x_mac_force_mode_ctrl, .vlan_profile_dump = rtl838x_vlan_profile_dump, + .vlan_profile_setup = rtl838x_vlan_profile_setup, .stp_get = rtl838x_stp_get, .stp_set = rtl838x_stp_set, .mac_port_ctrl = rtl838x_mac_port_ctrl, @@ -398,6 +431,8 @@ const struct rtl838x_reg rtl838x_reg = { .init_eee = rtl838x_init_eee, .port_eee_set = rtl838x_port_eee_set, .eee_port_ability = rtl838x_eee_port_ability, + .read_mcast_pmask = rtl838x_read_mcast_pmask, + .write_mcast_pmask = rtl838x_write_mcast_pmask, }; irqreturn_t rtl838x_switch_irq(int irq, void *dev_id) @@ -641,19 +676,18 @@ u32 rtl838x_hash(struct rtl838x_switch_priv *priv, u64 seed) return h; } -void rtl838x_vlan_profile_dump(int index) +void rtl838x_vlan_profile_dump(int profile) { - u32 profile; + u32 p; - if (index < 0 || index > 7) + if (profile < 0 || profile > 7) return; - profile = sw_r32(RTL838X_VLAN_PROFILE(index)); + p = sw_r32(RTL838X_VLAN_PROFILE(profile)); - pr_info("VLAN %d: L2 learning: %d, L2 Unknown MultiCast Field %x, \ - IPv4 Unknown MultiCast Field %x, IPv6 Unknown MultiCast Field: %x", - index, profile & 1, (profile >> 1) & 0x1ff, (profile >> 10) & 0x1ff, - (profile >> 19) & 0x1ff); + pr_info("VLAN profile %d: L2 learning: %d, UNKN L2MC FLD PMSK %d, \ + UNKN IPMC FLD PMSK %d, UNKN IPv6MC FLD PMSK: %d", + profile, p & 1, (p >> 1) & 0x1ff, (p >> 10) & 0x1ff, (p >> 19) & 0x1ff); } void rtl8380_sds_rst(int mac) diff --git a/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl838x.h b/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl838x.h index 928a23af77..35d5b1702a 100644 --- a/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl838x.h +++ b/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl838x.h @@ -332,8 +332,11 @@ /* Debug features */ #define RTL930X_STAT_PRVTE_DROP_COUNTER0 (0xB5B8) +#define MAX_VLANS 4096 #define MAX_LAGS 16 #define MAX_PRIOS 8 +#define MAX_MC_GROUPS 512 +#define UNKNOWN_MC_PMASK (MAX_MC_GROUPS - 1) enum phy_type { PHY_NONE = 0, @@ -426,6 +429,7 @@ struct rtl838x_reg { void (*vlan_set_tagged)(u32 vlan, struct rtl838x_vlan_info *info); void (*vlan_set_untagged)(u32 vlan, u64 portmask); void (*vlan_profile_dump)(int index); + void (*vlan_profile_setup)(int profile); void (*stp_get)(struct rtl838x_switch_priv *priv, u16 msti, u32 port_state[]); void (*stp_set)(struct rtl838x_switch_priv *priv, u16 msti, u32 port_state[]); int (*mac_force_mode_ctrl)(int port); @@ -454,6 +458,8 @@ struct rtl838x_reg { void (*port_eee_set)(struct rtl838x_switch_priv *priv, int port, bool enable); int (*eee_port_ability)(struct rtl838x_switch_priv *priv, struct ethtool_eee *e, int port); + u64 (*read_mcast_pmask)(int idx); + void (*write_mcast_pmask)(int idx, u64 portmask); }; struct rtl838x_switch_priv { diff --git a/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl839x.c b/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl839x.c index b2846deb11..825655cd54 100644 --- a/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl839x.c +++ b/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl839x.c @@ -48,68 +48,71 @@ static inline int rtl839x_tbl_access_data_0(int i) static void rtl839x_vlan_tables_read(u32 vlan, struct rtl838x_vlan_info *info) { - u32 cmd; - u64 v; - u32 u, w; + u32 u, v, w; + // Read VLAN table (0) via register 0 + struct table_reg *r = rtl_table_get(RTL8390_TBL_0, 0); - cmd = 1 << 16 /* Execute cmd */ - | 0 << 15 /* Read */ - | 0 << 12 /* Table type 0b000 */ - | (vlan & 0xfff); - rtl839x_exec_tbl0_cmd(cmd); + rtl_table_read(r, vlan); + u = sw_r32(rtl_table_data(r, 0)); + v = sw_r32(rtl_table_data(r, 1)); + w = sw_r32(rtl_table_data(r, 2)); + rtl_table_release(r); - v = sw_r32(RTL839X_TBL_ACCESS_DATA_0(0)); - v <<= 32; - u = sw_r32(RTL839X_TBL_ACCESS_DATA_0(1)); - v |= u; - info->tagged_ports = v >> 11; + info->tagged_ports = u; + info->tagged_ports = (info->tagged_ports << 21) | ((v >> 11) & 0x1fffff); + info->profile_id = w >> 30 | ((v & 1) << 2); + info->hash_mc_fid = !!(w & BIT(2)); + info->hash_uc_fid = !!(w & BIT(3)); + info->fid = (v >> 3) & 0xff; - w = sw_r32(RTL839X_TBL_ACCESS_DATA_0(2)); + // Read UNTAG table (0) via table register 1 + r = rtl_table_get(RTL8390_TBL_1, 0); + rtl_table_read(r, vlan); + u = sw_r32(rtl_table_data(r, 0)); + v = sw_r32(rtl_table_data(r, 1)); + rtl_table_release(r); - info->profile_id = w >> 30 | ((u & 1) << 2); - info->hash_mc_fid = !!(u & 2); - info->hash_uc_fid = !!(u & 4); - info->fid = (u >> 3) & 0xff; - - cmd = 1 << 15 /* Execute cmd */ - | 0 << 14 /* Read */ - | 0 << 12 /* Table type 0b00 */ - | (vlan & 0xfff); - rtl839x_exec_tbl1_cmd(cmd); - v = sw_r32(RTL839X_TBL_ACCESS_DATA_1(0)); - v <<= 32; - v |= sw_r32(RTL839X_TBL_ACCESS_DATA_1(1)); - info->untagged_ports = v >> 11; + info->untagged_ports = u; + info->untagged_ports = (info->untagged_ports << 21) | ((v >> 11) & 0x1fffff); } static void rtl839x_vlan_set_tagged(u32 vlan, struct rtl838x_vlan_info *info) { - u32 cmd = BIT(16) /* Execute cmd */ - | BIT(15) /* Write */ - | 0 << 12 /* Table type 0b00 */ - | (vlan & 0xfff); - u32 w; - u64 v = info->tagged_ports << 11; + u32 u, v, w; + // Access VLAN table (0) via register 0 + struct table_reg *r = rtl_table_get(RTL8390_TBL_0, 0); - v |= info->profile_id >> 2; - v |= info->hash_mc_fid ? 2 : 0; - v |= info->hash_uc_fid ? 4 : 0; + u = info->tagged_ports >> 21; + v = info->tagged_ports << 11; v |= ((u32)info->fid) << 3; - rtl839x_set_port_reg_be(v, RTL838X_TBL_ACCESS_DATA_0(0)); + v |= info->hash_uc_fid ? BIT(2) : 0; + v |= info->hash_mc_fid ? BIT(1) : 0; + v |= (info->profile_id & 0x4) ? 1 : 0; + w = ((u32)(info->profile_id & 3)) << 30; - w = info->profile_id; - sw_w32(w << 30, RTL838X_TBL_ACCESS_DATA_0(2)); - rtl839x_exec_tbl0_cmd(cmd); + sw_w32(u, rtl_table_data(r, 0)); + sw_w32(v, rtl_table_data(r, 1)); + sw_w32(w, rtl_table_data(r, 2)); + + rtl_table_write(r, vlan); + rtl_table_release(r); } static void rtl839x_vlan_set_untagged(u32 vlan, u64 portmask) { - u32 cmd = BIT(16) /* Execute cmd */ - | BIT(15) /* Write */ - | 0 << 12 /* Table type 0b00 */ - | (vlan & 0xfff); - rtl839x_set_port_reg_be(portmask << 11, RTL838X_TBL_ACCESS_DATA_1(0)); - rtl839x_exec_tbl1_cmd(cmd); + u32 u, v; + + // Access UNTAG table (0) via table register 1 + struct table_reg *r = rtl_table_get(RTL8390_TBL_1, 0); + + u = portmask >> 21; + v = portmask << 11; + + sw_w32(u, rtl_table_data(r, 0)); + sw_w32(v, rtl_table_data(r, 1)); + rtl_table_write(r, vlan); + + rtl_table_release(r); } static inline int rtl839x_mac_force_mode_ctrl(int p) @@ -243,9 +246,47 @@ static u64 rtl839x_read_cam(int idx, struct rtl838x_l2_entry *e) return entry; } -static inline int rtl839x_vlan_profile(int profile) +static u64 rtl839x_read_mcast_pmask(int idx) { - return RTL839X_VLAN_PROFILE(profile); + u64 portmask; + // Read MC_PMSK (2) via register RTL8390_TBL_L2 + struct table_reg *q = rtl_table_get(RTL8390_TBL_L2, 2); + + rtl_table_read(q, idx); + portmask = sw_r32(rtl_table_data(q, 0)); + portmask <<= 32; + portmask |= sw_r32(rtl_table_data(q, 1)); + portmask >>= 11; // LSB is bit 11 in data registers + rtl_table_release(q); + + return portmask; +} + +static void rtl839x_write_mcast_pmask(int idx, u64 portmask) +{ + // Access MC_PMSK (2) via register RTL8380_TBL_L2 + struct table_reg *q = rtl_table_get(RTL8390_TBL_L2, 2); + + portmask <<= 11; // LSB is bit 11 in data registers + sw_w32((u32)(portmask >> 32), rtl_table_data(q, 0)); + sw_w32((u32)((portmask & 0xfffff800)), rtl_table_data(q, 1)); + rtl_table_write(q, idx); + rtl_table_release(q); +} + +static void rtl839x_vlan_profile_setup(int profile) +{ + u32 p[2]; + u32 pmask_id = UNKNOWN_MC_PMASK; + + p[0] = pmask_id; // Use portmaks 0xfff for unknown IPv6 MC flooding + // Enable L2 Learning BIT 0, portmask UNKNOWN_MC_PMASK for IP/L2-MC traffic flooding + p[1] = 1 | pmask_id << 1 | pmask_id << 13; + + sw_w32(p[0], RTL839X_VLAN_PROFILE(profile)); + sw_w32(p[1], RTL839X_VLAN_PROFILE(profile) + 4); + + rtl839x_write_mcast_pmask(UNKNOWN_MC_PMASK, 0x000fffffffffffff); } static inline int rtl839x_vlan_port_egr_filter(int port) @@ -477,20 +518,21 @@ u32 rtl839x_hash(struct rtl838x_switch_priv *priv, u64 seed) return h; } -void rtl839x_vlan_profile_dump(int index) +void rtl839x_vlan_profile_dump(int profile) { - u32 profile, profile1; + u32 p[2]; - if (index < 0 || index > 7) + if (profile < 0 || profile > 7) return; - profile1 = sw_r32(RTL839X_VLAN_PROFILE(index) + 4); - profile = sw_r32(RTL839X_VLAN_PROFILE(index)); + p[0] = sw_r32(RTL839X_VLAN_PROFILE(profile)); + p[1] = sw_r32(RTL839X_VLAN_PROFILE(profile) + 4); - pr_debug("VLAN %d: L2 learning: %d, L2 Unknown MultiCast Field %x, \ - IPv4 Unknown MultiCast Field %x, IPv6 Unknown MultiCast Field: %x", - index, profile & 1, (profile >> 1) & 0xfff, (profile >> 13) & 0xfff, - (profile1) & 0xfff); + pr_info("VLAN profile %d: L2 learning: %d, UNKN L2MC FLD PMSK %d, \ + UNKN IPMC FLD PMSK %d, UNKN IPv6MC FLD PMSK: %d", + profile, p[1] & 1, (p[1] >> 1) & 0xfff, (p[1] >> 13) & 0xfff, + (p[0]) & 0xfff); + pr_info("VLAN profile %d: raw %08x, %08x\n", profile, p[0], p[1]); } static void rtl839x_stp_get(struct rtl838x_switch_priv *priv, u16 msti, u32 port_state[]) @@ -626,6 +668,7 @@ const struct rtl838x_reg rtl839x_reg = { .vlan_set_tagged = rtl839x_vlan_set_tagged, .vlan_set_untagged = rtl839x_vlan_set_untagged, .vlan_profile_dump = rtl839x_vlan_profile_dump, + .vlan_profile_setup = rtl839x_vlan_profile_setup, .stp_get = rtl839x_stp_get, .stp_set = rtl839x_stp_set, .mac_force_mode_ctrl = rtl839x_mac_force_mode_ctrl, @@ -652,4 +695,6 @@ const struct rtl838x_reg rtl839x_reg = { .init_eee = rtl839x_init_eee, .port_eee_set = rtl839x_port_eee_set, .eee_port_ability = rtl839x_eee_port_ability, + .read_mcast_pmask = rtl839x_read_mcast_pmask, + .write_mcast_pmask = rtl839x_write_mcast_pmask, }; diff --git a/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl930x.c b/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl930x.c index 4214c7694d..a6e5cb763f 100644 --- a/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl930x.c +++ b/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl930x.c @@ -54,7 +54,7 @@ inline static int rtl930x_trk_mbr_ctr(int group) static void rtl930x_vlan_tables_read(u32 vlan, struct rtl838x_vlan_info *info) { u32 v, w; - // Read VLAN table (0) via register 0 + // Read VLAN table (1) via register 0 struct table_reg *r = rtl_table_get(RTL9300_TBL_0, 1); rtl_table_read(r, vlan); @@ -99,22 +99,28 @@ static void rtl930x_vlan_set_tagged(u32 vlan, struct rtl838x_vlan_info *info) rtl_table_release(r); } -void rtl930x_vlan_profile_dump(int index) +void rtl930x_vlan_profile_dump(int profile) { - u32 profile[5]; + u32 p[5]; - if (index < 0 || index > 7) + if (profile < 0 || profile > 7) return; - profile[0] = sw_r32(RTL930X_VLAN_PROFILE_SET(index)); - profile[1] = sw_r32(RTL930X_VLAN_PROFILE_SET(index) + 4); - profile[2] = sw_r32(RTL930X_VLAN_PROFILE_SET(index) + 8) & 0x1FFFFFFF; - profile[3] = sw_r32(RTL930X_VLAN_PROFILE_SET(index) + 12) & 0x1FFFFFFF; - profile[4] = sw_r32(RTL930X_VLAN_PROFILE_SET(index) + 16) & 0x1FFFFFFF; + p[0] = sw_r32(RTL930X_VLAN_PROFILE_SET(profile)); + p[1] = sw_r32(RTL930X_VLAN_PROFILE_SET(profile) + 4); + p[2] = sw_r32(RTL930X_VLAN_PROFILE_SET(profile) + 8) & 0x1FFFFFFF; + p[3] = sw_r32(RTL930X_VLAN_PROFILE_SET(profile) + 12) & 0x1FFFFFFF; + p[4] = sw_r32(RTL930X_VLAN_PROFILE_SET(profile) + 16) & 0x1FFFFFFF; - pr_debug("VLAN %d: L2 learning: %d, L2 Unknown MultiCast Field %x, \ - IPv4 Unknown MultiCast Field %x, IPv6 Unknown MultiCast Field: %x", - index, profile[0] & (3 << 21), profile[2], profile[3], profile[4]); + pr_info("VLAN %d: L2 learn: %d; Unknown MC PMasks: L2 %0x, IPv4 %0x, IPv6: %0x", + profile, p[0] & (3 << 21), p[2], p[3], p[4]); + pr_info(" Routing enabled: IPv4 UC %c, IPv6 UC %c, IPv4 MC %c, IPv6 MC %c\n", + p[0] & BIT(17) ? 'y' : 'n', p[0] & BIT(16) ? 'y' : 'n', + p[0] & BIT(13) ? 'y' : 'n', p[0] & BIT(12) ? 'y' : 'n'); + pr_info(" Bridge enabled: IPv4 MC %c, IPv6 MC %c,\n", + p[0] & BIT(15) ? 'y' : 'n', p[0] & BIT(14) ? 'y' : 'n'); + pr_info("VLAN profile %d: raw %08x %08x %08x %08x %08x\n", + profile, p[0], p[1], p[2], p[3], p[4]); } static void rtl930x_vlan_set_untagged(u32 vlan, u64 portmask) @@ -126,6 +132,28 @@ static void rtl930x_vlan_set_untagged(u32 vlan, u64 portmask) rtl_table_release(r); } +static void rtl930x_vlan_profile_setup(int profile) +{ + u32 p[5]; + + pr_info("In %s\n", __func__); + p[0] = sw_r32(RTL930X_VLAN_PROFILE_SET(profile)); + p[1] = sw_r32(RTL930X_VLAN_PROFILE_SET(profile) + 4); + + // Enable routing of Ipv4/6 Unicast and IPv4/6 Multicast traffic + p[0] |= BIT(17) | BIT(16) | BIT(13) | BIT(12); + p[2] = 0x0fffffff; // L2 unknwon MC flooding portmask: all but the CPU-port + p[3] = 0x0fffffff; // IPv4 unknwon MC flooding portmask + p[4] = 0x0fffffff; // IPv6 unknwon MC flooding portmask + + sw_w32(p[0], RTL930X_VLAN_PROFILE_SET(profile)); + sw_w32(p[1], RTL930X_VLAN_PROFILE_SET(profile) + 4); + sw_w32(p[2], RTL930X_VLAN_PROFILE_SET(profile) + 8); + sw_w32(p[3], RTL930X_VLAN_PROFILE_SET(profile) + 12); + sw_w32(p[4], RTL930X_VLAN_PROFILE_SET(profile) + 16); + pr_info("Leaving %s\n", __func__); +} + static void rtl930x_stp_get(struct rtl838x_switch_priv *priv, u16 msti, u32 port_state[]) { int i; @@ -256,6 +284,35 @@ static u64 rtl930x_read_cam(int idx, struct rtl838x_l2_entry *e) return entry; } +static u64 rtl930x_read_mcast_pmask(int idx) +{ + u32 portmask; + // Read MC_PORTMASK (2) via register RTL9300_TBL_L2 + struct table_reg *q = rtl_table_get(RTL9300_TBL_L2, 2); + + rtl_table_read(q, idx); + portmask = sw_r32(rtl_table_data(q, 0)); + portmask >>= 3; + rtl_table_release(q); + + pr_debug("%s: Index idx %d has portmask %08x\n", __func__, idx, portmask); + return portmask; +} + +static void rtl930x_write_mcast_pmask(int idx, u64 portmask) +{ + u32 pm = portmask; + + // Access MC_PORTMASK (2) via register RTL9300_TBL_L2 + struct table_reg *q = rtl_table_get(RTL9300_TBL_L2, 2); + + pr_debug("%s: Index idx %d has portmask %08x\n", __func__, idx, pm); + pm <<= 3; + sw_w32(pm, rtl_table_data(q, 0)); + rtl_table_write(q, idx); + rtl_table_release(q); +} + u64 rtl930x_traffic_get(int source) { u32 v; @@ -669,6 +726,7 @@ const struct rtl838x_reg rtl930x_reg = { .vlan_set_tagged = rtl930x_vlan_set_tagged, .vlan_set_untagged = rtl930x_vlan_set_untagged, .vlan_profile_dump = rtl930x_vlan_profile_dump, + .vlan_profile_setup = rtl930x_vlan_profile_setup, .stp_get = rtl930x_stp_get, .stp_set = rtl930x_stp_set, .mac_force_mode_ctrl = rtl930x_mac_force_mode_ctrl, @@ -694,4 +752,6 @@ const struct rtl838x_reg rtl930x_reg = { .init_eee = rtl930x_init_eee, .port_eee_set = rtl930x_port_eee_set, .eee_port_ability = rtl930x_eee_port_ability, + .read_mcast_pmask = rtl930x_read_mcast_pmask, + .write_mcast_pmask = rtl930x_write_mcast_pmask, }; From 4342d27ec90cd0988fd3e62ccefbe66f2e691372 Mon Sep 17 00:00:00 2001 From: Birger Koblitz Date: Sat, 1 May 2021 16:36:32 +0200 Subject: [PATCH 39/62] realtek: Setup all VLANs with default configurations This sets up all VLANs with a default configuration on reset: - forward based on VLAN-ID and not the FID/MSTI - forward based on the inner VLAN-ID (not outer) Signed-off-by: Birger Koblitz --- .../files-5.4/drivers/net/dsa/rtl83xx/dsa.c | 34 +++++++++++++++++++ .../drivers/net/dsa/rtl83xx/rtl838x.c | 11 ++++++ .../drivers/net/dsa/rtl83xx/rtl838x.h | 7 ++++ .../drivers/net/dsa/rtl83xx/rtl839x.c | 11 ++++++ .../drivers/net/dsa/rtl83xx/rtl930x.c | 12 +++++++ 5 files changed, 75 insertions(+) diff --git a/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/dsa.c b/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/dsa.c index 1e902a1d7a..40130c287a 100644 --- a/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/dsa.c +++ b/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/dsa.c @@ -153,6 +153,36 @@ static enum dsa_tag_protocol rtl83xx_get_tag_protocol(struct dsa_switch *ds, int return DSA_TAG_PROTO_TRAILER; } +/* + * Initialize all VLANS + */ +static void rtl83xx_vlan_setup(struct rtl838x_switch_priv *priv) +{ + struct rtl838x_vlan_info info; + int i; + + pr_info("In %s\n", __func__); + + priv->r->vlan_profile_setup(0); + priv->r->vlan_profile_setup(1); + pr_info("UNKNOWN_MC_PMASK: %016llx\n", priv->r->read_mcast_pmask(UNKNOWN_MC_PMASK)); + priv->r->vlan_profile_dump(0); + + info.fid = 0; // Default Forwarding ID / MSTI + info.hash_uc_fid = false; // Do not build the L2 lookup hash with FID, but VID + info.hash_mc_fid = false; // Do the same for Multicast packets + info.profile_id = 0; // Use default Vlan Profile 0 + info.tagged_ports = 0; // Initially no port members + + // Initialize all vlans 0-4095 + for (i = 0; i < MAX_VLANS; i ++) + priv->r->vlan_set_tagged(i, &info); + + // Set forwarding action based on inner VLAN tag + for (i = 0; i < priv->cpu_port; i++) + priv->r->vlan_fwd_on_inner(i, true); +} + static int rtl83xx_setup(struct dsa_switch *ds) { int i; @@ -188,6 +218,8 @@ static int rtl83xx_setup(struct dsa_switch *ds) rtl83xx_init_stats(priv); + rtl83xx_vlan_setup(priv); + ds->configure_vlan_while_not_filtering = true; /* Enable MAC Polling PHY again */ @@ -228,6 +260,8 @@ static int rtl930x_setup(struct dsa_switch *ds) // TODO: Initialize statistics + rtl83xx_vlan_setup(priv); + ds->configure_vlan_while_not_filtering = true; rtl83xx_enable_phy_polling(priv); diff --git a/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl838x.c b/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl838x.c index b31b1ae6ba..9ecd189d91 100644 --- a/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl838x.c +++ b/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl838x.c @@ -92,6 +92,16 @@ static void rtl838x_vlan_set_untagged(u32 vlan, u64 portmask) rtl_table_release(r); } +/* Sets the L2 forwarding to be based on either the inner VLAN tag or the outer + */ +static void rtl838x_vlan_fwd_on_inner(int port, bool is_set) +{ + if (is_set) + sw_w32_mask(BIT(port), 0, RTL838X_VLAN_PORT_FWD); + else + sw_w32_mask(0, BIT(port), RTL838X_VLAN_PORT_FWD); +} + static inline int rtl838x_mac_force_mode_ctrl(int p) { return RTL838X_MAC_FORCE_MODE_CTRL + (p << 2); @@ -406,6 +416,7 @@ const struct rtl838x_reg rtl838x_reg = { .mac_force_mode_ctrl = rtl838x_mac_force_mode_ctrl, .vlan_profile_dump = rtl838x_vlan_profile_dump, .vlan_profile_setup = rtl838x_vlan_profile_setup, + .vlan_fwd_on_inner = rtl838x_vlan_fwd_on_inner, .stp_get = rtl838x_stp_get, .stp_set = rtl838x_stp_set, .mac_port_ctrl = rtl838x_mac_port_ctrl, diff --git a/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl838x.h b/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl838x.h index 35d5b1702a..5990b6453a 100644 --- a/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl838x.h +++ b/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl838x.h @@ -216,6 +216,12 @@ #define RTL931X_RMA_BPDU_FLD_PMSK (0x8950) #define RTL839X_RMA_BPDU_FLD_PMSK (0x125C) +#define RTL838X_L2_PORT_LM_ACT(p) (0x3208 + ((p) << 2)) +#define RTL838X_VLAN_PORT_FWD (0x3A78) +#define RTL839X_VLAN_PORT_FWD (0x27AC) +#define RTL930X_VLAN_PORT_FWD (0x834C) +#define RTL838X_VLAN_FID_CTRL (0x3aa8) + /* Port Mirroring */ #define RTL838X_MIR_CTRL (0x5D00) #define RTL838X_MIR_DPM_CTRL (0x5D20) @@ -460,6 +466,7 @@ struct rtl838x_reg { struct ethtool_eee *e, int port); u64 (*read_mcast_pmask)(int idx); void (*write_mcast_pmask)(int idx, u64 portmask); + void (*vlan_fwd_on_inner)(int port, bool is_set); }; struct rtl838x_switch_priv { diff --git a/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl839x.c b/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl839x.c index 825655cd54..bf2e3d3980 100644 --- a/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl839x.c +++ b/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl839x.c @@ -115,6 +115,16 @@ static void rtl839x_vlan_set_untagged(u32 vlan, u64 portmask) rtl_table_release(r); } +/* Sets the L2 forwarding to be based on either the inner VLAN tag or the outer + */ +static void rtl839x_vlan_fwd_on_inner(int port, bool is_set) +{ + if (is_set) + rtl839x_mask_port_reg_be(BIT_ULL(port), 0ULL, RTL839X_VLAN_PORT_FWD); + else + rtl839x_mask_port_reg_be(0ULL, BIT_ULL(port), RTL839X_VLAN_PORT_FWD); +} + static inline int rtl839x_mac_force_mode_ctrl(int p) { return RTL839X_MAC_FORCE_MODE_CTRL + (p << 2); @@ -669,6 +679,7 @@ const struct rtl838x_reg rtl839x_reg = { .vlan_set_untagged = rtl839x_vlan_set_untagged, .vlan_profile_dump = rtl839x_vlan_profile_dump, .vlan_profile_setup = rtl839x_vlan_profile_setup, + .vlan_fwd_on_inner = rtl839x_vlan_fwd_on_inner, .stp_get = rtl839x_stp_get, .stp_set = rtl839x_stp_set, .mac_force_mode_ctrl = rtl839x_mac_force_mode_ctrl, diff --git a/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl930x.c b/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl930x.c index a6e5cb763f..a80a6d89b2 100644 --- a/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl930x.c +++ b/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl930x.c @@ -132,6 +132,17 @@ static void rtl930x_vlan_set_untagged(u32 vlan, u64 portmask) rtl_table_release(r); } +/* Sets the L2 forwarding to be based on either the inner VLAN tag or the outer + */ +static void rtl930x_vlan_fwd_on_inner(int port, bool is_set) +{ + // Always set all tag modes to fwd based on either inner or outer tag + if (is_set) + sw_w32_mask(0, 0xf, RTL930X_VLAN_PORT_FWD + (port << 2)); + else + sw_w32_mask(0xf, 0, RTL930X_VLAN_PORT_FWD + (port << 2)); +} + static void rtl930x_vlan_profile_setup(int profile) { u32 p[5]; @@ -727,6 +738,7 @@ const struct rtl838x_reg rtl930x_reg = { .vlan_set_untagged = rtl930x_vlan_set_untagged, .vlan_profile_dump = rtl930x_vlan_profile_dump, .vlan_profile_setup = rtl930x_vlan_profile_setup, + .vlan_fwd_on_inner = rtl930x_vlan_fwd_on_inner, .stp_get = rtl930x_stp_get, .stp_set = rtl930x_stp_set, .mac_force_mode_ctrl = rtl930x_mac_force_mode_ctrl, From cde31976e37513cf2977e6d4b691f561344e61ed Mon Sep 17 00:00:00 2001 From: Birger Koblitz Date: Sat, 1 May 2021 20:39:59 +0200 Subject: [PATCH 40/62] realtek: Add support for Layer 2 Multicast Adds support for Layer 2 multicast by implementing the DSA port_mdb_* callbacks. The Kernel bridge listens to IGMP/MLD messages trapped to the CPU-port, and calls the Multicast Forwarding Database updates. The updates manage the L2 forwarding entries and the multicast port-maps. Signed-off-by: Birger Koblitz --- .../files-5.4/drivers/net/dsa/rtl83xx/dsa.c | 471 +++++++++++++----- .../drivers/net/dsa/rtl83xx/rtl838x.c | 292 ++++++++--- .../drivers/net/dsa/rtl83xx/rtl838x.h | 27 +- .../drivers/net/dsa/rtl83xx/rtl839x.c | 212 +++++--- .../drivers/net/dsa/rtl83xx/rtl930x.c | 314 +++++++++++- 5 files changed, 1020 insertions(+), 296 deletions(-) diff --git a/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/dsa.c b/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/dsa.c index 40130c287a..c5f243c55a 100644 --- a/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/dsa.c +++ b/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/dsa.c @@ -26,50 +26,6 @@ static void rtl83xx_init_stats(struct rtl838x_switch_priv *priv) mutex_unlock(&priv->reg_mutex); } -static void rtl83xx_write_cam(int idx, u32 *r) -{ - u32 cmd = BIT(16) /* Execute cmd */ - | BIT(15) /* Read */ - | BIT(13) /* Table type 0b01 */ - | (idx & 0x3f); - - sw_w32(r[0], RTL838X_TBL_ACCESS_L2_DATA(0)); - sw_w32(r[1], RTL838X_TBL_ACCESS_L2_DATA(1)); - sw_w32(r[2], RTL838X_TBL_ACCESS_L2_DATA(2)); - - sw_w32(cmd, RTL838X_TBL_ACCESS_L2_CTRL); - do { } while (sw_r32(RTL838X_TBL_ACCESS_L2_CTRL) & BIT(16)); -} - -static u64 rtl83xx_hash_key(struct rtl838x_switch_priv *priv, u64 mac, u32 vid) -{ - switch (priv->family_id) { - case RTL8380_FAMILY_ID: - return rtl838x_hash(priv, mac << 12 | vid); - case RTL8390_FAMILY_ID: - return rtl839x_hash(priv, mac << 12 | vid); - case RTL9300_FAMILY_ID: - return rtl930x_hash(priv, ((u64)vid) << 48 | mac); - default: - pr_err("Hash not implemented\n"); - } - return 0; -} - -static void rtl83xx_write_hash(int idx, u32 *r) -{ - u32 cmd = BIT(16) /* Execute cmd */ - | 0 << 15 /* Write */ - | 0 << 13 /* Table type 0b00 */ - | (idx & 0x1fff); - - sw_w32(0, RTL838X_TBL_ACCESS_L2_DATA(0)); - sw_w32(0, RTL838X_TBL_ACCESS_L2_DATA(1)); - sw_w32(0, RTL838X_TBL_ACCESS_L2_DATA(2)); - sw_w32(cmd, RTL838X_TBL_ACCESS_L2_CTRL); - do { } while (sw_r32(RTL838X_TBL_ACCESS_L2_CTRL) & BIT(16)); -} - static void rtl83xx_enable_phy_polling(struct rtl838x_switch_priv *priv) { int i; @@ -79,7 +35,7 @@ static void rtl83xx_enable_phy_polling(struct rtl838x_switch_priv *priv) /* Enable all ports with a PHY, including the SFP-ports */ for (i = 0; i < priv->cpu_port; i++) { if (priv->ports[i].phy) - v |= BIT(i); + v |= BIT_ULL(i); } pr_debug("%s: %16llx\n", __func__, v); @@ -204,7 +160,7 @@ static int rtl83xx_setup(struct dsa_switch *ds) */ for (i = 0; i < priv->cpu_port; i++) { if (priv->ports[i].phy) { - priv->r->set_port_reg_be(BIT_ULL(priv->cpu_port) | BIT(i), + priv->r->set_port_reg_be(BIT_ULL(priv->cpu_port) | BIT_ULL(i), priv->r->port_iso_ctrl(i)); port_bitmap |= BIT_ULL(i); } @@ -250,8 +206,8 @@ static int rtl930x_setup(struct dsa_switch *ds) for (i = 0; i < priv->cpu_port; i++) { if (priv->ports[i].phy) { - priv->r->traffic_set(i, BIT(priv->cpu_port) | BIT(i)); - port_bitmap |= 1ULL << i; + priv->r->traffic_set(i, BIT_ULL(priv->cpu_port) | BIT_ULL(i)); + port_bitmap |= BIT_ULL(i); } } priv->r->traffic_set(priv->cpu_port, port_bitmap); @@ -276,7 +232,7 @@ static void rtl83xx_phylink_validate(struct dsa_switch *ds, int port, struct rtl838x_switch_priv *priv = ds->priv; __ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, }; - pr_debug("In %s port %d", __func__, port); + pr_debug("In %s port %d, state is %d", __func__, port, state->interface); if (!phy_interface_mode_is_rgmii(state->interface) && state->interface != PHY_INTERFACE_MODE_NA && @@ -313,6 +269,10 @@ static void rtl83xx_phylink_validate(struct dsa_switch *ds, int port, if (port >= 24 && port <= 27 && priv->family_id == RTL8380_FAMILY_ID) phylink_set(mask, 1000baseX_Full); + /* On the RTL839x family of SoCs, ports 48 to 51 are SFP ports */ + if (port >=48 && port <= 51 && priv->family_id == RTL8390_FAMILY_ID) + phylink_set(mask, 1000baseX_Full); + phylink_set(mask, 10baseT_Half); phylink_set(mask, 10baseT_Full); phylink_set(mask, 100baseT_Half); @@ -345,7 +305,7 @@ static int rtl83xx_phylink_mac_link_state(struct dsa_switch *ds, int port, link = priv->r->get_port_reg_le(priv->r->mac_link_sts); if (link & BIT_ULL(port)) state->link = 1; - pr_debug("%s: link state: %llx\n", __func__, link & BIT_ULL(port)); + pr_debug("%s: link state port %d: %llx\n", __func__, port, link & BIT_ULL(port)); state->duplex = 0; if (priv->r->get_port_reg_le(priv->r->mac_link_dup_sts) & BIT_ULL(port)) @@ -364,7 +324,8 @@ static int rtl83xx_phylink_mac_link_state(struct dsa_switch *ds, int port, state->speed = SPEED_1000; break; case 3: - if (port == 24 || port == 26) /* Internal serdes */ + if (priv->family_id == RTL9300_FAMILY_ID + && (port == 24 || port == 26)) /* Internal serdes */ state->speed = SPEED_2500; else state->speed = SPEED_100; /* Is in fact 500Mbit */ @@ -378,7 +339,6 @@ static int rtl83xx_phylink_mac_link_state(struct dsa_switch *ds, int port, return 1; } - static void rtl83xx_config_interface(int port, phy_interface_t interface) { u32 old, int_shift, sds_shift; @@ -583,8 +543,11 @@ static int rtl83xx_port_enable(struct dsa_switch *ds, int port, v |= priv->ports[port].pm; priv->r->traffic_set(port, v); - sw_w32_mask(0, BIT(port), RTL930X_L2_PORT_SABLK_CTRL); - sw_w32_mask(0, BIT(port), RTL930X_L2_PORT_DABLK_CTRL); + // TODO: Figure out if this is necessary + if (priv->family_id == RTL9300_FAMILY_ID) { + sw_w32_mask(0, BIT(port), RTL930X_L2_PORT_SABLK_CTRL); + sw_w32_mask(0, BIT(port), RTL930X_L2_PORT_DABLK_CTRL); + } return 0; } @@ -689,7 +652,7 @@ static int rtl83xx_port_bridge_join(struct dsa_switch *ds, int port, struct net_device *bridge) { struct rtl838x_switch_priv *priv = ds->priv; - u64 port_bitmap = 1ULL << priv->cpu_port, v; + u64 port_bitmap = BIT_ULL(priv->cpu_port), v; int i; pr_debug("%s %x: %d %llx", __func__, (u32)priv, port, port_bitmap); @@ -705,8 +668,8 @@ static int rtl83xx_port_bridge_join(struct dsa_switch *ds, int port, if (priv->ports[i].enable) priv->r->traffic_enable(i, port); - priv->ports[i].pm |= 1ULL << port; - port_bitmap |= 1ULL << i; + priv->ports[i].pm |= BIT_ULL(port); + port_bitmap |= BIT_ULL(i); } } @@ -727,7 +690,7 @@ static void rtl83xx_port_bridge_leave(struct dsa_switch *ds, int port, struct net_device *bridge) { struct rtl838x_switch_priv *priv = ds->priv; - u64 port_bitmap = 1ULL << priv->cpu_port, v; + u64 port_bitmap = BIT_ULL(priv->cpu_port), v; int i; pr_debug("%s %x: %d", __func__, (u32)priv, port); @@ -745,7 +708,7 @@ static void rtl83xx_port_bridge_leave(struct dsa_switch *ds, int port, if (priv->ports[i].enable) priv->r->traffic_disable(i, port); - priv->ports[i].pm |= 1ULL << port; + priv->ports[i].pm |= BIT_ULL(port); port_bitmap &= ~BIT_ULL(i); } } @@ -897,17 +860,16 @@ static int rtl83xx_vlan_prepare(struct dsa_switch *ds, int port, struct rtl838x_vlan_info info; struct rtl838x_switch_priv *priv = ds->priv; - pr_info("%s: port %d\n", __func__, port); + priv->r->vlan_tables_read(0, &info); - mutex_lock(&priv->reg_mutex); - - priv->r->vlan_profile_dump(1); - priv->r->vlan_tables_read(1, &info); - - pr_info("Tagged ports %llx, untag %llx, prof %x, MC# %d, UC# %d, FID %x\n", + pr_debug("VLAN 0: Tagged ports %llx, untag %llx, profile %d, MC# %d, UC# %d, FID %x\n", info.tagged_ports, info.untagged_ports, info.profile_id, info.hash_mc_fid, info.hash_uc_fid, info.fid); + priv->r->vlan_tables_read(1, &info); + pr_debug("VLAN 1: Tagged ports %llx, untag %llx, profile %d, MC# %d, UC# %d, FID %x\n", + info.tagged_ports, info.untagged_ports, info.profile_id, + info.hash_mc_fid, info.hash_uc_fid, info.fid); priv->r->vlan_set_untagged(1, info.untagged_ports); pr_debug("SET: Untagged ports, VLAN %d: %llx\n", 1, info.untagged_ports); @@ -925,7 +887,7 @@ static void rtl83xx_vlan_add(struct dsa_switch *ds, int port, struct rtl838x_switch_priv *priv = ds->priv; int v; - pr_info("%s port %d, vid_end %d, vid_end %d, flags %x\n", __func__, + pr_debug("%s port %d, vid_end %d, vid_end %d, flags %x\n", __func__, port, vlan->vid_begin, vlan->vid_end, vlan->flags); if (vlan->vid_begin > 4095 || vlan->vid_end > 4095) { @@ -970,10 +932,10 @@ static void rtl83xx_vlan_add(struct dsa_switch *ds, int port, info.untagged_ports |= BIT_ULL(port); priv->r->vlan_set_untagged(v, info.untagged_ports); - pr_info("Untagged ports, VLAN %d: %llx\n", v, info.untagged_ports); + pr_debug("Untagged ports, VLAN %d: %llx\n", v, info.untagged_ports); priv->r->vlan_set_tagged(v, &info); - pr_info("Tagged ports, VLAN %d: %llx\n", v, info.tagged_ports); + pr_debug("Tagged ports, VLAN %d: %llx\n", v, info.tagged_ports); } mutex_unlock(&priv->reg_mutex); @@ -1024,59 +986,136 @@ static int rtl83xx_vlan_del(struct dsa_switch *ds, int port, return 0; } -static int rtl83xx_port_fdb_add(struct dsa_switch *ds, int port, - const unsigned char *addr, u16 vid) +static void dump_l2_entry(struct rtl838x_l2_entry *e) { - struct rtl838x_switch_priv *priv = ds->priv; - u64 mac = ether_addr_to_u64(addr); - u32 key = rtl83xx_hash_key(priv, mac, vid); - struct rtl838x_l2_entry e; - u32 r[3]; + pr_info("MAC: %02x:%02x:%02x:%02x:%02x:%02x vid: %d, rvid: %d, port: %d, valid: %d\n", + e->mac[0], e->mac[1], e->mac[2], e->mac[3], e->mac[4], e->mac[5], + e->vid, e->rvid, e->port, e->valid); + + if (e->type != L2_MULTICAST) { + pr_info("Type: %d, is_static: %d, is_ip_mc: %d, is_ipv6_mc: %d, block_da: %d\n", + e->type, e->is_static, e->is_ip_mc, e->is_ipv6_mc, e->block_da); + pr_info(" block_sa: %d, susp: %d, nh: %d, age: %d, is_trunk: %d, trunk: %d\n", + e->block_sa, e->suspended, e->next_hop, e->age, e->is_trunk, e->trunk); + } + if (e->type == L2_MULTICAST) + pr_info(" L2_MULTICAST mc_portmask_index: %d\n", e->mc_portmask_index); + if (e->is_ip_mc || e->is_ipv6_mc) + pr_info(" mc_portmask_index: %d, mc_gip: %d, mc_sip: %d\n", + e->mc_portmask_index, e->mc_gip, e->mc_sip); + pr_info(" stack_dev: %d\n", e->stack_dev); + if (e->next_hop) + pr_info(" nh_route_id: %d\n", e->nh_route_id); +} + +static void rtl83xx_setup_l2_uc_entry(struct rtl838x_l2_entry *e, int port, int vid, u64 mac) +{ + e->is_ip_mc = e->is_ipv6_mc = false; + e->valid = true; + e->age = 3; + e->port = port, + e->vid = vid; + u64_to_ether_addr(mac, e->mac); +} + +static void rtl83xx_setup_l2_mc_entry(struct rtl838x_switch_priv *priv, + struct rtl838x_l2_entry *e, int vid, u64 mac, int mc_group) +{ + e->is_ip_mc = e->is_ipv6_mc = false; + e->valid = true; + e->mc_portmask_index = mc_group; + e->type = L2_MULTICAST; + e->rvid = e->vid = vid; + pr_debug("%s: vid: %d, rvid: %d\n", __func__, e->vid, e->rvid); + u64_to_ether_addr(mac, e->mac); +} + +/* + * Uses the seed to identify a hash bucket in the L2 using the derived hash key and then loops + * over the entries in the bucket until either a matching entry is found or an empty slot + * Returns the filled in rtl838x_l2_entry and the index in the bucket when an entry was found + * when an empty slot was found and must exist is false, the index of the slot is returned + * when no slots are available returns -1 + */ +static int rtl83xx_find_l2_hash_entry(struct rtl838x_switch_priv *priv, u64 seed, + bool must_exist, struct rtl838x_l2_entry *e) +{ + int i, idx = -1; + u32 key = priv->r->l2_hash_key(priv, seed); u64 entry; - int idx = -1, err = 0, i; - mutex_lock(&priv->reg_mutex); - for (i = 0; i < 4; i++) { - entry = priv->r->read_l2_entry_using_hash(key, i, &e); - if (!e.valid) { - idx = (key << 2) | i; - break; - } - if ((entry & 0x0fffffffffffffffULL) == ((mac << 12) | vid)) { - idx = (key << 2) | i; + pr_debug("%s: using key %x, for seed %016llx\n", __func__, key, seed); + // Loop over all entries in the hash-bucket and over the second block on 93xx SoCs + for (i = 0; i < priv->l2_bucket_size; i++) { + entry = priv->r->read_l2_entry_using_hash(key, i, e); + pr_debug("valid %d, mac %016llx\n", e->valid, ether_addr_to_u64(&e->mac[0])); + if (must_exist && !e->valid) + continue; + if (!e->valid || ((entry & 0x0fffffffffffffffULL) == seed)) { + idx = i > 3 ? ((key >> 14) & 0xffff) | i >> 1 : ((key << 2) | i) & 0xffff; break; } } - if (idx >= 0) { - r[0] = 3 << 17 | port << 12; // Aging and port - r[0] |= vid; - r[1] = mac >> 16; - r[2] = (mac & 0xffff) << 12; /* rvid = 0 */ - rtl83xx_write_hash(idx, r); - goto out; - } - /* Hash buckets full, try CAM */ + return idx; +} + +/* + * Uses the seed to identify an entry in the CAM by looping over all its entries + * Returns the filled in rtl838x_l2_entry and the index in the CAM when an entry was found + * when an empty slot was found the index of the slot is returned + * when no slots are available returns -1 + */ +static int rtl83xx_find_l2_cam_entry(struct rtl838x_switch_priv *priv, u64 seed, + bool must_exist, struct rtl838x_l2_entry *e) +{ + int i, idx = -1; + u64 entry; + for (i = 0; i < 64; i++) { - entry = priv->r->read_cam(i, &e); - if (!e.valid) { + entry = priv->r->read_cam(i, e); + if (!must_exist && !e->valid) { if (idx < 0) /* First empty entry? */ idx = i; break; - } else if ((entry & 0x0fffffffffffffffULL) == ((mac << 12) | vid)) { + } else if ((entry & 0x0fffffffffffffffULL) == seed) { pr_debug("Found entry in CAM\n"); idx = i; break; } } + return idx; +} + +static int rtl83xx_port_fdb_add(struct dsa_switch *ds, int port, + const unsigned char *addr, u16 vid) +{ + struct rtl838x_switch_priv *priv = ds->priv; + u64 mac = ether_addr_to_u64(addr); + struct rtl838x_l2_entry e; + int err = 0, idx; + u64 seed = priv->r->l2_hash_seed(mac, vid); + + mutex_lock(&priv->reg_mutex); + + idx = rtl83xx_find_l2_hash_entry(priv, seed, false, &e); + + // Found an existing or empty entry if (idx >= 0) { - r[0] = 3 << 17 | port << 12; // Aging - r[0] |= vid; - r[1] = mac >> 16; - r[2] = (mac & 0xffff) << 12; /* rvid = 0 */ - rtl83xx_write_cam(idx, r); + rtl83xx_setup_l2_uc_entry(&e, port, vid, mac); + priv->r->write_l2_entry_using_hash(idx >> 2, idx & 0x3, &e); goto out; } + + // Hash buckets full, try CAM + rtl83xx_find_l2_cam_entry(priv, seed, false, &e); + + if (idx >= 0) { + rtl83xx_setup_l2_uc_entry(&e, port, vid, mac); + priv->r->write_cam(idx, &e); + goto out; + } + err = -ENOTSUPP; out: mutex_unlock(&priv->reg_mutex); @@ -1088,41 +1127,29 @@ static int rtl83xx_port_fdb_del(struct dsa_switch *ds, int port, { struct rtl838x_switch_priv *priv = ds->priv; u64 mac = ether_addr_to_u64(addr); - u32 key = rtl83xx_hash_key(priv, mac, vid); struct rtl838x_l2_entry e; - u32 r[3]; - u64 entry; - int idx = -1, err = 0, i; + int err = 0, idx; + u64 seed = priv->r->l2_hash_seed(mac, vid); - pr_debug("In %s, mac %llx, vid: %d, key: %x08x\n", __func__, mac, vid, key); + pr_info("In %s, mac %llx, vid: %d\n", __func__, mac, vid); mutex_lock(&priv->reg_mutex); - for (i = 0; i < 4; i++) { - entry = priv->r->read_l2_entry_using_hash(key, i, &e); - if (!e.valid) - continue; - if ((entry & 0x0fffffffffffffffULL) == ((mac << 12) | vid)) { - idx = (key << 2) | i; - break; - } - } + idx = rtl83xx_find_l2_hash_entry(priv, seed, true, &e); + + pr_info("Found entry index %d, key %d and bucket %d\n", idx, idx >> 2, idx & 3); if (idx >= 0) { - r[0] = r[1] = r[2] = 0; - rtl83xx_write_hash(idx, r); + e.valid = false; + dump_l2_entry(&e); + priv->r->write_l2_entry_using_hash(idx >> 2, idx & 0x3, &e); goto out; } /* Check CAM for spillover from hash buckets */ - for (i = 0; i < 64; i++) { - entry = priv->r->read_cam(i, &e); - if ((entry & 0x0fffffffffffffffULL) == ((mac << 12) | vid)) { - idx = i; - break; - } - } + rtl83xx_find_l2_cam_entry(priv, seed, true, &e); + if (idx >= 0) { - r[0] = r[1] = r[2] = 0; - rtl83xx_write_cam(idx, r); + e.valid = false; + priv->r->write_cam(idx, &e); goto out; } err = -ENOENT; @@ -1137,8 +1164,7 @@ static int rtl83xx_port_fdb_dump(struct dsa_switch *ds, int port, struct rtl838x_l2_entry e; struct rtl838x_switch_priv *priv = ds->priv; int i; - u32 fid; - u32 pkey; + u32 fid, pkey; u64 mac; mutex_lock(&priv->reg_mutex); @@ -1150,13 +1176,25 @@ static int rtl83xx_port_fdb_dump(struct dsa_switch *ds, int port, continue; if (e.port == port) { - fid = (i & 0x3ff) | (e.rvid & ~0x3ff); + fid = ((i >> 2) & 0x3ff) | (e.rvid & ~0x3ff); mac = ether_addr_to_u64(&e.mac[0]); - pkey = rtl838x_hash(priv, mac << 12 | fid); + pkey = priv->r->l2_hash_key(priv, priv->r->l2_hash_seed(mac, fid)); fid = (pkey & 0x3ff) | (fid & ~0x3ff); - pr_debug("-> mac %016llx, fid: %d\n", mac, fid); + pr_info("-> index %d, key %x, bucket %d, dmac %016llx, fid: %x rvid: %x\n", + i, i >> 2, i & 0x3, mac, fid, e.rvid); + dump_l2_entry(&e); + u64 seed = priv->r->l2_hash_seed(mac, e.rvid); + u32 key = priv->r->l2_hash_key(priv, seed); + pr_info("seed: %016llx, key based on rvid: %08x\n", seed, key); cb(e.mac, e.vid, e.is_static, data); } + if (e.type == L2_MULTICAST) { + u64 portmask = priv->r->read_mcast_pmask(e.mc_portmask_index); + if (portmask & BIT_ULL(port)) { + dump_l2_entry(&e); + pr_info(" PM: %016llx\n", portmask); + } + } } for (i = 0; i < 64; i++) { @@ -1173,6 +1211,164 @@ static int rtl83xx_port_fdb_dump(struct dsa_switch *ds, int port, return 0; } +static int rtl83xx_port_mdb_prepare(struct dsa_switch *ds, int port, + const struct switchdev_obj_port_mdb *mdb) +{ + struct rtl838x_switch_priv *priv = ds->priv; + + if (priv->id >= 0x9300) + return -EOPNOTSUPP; + + return 0; +} + +static int rtl83xx_mc_group_alloc(struct rtl838x_switch_priv *priv, int port) +{ + int mc_group = find_first_zero_bit(priv->mc_group_bm, MAX_MC_GROUPS - 1); + u64 portmask; + + if (mc_group >= MAX_MC_GROUPS - 1) + return -1; + + pr_debug("Using MC group %d\n", mc_group); + set_bit(mc_group, priv->mc_group_bm); + mc_group++; // We cannot use group 0, as this is used for lookup miss flooding + portmask = BIT_ULL(port); + priv->r->write_mcast_pmask(mc_group, portmask); + + return mc_group; +} + +static u64 rtl83xx_mc_group_add_port(struct rtl838x_switch_priv *priv, int mc_group, int port) +{ + u64 portmask = priv->r->read_mcast_pmask(mc_group); + + portmask |= BIT_ULL(port); + priv->r->write_mcast_pmask(mc_group, portmask); + + return portmask; +} + +static u64 rtl83xx_mc_group_del_port(struct rtl838x_switch_priv *priv, int mc_group, int port) +{ + u64 portmask = priv->r->read_mcast_pmask(mc_group); + + portmask &= ~BIT_ULL(port); + priv->r->write_mcast_pmask(mc_group, portmask); + if (!portmask) + clear_bit(mc_group, priv->mc_group_bm); + + return portmask; +} + +static void rtl83xx_port_mdb_add(struct dsa_switch *ds, int port, + const struct switchdev_obj_port_mdb *mdb) +{ + struct rtl838x_switch_priv *priv = ds->priv; + u64 mac = ether_addr_to_u64(mdb->addr); + struct rtl838x_l2_entry e; + int err = 0, idx; + int vid = mdb->vid; + u64 seed = priv->r->l2_hash_seed(mac, vid); + int mc_group; + + pr_debug("In %s port %d, mac %llx, vid: %d\n", __func__, port, mac, vid); + mutex_lock(&priv->reg_mutex); + + idx = rtl83xx_find_l2_hash_entry(priv, seed, false, &e); + + // Found an existing or empty entry + if (idx >= 0) { + if (e.valid) { + pr_debug("Found an existing entry %016llx, mc_group %d\n", + ether_addr_to_u64(e.mac), e.mc_portmask_index); + rtl83xx_mc_group_add_port(priv, e.mc_portmask_index, port); + } else { + pr_debug("New entry for seed %016llx\n", seed); + mc_group = rtl83xx_mc_group_alloc(priv, port); + if (mc_group < 0) { + err = -ENOTSUPP; + goto out; + } + rtl83xx_setup_l2_mc_entry(priv, &e, vid, mac, mc_group); + priv->r->write_l2_entry_using_hash(idx >> 2, idx & 0x3, &e); + } + goto out; + } + + // Hash buckets full, try CAM + rtl83xx_find_l2_cam_entry(priv, seed, false, &e); + + if (idx >= 0) { + if (e.valid) { + pr_debug("Found existing CAM entry %016llx, mc_group %d\n", + ether_addr_to_u64(e.mac), e.mc_portmask_index); + rtl83xx_mc_group_add_port(priv, e.mc_portmask_index, port); + } else { + pr_debug("New entry\n"); + mc_group = rtl83xx_mc_group_alloc(priv, port); + if (mc_group < 0) { + err = -ENOTSUPP; + goto out; + } + rtl83xx_setup_l2_mc_entry(priv, &e, vid, mac, mc_group); + priv->r->write_cam(idx, &e); + } + goto out; + } + + err = -ENOTSUPP; +out: + mutex_unlock(&priv->reg_mutex); + if (err) + dev_err(ds->dev, "failed to add MDB entry\n"); +} + +int rtl83xx_port_mdb_del(struct dsa_switch *ds, int port, + const struct switchdev_obj_port_mdb *mdb) +{ + struct rtl838x_switch_priv *priv = ds->priv; + u64 mac = ether_addr_to_u64(mdb->addr); + struct rtl838x_l2_entry e; + int err = 0, idx; + int vid = mdb->vid; + u64 seed = priv->r->l2_hash_seed(mac, vid); + u64 portmask; + + pr_debug("In %s, port %d, mac %llx, vid: %d\n", __func__, port, mac, vid); + mutex_lock(&priv->reg_mutex); + + idx = rtl83xx_find_l2_hash_entry(priv, seed, true, &e); + + pr_debug("Found entry index %d, key %d and bucket %d\n", idx, idx >> 2, idx & 3); + if (idx >= 0) { + portmask = rtl83xx_mc_group_del_port(priv, e.mc_portmask_index, port); + if (!portmask) { + e.valid = false; + // dump_l2_entry(&e); + priv->r->write_l2_entry_using_hash(idx >> 2, idx & 0x3, &e); + } + goto out; + } + + /* Check CAM for spillover from hash buckets */ + rtl83xx_find_l2_cam_entry(priv, seed, true, &e); + + if (idx >= 0) { + portmask = rtl83xx_mc_group_del_port(priv, e.mc_portmask_index, port); + if (!portmask) { + e.valid = false; + // dump_l2_entry(&e); + priv->r->write_cam(idx, &e); + } + goto out; + } + // TODO: Re-enable with a newer kernel: err = -ENOENT; +out: + mutex_unlock(&priv->reg_mutex); + return err; +} + static int rtl83xx_port_mirror_add(struct dsa_switch *ds, int port, struct dsa_mall_mirror_tc_entry *mirror, bool ingress) @@ -1339,6 +1535,10 @@ const struct dsa_switch_ops rtl83xx_switch_ops = { .port_fdb_del = rtl83xx_port_fdb_del, .port_fdb_dump = rtl83xx_port_fdb_dump, + .port_mdb_prepare = rtl83xx_port_mdb_prepare, + .port_mdb_add = rtl83xx_port_mdb_add, + .port_mdb_del = rtl83xx_port_mdb_del, + .port_mirror_add = rtl83xx_port_mirror_add, .port_mirror_del = rtl83xx_port_mirror_del, }; @@ -1380,4 +1580,9 @@ const struct dsa_switch_ops rtl930x_switch_ops = { .port_fdb_add = rtl83xx_port_fdb_add, .port_fdb_del = rtl83xx_port_fdb_del, .port_fdb_dump = rtl83xx_port_fdb_dump, + + .port_mdb_prepare = rtl83xx_port_mdb_prepare, + .port_mdb_add = rtl83xx_port_mdb_add, + .port_mdb_del = rtl83xx_port_mdb_del, + }; diff --git a/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl838x.c b/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl838x.c index 9ecd189d91..dfd773c5e6 100644 --- a/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl838x.c +++ b/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl838x.c @@ -102,6 +102,40 @@ static void rtl838x_vlan_fwd_on_inner(int port, bool is_set) sw_w32_mask(0, BIT(port), RTL838X_VLAN_PORT_FWD); } +static u64 rtl838x_l2_hash_seed(u64 mac, u32 vid) +{ + return mac << 12 | vid; +} + +/* + * Applies the same hash algorithm as the one used currently by the ASIC to the seed + * and returns a key into the L2 hash table + */ +static u32 rtl838x_l2_hash_key(struct rtl838x_switch_priv *priv, u64 seed) +{ + u32 h1, h2, h3, h; + + if (sw_r32(priv->r->l2_ctrl_0) & 1) { + h1 = (seed >> 11) & 0x7ff; + h1 = ((h1 & 0x1f) << 6) | ((h1 >> 5) & 0x3f); + + h2 = (seed >> 33) & 0x7ff; + h2 = ((h2 & 0x3f) << 5) | ((h2 >> 6) & 0x1f); + + h3 = (seed >> 44) & 0x7ff; + h3 = ((h3 & 0x7f) << 4) | ((h3 >> 7) & 0xf); + + h = h1 ^ h2 ^ h3 ^ ((seed >> 55) & 0x1ff); + h ^= ((seed >> 22) & 0x7ff) ^ (seed & 0x7ff); + } else { + h = ((seed >> 55) & 0x1ff) ^ ((seed >> 44) & 0x7ff) + ^ ((seed >> 33) & 0x7ff) ^ ((seed >> 22) & 0x7ff) + ^ ((seed >> 11) & 0x7ff) ^ (seed & 0x7ff); + } + + return h; +} + static inline int rtl838x_mac_force_mode_ctrl(int p) { return RTL838X_MAC_FORCE_MODE_CTRL + (p << 2); @@ -132,84 +166,202 @@ inline static int rtl838x_trk_mbr_ctr(int group) return RTL838X_TRK_MBR_CTR + (group << 2); } -static u64 rtl838x_read_l2_entry_using_hash(u32 hash, u32 position, struct rtl838x_l2_entry *e) +/* + * Fills an L2 entry structure from the SoC registers + */ +static void rtl838x_fill_l2_entry(u32 r[], struct rtl838x_l2_entry *e) +{ + /* Table contains different entry types, we need to identify the right one: + * Check for MC entries, first + * In contrast to the RTL93xx SoCs, there is no valid bit, use heuristics to + * identify valid entries + */ + e->is_ip_mc = !!(r[0] & BIT(22)); + e->is_ipv6_mc = !!(r[0] & BIT(21)); + e->type = L2_INVALID; + + if (!e->is_ip_mc && !e->is_ipv6_mc) { + e->mac[0] = (r[1] >> 20); + e->mac[1] = (r[1] >> 12); + e->mac[2] = (r[1] >> 4); + e->mac[3] = (r[1] & 0xf) << 4 | (r[2] >> 28); + e->mac[4] = (r[2] >> 20); + e->mac[5] = (r[2] >> 12); + + e->rvid = r[2] & 0xfff; + e->vid = r[0] & 0xfff; + + /* Is it a unicast entry? check multicast bit */ + if (!(e->mac[0] & 1)) { + e->is_static = !!((r[0] >> 19) & 1); + e->port = (r[0] >> 12) & 0x1f; + e->block_da = !!(r[1] & BIT(30)); + e->block_sa = !!(r[1] & BIT(31)); + e->suspended = !!(r[1] & BIT(29)); + e->next_hop = !!(r[1] & BIT(28)); + if (e->next_hop) { + pr_info("Found next hop entry, need to read extra data\n"); + e->nh_vlan_target = !!(r[0] & BIT(9)); + e->nh_route_id = r[0] & 0x1ff; + } + e->age = (r[0] >> 17) & 0x3; + e->valid = true; + + /* A valid entry has one of mutli-cast, aging, sa/da-blocking, + * next-hop or static entry bit set */ + if (!(r[0] & 0x007c0000) && !(r[1] & 0xd0000000)) + e->valid = false; + else + e->type = L2_UNICAST; + } else { // L2 multicast + pr_info("Got L2 MC entry: %08x %08x %08x\n", r[0], r[1], r[2]); + e->valid = true; + e->type = L2_MULTICAST; + e->mc_portmask_index = (r[0] >> 12) & 0x1ff; + } + } else { // IPv4 and IPv6 multicast + e->valid = true; + e->mc_portmask_index = (r[0] >> 12) & 0x1ff; + e->mc_gip = r[1]; + e->mc_sip = r[2]; + e->rvid = r[0] & 0xfff; + } + if (e->is_ip_mc) + e->type = IP4_MULTICAST; + if (e->is_ipv6_mc) + e->type = IP6_MULTICAST; +} + +/* + * Fills the 3 SoC table registers r[] with the information of in the rtl838x_l2_entry + */ +static void rtl838x_fill_l2_row(u32 r[], struct rtl838x_l2_entry *e) +{ + u64 mac = ether_addr_to_u64(e->mac); + + if (!e->valid) { + r[0] = r[1] = r[2] = 0; + return; + } + + r[0] = e->is_ip_mc ? BIT(22) : 0; + r[0] |= e->is_ipv6_mc ? BIT(21) : 0; + + if (!e->is_ip_mc && !e->is_ipv6_mc) { + r[1] = mac >> 20; + r[2] = (mac & 0xfffff) << 12; + + /* Is it a unicast entry? check multicast bit */ + if (!(e->mac[0] & 1)) { + r[0] |= e->is_static ? BIT(19) : 0; + r[0] |= (e->port & 0x3f) << 12; + r[0] |= e->vid; + r[1] |= e->block_da ? BIT(30) : 0; + r[1] |= e->block_sa ? BIT(31) : 0; + r[1] |= e->suspended ? BIT(29) : 0; + r[2] |= e->rvid & 0xfff; + if (e->next_hop) { + r[1] |= BIT(28); + r[0] |= e->nh_vlan_target ? BIT(9) : 0; + r[0] |= e->nh_route_id &0x1ff; + } + r[0] |= (e->age & 0x3) << 17; + } else { // L2 Multicast + r[0] |= (e->mc_portmask_index & 0x1ff) << 12; + r[2] |= e->rvid & 0xfff; + r[0] |= e->vid & 0xfff; + pr_info("FILL MC: %08x %08x %08x\n", r[0], r[1], r[2]); + } + } else { // IPv4 and IPv6 multicast + r[1] = e->mc_gip; + r[2] = e->mc_sip; + r[0] |= e->rvid; + } +} + +/* + * Read an L2 UC or MC entry out of a hash bucket of the L2 forwarding table + * hash is the id of the bucket and pos is the position of the entry in that bucket + * The data read from the SoC is filled into rtl838x_l2_entry + */ +static u64 rtl838x_read_l2_entry_using_hash(u32 hash, u32 pos, struct rtl838x_l2_entry *e) { u64 entry; u32 r[3]; + struct table_reg *q = rtl_table_get(RTL8380_TBL_L2, 0); // Access L2 Table 0 + u32 idx = (0 << 14) | (hash << 2) | pos; // Search SRAM, with hash and at pos in bucket + int i; - /* Search in SRAM, with hash and at position in hash bucket (0-3) */ - u32 idx = (0 << 14) | (hash << 2) | position; + rtl_table_read(q, idx); + for (i= 0; i < 3; i++) + r[i] = sw_r32(rtl_table_data(q, i)); - u32 cmd = BIT(16) /* Execute cmd */ - | BIT(15) /* Read */ - | 0 << 13 /* Table type 0b00 */ - | (idx & 0x1fff); + rtl_table_release(q); - sw_w32(cmd, RTL838X_TBL_ACCESS_L2_CTRL); - do { } while (sw_r32(RTL838X_TBL_ACCESS_L2_CTRL) & BIT(16)); - r[0] = sw_r32(RTL838X_TBL_ACCESS_L2_DATA(0)); - r[1] = sw_r32(RTL838X_TBL_ACCESS_L2_DATA(1)); - r[2] = sw_r32(RTL838X_TBL_ACCESS_L2_DATA(2)); - - e->mac[0] = (r[1] >> 20); - e->mac[1] = (r[1] >> 12); - e->mac[2] = (r[1] >> 4); - e->mac[3] = (r[1] & 0xf) << 4 | (r[2] >> 28); - e->mac[4] = (r[2] >> 20); - e->mac[5] = (r[2] >> 12); - e->is_static = !!((r[0] >> 19) & 1); - e->vid = r[0] & 0xfff; - e->rvid = r[2] & 0xfff; - e->port = (r[0] >> 12) & 0x1f; - - e->valid = true; - if (!(r[0] >> 17)) /* Check for invalid entry */ - e->valid = false; - - if (e->valid) - pr_debug("Found in Hash: R1 %x R2 %x R3 %x\n", r[0], r[1], r[2]); + rtl838x_fill_l2_entry(r, e); + if (!e->valid) + return 0; entry = (((u64) r[1]) << 32) | (r[2] & 0xfffff000) | (r[0] & 0xfff); return entry; } +static void rtl838x_write_l2_entry_using_hash(u32 hash, u32 pos, struct rtl838x_l2_entry *e) +{ + u32 r[3]; + struct table_reg *q = rtl_table_get(RTL8380_TBL_L2, 0); + int i; + + u32 idx = (0 << 14) | (hash << 2) | pos; // Access SRAM, with hash and at pos in bucket + + rtl838x_fill_l2_row(r, e); + + for (i= 0; i < 3; i++) + sw_w32(r[i], rtl_table_data(q, i)); + + rtl_table_write(q, idx); + rtl_table_release(q); +} + static u64 rtl838x_read_cam(int idx, struct rtl838x_l2_entry *e) { u64 entry; u32 r[3]; + struct table_reg *q = rtl_table_get(RTL8380_TBL_L2, 1); // Access L2 Table 1 + int i; - u32 cmd = BIT(16) /* Execute cmd */ - | BIT(15) /* Read */ - | BIT(13) /* Table type 0b01 */ - | (idx & 0x3f); - sw_w32(cmd, RTL838X_TBL_ACCESS_L2_CTRL); - do { } while (sw_r32(RTL838X_TBL_ACCESS_L2_CTRL) & BIT(16)); - r[0] = sw_r32(RTL838X_TBL_ACCESS_L2_DATA(0)); - r[1] = sw_r32(RTL838X_TBL_ACCESS_L2_DATA(1)); - r[2] = sw_r32(RTL838X_TBL_ACCESS_L2_DATA(2)); + rtl_table_read(q, idx); + for (i= 0; i < 3; i++) + r[i] = sw_r32(rtl_table_data(q, i)); - e->mac[0] = (r[1] >> 20); - e->mac[1] = (r[1] >> 12); - e->mac[2] = (r[1] >> 4); - e->mac[3] = (r[1] & 0xf) << 4 | (r[2] >> 28); - e->mac[4] = (r[2] >> 20); - e->mac[5] = (r[2] >> 12); - e->is_static = !!((r[0] >> 19) & 1); - e->vid = r[0] & 0xfff; - e->rvid = r[2] & 0xfff; - e->port = (r[0] >> 12) & 0x1f; + rtl_table_release(q); - e->valid = true; - if (!(r[0] >> 17)) /* Check for invalid entry */ - e->valid = false; + rtl838x_fill_l2_entry(r, e); + if (!e->valid) + return 0; - if (e->valid) - pr_debug("Found in CAM: R1 %x R2 %x R3 %x\n", r[0], r[1], r[2]); + pr_debug("Found in CAM: R1 %x R2 %x R3 %x\n", r[0], r[1], r[2]); + // Return MAC with concatenated VID ac concatenated ID entry = (((u64) r[1]) << 32) | (r[2] & 0xfffff000) | (r[0] & 0xfff); return entry; } +static void rtl838x_write_cam(int idx, struct rtl838x_l2_entry *e) +{ + u32 r[3]; + struct table_reg *q = rtl_table_get(RTL8380_TBL_L2, 1); // Access L2 Table 1 + int i; + + rtl838x_fill_l2_row(r, e); + + for (i= 0; i < 3; i++) + sw_w32(r[i], rtl_table_data(q, i)); + + rtl_table_write(q, idx); + rtl_table_release(q); +} + static u64 rtl838x_read_mcast_pmask(int idx) { u32 portmask; @@ -431,7 +583,9 @@ const struct rtl838x_reg rtl838x_reg = { .mac_rx_pause_sts = RTL838X_MAC_RX_PAUSE_STS, .mac_tx_pause_sts = RTL838X_MAC_TX_PAUSE_STS, .read_l2_entry_using_hash = rtl838x_read_l2_entry_using_hash, + .write_l2_entry_using_hash = rtl838x_write_l2_entry_using_hash, .read_cam = rtl838x_read_cam, + .write_cam = rtl838x_write_cam, .vlan_port_egr_filter = RTL838X_VLAN_PORT_EGR_FLTR, .vlan_port_igr_filter = RTL838X_VLAN_PORT_IGR_FLTR(0), .vlan_port_pb = RTL838X_VLAN_PORT_PB_VLAN, @@ -442,6 +596,8 @@ const struct rtl838x_reg rtl838x_reg = { .init_eee = rtl838x_init_eee, .port_eee_set = rtl838x_port_eee_set, .eee_port_ability = rtl838x_eee_port_ability, + .l2_hash_seed = rtl838x_l2_hash_seed, + .l2_hash_key = rtl838x_l2_hash_key, .read_mcast_pmask = rtl838x_read_mcast_pmask, .write_mcast_pmask = rtl838x_write_mcast_pmask, }; @@ -659,34 +815,6 @@ void rtl8380_get_version(struct rtl838x_switch_priv *priv) } } -/* - * Applies the same hash algorithm as the one used currently by the ASIC - */ -u32 rtl838x_hash(struct rtl838x_switch_priv *priv, u64 seed) -{ - u32 h1, h2, h3, h; - - if (sw_r32(priv->r->l2_ctrl_0) & 1) { - h1 = (seed >> 11) & 0x7ff; - h1 = ((h1 & 0x1f) << 6) | ((h1 >> 5) & 0x3f); - - h2 = (seed >> 33) & 0x7ff; - h2 = ((h2 & 0x3f) << 5) | ((h2 >> 6) & 0x1f); - - h3 = (seed >> 44) & 0x7ff; - h3 = ((h3 & 0x7f) << 4) | ((h3 >> 7) & 0xf); - - h = h1 ^ h2 ^ h3 ^ ((seed >> 55) & 0x1ff); - h ^= ((seed >> 22) & 0x7ff) ^ (seed & 0x7ff); - } else { - h = ((seed >> 55) & 0x1ff) ^ ((seed >> 44) & 0x7ff) - ^ ((seed >> 33) & 0x7ff) ^ ((seed >> 22) & 0x7ff) - ^ ((seed >> 11) & 0x7ff) ^ (seed & 0x7ff); - } - - return h; -} - void rtl838x_vlan_profile_dump(int profile) { u32 p; diff --git a/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl838x.h b/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl838x.h index 5990b6453a..b2097363b9 100644 --- a/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl838x.h +++ b/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl838x.h @@ -341,6 +341,7 @@ #define MAX_VLANS 4096 #define MAX_LAGS 16 #define MAX_PRIOS 8 +#define RTL930X_PORT_IGNORE 0x3f #define MAX_MC_GROUPS 512 #define UNKNOWN_MC_PMASK (MAX_MC_GROUPS - 1) @@ -398,8 +399,27 @@ struct rtl838x_l2_entry { bool next_hop; int age; u8 trunk; - u8 stackDev; + bool is_trunk; + u8 stack_dev; u16 mc_portmask_index; + u32 mc_gip; + u32 mc_sip; + u16 mc_mac_index; + u16 nh_route_id; + bool nh_vlan_target; // Only RTL83xx: VLAN used for next hop +}; + +struct rtl838x_nexthop { + u16 id; // ID in HW Nexthop table + u32 ip; // IP Addres of nexthop + u32 dev_id; + u16 port; + u16 vid; + u16 fid; + u64 mac; + u16 mac_id; + u16 l2_id; // Index of this next hop forwarding entry in L2 FIB table + u16 if_id; }; struct rtl838x_switch_priv; @@ -451,7 +471,9 @@ struct rtl838x_reg { int mac_rx_pause_sts; int mac_tx_pause_sts; u64 (*read_l2_entry_using_hash)(u32 hash, u32 position, struct rtl838x_l2_entry *e); + void (*write_l2_entry_using_hash)(u32 hash, u32 pos, struct rtl838x_l2_entry *e); u64 (*read_cam)(int idx, struct rtl838x_l2_entry *e); + void (*write_cam)(int idx, struct rtl838x_l2_entry *e); int vlan_port_egr_filter; int vlan_port_igr_filter; int vlan_port_pb; @@ -464,6 +486,8 @@ struct rtl838x_reg { void (*port_eee_set)(struct rtl838x_switch_priv *priv, int port, bool enable); int (*eee_port_ability)(struct rtl838x_switch_priv *priv, struct ethtool_eee *e, int port); + u64 (*l2_hash_seed)(u64 mac, u32 vid); + u32 (*l2_hash_key)(struct rtl838x_switch_priv *priv, u64 seed); u64 (*read_mcast_pmask)(int idx); void (*write_mcast_pmask)(int idx, u64 portmask); void (*vlan_fwd_on_inner)(int port, bool is_set); @@ -494,6 +518,7 @@ struct rtl838x_switch_priv { struct net_device *lag_devs[MAX_LAGS]; struct notifier_block nb; bool eee_enabled; + unsigned long int mc_group_bm[MAX_MC_GROUPS >> 5]; }; void rtl838x_dbgfs_init(struct rtl838x_switch_priv *priv); diff --git a/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl839x.c b/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl839x.c index bf2e3d3980..74472461a1 100644 --- a/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl839x.c +++ b/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl839x.c @@ -125,6 +125,45 @@ static void rtl839x_vlan_fwd_on_inner(int port, bool is_set) rtl839x_mask_port_reg_be(0ULL, BIT_ULL(port), RTL839X_VLAN_PORT_FWD); } +/* + * Hash seed is vid (actually rvid) concatenated with the MAC address + */ +static u64 rtl839x_l2_hash_seed(u64 mac, u32 vid) +{ + u64 v = vid; + + v <<= 48; + v |= mac; + + return v; +} + +/* + * Applies the same hash algorithm as the one used currently by the ASIC to the seed + * and returns a key into the L2 hash table + */ +static u32 rtl839x_l2_hash_key(struct rtl838x_switch_priv *priv, u64 seed) +{ + u32 h1, h2, h; + + if (sw_r32(priv->r->l2_ctrl_0) & 1) { + h1 = (u32) (((seed >> 60) & 0x3f) ^ ((seed >> 54) & 0x3f) + ^ ((seed >> 36) & 0x3f) ^ ((seed >> 30) & 0x3f) + ^ ((seed >> 12) & 0x3f) ^ ((seed >> 6) & 0x3f)); + h2 = (u32) (((seed >> 48) & 0x3f) ^ ((seed >> 42) & 0x3f) + ^ ((seed >> 24) & 0x3f) ^ ((seed >> 18) & 0x3f) + ^ (seed & 0x3f)); + h = (h1 << 6) | h2; + } else { + h = (seed >> 60) + ^ ((((seed >> 48) & 0x3f) << 6) | ((seed >> 54) & 0x3f)) + ^ ((seed >> 36) & 0xfff) ^ ((seed >> 24) & 0xfff) + ^ ((seed >> 12) & 0xfff) ^ (seed & 0xfff); + } + + return h; +} + static inline int rtl839x_mac_force_mode_ctrl(int p) { return RTL839X_MAC_FORCE_MODE_CTRL + (p << 2); @@ -205,55 +244,131 @@ static void rtl839x_fill_l2_entry(u32 r[], struct rtl838x_l2_entry *e) } } -static u64 rtl839x_read_l2_entry_using_hash(u32 hash, u32 position, struct rtl838x_l2_entry *e) +/* + * Fills the 3 SoC table registers r[] with the information of in the rtl838x_l2_entry + */ +static void rtl839x_fill_l2_row(u32 r[], struct rtl838x_l2_entry *e) +{ + if (!e->valid) { + r[0] = r[1] = r[2] = 0; + return; + } + + r[2] = e->is_ip_mc ? BIT(31) : 0; + r[2] |= e->is_ipv6_mc ? BIT(30) : 0; + + if (!e->is_ip_mc && !e->is_ipv6_mc) { + r[0] = ((u32)e->mac[0]) << 12; + r[0] |= ((u32)e->mac[1]) << 4; + r[0] |= ((u32)e->mac[2]) >> 4; + r[1] = ((u32)e->mac[2]) << 28; + r[1] |= ((u32)e->mac[3]) << 20; + r[1] |= ((u32)e->mac[4]) << 12; + r[1] |= ((u32)e->mac[5]) << 4; + + if (!(e->mac[0] & 1)) { // Not multicast + r[2] |= e->is_static ? BIT(18) : 0; + r[2] |= e->vid << 4; + r[0] |= ((u32)e->rvid) << 20; + r[2] |= e->port << 24; + r[2] |= e->block_da ? BIT(19) : 0; + r[2] |= e->block_sa ? BIT(20) : 0; + r[2] |= e->suspended ? BIT(17) : 0; + if (e->next_hop) { + r[2] |= BIT(16); + r[2] |= e->nh_vlan_target ? BIT(15) : 0; + r[2] |= (e->nh_route_id & 0x7ff) << 4; + } + r[2] |= ((u32)e->age) << 21; + } else { // L2 Multicast + r[0] |= ((u32)e->rvid) << 20; + r[2] |= ((u32)e->mc_portmask_index) << 6; + pr_debug("Write L2 MC entry: %08x %08x %08x\n", r[0], r[1], r[2]); + } + } else { // IPv4 or IPv6 MC entry + r[0] = ((u32)e->rvid) << 20; + r[2] |= ((u32)e->mc_portmask_index) << 6; + r[1] = e->mc_gip; + } +} + +/* + * Read an L2 UC or MC entry out of a hash bucket of the L2 forwarding table + * hash is the id of the bucket and pos is the position of the entry in that bucket + * The data read from the SoC is filled into rtl838x_l2_entry + */ +static u64 rtl839x_read_l2_entry_using_hash(u32 hash, u32 pos, struct rtl838x_l2_entry *e) { - u64 entry; u32 r[3]; + struct table_reg *q = rtl_table_get(RTL8390_TBL_L2, 0); + u32 idx = (0 << 14) | (hash << 2) | pos; // Search SRAM, with hash and at pos in bucket + int i; - /* Search in SRAM, with hash and at position in hash bucket (0-3) */ - u32 idx = (0 << 14) | (hash << 2) | position; + rtl_table_read(q, idx); + for (i= 0; i < 3; i++) + r[i] = sw_r32(rtl_table_data(q, i)); - u32 cmd = 1 << 17 /* Execute cmd */ - | 0 << 16 /* Read */ - | 0 << 14 /* Table type 0b00 */ - | (idx & 0x3fff); - - sw_w32(cmd, RTL839X_TBL_ACCESS_L2_CTRL); - do { } while (sw_r32(RTL839X_TBL_ACCESS_L2_CTRL) & (1 << 17)); - r[0] = sw_r32(RTL839X_TBL_ACCESS_L2_DATA(0)); - r[1] = sw_r32(RTL839X_TBL_ACCESS_L2_DATA(1)); - r[2] = sw_r32(RTL839X_TBL_ACCESS_L2_DATA(2)); + rtl_table_release(q); rtl839x_fill_l2_entry(r, e); + if (!e->valid) + return 0; - entry = (((u64) r[0]) << 12) | ((r[1] & 0xfffffff0) << 12) | ((r[2] >> 4) & 0xfff); - return entry; + return rtl839x_l2_hash_seed(ether_addr_to_u64(&e->mac[0]), e->rvid); +} + +static void rtl839x_write_l2_entry_using_hash(u32 hash, u32 pos, struct rtl838x_l2_entry *e) +{ + u32 r[3]; + struct table_reg *q = rtl_table_get(RTL8390_TBL_L2, 0); + int i; + + u32 idx = (0 << 14) | (hash << 2) | pos; // Access SRAM, with hash and at pos in bucket + + rtl839x_fill_l2_row(r, e); + + for (i= 0; i < 3; i++) + sw_w32(r[i], rtl_table_data(q, i)); + + rtl_table_write(q, idx); + rtl_table_release(q); } static u64 rtl839x_read_cam(int idx, struct rtl838x_l2_entry *e) { - u64 entry; u32 r[3]; + struct table_reg *q = rtl_table_get(RTL8390_TBL_L2, 1); // Access L2 Table 1 + int i; - u32 cmd = 1 << 17 /* Execute cmd */ - | 0 << 16 /* Read */ - | 1 << 14 /* Table type 0b01 */ - | (idx & 0x3f); - sw_w32(cmd, RTL839X_TBL_ACCESS_L2_CTRL); - do { } while (sw_r32(RTL839X_TBL_ACCESS_L2_CTRL) & (1 << 17)); - r[0] = sw_r32(RTL839X_TBL_ACCESS_L2_DATA(0)); - r[1] = sw_r32(RTL839X_TBL_ACCESS_L2_DATA(1)); - r[2] = sw_r32(RTL839X_TBL_ACCESS_L2_DATA(2)); + rtl_table_read(q, idx); + for (i= 0; i < 3; i++) + r[i] = sw_r32(rtl_table_data(q, i)); + rtl_table_release(q); rtl839x_fill_l2_entry(r, e); - if (e->valid) - pr_info("Found in CAM: R1 %x R2 %x R3 %x\n", r[0], r[1], r[2]); - else + if (!e->valid) return 0; - entry = (((u64) r[0]) << 12) | ((r[1] & 0xfffffff0) << 12) | ((r[2] >> 4) & 0xfff); - return entry; + pr_debug("Found in CAM: R1 %x R2 %x R3 %x\n", r[0], r[1], r[2]); + + // Return MAC with concatenated VID ac concatenated ID + return rtl839x_l2_hash_seed(ether_addr_to_u64(&e->mac[0]), e->rvid); +} + +static void rtl839x_write_cam(int idx, struct rtl838x_l2_entry *e) +{ + u32 r[3]; + struct table_reg *q = rtl_table_get(RTL8390_TBL_L2, 1); // Access L2 Table 1 + int i; + + rtl839x_fill_l2_row(r, e); + + for (i= 0; i < 3; i++) + sw_w32(r[i], rtl_table_data(q, i)); + + rtl_table_write(q, idx); + rtl_table_release(q); } static u64 rtl839x_read_mcast_pmask(int idx) @@ -326,7 +441,7 @@ void rtl839x_traffic_enable(int source, int dest) void rtl839x_traffic_disable(int source, int dest) { - rtl839x_mask_port_reg_be(BIT(dest), 0, rtl839x_port_iso_ctrl(source)); + rtl839x_mask_port_reg_be(BIT_ULL(dest), 0, rtl839x_port_iso_ctrl(source)); } irqreturn_t rtl839x_switch_irq(int irq, void *dev_id) @@ -341,10 +456,10 @@ irqreturn_t rtl839x_switch_irq(int irq, void *dev_id) rtl839x_set_port_reg_le(ports, RTL839X_ISR_PORT_LINK_STS_CHG); pr_debug("RTL8390 Link change: status: %x, ports %llx\n", status, ports); - for (i = 0; i < 52; i++) { - if (ports & (1ULL << i)) { + for (i = 0; i < RTL839X_CPU_PORT; i++) { + if (ports & BIT_ULL(i)) { link = rtl839x_get_port_reg_le(RTL839X_MAC_LINK_STS); - if (link & (1ULL << i)) + if (link & BIT_ULL(i)) dsa_port_phylink_mac_change(ds, i, true); else dsa_port_phylink_mac_change(ds, i, false); @@ -372,7 +487,6 @@ int rtl8390_sds_power(int mac, int val) return 0; } - int rtl839x_read_phy(u32 port, u32 page, u32 reg, u32 *val) { u32 v; @@ -506,28 +620,6 @@ void rtl8390_get_version(struct rtl838x_switch_priv *priv) priv->version = RTL8390_VERSION_A; } -u32 rtl839x_hash(struct rtl838x_switch_priv *priv, u64 seed) -{ - u32 h1, h2, h; - - if (sw_r32(priv->r->l2_ctrl_0) & 1) { - h1 = (u32) (((seed >> 60) & 0x3f) ^ ((seed >> 54) & 0x3f) - ^ ((seed >> 36) & 0x3f) ^ ((seed >> 30) & 0x3f) - ^ ((seed >> 12) & 0x3f) ^ ((seed >> 6) & 0x3f)); - h2 = (u32) (((seed >> 48) & 0x3f) ^ ((seed >> 42) & 0x3f) - ^ ((seed >> 24) & 0x3f) ^ ((seed >> 18) & 0x3f) - ^ (seed & 0x3f)); - h = (h1 << 6) | h2; - } else { - h = (seed >> 60) - ^ ((((seed >> 48) & 0x3f) << 6) | ((seed >> 54) & 0x3f)) - ^ ((seed >> 36) & 0xfff) ^ ((seed >> 24) & 0xfff) - ^ ((seed >> 12) & 0xfff) ^ (seed & 0xfff); - } - - return h; -} - void rtl839x_vlan_profile_dump(int profile) { u32 p[2]; @@ -695,7 +787,9 @@ const struct rtl838x_reg rtl839x_reg = { .mac_rx_pause_sts = RTL839X_MAC_RX_PAUSE_STS, .mac_tx_pause_sts = RTL839X_MAC_TX_PAUSE_STS, .read_l2_entry_using_hash = rtl839x_read_l2_entry_using_hash, + .write_l2_entry_using_hash = rtl839x_write_l2_entry_using_hash, .read_cam = rtl839x_read_cam, + .write_cam = rtl839x_write_cam, .vlan_port_egr_filter = RTL839X_VLAN_PORT_EGR_FLTR(0), .vlan_port_igr_filter = RTL839X_VLAN_PORT_IGR_FLTR(0), .vlan_port_pb = RTL839X_VLAN_PORT_PB_VLAN, @@ -706,6 +800,8 @@ const struct rtl838x_reg rtl839x_reg = { .init_eee = rtl839x_init_eee, .port_eee_set = rtl839x_port_eee_set, .eee_port_ability = rtl839x_eee_port_ability, + .l2_hash_seed = rtl839x_l2_hash_seed, + .l2_hash_key = rtl839x_l2_hash_key, .read_mcast_pmask = rtl839x_read_mcast_pmask, .write_mcast_pmask = rtl839x_write_mcast_pmask, }; diff --git a/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl930x.c b/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl930x.c index a80a6d89b2..820c78165a 100644 --- a/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl930x.c +++ b/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl930x.c @@ -207,12 +207,74 @@ static inline int rtl930x_mac_link_spd_sts(int p) return RTL930X_MAC_LINK_SPD_STS(p); } +static u64 rtl930x_l2_hash_seed(u64 mac, u32 vid) +{ + u64 v = vid; + + v <<= 48; + v |= mac; + + return v; +} + +/* + * Calculate both the block 0 and the block 1 hash by applyingthe same hash + * algorithm as the one used currently by the ASIC to the seed, and return + * both hashes in the lower and higher word of the return value since only 12 bit of + * the hash are significant + */ +static u32 rtl930x_l2_hash_key(struct rtl838x_switch_priv *priv, u64 seed) +{ + u32 k0, k1, h1, h2, h; + + k0 = (u32) (((seed >> 55) & 0x1f) ^ ((seed >> 44) & 0x7ff) + ^ ((seed >> 33) & 0x7ff) ^ ((seed >> 22) & 0x7ff) + ^ ((seed >> 11) & 0x7ff) ^ (seed & 0x7ff)); + + h1 = (seed >> 11) & 0x7ff; + h1 = ((h1 & 0x1f) << 6) | ((h1 >> 5) & 0x3f); + + h2 = (seed >> 33) & 0x7ff; + h2 = ((h2 & 0x3f) << 5)| ((h2 >> 6) & 0x3f); + + k1 = (u32) (((seed << 55) & 0x1f) ^ ((seed >> 44) & 0x7ff) ^ h2 + ^ ((seed >> 22) & 0x7ff) ^ h1 + ^ (seed & 0x7ff)); + + // Algorithm choice for block 0 + if (sw_r32(RTL930X_L2_CTRL) & BIT(0)) + h = k1; + else + h = k0; + + /* Algorithm choice for block 1 + * Since k0 and k1 are < 2048, adding 2048 will offset the hash into the second + * half of hash-space + * 2048 is in fact the hash-table size 16384 divided by 4 hashes per bucket + * divided by 2 to divide the hash space in 2 + */ + if (sw_r32(RTL930X_L2_CTRL) & BIT(1)) + h |= (k1 + 2048) << 16; + else + h |= (k0 + 2048) << 16; + + return h; +} + +/* + * Fills an L2 entry structure from the SoC registers + */ static void rtl930x_fill_l2_entry(u32 r[], struct rtl838x_l2_entry *e) { + pr_debug("In %s valid?\n", __func__); e->valid = !!(r[2] & BIT(31)); if (!e->valid) return; + pr_debug("In %s is valid\n", __func__); + e->is_ip_mc = false; + e->is_ipv6_mc = false; + // TODO: Is there not a function to copy directly MAC memory? e->mac[0] = (r[0] >> 24); e->mac[1] = (r[0] >> 16); @@ -221,61 +283,164 @@ static void rtl930x_fill_l2_entry(u32 r[], struct rtl838x_l2_entry *e) e->mac[4] = (r[1] >> 24); e->mac[5] = (r[1] >> 16); + e->next_hop = !!(r[2] & BIT(12)); + e->rvid = r[1] & 0xfff; + /* Is it a unicast entry? check multicast bit */ if (!(e->mac[0] & 1)) { e->type = L2_UNICAST; e->is_static = !!(r[2] & BIT(14)); - e->vid = r[2] & 0xfff; - e->rvid = r[1] & 0xfff; e->port = (r[2] >> 20) & 0x3ff; // Check for trunk port if (r[2] & BIT(30)) { - e->stackDev = (e->port >> 9) & 1; + e->is_trunk = true; + e->stack_dev = (e->port >> 9) & 1; e->trunk = e->port & 0x3f; } else { - e->stackDev = (e->port >> 6) & 0xf; + e->is_trunk = false; + e->stack_dev = (e->port >> 6) & 0xf; e->port = e->port & 0x3f; } e->block_da = !!(r[2] & BIT(15)); e->block_sa = !!(r[2] & BIT(16)); e->suspended = !!(r[2] & BIT(13)); - e->next_hop = !!(r[2] & BIT(12)); e->age = (r[2] >> 17) & 3; e->valid = true; - + // the UC_VID field in hardware is used for the VID or for the route id + if (e->next_hop) { + e->nh_route_id = r[2] & 0xfff; + e->vid = 0; + } else { + e->vid = r[2] & 0xfff; + e->nh_route_id = 0; + } } else { e->valid = true; e->type = L2_MULTICAST; - e->mc_portmask_index = (r[2]>>6) & 0xfff; + e->mc_portmask_index = (r[2] >> 16) & 0x3ff; } } -static u64 rtl930x_read_l2_entry_using_hash(u32 hash, u32 position, struct rtl838x_l2_entry *e) +/* + * Fills the 3 SoC table registers r[] with the information of in the rtl838x_l2_entry + */ +static void rtl930x_fill_l2_row(u32 r[], struct rtl838x_l2_entry *e) +{ + u32 port; + + if (!e->valid) { + r[0] = r[1] = r[2] = 0; + return; + } + + r[2] = BIT(31); // Set valid bit + + r[0] = ((u32)e->mac[0]) << 24 | ((u32)e->mac[1]) << 16 + | ((u32)e->mac[2]) << 8 | ((u32)e->mac[3]); + r[1] = ((u32)e->mac[4]) << 24 | ((u32)e->mac[5]) << 16; + + r[2] |= e->next_hop ? BIT(12) : 0; + + if (e->type == L2_UNICAST) { + r[2] |= e->is_static ? BIT(14) : 0; + r[1] |= e->rvid & 0xfff; + r[2] |= (e->port & 0x3ff) << 20; + if (e->is_trunk) { + r[2] |= BIT(30); + port = e->stack_dev << 9 | (e->port & 0x3f); + } else { + port = (e->stack_dev & 0xf) << 6; + port |= e->port & 0x3f; + } + r[2] |= port << 20; + r[2] |= e->block_da ? BIT(15) : 0; + r[2] |= e->block_sa ? BIT(17) : 0; + r[2] |= e->suspended ? BIT(13) : 0; + r[2] |= (e->age & 0x3) << 17; + // the UC_VID field in hardware is used for the VID or for the route id + if (e->next_hop) + r[2] |= e->nh_route_id & 0xfff; + else + r[2] |= e->vid & 0xfff; + } else { // L2_MULTICAST + r[2] |= (e->mc_portmask_index & 0x3ff) << 16; + r[2] |= e->mc_mac_index & 0x7ff; + } +} + +/* + * Read an L2 UC or MC entry out of a hash bucket of the L2 forwarding table + * hash is the id of the bucket and pos is the position of the entry in that bucket + * The data read from the SoC is filled into rtl838x_l2_entry + */ +static u64 rtl930x_read_l2_entry_using_hash(u32 hash, u32 pos, struct rtl838x_l2_entry *e) { - u64 entry; u32 r[3]; struct table_reg *q = rtl_table_get(RTL9300_TBL_L2, 0); - u32 idx = (0 << 14) | (hash << 2) | position; + u32 idx; int i; + u64 mac; + u64 seed; + + pr_debug("%s: hash %08x, pos: %d\n", __func__, hash, pos); + + /* On the RTL93xx, 2 different hash algorithms are used making it a total of + * 8 buckets that need to be searched, 4 for each hash-half + * Use second hash space when bucket is between 4 and 8 */ + if (pos >= 4) { + pos -= 4; + hash >>= 16; + } else { + hash &= 0xffff; + } + + idx = (0 << 14) | (hash << 2) | pos; // Search SRAM, with hash and at pos in bucket + pr_debug("%s: NOW hash %08x, pos: %d\n", __func__, hash, pos); rtl_table_read(q, idx); - for (i= 0; i < 3; i++) + for (i = 0; i < 3; i++) r[i] = sw_r32(rtl_table_data(q, i)); rtl_table_release(q); rtl930x_fill_l2_entry(r, e); + + pr_debug("%s: valid: %d, nh: %d\n", __func__, e->valid, e->next_hop); if (!e->valid) return 0; - entry = ((u64)r[0] << 32) | (r[1] & 0xffff0000) | e->vid; - return entry; + mac = ((u64)e->mac[0]) << 40 | ((u64)e->mac[1]) << 32 | ((u64)e->mac[2]) << 24 + | ((u64)e->mac[3]) << 16 | ((u64)e->mac[4]) << 8 | ((u64)e->mac[5]); + + seed = rtl930x_l2_hash_seed(mac, e->rvid); + pr_debug("%s: mac %016llx, seed %016llx\n", __func__, mac, seed); + // return vid with concatenated mac as unique id + return seed; +} + +static void rtl930x_write_l2_entry_using_hash(u32 hash, u32 pos, struct rtl838x_l2_entry *e) +{ + u32 r[3]; + struct table_reg *q = rtl_table_get(RTL9300_TBL_L2, 0); + u32 idx = (0 << 14) | (hash << 2) | pos; // Access SRAM, with hash and at pos in bucket + int i; + + pr_info("%s: hash %d, pos %d\n", __func__, hash, pos); + pr_info("%s: index %d -> mac %02x:%02x:%02x:%02x:%02x:%02x\n", __func__, idx, + e->mac[0], e->mac[1], e->mac[2], e->mac[3],e->mac[4],e->mac[5]); + + rtl930x_fill_l2_row(r, e); + + for (i= 0; i < 3; i++) + sw_w32(r[i], rtl_table_data(q, i)); + + rtl_table_write(q, idx); + rtl_table_release(q); } static u64 rtl930x_read_cam(int idx, struct rtl838x_l2_entry *e) { - u64 entry; u32 r[3]; struct table_reg *q = rtl_table_get(RTL9300_TBL_L2, 1); int i; @@ -290,9 +455,113 @@ static u64 rtl930x_read_cam(int idx, struct rtl838x_l2_entry *e) if (!e->valid) return 0; - entry = ((u64)r[0] << 32) | (r[1] & 0xffff0000) | e->vid; + // return mac with concatenated vid as unique id + return ((u64)r[0] << 28) | ((r[1] & 0xffff0000) >> 4) | e->vid; +} - return entry; +static void rtl930x_write_cam(int idx, struct rtl838x_l2_entry *e) +{ + u32 r[3]; + struct table_reg *q = rtl_table_get(RTL9300_TBL_L2, 1); // Access L2 Table 1 + int i; + + rtl930x_fill_l2_row(r, e); + + for (i= 0; i < 3; i++) + sw_w32(r[i], rtl_table_data(q, i)); + + rtl_table_write(q, idx); + rtl_table_release(q); +} + +static void dump_l2_entry(struct rtl838x_l2_entry *e) +{ + pr_info("MAC: %02x:%02x:%02x:%02x:%02x:%02x vid: %d, rvid: %d, port: %d, valid: %d\n", + e->mac[0], e->mac[1], e->mac[2], e->mac[3], e->mac[4], e->mac[5], + e->vid, e->rvid, e->port, e->valid); + pr_info("Type: %d, is_static: %d, is_ip_mc: %d, is_ipv6_mc: %d, block_da: %d\n", + e->type, e->is_static, e->is_ip_mc, e->is_ipv6_mc, e->block_da); + pr_info(" block_sa: %d, suspended: %d, next_hop: %d, age: %d, is_trunk: %d, trunk: %d\n", + e->block_sa, e->suspended, e->next_hop, e->age, e->is_trunk, e->trunk); + if (e->is_ip_mc || e->is_ipv6_mc) + pr_info(" mc_portmask_index: %d, mc_gip: %d, mc_sip: %d\n", + e->mc_portmask_index, e->mc_gip, e->mc_sip); + pr_info(" stac_dev: %d, nh_route_id: %d, port: %d, dev_id\n", + e->stack_dev, e->nh_route_id, e->port); +} + +/* + * Add an L2 nexthop entry for the L3 routing system in the SoC + * Use VID and MAC in rtl838x_l2_entry to identify either a free slot in the L2 hash table + * or mark an existing entry as a nexthop by setting it's nexthop bit + * Called from the L3 layer + * The index in the L2 hash table is filled into nh->l2_id; + */ +static int rtl930x_l2_nexthop_add(struct rtl838x_switch_priv *priv, struct rtl838x_nexthop *nh) +{ + struct rtl838x_l2_entry e; + u64 seed = rtl930x_l2_hash_seed(nh->mac, nh->vid); + u32 key = rtl930x_l2_hash_key(priv, seed); + int i, idx = -1; + u64 entry; + + pr_info("%s searching for %08llx vid %d with key %d, seed: %016llx\n", + __func__, nh->mac, nh->vid, key, seed); + + e.type = L2_UNICAST; + e.rvid = nh->fid; // Verify its the forwarding ID!!! l2_entry.un.unicast.fid + u64_to_ether_addr(nh->mac, &e.mac[0]); + e.port = RTL930X_PORT_IGNORE; + + // Loop over all entries in the hash-bucket and over the second block on 93xx SoCs + for (i = 0; i < priv->l2_bucket_size; i++) { + entry = rtl930x_read_l2_entry_using_hash(key, i, &e); + pr_info("%s i: %d, entry %016llx, seed %016llx\n", __func__, i, entry, seed); + if (e.valid && e.next_hop) + continue; + if (!e.valid || ((entry & 0x0fffffffffffffffULL) == seed)) { + idx = i > 3 ? ((key >> 14) & 0xffff) | i >> 1 + : ((key << 2) | i) & 0xffff; + break; + } + } + + pr_info("%s: found idx %d and i %d\n", __func__, idx, i); + + if (idx < 0) { + pr_err("%s: No more L2 forwarding entries available\n", __func__); + return -1; + } + + // Found an existing or empty entry, make it a nexthop entry + pr_info("%s BEFORE -> key %d, pos: %d, index: %d\n", __func__, key, i, idx); + dump_l2_entry(&e); + nh->l2_id = idx; + + // Found an existing (e->valid is true) or empty entry, make it a nexthop entry + if (e.valid) { + nh->port = e.port; + nh->fid = e.rvid; + nh->vid = e.vid; + nh->dev_id = e.stack_dev; + } else { + e.valid = true; + e.is_static = false; + e.vid = nh->vid; + e.rvid = nh->fid; + e.port = RTL930X_PORT_IGNORE; + u64_to_ether_addr(nh->mac, &e.mac[0]); + } + e.next_hop = true; + // For nexthop entries, the vid field in the table is used to denote the dest mac_id + e.nh_route_id = nh->mac_id; + pr_info("%s AFTER\n", __func__); + dump_l2_entry(&e); + + rtl930x_write_l2_entry_using_hash(idx >> 2, idx & 0x3, &e); + + // _dal_longan_l2_nexthop_add + return 0; } static u64 rtl930x_read_mcast_pmask(int idx) @@ -485,7 +754,6 @@ int rtl930x_read_phy(u32 port, u32 page, u32 reg, u32 *val) u32 v; int err = 0; -// pr_info("In %s\n", __func__); if (port > 63 || page > 4095 || reg > 31) return -ENOTSUPP; @@ -531,12 +799,12 @@ int rtl930x_write_mmd_phy(u32 port, u32 devnum, u32 regnum, u32 val) // Set MMD device number and register to write to sw_w32(devnum << 16 | (regnum & 0xffff), RTL930X_SMI_ACCESS_PHY_CTRL_3); - v = BIT(2)| BIT(1)| BIT(0); // WRITE | MMD-access | EXEC + v = BIT(2) | BIT(1) | BIT(0); // WRITE | MMD-access | EXEC sw_w32(v, RTL930X_SMI_ACCESS_PHY_CTRL_1); do { v = sw_r32(RTL930X_SMI_ACCESS_PHY_CTRL_1); - } while ( v & BIT(0)); + } while (v & BIT(0)); pr_debug("%s: port %d, regnum: %x, val: %x (err %d)\n", __func__, port, regnum, val, err); mutex_unlock(&smi_lock); @@ -559,12 +827,12 @@ int rtl930x_read_mmd_phy(u32 port, u32 devnum, u32 regnum, u32 *val) // Set MMD device number and register to write to sw_w32(devnum << 16 | (regnum & 0xffff), RTL930X_SMI_ACCESS_PHY_CTRL_3); - v = BIT(1)| BIT(0); // MMD-access | EXEC + v = BIT(1) | BIT(0); // MMD-access | EXEC sw_w32(v, RTL930X_SMI_ACCESS_PHY_CTRL_1); do { v = sw_r32(RTL930X_SMI_ACCESS_PHY_CTRL_1); - } while ( v & 0x1); + } while (v & BIT(0)); // There is no error-checking via BIT 25 of v, as it does not seem to be set correctly *val = (sw_r32(RTL930X_SMI_ACCESS_PHY_CTRL_2) & 0xffff); pr_debug("%s: port %d, regnum: %x, val: %x (err %d)\n", __func__, port, regnum, *val, err); @@ -574,7 +842,6 @@ int rtl930x_read_mmd_phy(u32 port, u32 devnum, u32 regnum, u32 *val) return err; } - /* * Calculate both the block 0 and the block 1 hash, and return in * lower and higher word of the return value since only 12 bit of @@ -617,6 +884,7 @@ u32 rtl930x_hash(struct rtl838x_switch_priv *priv, u64 seed) return h; } + /* * Enables or disables the EEE/EEEP capability of a port */ @@ -754,7 +1022,9 @@ const struct rtl838x_reg rtl930x_reg = { .mac_rx_pause_sts = RTL930X_MAC_RX_PAUSE_STS, .mac_tx_pause_sts = RTL930X_MAC_TX_PAUSE_STS, .read_l2_entry_using_hash = rtl930x_read_l2_entry_using_hash, + .write_l2_entry_using_hash = rtl930x_write_l2_entry_using_hash, .read_cam = rtl930x_read_cam, + .write_cam = rtl930x_write_cam, .vlan_port_egr_filter = RTL930X_VLAN_PORT_EGR_FLTR, .vlan_port_igr_filter = RTL930X_VLAN_PORT_IGR_FLTR(0), .vlan_port_pb = RTL930X_VLAN_PORT_PB_VLAN, From af3a1adee063fa31cc05649f718f6ef2488a5232 Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Thu, 29 Apr 2021 02:06:09 +0100 Subject: [PATCH 41/62] uboot-mediatek: unifi-6-lr: fix erase of production parition mtd erase needs to be aligned with erase blocks. Use padded image size for erasing the production volume. As the environment grew above the current size of 0x1000 bytes by introducing the new padding function, increase the env size to 0x4000. While at it, clean up reset button function to work to more reliable on that board. Signed-off-by: Daniel Golle --- ...0-mt7622-generic-reset-button-ignore-env.patch | 15 ++++++++------- .../patches/412-add-ubnt-unifi-6-lr.patch | 13 +++++++------ 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/package/boot/uboot-mediatek/patches/300-mt7622-generic-reset-button-ignore-env.patch b/package/boot/uboot-mediatek/patches/300-mt7622-generic-reset-button-ignore-env.patch index 8b38248757..e794e0a0db 100644 --- a/package/boot/uboot-mediatek/patches/300-mt7622-generic-reset-button-ignore-env.patch +++ b/package/boot/uboot-mediatek/patches/300-mt7622-generic-reset-button-ignore-env.patch @@ -17,7 +17,7 @@ DECLARE_GLOBAL_DATA_PTR; -@@ -20,7 +27,19 @@ int board_init(void) +@@ -20,7 +27,20 @@ int board_init(void) int board_late_init(void) { @@ -25,16 +25,17 @@ + struct udevice *dev; + int ret; + -+ ret = !!button_get_by_label(CONFIG_RESET_BUTTON_LABEL, &dev); -+ -+ if (!ret) { ++ if (!button_get_by_label(CONFIG_RESET_BUTTON_LABEL, &dev)) { ++ puts("reset button found\n"); +#ifdef CONFIG_RESET_BUTTON_SETTLE_DELAY -+ udelay(1000 * CONFIG_RESET_BUTTON_SETTLE_DELAY); ++ mdelay(CONFIG_RESET_BUTTON_SETTLE_DELAY); +#endif -+ ret = !button_get_state(dev); ++ if (button_get_state(dev) == BUTTON_ON) { ++ puts("button pushed, resetting environment\n"); ++ gd->env_valid = ENV_INVALID; ++ } + } + -+ gd->env_valid = ret; //to load environment variable from persistent store env_relocate(); return 0; } diff --git a/package/boot/uboot-mediatek/patches/412-add-ubnt-unifi-6-lr.patch b/package/boot/uboot-mediatek/patches/412-add-ubnt-unifi-6-lr.patch index 1af0da13c5..8e8fe04a07 100644 --- a/package/boot/uboot-mediatek/patches/412-add-ubnt-unifi-6-lr.patch +++ b/package/boot/uboot-mediatek/patches/412-add-ubnt-unifi-6-lr.patch @@ -10,12 +10,12 @@ +CONFIG_USE_DEFAULT_ENV_FILE=y +CONFIG_ENV_IS_IN_MTD=y +CONFIG_ENV_MTD_NAME="nor0" -+CONFIG_ENV_SIZE_REDUND=0x0 -+CONFIG_ENV_SIZE=0x1000 ++CONFIG_ENV_SIZE_REDUND=0x4000 ++CONFIG_ENV_SIZE=0x4000 +CONFIG_ENV_OFFSET=0xc0000 +CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG=y +CONFIG_BOARD_LATE_INIT=y -+CONFIG_RESET_BUTTON_SETTLE_DELAY=200 ++CONFIG_RESET_BUTTON_SETTLE_DELAY=400 +CONFIG_BOOTP_SEND_HOSTNAME=y +CONFIG_DEFAULT_ENV_FILE="ubnt_unifi-6-lr_env" +CONFIG_DEBUG_UART_BASE=0x11002000 @@ -356,7 +356,7 @@ mt8512-bm1-emmc.dtb \ --- /dev/null +++ b/ubnt_unifi-6-lr_env -@@ -0,0 +1,51 @@ +@@ -0,0 +1,52 @@ +mtdparts=nor0:128k(bl2),640k(fip),64k(u-boot-env),256k(factory),64k(eeprom),15232k(recovery),-(firmware) +ethaddr_factory=mtd read nor0 $loadaddr 0x110000 0x10000 && env readmem -b ethaddr $loadaddr 0x6 ; setenv ethaddr_factory +ipaddr=192.168.1.1 @@ -402,8 +402,9 @@ +reset_factory=mtd erase nor0 0xc0000 0x10000 && reset +nor_read_production=mtd read nor0 $loadaddr 0x1000000 0x1000 && imsz $loadaddr image_size && mtd read nor0 $loadaddr 0x1000000 $image_size +nor_read_recovery=mtd read nor0 $loadaddr 0x120000 0x1000 && imsz $loadaddr image_size && mtd read nor0 $loadaddr 0x120000 $image_size -+nor_write_production=mtd erase nor0 0x1000000 $filesize && mtd write nor0 $loadaddr 0x1000000 $filesize -+nor_write_recovery=mtd erase nor0 0x120000 0xee0000 && mtd write nor0 $loadaddr 0x120000 $filesize ++nor_pad_size=imsz $loadaddr image_size ; setexpr image_eb $image_size / 0x1000 ; setexpr tmp1 image_size % 0x1000 ; test 0x$tmp1 -gt 0 && setexpr image_eb $image_eb + 1 ; setexpr image_eb $image_eb * 0x1000 ++nor_write_production=run nor_pad_size ; test 0x$image_eb -le 0x3000000 && mtd erase nor0 0x1000000 0x$image_eb && mtd write nor0 $loadaddr 0x1000000 $filesize ++nor_write_recovery=run nor_pad_size ; test 0x$image_eb -le 0xee0000 && mtd erase nor0 0x120000 0x$image_eb && mtd write nor0 $loadaddr 0x120000 $filesize +_init_env=setenv _init_env ; saveenv +_firstboot=setenv _firstboot ; run _switch_to_menu ; run ethaddr_factory ; run _init_env ; run boot_first +_switch_to_menu=setenv _switch_to_menu ; setenv bootdelay 3 ; setenv bootmenu_delay 3 ; setenv bootmenu_0 $bootmenu_0d ; setenv bootmenu_0d ; run _bootmenu_update_title From f990bddf6fb954bcbfc4fbcd54912e8d33800495 Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Thu, 29 Apr 2021 23:48:28 +0100 Subject: [PATCH 42/62] uboot-envtools: change size for unifi-6-lr The previous commit increased the U-Boot environment size of the UniFi 6 LR to 0x4000. Also change it uboot-envtools accordingly. Signed-off-by: Daniel Golle --- package/boot/uboot-envtools/files/mediatek | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package/boot/uboot-envtools/files/mediatek b/package/boot/uboot-envtools/files/mediatek index 5e71dc71c9..495a837274 100644 --- a/package/boot/uboot-envtools/files/mediatek +++ b/package/boot/uboot-envtools/files/mediatek @@ -36,7 +36,7 @@ buffalo,wsr-2533dhp2) ubootenv_add_uci_config "/dev/mtd3" "0x0" "0x1000" "0x20000" ;; ubnt,unifi-6-lr-ubootmod) - ubootenv_add_uci_config "/dev/mtd2" "0x0" "0x1000" "0x10000" + ubootenv_add_uci_config "/dev/mtd2" "0x0" "0x4000" "0x10000" ;; esac From 6967903b01ea9f7c9f70d0185c3da276801dd78f Mon Sep 17 00:00:00 2001 From: Sven Roederer Date: Fri, 7 May 2021 21:35:20 +0200 Subject: [PATCH 43/62] imagebuilder: unset BINARY_FOLDER and DOWNLOAD_FOLDER in final archive Using these config-options to customize the folders used at build-time makes these folder settings appear in generated archive. This causes the imagebuilder to be not portable, as it's going to use the build-time folders on the new systems. Errors look like: mkdir: cannot create directory '/mnt/build': Permission denied Makefile:116: recipe for target '_call_image' failed make[2]: *** [_call_image] Error 1 Makefile:241: recipe for target 'image' failed make[1]: *** [image] Error 2 The build-time settings of these folders are passed into the archives via .config file. The expected behavior is that after unpacking the imagebuilder acts like these settings have their defaults, using intree folders. So unset the build-time settings. Signed-off-by: Sven Roederer --- target/imagebuilder/Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/target/imagebuilder/Makefile b/target/imagebuilder/Makefile index f9c08776a8..0580e41c57 100644 --- a/target/imagebuilder/Makefile +++ b/target/imagebuilder/Makefile @@ -29,6 +29,8 @@ $(BIN_DIR)/$(IB_NAME).tar.xz: clean mkdir -p $(IB_KDIR) $(IB_LDIR) $(PKG_BUILD_DIR)/staging_dir/host/lib \ $(PKG_BUILD_DIR)/target $(PKG_BUILD_DIR)/scripts $(IB_DTSDIR) -cp $(TOPDIR)/.config $(PKG_BUILD_DIR)/.config + $(SED) 's/^CONFIG_BINARY_FOLDER=.*/# CONFIG_BINARY_FOLDER is not set/' $(PKG_BUILD_DIR)/.config + $(SED) 's/^CONFIG_DOWNLOAD_FOLDER=.*/# CONFIG_DOWNLOAD_FOLDER is not set/' $(PKG_BUILD_DIR)/.config $(CP) -L \ $(INCLUDE_DIR) $(SCRIPT_DIR) \ $(TOPDIR)/rules.mk \ From 1e4b191ac8901328a726ebdc09ebe35da4363521 Mon Sep 17 00:00:00 2001 From: Sven Roederer Date: Fri, 7 May 2021 21:35:21 +0200 Subject: [PATCH 44/62] sdk: unset BINARY_FOLDER and DOWNLOAD_FOLDER in final archives Using these config-options to customize the folders used at build-time makes these folder settings appear in generated archive. This causes the SDK to be not portable, as it's going to use the build-time folders on the new systems. The errors vary from passing the build, disk out-of-space to permission denied. The build-time settings of these folders are passed into the archive via Config.build. The expected behavior is that the SDK acts after unpacking like these settings have their defaults, using intree folders. So just filter these folders out when running convert-config.pl to create Config.build. This addresses the same issue that's fixed in the previous commit for the imagebuilder. Signed-off-by: Sven Roederer --- target/sdk/convert-config.pl | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/target/sdk/convert-config.pl b/target/sdk/convert-config.pl index f73744af09..08189df95c 100755 --- a/target/sdk/convert-config.pl +++ b/target/sdk/convert-config.pl @@ -9,7 +9,13 @@ while (<>) { chomp; next if /^CONFIG_SIGNED_PACKAGES/; - if (/^CONFIG_([^=]+)=(.*)$/) { + if (/^CONFIG_((BINARY)|(DOWNLOAD))_FOLDER=(.*)$/) { + # We don't want to preserve the build setting of + # BINARY_FOLDER and DOWNLOAD_FOLDER. + $var = "$1_FOLDER"; + $val = '""'; + $type = "string"; + } elsif (/^CONFIG_([^=]+)=(.*)$/) { $var = $1; $val = $2; From 979f4063668185182db7bd2ad4efe6010047765e Mon Sep 17 00:00:00 2001 From: Baptiste Jonglez Date: Mon, 3 May 2021 12:39:47 +0200 Subject: [PATCH 45/62] ipq40xx: fix hard_config partition size on MikroTik hAP-ac2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The routerbootparts driver dynamically discovers the location of MikroTik partitions, but it cannot determine their size (except by extending them up to the start of the next discovered partition). The hard_config partition has a default size of 0x1000 in the driver, while it actually takes 0x2000 on the hAP-ac2. Set the correct size in the hAP-ac2 DTS. On most devices, this isn't a problem as the actual data fits in 0x1000 bytes. However, some devices have larger data that doesn't fit in 0x1000 bytes. In any case, all devices seen so far have enough space for a 0x2000 hard_config partition before the start of the dtb_config partition. With the current 0x1000 size: 0x00000000e000-0x00000000f000 : "hard_config" 0x000000010000-0x000000017bbc : "dtb_config" With this patch extending the size to 0x2000: 0x00000000e000-0x000000010000 : "hard_config" 0x000000010000-0x000000017bbc : "dtb_config" Other ipq40xx boards may need the same fix but it needs testing. References: https://forum.openwrt.org/t/support-for-mikrotik-hap-ac2/23333/324 Acked-by: Thibaut VARÈNE Signed-off-by: Baptiste Jonglez --- .../ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-hap-ac2.dts | 1 + 1 file changed, 1 insertion(+) diff --git a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-hap-ac2.dts b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-hap-ac2.dts index e1e6326ae9..d03409b556 100644 --- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-hap-ac2.dts +++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-hap-ac2.dts @@ -191,6 +191,7 @@ hard_config { read-only; + size = <0x2000>; }; dtb_config { From 2eda042d553c23590c9d6ade8a1a17ffcfb4be7c Mon Sep 17 00:00:00 2001 From: Thomas Richard Date: Tue, 20 Apr 2021 16:49:02 +0200 Subject: [PATCH 46/62] uqmi: fix network registration loop With some debug in qmi.sh using following patch, some errors are visible in the registration step @@ -29,6 +29,7 @@ proto_qmi_init_config() { } proto_qmi_setup() { + set -x local interface="$1" local dataformat connstat plmn_mode mcc mnc local device apn auth username password pincode delay modes pdptype @@ -224,6 +225,8 @@ proto_qmi_setup() { fi done + registration=$(uqmi -s -d "$device" --get-serving-system) + [ -n "$modes" ] && uqmi -s -d "$device" --set-network-modes "$modes" > /dev/null 2>&1 echo "Starting network $interface" During the boot of the system, modem could not start automatically its network registration. netifd: wan (9235): + echo 'Waiting for network registration' netifd: wan (9235): Waiting for network registration netifd: wan (9235): + local 'registration_timeout=0' netifd: wan (9235): + uqmi -s -d /dev/cdc-wdm1 --get-serving-system netifd: wan (9235): + grep '"searching"' netifd: wan (9235): + uqmi -s -d /dev/cdc-wdm1 --get-serving-system netifd: wan (9235): + registration='{"registration":"not_registered","plmn_mcc":208,"plmn_mnc":20,"plmn_description":"","roaming":true}' netifd: wan (9235): + '[' -n ] netifd: wan (9235): + echo 'Starting network wan' As the while loop checks only "searching" pattern, uqmi.sh script quits searching loop and continues whereas the modem is not registered Other issue, after X seconds modem stops searching. netifd: wan (9213): + uqmi -s -d /dev/cdc-wdm0 --get-serving-system netifd: wan (9213): + grep '"searching"' netifd: wan (9213): + '[' -e /dev/cdc-wdm0 ] netifd: wan (9213): + '[' 3 -lt 0 -o 0 '=' 0 ] netifd: wan (9213): + let registration_timeout++ netifd: wan (9213): + sleep 1 netifd: wan (9213): + uqmi -s -d /dev/cdc-wdm0 --get-serving-system netifd: wan (9213): + grep '"searching"' netifd: wan (9213): + uqmi -s -d /dev/cdc-wdm0 --get-serving-system netifd: wan (9213): + registration='{"registration":"not_registered"}' netifd: wan (9213): + '[' -n ] netifd: wan (9213): + echo 'Starting network wan' netifd: wan (9213): Starting network wan If registration_timeout is not expired, registration can be restarted Signed-off-by: Thomas Richard Tested-by: Florian Eckert --- package/network/utils/uqmi/Makefile | 2 +- .../utils/uqmi/files/lib/netifd/proto/qmi.sh | 35 ++++++++++++++----- 2 files changed, 27 insertions(+), 10 deletions(-) diff --git a/package/network/utils/uqmi/Makefile b/package/network/utils/uqmi/Makefile index 68958a3729..da54ba0f46 100644 --- a/package/network/utils/uqmi/Makefile +++ b/package/network/utils/uqmi/Makefile @@ -1,7 +1,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=uqmi -PKG_RELEASE:=2 +PKG_RELEASE:=3 PKG_SOURCE_PROTO:=git PKG_SOURCE_URL=$(PROJECT_GIT)/project/uqmi.git diff --git a/package/network/utils/uqmi/files/lib/netifd/proto/qmi.sh b/package/network/utils/uqmi/files/lib/netifd/proto/qmi.sh index a6c785eb56..c0134f44dd 100755 --- a/package/network/utils/uqmi/files/lib/netifd/proto/qmi.sh +++ b/package/network/utils/uqmi/files/lib/netifd/proto/qmi.sh @@ -209,19 +209,36 @@ proto_qmi_setup() { uqmi -s -d "$device" --sync > /dev/null 2>&1 + uqmi -s -d "$device" --network-register > /dev/null 2>&1 + echo "Waiting for network registration" + sleep 1 local registration_timeout=0 - while uqmi -s -d "$device" --get-serving-system | grep '"searching"' > /dev/null; do - [ -e "$device" ] || return 1 - if [ "$registration_timeout" -lt "$timeout" -o "$timeout" = "0" ]; then - let registration_timeout++ - sleep 1; + local registration_state="" + while true; do + registration_state=$(uqmi -s -d "$device" --get-serving-system 2>/dev/null | jsonfilter -e "@.registration" 2>/dev/null) + + [ "$registration_state" = "registered" ] && break + + if [ "$registration_state" = "searching" ] || [ "$registration_state" = "not_registered" ]; then + if [ "$registration_timeout" -lt "$timeout" ] || [ "$timeout" = "0" ]; then + [ "$registration_state" = "searching" ] || { + echo "Device stopped network registration. Restart network registration" + uqmi -s -d "$device" --network-register > /dev/null 2>&1 + } + let registration_timeout++ + sleep 1 + continue + fi + echo "Network registration failed, registration timeout reached" else - echo "Network registration failed" - proto_notify_error "$interface" NETWORK_REGISTRATION_FAILED - proto_block_restart "$interface" - return 1 + # registration_state is 'registration_denied' or 'unknown' or '' + echo "Network registration failed (reason: '$registration_state')" fi + + proto_notify_error "$interface" NETWORK_REGISTRATION_FAILED + proto_block_restart "$interface" + return 1 done [ -n "$modes" ] && uqmi -s -d "$device" --set-network-modes "$modes" > /dev/null 2>&1 From f68c9474acf9a65b5a9538db8e45c173462487e3 Mon Sep 17 00:00:00 2001 From: Bas Mevissen Date: Tue, 20 Apr 2021 01:08:19 +0200 Subject: [PATCH 47/62] Extend checks on build prerequisites for building OpenWRT core OpenWRT requires a number of Perl modules to be installed. It wasn't checking on all of them. This patch adds checks for Perl FindBin, File::Copy, File::Compare and Thread::Queue modules. Failing to install these, will have the build break at some point. By adding these to the prereq-build.mk script, they are checked on forehand. Tested on a Fedora 33 and 34 (beta) that was freshly installed. Fedora appears to break up Perl modules into small packages that need to be installed for the build to succeed. Signed-off-by: Bas Mevissen --- include/prereq-build.mk | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/include/prereq-build.mk b/include/prereq-build.mk index 0375ef6861..8adf0d03dd 100644 --- a/include/prereq-build.mk +++ b/include/prereq-build.mk @@ -65,11 +65,22 @@ $(eval $(call TestHostCommand,perl-data-dumper, \ Please install the Perl Data::Dumper module, \ perl -MData::Dumper -e 1)) +$(eval $(call TestHostCommand,perl-findbin, \ + Please install the Perl FindBin module, \ + perl -MFindBin -e 1)) + +$(eval $(call TestHostCommand,perl-file-copy, \ + Please install the Perl File::Copy module, \ + perl -MFile::Copy -e 1)) + +$(eval $(call TestHostCommand,perl-file-compare, \ + Please install the Perl File::Compare module, \ + perl -MFile::Compare -e 1)) + $(eval $(call TestHostCommand,perl-thread-queue, \ Please install the Perl Thread::Queue module, \ perl -MThread::Queue -e 1)) - $(eval $(call SetupHostCommand,tar,Please install GNU 'tar', \ gtar --version 2>&1 | grep GNU, \ gnutar --version 2>&1 | grep GNU, \ From d62825dd77b3990b8ff2cf341ff3a8b16f4883d1 Mon Sep 17 00:00:00 2001 From: Mark Mentovai Date: Sat, 8 May 2021 11:00:55 -0400 Subject: [PATCH 48/62] ipq806x: dwmac: fix GMACs connected via SGMII fixed-link MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit fa731838c524 cleared the forced speed in the QSGMII PCS_ALL_CH_CTL register during probe, but this is only correct for GMACs that are not configured with fixed-link. This prevented GMACs configured with both phy-mode = "sgmii" and fixed-link from working properly, as discussed at https://github.com/openwrt/openwrt/pull/3954#issuecomment-834625090 and the comments that follow. Notably, this prevented all communication between gmac2 and the switch on the Netgear R7800. The correct behavior is to set the QSGMII PCS_ALL_CH_CTL register by considering the gmac's fixed-link child, setting the speed as directed by fixed-link if present, and otherwise clearing it as was done previously. Fixes: fa731838c524 ("ipq806x: dwmac: clear forced speed during probe") Signed-off-by: Mark Mentovai Tested-by: Hannu Nyman Run-tested: ipq806x/ubnt,unifi-ac-hd, ipq806x/netgear,r7800 Cc: Petr Štetiar Cc: Ansuel Smith Tested-by: Ansuel Smith --- ...-dwmac-ipq806x-qsgmii-pcs-all-ch-ctl.patch | 62 +++++++++++++++++-- 1 file changed, 56 insertions(+), 6 deletions(-) diff --git a/target/linux/ipq806x/patches-5.4/100-dwmac-ipq806x-qsgmii-pcs-all-ch-ctl.patch b/target/linux/ipq806x/patches-5.4/100-dwmac-ipq806x-qsgmii-pcs-all-ch-ctl.patch index 6cdbf4d3dc..3c497ead6a 100644 --- a/target/linux/ipq806x/patches-5.4/100-dwmac-ipq806x-qsgmii-pcs-all-ch-ctl.patch +++ b/target/linux/ipq806x/patches-5.4/100-dwmac-ipq806x-qsgmii-pcs-all-ch-ctl.patch @@ -18,16 +18,66 @@ #define QSGMII_PCS_CAL_LCKDT_CTL 0x120 #define QSGMII_PCS_CAL_LCKDT_CTL_RST BIT(19) -@@ -345,6 +356,12 @@ static int ipq806x_gmac_probe(struct pla +@@ -241,6 +252,36 @@ static void ipq806x_gmac_fix_mac_speed(v + ipq806x_gmac_set_speed(gmac, speed); + } + ++static int ++ipq806x_gmac_get_qsgmii_pcs_speed_val(struct platform_device *pdev) { ++ struct device_node *fixed_link_node; ++ int rv; ++ int fixed_link_speed; ++ ++ if (!of_phy_is_fixed_link(pdev->dev.of_node)) ++ return 0; ++ ++ fixed_link_node = of_get_child_by_name(pdev->dev.of_node, "fixed-link"); ++ if (!fixed_link_node) ++ return -1; ++ ++ rv = of_property_read_u32(fixed_link_node, "speed", &fixed_link_speed); ++ of_node_put(fixed_link_node); ++ if (rv) ++ return -1; ++ ++ switch (fixed_link_speed) { ++ case SPEED_1000: ++ return QSGMII_PCS_CH_SPEED_FORCE | QSGMII_PCS_CH_SPEED_1000; ++ case SPEED_100: ++ return QSGMII_PCS_CH_SPEED_FORCE | QSGMII_PCS_CH_SPEED_100; ++ case SPEED_10: ++ return QSGMII_PCS_CH_SPEED_FORCE | QSGMII_PCS_CH_SPEED_10; ++ } ++ ++ return -1; ++} ++ + static int ipq806x_gmac_probe(struct platform_device *pdev) + { + struct plat_stmmacenet_data *plat_dat; +@@ -249,6 +290,7 @@ static int ipq806x_gmac_probe(struct pla + struct ipq806x_gmac *gmac; + int val; + int err; ++ int qsgmii_pcs_speed; + + val = stmmac_get_platform_resources(pdev, &stmmac_res); + if (val) +@@ -345,6 +387,17 @@ static int ipq806x_gmac_probe(struct pla 0x1ul << QSGMII_PHY_RX_INPUT_EQU_OFFSET | 0x2ul << QSGMII_PHY_CDR_PI_SLEW_OFFSET | 0xCul << QSGMII_PHY_TX_DRV_AMP_OFFSET); + -+ regmap_update_bits(gmac->qsgmii_csr, -+ QSGMII_PCS_ALL_CH_CTL, -+ QSGMII_PCS_CH_SPEED_MASK << -+ QSGMII_PCS_CH_SPEED_SHIFT(gmac->id), -+ 0); ++ qsgmii_pcs_speed = ipq806x_gmac_get_qsgmii_pcs_speed_val(pdev); ++ if (qsgmii_pcs_speed != -1) { ++ regmap_update_bits( ++ gmac->qsgmii_csr, ++ QSGMII_PCS_ALL_CH_CTL, ++ QSGMII_PCS_CH_SPEED_MASK << ++ QSGMII_PCS_CH_SPEED_SHIFT(gmac->id), ++ qsgmii_pcs_speed << ++ QSGMII_PCS_CH_SPEED_SHIFT(gmac->id)); ++ } } plat_dat->has_gmac = true; From 2db9dded0a1a6133398e75006320f6c1f5d0e17b Mon Sep 17 00:00:00 2001 From: Stefan Lippers-Hollmann Date: Fri, 7 May 2021 00:44:03 +0200 Subject: [PATCH 49/62] ipq806x: nbg6817: case-insensitive qcom-smem partitions The out-of-tree qcom-smem patches traditionally displayed mtd partition names in upper case, starting with the new mainline qcom-smem support in kernel v5.10, it switches to normalizing the partition names to lower case. Signed-off-by: Stefan Lippers-Hollmann --- .../ipq806x/base-files/etc/board.d/02_network | 5 ++++- .../etc/hotplug.d/firmware/11-ath10k-caldata | 20 +++++++++++++++---- .../ipq806x/base-files/lib/upgrade/zyxel.sh | 5 ++++- 3 files changed, 24 insertions(+), 6 deletions(-) diff --git a/target/linux/ipq806x/base-files/etc/board.d/02_network b/target/linux/ipq806x/base-files/etc/board.d/02_network index 81edc569a7..511794a3ce 100644 --- a/target/linux/ipq806x/base-files/etc/board.d/02_network +++ b/target/linux/ipq806x/base-files/etc/board.d/02_network @@ -69,7 +69,10 @@ ubnt,unifi-ac-hd) ucidef_set_interface_lan "eth0 eth1" ;; zyxel,nbg6817) - hw_mac_addr=$(mtd_get_mac_ascii 0:APPSBLENV ethaddr) + hw_mac_addr=$(mtd_get_mac_ascii 0:appsblenv ethaddr) + # XXX: drop upper case after kernel v5.4 is gone (qcom-smem) + [ -n "$hw_mac_addr" ] || \ + hw_mac_addr=$(mtd_get_mac_ascii 0:APPSBLENV ethaddr) ucidef_add_switch "switch0" \ "1:lan" "2:lan" "3:lan" "4:lan" "6@eth1" "5:wan" "0@eth0" ucidef_set_interface_macaddr "lan" "$(macaddr_add $hw_mac_addr 2)" diff --git a/target/linux/ipq806x/base-files/etc/hotplug.d/firmware/11-ath10k-caldata b/target/linux/ipq806x/base-files/etc/hotplug.d/firmware/11-ath10k-caldata index 3befc40630..a05bd99bc7 100644 --- a/target/linux/ipq806x/base-files/etc/hotplug.d/firmware/11-ath10k-caldata +++ b/target/linux/ipq806x/base-files/etc/hotplug.d/firmware/11-ath10k-caldata @@ -45,8 +45,14 @@ case "$FIRMWARE" in ath10k_patch_mac $(macaddr_add $(mtd_get_mac_binary default-mac 0x0) -1) ;; zyxel,nbg6817) - caldata_extract "0:ART" 0x1000 0x2f20 - ath10k_patch_mac $(macaddr_add $(mtd_get_mac_ascii 0:APPSBLENV ethaddr) +1) + if [ -b "$(find_mtd_part 0:art)" ]; then + caldata_extract "0:art" 0x1000 0x2f20 + ath10k_patch_mac $(macaddr_add $(mtd_get_mac_ascii 0:appsblenv ethaddr) +1) + else + # XXX: drop upper case after kernel v5.4 is gone (qcom-smem) + caldata_extract "0:ART" 0x1000 0x2f20 + ath10k_patch_mac $(macaddr_add $(mtd_get_mac_ascii 0:APPSBLENV ethaddr) +1) + fi ;; esac ;; @@ -85,8 +91,14 @@ case "$FIRMWARE" in ath10k_patch_mac $(mtd_get_mac_binary default-mac 0x0) ;; zyxel,nbg6817) - caldata_extract "0:ART" 0x5000 0x2f20 - ath10k_patch_mac $(mtd_get_mac_ascii 0:APPSBLENV ethaddr) + if [ -b "$(find_mtd_part 0:art)" ]; then + caldata_extract "0:art" 0x5000 0x2f20 + ath10k_patch_mac $(mtd_get_mac_ascii 0:appsblenv ethaddr) + else + # XXX: drop upper case after kernel v5.4 is gone (qcom-smem) + caldata_extract "0:ART" 0x5000 0x2f20 + ath10k_patch_mac $(mtd_get_mac_ascii 0:APPSBLENV ethaddr) + fi ;; esac ;; diff --git a/target/linux/ipq806x/base-files/lib/upgrade/zyxel.sh b/target/linux/ipq806x/base-files/lib/upgrade/zyxel.sh index cece018b31..50f8a3ceaf 100644 --- a/target/linux/ipq806x/base-files/lib/upgrade/zyxel.sh +++ b/target/linux/ipq806x/base-files/lib/upgrade/zyxel.sh @@ -90,7 +90,10 @@ zyxel_do_upgrade() { [ -b "${rootfs}" ] || return 1 case "$board" in zyxel,nbg6817) - local dualflagmtd="$(find_mtd_part 0:DUAL_FLAG)" + local dualflagmtd="$(find_mtd_part 0:dual_flag)" + # XXX: drop upper case after kernel v5.4 is gone (qcom-smem) + [ -b $dualflagmtd ] || \ + dualflagmtd="$(find_mtd_part 0:DUAL_FLAG)" [ -b $dualflagmtd ] || return 1 case "$rootfs" in From f70e11cd974effdea1ed2ae0ded3033984ba3dad Mon Sep 17 00:00:00 2001 From: Stefan Lippers-Hollmann Date: Fri, 7 May 2021 01:00:58 +0200 Subject: [PATCH 50/62] ipq806x: g10: case-insensitive qcom-smem partitions The out-of-tree qcom-smem patches traditionally displayed mtd partition names in upper case, starting with the new mainline qcom-smem support in kernel v5.10, it switches to normalizing the partition names to lower case. Signed-off-by: Stefan Lippers-Hollmann --- .../etc/hotplug.d/firmware/11-ath10k-caldata | 14 ++++++++++++-- .../linux/ipq806x/base-files/lib/upgrade/asrock.sh | 4 +++- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/target/linux/ipq806x/base-files/etc/hotplug.d/firmware/11-ath10k-caldata b/target/linux/ipq806x/base-files/etc/hotplug.d/firmware/11-ath10k-caldata index a05bd99bc7..3dd7a51d5d 100644 --- a/target/linux/ipq806x/base-files/etc/hotplug.d/firmware/11-ath10k-caldata +++ b/target/linux/ipq806x/base-files/etc/hotplug.d/firmware/11-ath10k-caldata @@ -10,7 +10,12 @@ case "$FIRMWARE" in "ath10k/pre-cal-pci-0000:01:00.0.bin") case $board in asrock,g10) - caldata_extract "0:ART" 0x1000 0x2f20 + if [ -b "$(find_mtd_part 0:art)" ]; then + caldata_extract "0:art" 0x1000 0x2f20 + else + # XXX: drop upper case after kernel v5.4 is gone (qcom-smem) + caldata_extract "0:ART" 0x1000 0x2f20 + fi ;; buffalo,wxr-2533dhp) caldata_extract "ART" 0x1000 0x2f20 @@ -59,7 +64,12 @@ case "$FIRMWARE" in "ath10k/pre-cal-pci-0001:01:00.0.bin") case $board in asrock,g10) - caldata_extract "0:ART" 0x5000 0x2f20 + if [ -b "$(find_mtd_part 0:art)" ]; then + caldata_extract "0:art" 0x5000 0x2f20 + else + # XXX: drop upper case after kernel v5.4 is gone (qcom-smem) + caldata_extract "0:ART" 0x5000 0x2f20 + fi ;; buffalo,wxr-2533dhp) caldata_extract "ART" 0x5000 0x2f20 diff --git a/target/linux/ipq806x/base-files/lib/upgrade/asrock.sh b/target/linux/ipq806x/base-files/lib/upgrade/asrock.sh index 9e1376a578..8be737d2da 100644 --- a/target/linux/ipq806x/base-files/lib/upgrade/asrock.sh +++ b/target/linux/ipq806x/base-files/lib/upgrade/asrock.sh @@ -1,7 +1,9 @@ . /lib/functions.sh asrock_bootconfig_mangle() { - local mtdnum="$( find_mtd_index 0:BOOTCONFIG )" + local mtdnum="$(find_mtd_index 0:bootconfig)" + # XXX: drop upper case after kernel v5.4 is gone (qcom-smem) + [ -n "$mtdnum" ] || mtdnum="$(find_mtd_index 0:BOOTCONFIG)" if [ -z "$mtdnum" ]; then echo "cannot find bootconfig mtd partition" From 435dc2e77e3b6a92b3be1e386bf99d4d458d2bb9 Mon Sep 17 00:00:00 2001 From: Stefan Lippers-Hollmann Date: Fri, 7 May 2021 01:09:50 +0200 Subject: [PATCH 51/62] ipq806x: ecw5410: case-insensitive qcom-smem partitions The out-of-tree qcom-smem patches traditionally displayed mtd partition names in upper case, starting with the new mainline qcom-smem support in kernel v5.10, it switches to normalizing the partition names to lower case. Signed-off-by: Stefan Lippers-Hollmann --- .../ipq806x/base-files/etc/board.d/02_network | 10 ++++++++-- .../etc/hotplug.d/firmware/11-ath10k-caldata | 14 ++++++++++++-- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/target/linux/ipq806x/base-files/etc/board.d/02_network b/target/linux/ipq806x/base-files/etc/board.d/02_network index 511794a3ce..abdab89857 100644 --- a/target/linux/ipq806x/base-files/etc/board.d/02_network +++ b/target/linux/ipq806x/base-files/etc/board.d/02_network @@ -28,8 +28,14 @@ tplink,vr2600v) ;; edgecore,ecw5410) ucidef_set_interfaces_lan_wan "eth1" "eth0" - ucidef_set_interface_macaddr "lan" "$(mtd_get_mac_binary "0:ART" 0x6)" - ucidef_set_interface_macaddr "wan" "$(mtd_get_mac_binary "0:ART" 0x0)" + if [ -b "$(find_mtd_part 0:art)" ]; then + ucidef_set_interface_macaddr "lan" "$(mtd_get_mac_binary "0:art" 0x6)" + ucidef_set_interface_macaddr "wan" "$(mtd_get_mac_binary "0:art" 0x0)" + else + # XXX: drop upper case after kernel v5.4 is gone (qcom-smem) + ucidef_set_interface_macaddr "lan" "$(mtd_get_mac_binary "0:ART" 0x6)" + ucidef_set_interface_macaddr "wan" "$(mtd_get_mac_binary "0:ART" 0x0)" + fi ;; linksys,ea7500-v1) hw_mac_addr=$(mtd_get_mac_ascii devinfo hw_mac_addr) diff --git a/target/linux/ipq806x/base-files/etc/hotplug.d/firmware/11-ath10k-caldata b/target/linux/ipq806x/base-files/etc/hotplug.d/firmware/11-ath10k-caldata index 3dd7a51d5d..fca35516ec 100644 --- a/target/linux/ipq806x/base-files/etc/hotplug.d/firmware/11-ath10k-caldata +++ b/target/linux/ipq806x/base-files/etc/hotplug.d/firmware/11-ath10k-caldata @@ -22,7 +22,12 @@ case "$FIRMWARE" in ath10k_patch_mac $(mtd_get_mac_binary ART 0x1e) ;; edgecore,ecw5410) - caldata_extract "0:ART" 0x1000 0x2f20 + if [ -b "$(find_mtd_part 0:art)" ]; then + caldata_extract "0:art" 0x1000 0x2f20 + else + # XXX: drop upper case after kernel v5.4 is gone (qcom-smem) + caldata_extract "0:ART" 0x1000 0x2f20 + fi ;; linksys,ea7500-v1 |\ linksys,ea8500) @@ -115,7 +120,12 @@ case "$FIRMWARE" in "ath10k/pre-cal-pci-0002:01:00.0.bin") case $board in edgecore,ecw5410) - caldata_extract "0:ART" 0x5000 0x2f20 + if [ -b "$(find_mtd_part 0:art)" ]; then + caldata_extract "0:art" 0x5000 0x2f20 + else + # XXX: drop upper case after kernel v5.4 is gone (qcom-smem) + caldata_extract "0:ART" 0x5000 0x2f20 + fi ;; esac ;; From c91c0c1f851a8511466735f7ca1ba888d3b088a4 Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Sat, 8 May 2021 22:34:16 +0100 Subject: [PATCH 52/62] arm-trusted-firmware-mediatek: update to git HEAD Most notably this enabled use of pstore/ramoops on MT7622 as DRAM content is now preserved over reboot. Signed-off-by: Daniel Golle --- package/boot/arm-trusted-firmware-mediatek/Makefile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package/boot/arm-trusted-firmware-mediatek/Makefile b/package/boot/arm-trusted-firmware-mediatek/Makefile index a1787ead21..4cf9bec7e9 100644 --- a/package/boot/arm-trusted-firmware-mediatek/Makefile +++ b/package/boot/arm-trusted-firmware-mediatek/Makefile @@ -13,9 +13,9 @@ PKG_RELEASE:=$(AUTORELEASE) PKG_SOURCE_PROTO:=git PKG_SOURCE_URL=https://github.com/mtk-openwrt/arm-trusted-firmware.git -PKG_SOURCE_DATE:=2021-04-28 -PKG_SOURCE_VERSION:=a63914612904642ed974390fff620f7003ebc20a -PKG_MIRROR_HASH:=6396a36406ceecf667470d0d673552751573de65497bf97d1e2af3505fe79366 +PKG_SOURCE_DATE:=2021-05-08 +PKG_SOURCE_VERSION:=d2c75b2139be003887af9cc5a94da5e9bdc59de7 +PKG_MIRROR_HASH:=4af9ce8e11511afee7f588cc982946c06339edbfa47afef6a7f3e2231ac9f34d PKG_MAINTAINER:=Daniel Golle From cc201759b69e6e61736005864d99cdac44b7e19f Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Fri, 7 May 2021 16:47:26 +0100 Subject: [PATCH 53/62] uboot-mediaktek: add support for PSTORE and check it on boot Add support for pstore/ramoops now that DRAM content is preserved over reboot on MT7622. On each boot, check pstore and boot to recovery image in case there are records stored in it. Signed-off-by: Daniel Golle --- .../patches/050-mt7622-enable-pstore.patch | 33 ++++++++ .../patches/230-cmd-add-pstore-check.patch | 78 +++++++++++++++++++ .../404-add-bananapi_bpi-r64_defconfigs.patch | 21 ++--- .../patches/410-add-linksys-e8450.patch | 7 +- .../patches/412-add-ubnt-unifi-6-lr.patch | 7 +- 5 files changed, 131 insertions(+), 15 deletions(-) create mode 100644 package/boot/uboot-mediatek/patches/050-mt7622-enable-pstore.patch create mode 100644 package/boot/uboot-mediatek/patches/230-cmd-add-pstore-check.patch diff --git a/package/boot/uboot-mediatek/patches/050-mt7622-enable-pstore.patch b/package/boot/uboot-mediatek/patches/050-mt7622-enable-pstore.patch new file mode 100644 index 0000000000..42d60c3f66 --- /dev/null +++ b/package/boot/uboot-mediatek/patches/050-mt7622-enable-pstore.patch @@ -0,0 +1,33 @@ +--- a/arch/arm/dts/mt7622.dtsi ++++ b/arch/arm/dts/mt7622.dtsi +@@ -37,6 +37,30 @@ + }; + }; + ++ psci { ++ compatible = "arm,psci-1.0"; ++ method = "smc"; ++ }; ++ ++ reserved-memory { ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ranges; ++ ++ /* 64 KiB reserved for ramoops/pstore */ ++ ramoops@0x42ff0000 { ++ compatible = "ramoops"; ++ reg = <0 0x42ff0000 0 0x10000>; ++ record-size = <0x1000>; ++ }; ++ ++ /* 192 KiB reserved for ARM Trusted Firmware (BL31) */ ++ secmon_reserved: secmon@43000000 { ++ reg = <0 0x43000000 0 0x30000>; ++ no-map; ++ }; ++ }; ++ + snfi: snfi@1100d000 { + compatible = "mediatek,mtk-snfi-spi"; + reg = <0x1100d000 0x2000>; diff --git a/package/boot/uboot-mediatek/patches/230-cmd-add-pstore-check.patch b/package/boot/uboot-mediatek/patches/230-cmd-add-pstore-check.patch new file mode 100644 index 0000000000..587245d2ab --- /dev/null +++ b/package/boot/uboot-mediatek/patches/230-cmd-add-pstore-check.patch @@ -0,0 +1,78 @@ +--- a/cmd/pstore.c ++++ b/cmd/pstore.c +@@ -207,6 +207,58 @@ static int pstore_set(struct cmd_tbl *cm + } + + /** ++ * pstore_check() - Check for pstore records ++ * @cmdtp: Command data struct pointer ++ * @flag: Command flag ++ * @argc: Command-line argument count ++ * @argv: Array of command-line arguments ++ * ++ * Return: 0 if there are records in pstore, 1 otherwise ++ */ ++static int pstore_check(struct cmd_tbl *cmdtp, int flag, int argc, ++ char * const argv[]) ++{ ++ phys_addr_t ptr; ++ char *buffer; ++ u32 size; ++ int header_len = 0; ++ bool compressed; ++ ++ if (pstore_length == 0) { ++ printf("Please set PStore configuration\n"); ++ return CMD_RET_USAGE; ++ } ++ ++ if (buffer_size == 0) ++ pstore_init_buffer_size(); ++ ++ buffer = malloc_cache_aligned(buffer_size); ++ ++ ptr = pstore_addr; ++ phys_addr_t ptr_end = ptr + pstore_length - pstore_pmsg_size ++ - pstore_ftrace_size - pstore_console_size; ++ ++ while (ptr < ptr_end) { ++ size = pstore_get_buffer(PERSISTENT_RAM_SIG, ptr, ++ pstore_record_size, buffer); ++ ptr += pstore_record_size; ++ ++ if (size == 0) ++ continue; ++ ++ header_len = pstore_read_kmsg_hdr(buffer, &compressed); ++ if (header_len == 0) ++ continue; ++ ++ free(buffer); ++ return 0; ++ } ++ ++ free(buffer); ++ return 1; ++} ++ ++/** + * pstore_print_buffer() - Print buffer + * @type: buffer type + * @buffer: buffer to print +@@ -458,6 +510,7 @@ static int pstore_save(struct cmd_tbl *c + + static struct cmd_tbl cmd_pstore_sub[] = { + U_BOOT_CMD_MKENT(set, 8, 0, pstore_set, "", ""), ++ U_BOOT_CMD_MKENT(check, 1, 0, pstore_check, "", ""), + U_BOOT_CMD_MKENT(display, 3, 0, pstore_display, "", ""), + U_BOOT_CMD_MKENT(save, 4, 0, pstore_save, "", ""), + }; +@@ -531,6 +584,8 @@ U_BOOT_CMD(pstore, 10, 0, do_pstore, + " 'pmsg-size' is the size of the user space logs record.\n" + " 'ecc-size' enables/disables ECC support and specifies ECC buffer size in\n" + " bytes (0 disables it, 1 is a special value, means 16 bytes ECC).\n" ++ "pstore check\n" ++ "- Returns true if there are records in pstore.\n" + "pstore display [record-type] [nb]\n" + "- Display existing records in pstore reserved memory. A 'record-type' can\n" + " be given to only display records of this kind. 'record-type' can be one\n" diff --git a/package/boot/uboot-mediatek/patches/404-add-bananapi_bpi-r64_defconfigs.patch b/package/boot/uboot-mediatek/patches/404-add-bananapi_bpi-r64_defconfigs.patch index ceaa15045e..72913e4d2f 100644 --- a/package/boot/uboot-mediatek/patches/404-add-bananapi_bpi-r64_defconfigs.patch +++ b/package/boot/uboot-mediatek/patches/404-add-bananapi_bpi-r64_defconfigs.patch @@ -1,6 +1,6 @@ --- /dev/null +++ b/configs/mt7622_bananapi_bpi-r64-sdmmc_defconfig -@@ -0,0 +1,157 @@ +@@ -0,0 +1,158 @@ +CONFIG_ARM=y +CONFIG_POSITION_INDEPENDENT=y +CONFIG_ARCH_MEDIATEK=y @@ -74,7 +74,8 @@ +CONFIG_CMD_UBIFS=y +CONFIG_CMD_ASKENV=y +CONFIG_CMD_PART=y -+# CONFIG_CMD_PSTORE is not set ++CONFIG_CMD_PSTORE=y ++CONFIG_CMD_PSTORE_MEM_ADDR=0x42ff0000 +CONFIG_CMD_RARP=y +CONFIG_CMD_SETEXPR=y +CONFIG_CMD_SLEEP=y @@ -165,7 +166,7 @@ +serverip=192.168.1.254 +loadaddr=0x4007ff28 +bootargs=root=/dev/mmcblk1p65 -+bootcmd=run boot_sdmmc ++bootcmd=if pstore check ; then run boot_recovery ; else run boot_sdmmc ; fi +bootconf=config-mt7622-bananapi-bpi-r64-pcie1 +bootconf_pcie=config-mt7622-bananapi-bpi-r64-pcie1 +bootconf_sata=config-mt7622-bananapi-bpi-r64-sata @@ -244,7 +245,7 @@ +_bootmenu_update_title=setenv _bootmenu_update_title ; setenv bootmenu_title "$bootmenu_title $ver" --- /dev/null +++ b/configs/mt7622_bananapi_bpi-r64-emmc_defconfig -@@ -0,0 +1,144 @@ +@@ -0,0 +1,145 @@ +CONFIG_ARM=y +CONFIG_POSITION_INDEPENDENT=y +CONFIG_ARCH_MEDIATEK=y @@ -313,7 +314,8 @@ +CONFIG_CMD_TFTPSRV=y +CONFIG_CMD_ASKENV=y +CONFIG_CMD_PART=y -+# CONFIG_CMD_PSTORE is not set ++CONFIG_CMD_PSTORE=y ++CONFIG_CMD_PSTORE_MEM_ADDR=0x42ff0000 +CONFIG_CMD_RARP=y +CONFIG_CMD_SETEXPR=y +CONFIG_CMD_SLEEP=y @@ -395,7 +397,7 @@ +ipaddr=192.168.1.1 +serverip=192.168.1.254 +loadaddr=0x4007ff28 -+bootcmd=run boot_emmc ++bootcmd=if pstore check ; then run boot_recovery ; else run boot_emmc ; fi +bootargs=root=/dev/mmcblk0p65 +bootconf=config-mt7622-bananapi-bpi-r64-pcie1 +bootconf_pcie=config-mt7622-bananapi-bpi-r64-pcie1 @@ -448,7 +450,7 @@ +_bootmenu_update_title=setenv _bootmenu_update_title ; setenv bootmenu_title "$bootmenu_title $ver" --- /dev/null +++ b/configs/mt7622_bananapi_bpi-r64-snand_defconfig -@@ -0,0 +1,138 @@ +@@ -0,0 +1,139 @@ +CONFIG_ARM=y +CONFIG_POSITION_INDEPENDENT=y +CONFIG_ARCH_MEDIATEK=y @@ -519,7 +521,8 @@ +CONFIG_CMD_UBIFS=y +CONFIG_CMD_ASKENV=y +CONFIG_CMD_PART=y -+# CONFIG_CMD_PSTORE is not set ++CONFIG_CMD_PSTORE=y ++CONFIG_CMD_PSTORE_MEM_ADDR=0x42ff0000 +CONFIG_CMD_RARP=y +CONFIG_CMD_SETEXPR=y +CONFIG_CMD_SLEEP=y @@ -594,7 +597,7 @@ +serverip=192.168.1.254 +loadaddr=0x4007ff28 +bootargs=root=/dev/ubiblock0_2p1 -+bootcmd=run boot_ubi ++bootcmd=if pstore check ; then run boot_recovery ; else run boot_ubi ; fi +bootconf=config-mt7622-bananapi-bpi-r64-pcie1 +bootconf_pcie=config-mt7622-bananapi-bpi-r64-pcie1 +bootconf_sata=config-mt7622-bananapi-bpi-r64-sata diff --git a/package/boot/uboot-mediatek/patches/410-add-linksys-e8450.patch b/package/boot/uboot-mediatek/patches/410-add-linksys-e8450.patch index a6eb40f1d2..f09a7db137 100644 --- a/package/boot/uboot-mediatek/patches/410-add-linksys-e8450.patch +++ b/package/boot/uboot-mediatek/patches/410-add-linksys-e8450.patch @@ -1,6 +1,6 @@ --- /dev/null +++ b/configs/mt7622_linksys_e8450_defconfig -@@ -0,0 +1,133 @@ +@@ -0,0 +1,134 @@ +CONFIG_ARM=y +CONFIG_POSITION_INDEPENDENT=y +CONFIG_ARCH_MEDIATEK=y @@ -69,7 +69,8 @@ +CONFIG_CMD_UBIFS=y +CONFIG_CMD_ASKENV=y +CONFIG_CMD_PART=y -+# CONFIG_CMD_PSTORE is not set ++CONFIG_CMD_PSTORE=y ++CONFIG_CMD_PSTORE_MEM_ADDR=0x42ff0000 +CONFIG_CMD_RARP=y +CONFIG_CMD_SETEXPR=y +CONFIG_CMD_SLEEP=y @@ -350,7 +351,7 @@ +ipaddr=192.168.1.1 +serverip=192.168.1.254 +loadaddr=0x4007ff28 -+bootcmd=run boot_ubi ++bootcmd=if pstore check ; then run boot_recovery ; else run boot_ubi ; fi +bootdelay=0 +bootfile=openwrt-mediatek-mt7622-linksys_e8450-ubi-initramfs-recovery.itb +bootfile_bl2=openwrt-mediatek-mt7622-linksys_e8450-ubi-preloader.bin diff --git a/package/boot/uboot-mediatek/patches/412-add-ubnt-unifi-6-lr.patch b/package/boot/uboot-mediatek/patches/412-add-ubnt-unifi-6-lr.patch index 8e8fe04a07..d9b8a01f73 100644 --- a/package/boot/uboot-mediatek/patches/412-add-ubnt-unifi-6-lr.patch +++ b/package/boot/uboot-mediatek/patches/412-add-ubnt-unifi-6-lr.patch @@ -1,6 +1,6 @@ --- /dev/null +++ b/configs/mt7622_ubnt_unifi-6-lr_defconfig -@@ -0,0 +1,138 @@ +@@ -0,0 +1,139 @@ +CONFIG_ARM=y +CONFIG_POSITION_INDEPENDENT=y +CONFIG_ARCH_MEDIATEK=y @@ -72,7 +72,8 @@ +CONFIG_CMD_TFTPSRV=y +# CONFIG_CMD_UNLZ4 is not set +CONFIG_CMD_ASKENV=y -+# CONFIG_CMD_PSTORE is not set ++CONFIG_CMD_PSTORE=y ++CONFIG_CMD_PSTORE_MEM_ADDR=0x42ff0000 +CONFIG_CMD_RARP=y +CONFIG_CMD_SETEXPR=y +CONFIG_CMD_SLEEP=y @@ -362,7 +363,7 @@ +ipaddr=192.168.1.1 +serverip=192.168.1.254 +loadaddr=0x40080000 -+bootcmd=run boot_nor ++bootcmd=if pstore check ; then run boot_recovery ; else run boot_nor ; fi +bootdelay=0 +bootfile=openwrt-mediatek-mt7622-ubnt_unifi-6-lr-ubootmod-initramfs-recovery.itb +bootfile_bl2=openwrt-mediatek-mt7622-ubnt_unifi-6-lr-ubootmod-preloader.bin From e1adb1fa39dd5ef97280ad1b2bb9e8ff4c43674f Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Fri, 7 May 2021 16:53:09 +0100 Subject: [PATCH 54/62] mediatek: reserve memory for ramoops and enable PSTORE Reserve 64KiB of memory for crashlogs and enable PSTORE feature in kernel config for MT7622. Signed-off-by: Daniel Golle --- target/linux/mediatek/mt7622/config-5.10 | 33 +++++++++++++++++-- .../105-dts-mt7622-enable-pstore.patch | 25 ++++++++++++++ .../131-dts-mt7622-add-snand-support.patch | 2 +- ...ek-Split-PCIe-node-for-MT2712-MT7622.patch | 4 +-- ..._eth_soc-add-support-for-coherent-DM.patch | 4 +-- ...ediatek-add-support-for-coherent-DMA.patch | 10 +++--- 6 files changed, 65 insertions(+), 13 deletions(-) create mode 100644 target/linux/mediatek/patches-5.10/105-dts-mt7622-enable-pstore.patch diff --git a/target/linux/mediatek/mt7622/config-5.10 b/target/linux/mediatek/mt7622/config-5.10 index 1ab925190a..caf0293f41 100644 --- a/target/linux/mediatek/mt7622/config-5.10 +++ b/target/linux/mediatek/mt7622/config-5.10 @@ -1,4 +1,5 @@ CONFIG_64BIT=y +# CONFIG_AHCI_MTK is not set CONFIG_ARCH_DMA_ADDR_T_64BIT=y CONFIG_ARCH_KEEP_MEMBLOCK=y CONFIG_ARCH_MEDIATEK=y @@ -114,6 +115,8 @@ CONFIG_CRYPTO_ACOMP2=y CONFIG_CRYPTO_AEAD=y CONFIG_CRYPTO_AEAD2=y CONFIG_CRYPTO_CMAC=y +CONFIG_CRYPTO_CRC32=y +CONFIG_CRYPTO_CRC32C=y CONFIG_CRYPTO_DEFLATE=y CONFIG_CRYPTO_DRBG=y CONFIG_CRYPTO_DRBG_HMAC=y @@ -137,6 +140,7 @@ CONFIG_CRYPTO_RNG=y CONFIG_CRYPTO_RNG2=y CONFIG_CRYPTO_RNG_DEFAULT=y CONFIG_CRYPTO_SHA256=y +CONFIG_CRYPTO_ZSTD=y CONFIG_DCACHE_WORD_ACCESS=y CONFIG_DEBUG_MISC=y CONFIG_DEVTMPFS=y @@ -155,12 +159,14 @@ CONFIG_DYNAMIC_DEBUG=y CONFIG_EDAC_SUPPORT=y CONFIG_EINT_MTK=y CONFIG_EXT4_FS=y +CONFIG_F2FS_FS=y CONFIG_FIT_PARTITION=y CONFIG_FIXED_PHY=y CONFIG_FIX_EARLYCON_MEM=y # CONFIG_FLATMEM_MANUAL is not set CONFIG_FRAME_POINTER=y -CONFIG_F2FS_FS=y +CONFIG_FS_IOMAP=y +CONFIG_FS_MBCACHE=y # CONFIG_FUJITSU_ERRATUM_010001 is not set CONFIG_FW_LOADER_PAGED_BUF=y CONFIG_GENERIC_ALLOCATOR=y @@ -217,6 +223,7 @@ CONFIG_IRQ_DOMAIN_HIERARCHY=y CONFIG_IRQ_FORCED_THREADING=y CONFIG_IRQ_TIME_ACCOUNTING=y CONFIG_IRQ_WORK=y +CONFIG_JBD2=y CONFIG_JUMP_LABEL=y CONFIG_LEDS_UBNT_LEDBAR=y CONFIG_LIBFDT=y @@ -228,6 +235,7 @@ CONFIG_LZO_DECOMPRESS=y CONFIG_MAGIC_SYSRQ=y CONFIG_MDIO_BUS=y CONFIG_MDIO_DEVICE=y +CONFIG_MDIO_DEVRES=y CONFIG_MEDIATEK_MT6577_AUXADC=y CONFIG_MEDIATEK_WATCHDOG=y CONFIG_MEMFD_CREATE=y @@ -245,10 +253,10 @@ CONFIG_MTD_NAND_ECC=y CONFIG_MTD_NAND_ECC_SW_HAMMING=y CONFIG_MTD_NAND_MTK=y CONFIG_MTD_NAND_MTK_BMT=y +CONFIG_MTD_PARSER_TRX=y CONFIG_MTD_RAW_NAND=y CONFIG_MTD_SPI_NAND=y CONFIG_MTD_SPI_NOR=y -CONFIG_MTD_PARSER_TRX=y CONFIG_MTD_SPLIT_FIRMWARE=y CONFIG_MTD_SPLIT_FIT_FW=y CONFIG_MTD_UBI=y @@ -337,6 +345,20 @@ CONFIG_POWER_RESET=y CONFIG_POWER_RESET_SYSCON=y CONFIG_POWER_SUPPLY=y CONFIG_PRINTK_TIME=y +CONFIG_PSTORE=y +# CONFIG_PSTORE_842_COMPRESS is not set +# CONFIG_PSTORE_BLK is not set +CONFIG_PSTORE_COMPRESS=y +CONFIG_PSTORE_COMPRESS_DEFAULT="deflate" +CONFIG_PSTORE_CONSOLE=y +CONFIG_PSTORE_DEFLATE_COMPRESS=y +CONFIG_PSTORE_DEFLATE_COMPRESS_DEFAULT=y +# CONFIG_PSTORE_LZ4HC_COMPRESS is not set +# CONFIG_PSTORE_LZ4_COMPRESS is not set +# CONFIG_PSTORE_LZO_COMPRESS is not set +CONFIG_PSTORE_PMSG=y +CONFIG_PSTORE_RAM=y +# CONFIG_PSTORE_ZSTD_COMPRESS is not set CONFIG_PWM=y CONFIG_PWM_MEDIATEK=y # CONFIG_PWM_MTK_DISP is not set @@ -349,6 +371,9 @@ CONFIG_RATIONAL=y CONFIG_RCU_NEED_SEGCBLIST=y CONFIG_RCU_STALL_COMMON=y CONFIG_REALTEK_PHY=y +CONFIG_REED_SOLOMON=y +CONFIG_REED_SOLOMON_DEC8=y +CONFIG_REED_SOLOMON_ENC8=y CONFIG_REGMAP=y CONFIG_REGMAP_MMIO=y CONFIG_REGULATOR=y @@ -363,7 +388,6 @@ CONFIG_RTC_DRV_MT7622=y CONFIG_RTC_I2C_AND_SPI=y CONFIG_RTL8367S_GSW=y CONFIG_RWSEM_SPIN_ON_OWNER=y -CONFIG_SATA_HOST=y CONFIG_SCSI=y # CONFIG_SECTION_MISMATCH_WARN_ONLY is not set CONFIG_SERIAL_8250_FSL=y @@ -430,6 +454,9 @@ CONFIG_WATCHDOG_PRETIMEOUT_GOV_PANIC=y CONFIG_WATCHDOG_PRETIMEOUT_GOV_SEL=m CONFIG_WATCHDOG_SYSFS=y CONFIG_XPS=y +CONFIG_XXHASH=y CONFIG_ZLIB_DEFLATE=y CONFIG_ZLIB_INFLATE=y CONFIG_ZONE_DMA32=y +CONFIG_ZSTD_COMPRESS=y +CONFIG_ZSTD_DECOMPRESS=y diff --git a/target/linux/mediatek/patches-5.10/105-dts-mt7622-enable-pstore.patch b/target/linux/mediatek/patches-5.10/105-dts-mt7622-enable-pstore.patch new file mode 100644 index 0000000000..6ef56f8584 --- /dev/null +++ b/target/linux/mediatek/patches-5.10/105-dts-mt7622-enable-pstore.patch @@ -0,0 +1,25 @@ +--- a/arch/arm64/boot/dts/mediatek/mt7622.dtsi ++++ b/arch/arm64/boot/dts/mediatek/mt7622.dtsi +@@ -111,7 +111,7 @@ + }; + + psci { +- compatible = "arm,psci-0.2"; ++ compatible = "arm,psci-1.0"; + method = "smc"; + }; + +@@ -127,6 +127,13 @@ + #size-cells = <2>; + ranges; + ++ /* 64 KiB reserved for ramoops/pstore */ ++ ramoops@0x42ff0000 { ++ compatible = "ramoops"; ++ reg = <0 0x42ff0000 0 0x10000>; ++ record-size = <0x1000>; ++ }; ++ + /* 192 KiB reserved for ARM Trusted Firmware (BL31) */ + secmon_reserved: secmon@43000000 { + reg = <0 0x43000000 0 0x30000>; diff --git a/target/linux/mediatek/patches-5.10/131-dts-mt7622-add-snand-support.patch b/target/linux/mediatek/patches-5.10/131-dts-mt7622-add-snand-support.patch index de96162e8a..5f89d58b06 100644 --- a/target/linux/mediatek/patches-5.10/131-dts-mt7622-add-snand-support.patch +++ b/target/linux/mediatek/patches-5.10/131-dts-mt7622-add-snand-support.patch @@ -1,6 +1,6 @@ --- a/arch/arm64/boot/dts/mediatek/mt7622.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt7622.dtsi -@@ -554,6 +554,19 @@ +@@ -561,6 +561,19 @@ status = "disabled"; }; diff --git a/target/linux/mediatek/patches-5.10/602-arm64-dts-mediatek-Split-PCIe-node-for-MT2712-MT7622.patch b/target/linux/mediatek/patches-5.10/602-arm64-dts-mediatek-Split-PCIe-node-for-MT2712-MT7622.patch index 3303d39342..427ed226fd 100644 --- a/target/linux/mediatek/patches-5.10/602-arm64-dts-mediatek-Split-PCIe-node-for-MT2712-MT7622.patch +++ b/target/linux/mediatek/patches-5.10/602-arm64-dts-mediatek-Split-PCIe-node-for-MT2712-MT7622.patch @@ -281,7 +281,7 @@ Signed-off-by: chuanjia.liu &pio { --- a/arch/arm64/boot/dts/mediatek/mt7622.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt7622.dtsi -@@ -794,45 +794,41 @@ +@@ -801,45 +801,41 @@ #reset-cells = <1>; }; @@ -344,7 +344,7 @@ Signed-off-by: chuanjia.liu interrupt-map-mask = <0 0 0 7>; interrupt-map = <0 0 0 1 &pcie_intc0 0>, <0 0 0 2 &pcie_intc0 1>, -@@ -844,15 +840,39 @@ +@@ -851,15 +847,39 @@ #interrupt-cells = <1>; }; }; diff --git a/target/linux/mediatek/patches-5.10/700-net-ethernet-mtk_eth_soc-add-support-for-coherent-DM.patch b/target/linux/mediatek/patches-5.10/700-net-ethernet-mtk_eth_soc-add-support-for-coherent-DM.patch index 57f6ec69a0..0b028cdcee 100644 --- a/target/linux/mediatek/patches-5.10/700-net-ethernet-mtk_eth_soc-add-support-for-coherent-DM.patch +++ b/target/linux/mediatek/patches-5.10/700-net-ethernet-mtk_eth_soc-add-support-for-coherent-DM.patch @@ -9,7 +9,7 @@ Signed-off-by: Felix Fietkau --- a/arch/arm64/boot/dts/mediatek/mt7622.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt7622.dtsi -@@ -357,7 +357,7 @@ +@@ -364,7 +364,7 @@ }; cci_control2: slave-if@5000 { @@ -18,7 +18,7 @@ Signed-off-by: Felix Fietkau interface-type = "ace"; reg = <0x5000 0x1000>; }; -@@ -969,6 +969,8 @@ +@@ -976,6 +976,8 @@ power-domains = <&scpsys MT7622_POWER_DOMAIN_ETHSYS>; mediatek,ethsys = <ðsys>; mediatek,sgmiisys = <&sgmiisys>; diff --git a/target/linux/mediatek/patches-5.10/710-pci-pcie-mediatek-add-support-for-coherent-DMA.patch b/target/linux/mediatek/patches-5.10/710-pci-pcie-mediatek-add-support-for-coherent-DMA.patch index 0156d89bba..e3800bdf9d 100644 --- a/target/linux/mediatek/patches-5.10/710-pci-pcie-mediatek-add-support-for-coherent-DMA.patch +++ b/target/linux/mediatek/patches-5.10/710-pci-pcie-mediatek-add-support-for-coherent-DMA.patch @@ -10,7 +10,7 @@ Signed-off-by: Felix Fietkau --- a/arch/arm64/boot/dts/mediatek/mt7622.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt7622.dtsi -@@ -805,6 +805,8 @@ +@@ -812,6 +812,8 @@ reg = <0 0x1a143000 0 0x1000>; reg-names = "port0"; mediatek,pcie-cfg = <&pciecfg>; @@ -19,7 +19,7 @@ Signed-off-by: Felix Fietkau #address-cells = <3>; #size-cells = <2>; interrupts = ; -@@ -822,6 +824,7 @@ +@@ -829,6 +831,7 @@ bus-range = <0x00 0xff>; ranges = <0x82000000 0 0x20000000 0x0 0x20000000 0 0x8000000>; status = "disabled"; @@ -27,7 +27,7 @@ Signed-off-by: Felix Fietkau slot0: pcie@0,0 { reg = <0x0000 0 0 0 0>; -@@ -848,6 +851,8 @@ +@@ -855,6 +858,8 @@ reg = <0 0x1a145000 0 0x1000>; reg-names = "port1"; mediatek,pcie-cfg = <&pciecfg>; @@ -36,7 +36,7 @@ Signed-off-by: Felix Fietkau #address-cells = <3>; #size-cells = <2>; interrupts = ; -@@ -866,6 +871,7 @@ +@@ -873,6 +878,7 @@ bus-range = <0x00 0xff>; ranges = <0x82000000 0 0x28000000 0x0 0x28000000 0 0x8000000>; status = "disabled"; @@ -44,7 +44,7 @@ Signed-off-by: Felix Fietkau slot1: pcie@1,0 { reg = <0x0800 0 0 0 0>; -@@ -925,6 +931,11 @@ +@@ -932,6 +938,11 @@ }; }; From da16b801a32a53ba4315d8cc67b7ac0deb7ff4c0 Mon Sep 17 00:00:00 2001 From: John Audia Date: Fri, 7 May 2021 08:51:44 -0400 Subject: [PATCH 55/62] kernel: bump 5.4 to 5.4.117 All patches automatically rebased. Build system: x86_64 Build-tested: ipq806x/R7800 Run-tested: ipq806x/R7800 No dmesg regressions, everything functional Signed-off-by: John Audia --- include/kernel-version.mk | 4 ++-- ...q-add-Krait-dedicated-scaling-driver.patch | 10 +++++----- ...-v5.11-dmaengine-qcom-add_ADM_driver.patch | 10 ---------- ....12-mtd-parsers-Add-Qcom-SMEM-parser.patch | 20 +++++-------------- 4 files changed, 12 insertions(+), 32 deletions(-) diff --git a/include/kernel-version.mk b/include/kernel-version.mk index 5b003e31a0..f343716e01 100644 --- a/include/kernel-version.mk +++ b/include/kernel-version.mk @@ -6,10 +6,10 @@ ifdef CONFIG_TESTING_KERNEL KERNEL_PATCHVER:=$(KERNEL_TESTING_PATCHVER) endif -LINUX_VERSION-5.4 = .116 +LINUX_VERSION-5.4 = .117 LINUX_VERSION-5.10 = .33 -LINUX_KERNEL_HASH-5.4.116 = fa8bce778c23a2c5be36e5b5b5005bcfd4ac3df8a90999e9e64189634bbbc9aa +LINUX_KERNEL_HASH-5.4.117 = 4e989b5775830092e5c76b5cca65ebff862ad0c87d0b58c3a20d415c3d4ec770 LINUX_KERNEL_HASH-5.10.33 = 933fdbc36371c0f830b7a6a957a559fca2dad1cc0eaa852ef42fb168185b4315 remove_uri_prefix=$(subst git://,,$(subst http://,,$(subst https://,,$(1)))) diff --git a/target/linux/ipq806x/patches-5.4/098-1-cpufreq-add-Krait-dedicated-scaling-driver.patch b/target/linux/ipq806x/patches-5.4/098-1-cpufreq-add-Krait-dedicated-scaling-driver.patch index eb9978154d..cfc4341ebc 100644 --- a/target/linux/ipq806x/patches-5.4/098-1-cpufreq-add-Krait-dedicated-scaling-driver.patch +++ b/target/linux/ipq806x/patches-5.4/098-1-cpufreq-add-Krait-dedicated-scaling-driver.patch @@ -29,7 +29,7 @@ Signed-off-by: Ansuel Smith --- a/drivers/cpufreq/Kconfig.arm +++ b/drivers/cpufreq/Kconfig.arm -@@ -150,6 +150,18 @@ config ARM_QCOM_CPUFREQ_HW +@@ -155,6 +155,18 @@ config ARM_QCOM_CPUFREQ_HW The driver implements the cpufreq interface for this HW engine. Say Y if you want to support CPUFreq HW. @@ -48,7 +48,7 @@ Signed-off-by: Ansuel Smith config ARM_RASPBERRYPI_CPUFREQ tristate "Raspberry Pi cpufreq support" depends on CLK_RASPBERRYPI || COMPILE_TEST -@@ -339,4 +351,4 @@ config ARM_PXA2xx_CPUFREQ +@@ -338,4 +350,4 @@ config ARM_PXA2xx_CPUFREQ help This add the CPUFreq driver support for Intel PXA2xx SOCs. @@ -57,7 +57,7 @@ Signed-off-by: Ansuel Smith \ No newline at end of file --- a/drivers/cpufreq/Makefile +++ b/drivers/cpufreq/Makefile -@@ -63,6 +63,7 @@ obj-$(CONFIG_ARM_PXA2xx_CPUFREQ) += pxa2 +@@ -65,6 +65,7 @@ obj-$(CONFIG_ARM_PXA2xx_CPUFREQ) += pxa2 obj-$(CONFIG_PXA3xx) += pxa3xx-cpufreq.o obj-$(CONFIG_ARM_QCOM_CPUFREQ_HW) += qcom-cpufreq-hw.o obj-$(CONFIG_ARM_QCOM_CPUFREQ_NVMEM) += qcom-cpufreq-nvmem.o @@ -65,8 +65,8 @@ Signed-off-by: Ansuel Smith obj-$(CONFIG_ARM_RASPBERRYPI_CPUFREQ) += raspberrypi-cpufreq.o obj-$(CONFIG_ARM_S3C2410_CPUFREQ) += s3c2410-cpufreq.o obj-$(CONFIG_ARM_S3C2412_CPUFREQ) += s3c2412-cpufreq.o -@@ -86,6 +87,7 @@ obj-$(CONFIG_ARM_TEGRA186_CPUFREQ) += te - obj-$(CONFIG_ARM_TEGRA194_CPUFREQ) += tegra194-cpufreq.o +@@ -87,6 +88,7 @@ obj-$(CONFIG_ARM_TEGRA124_CPUFREQ) += te + obj-$(CONFIG_ARM_TEGRA186_CPUFREQ) += tegra186-cpufreq.o obj-$(CONFIG_ARM_TI_CPUFREQ) += ti-cpufreq.o obj-$(CONFIG_ARM_VEXPRESS_SPC_CPUFREQ) += vexpress-spc-cpufreq.o +obj-$(CONFIG_ARM_KRAIT_CPUFREQ) += krait-cpufreq.o diff --git a/target/linux/ipq806x/patches-5.4/100-v5.11-dmaengine-qcom-add_ADM_driver.patch b/target/linux/ipq806x/patches-5.4/100-v5.11-dmaengine-qcom-add_ADM_driver.patch index 45062d52fc..2d24da01e4 100644 --- a/target/linux/ipq806x/patches-5.4/100-v5.11-dmaengine-qcom-add_ADM_driver.patch +++ b/target/linux/ipq806x/patches-5.4/100-v5.11-dmaengine-qcom-add_ADM_driver.patch @@ -31,8 +31,6 @@ Signed-off-by: Vinod Koul 3 files changed, 915 insertions(+) create mode 100644 drivers/dma/qcom/qcom_adm.c -diff --git a/drivers/dma/qcom/Kconfig b/drivers/dma/qcom/Kconfig -index 3bcb689162c67..0389d60d2604a 100644 --- a/drivers/dma/qcom/Kconfig +++ b/drivers/dma/qcom/Kconfig @@ -1,4 +1,15 @@ @@ -51,8 +49,6 @@ index 3bcb689162c67..0389d60d2604a 100644 config QCOM_BAM_DMA tristate "QCOM BAM DMA support" depends on ARCH_QCOM || (COMPILE_TEST && OF && ARM) -diff --git a/drivers/dma/qcom/Makefile b/drivers/dma/qcom/Makefile -index 1ae92da88b0c9..346e643fbb6db 100644 --- a/drivers/dma/qcom/Makefile +++ b/drivers/dma/qcom/Makefile @@ -1,4 +1,5 @@ @@ -61,9 +57,6 @@ index 1ae92da88b0c9..346e643fbb6db 100644 obj-$(CONFIG_QCOM_BAM_DMA) += bam_dma.o obj-$(CONFIG_QCOM_HIDMA_MGMT) += hdma_mgmt.o hdma_mgmt-objs := hidma_mgmt.o hidma_mgmt_sys.o -diff --git a/drivers/dma/qcom/qcom_adm.c b/drivers/dma/qcom/qcom_adm.c -new file mode 100644 -index 0000000000000..9b6f8e050ecce --- /dev/null +++ b/drivers/dma/qcom/qcom_adm.c @@ -0,0 +1,903 @@ @@ -970,6 +963,3 @@ index 0000000000000..9b6f8e050ecce +MODULE_AUTHOR("Andy Gross "); +MODULE_DESCRIPTION("QCOM ADM DMA engine driver"); +MODULE_LICENSE("GPL v2"); --- -cgit 1.2.3-1.el7 - diff --git a/target/linux/ipq806x/patches-5.4/101-5.12-mtd-parsers-Add-Qcom-SMEM-parser.patch b/target/linux/ipq806x/patches-5.4/101-5.12-mtd-parsers-Add-Qcom-SMEM-parser.patch index 7aec4fcc83..a78dc82a47 100644 --- a/target/linux/ipq806x/patches-5.4/101-5.12-mtd-parsers-Add-Qcom-SMEM-parser.patch +++ b/target/linux/ipq806x/patches-5.4/101-5.12-mtd-parsers-Add-Qcom-SMEM-parser.patch @@ -17,15 +17,12 @@ Link: https://lore.kernel.org/linux-mtd/20210104041137.113075-3-manivannan.sadha 3 files changed, 179 insertions(+) create mode 100644 drivers/mtd/parsers/qcomsmempart.c -diff --git a/drivers/mtd/parsers/Kconfig b/drivers/mtd/parsers/Kconfig -index e72354322f628..d90c302290522 100644 --- a/drivers/mtd/parsers/Kconfig +++ b/drivers/mtd/parsers/Kconfig -@@ -160,6 +160,14 @@ config MTD_REDBOOT_PARTS_READONLY - 'FIS directory' images, enable this option. +@@ -196,6 +196,14 @@ config MTD_REDBOOT_PARTS_READONLY endif # MTD_REDBOOT_PARTS -+ + +config MTD_QCOMSMEM_PARTS + tristate "Qualcomm SMEM NAND flash partition parser" + depends on MTD_NAND_QCOM || COMPILE_TEST @@ -33,22 +30,18 @@ index e72354322f628..d90c302290522 100644 + help + This provides support for parsing partitions from Shared Memory (SMEM) + for NAND flash on Qualcomm platforms. - ++ config MTD_ROUTERBOOT_PARTS tristate "RouterBoot flash partition parser" -diff --git a/drivers/mtd/parsers/Makefile b/drivers/mtd/parsers/Makefile -index b0c5f62f9e858..50eb0b0a22105 100644 + depends on MTD && OF --- a/drivers/mtd/parsers/Makefile +++ b/drivers/mtd/parsers/Makefile -@@ -9,4 +9,5 @@ obj-$(CONFIG_MTD_AFS_PARTS) += afs.o +@@ -13,4 +13,5 @@ obj-$(CONFIG_MTD_AFS_PARTS) += afs.o obj-$(CONFIG_MTD_PARSER_TRX) += parser_trx.o obj-$(CONFIG_MTD_SHARPSL_PARTS) += sharpslpart.o obj-$(CONFIG_MTD_REDBOOT_PARTS) += redboot.o +obj-$(CONFIG_MTD_QCOMSMEM_PARTS) += qcomsmempart.o obj-$(CONFIG_MTD_ROUTERBOOT_PARTS) += routerbootpart.o -diff --git a/drivers/mtd/parsers/qcomsmempart.c b/drivers/mtd/parsers/qcomsmempart.c -new file mode 100644 -index 0000000000000..808cb33d71f8e --- /dev/null +++ b/drivers/mtd/parsers/qcomsmempart.c @@ -0,0 +1,170 @@ @@ -222,6 +215,3 @@ index 0000000000000..808cb33d71f8e +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Manivannan Sadhasivam "); +MODULE_DESCRIPTION("Qualcomm SMEM NAND flash partition parser"); --- -cgit 1.2.3-1.el7 - From a1afeb927010ad5e6124e55f1874f4aece496ee7 Mon Sep 17 00:00:00 2001 From: Mark Mentovai Date: Sat, 8 May 2021 14:24:52 -0400 Subject: [PATCH 56/62] ipq806x: Add mising devices to kernel 5.10 d53be2a2e981 migrated 0069-arm-boot-add-dts-files.patch from patches-5.4 to patches-5.10, but a subsequent patch in that set, 1e25423be8ac, erroneously removed several devices: ipq8062/nec,wg2600hp3 from 3bb16185737c ipq8064/asrock,g10 from 98b86296e67d ipq8064/ubnt,unifi-ac-hd from 4e46beb31342 Signed-off-by: Mark Mentovai Run-tested: ipq806x/ubnt,unifi-ac-hd Cc: Ansuel Smith --- .../ipq806x/patches-5.10/0069-arm-boot-add-dts-files.patch | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/target/linux/ipq806x/patches-5.10/0069-arm-boot-add-dts-files.patch b/target/linux/ipq806x/patches-5.10/0069-arm-boot-add-dts-files.patch index d5b1d4473b..2b069b8cfb 100644 --- a/target/linux/ipq806x/patches-5.10/0069-arm-boot-add-dts-files.patch +++ b/target/linux/ipq806x/patches-5.10/0069-arm-boot-add-dts-files.patch @@ -10,8 +10,11 @@ Signed-off-by: John Crispin --- a/arch/arm/boot/dts/Makefile +++ b/arch/arm/boot/dts/Makefile -@@ -909,6 +909,20 @@ dtb-$(CONFIG_ARCH_QCOM) += \ +@@ -907,8 +907,25 @@ + qcom-ipq4019-ap.dk04.1-c3.dtb \ + qcom-ipq4019-ap.dk07.1-c1.dtb \ qcom-ipq4019-ap.dk07.1-c2.dtb \ ++ qcom-ipq8062-wg2600hp3.dtb \ qcom-ipq8064-ap148.dtb \ qcom-ipq8064-rb3011.dtb \ + qcom-ipq8064-c2600.dtb \ @@ -20,8 +23,10 @@ Signed-off-by: John Crispin + qcom-ipq8064-ap161.dtb \ + qcom-ipq8064-ea7500-v1.dtb \ + qcom-ipq8064-ea8500.dtb \ ++ qcom-ipq8064-g10.dtb \ + qcom-ipq8064-r7500.dtb \ + qcom-ipq8064-r7500v2.dtb \ ++ qcom-ipq8064-unifi-ac-hd.dtb \ + qcom-ipq8064-wg2600hp.dtb \ + qcom-ipq8064-wpq864.dtb \ + qcom-ipq8064-wxr-2533dhp.dtb \ From 62850e7a77befd1fbbceaec5c609e1538b152eba Mon Sep 17 00:00:00 2001 From: Mark Mentovai Date: Sat, 8 May 2021 14:24:53 -0400 Subject: [PATCH 57/62] ipq806x: Bring missing patches from 5.4 to 5.10 Kernel 5.10 support for ipq806x was added at the same time that these patches were developed for kernel 5.4. This carries the patches forward to kernel 5.10. fa731838c524 ipq806x: dwmac: clear forced speed during probe 75ca641f1b84 ipq806x: Add "snps,dwmac" to all gmac compatible= d62825dd77b3 ipq806x: dwmac: set forced speed when using fixed-link Signed-off-by: Mark Mentovai Run-tested: ipq806x/ubnt,unifi-ac-hd Cc: Ansuel Smith --- .../082-ipq8064-dtsi-tweaks.patch | 36 ++++++++ ...-dwmac-ipq806x-qsgmii-pcs-all-ch-ctl.patch | 83 +++++++++++++++++++ 2 files changed, 119 insertions(+) create mode 100644 target/linux/ipq806x/patches-5.10/101-dwmac-ipq806x-qsgmii-pcs-all-ch-ctl.patch diff --git a/target/linux/ipq806x/patches-5.10/082-ipq8064-dtsi-tweaks.patch b/target/linux/ipq806x/patches-5.10/082-ipq8064-dtsi-tweaks.patch index b6e8e915eb..c91fb68dc4 100644 --- a/target/linux/ipq806x/patches-5.10/082-ipq8064-dtsi-tweaks.patch +++ b/target/linux/ipq806x/patches-5.10/082-ipq8064-dtsi-tweaks.patch @@ -141,6 +141,42 @@ }; tcsr: syscon@1a400000 { +@@ -622,7 +649,7 @@ + + gmac0: ethernet@37000000 { + device_type = "network"; +- compatible = "qcom,ipq806x-gmac"; ++ compatible = "qcom,ipq806x-gmac", "snps,dwmac"; + reg = <0x37000000 0x200000>; + interrupts = ; + interrupt-names = "macirq"; +@@ -645,7 +672,7 @@ + + gmac1: ethernet@37200000 { + device_type = "network"; +- compatible = "qcom,ipq806x-gmac"; ++ compatible = "qcom,ipq806x-gmac", "snps,dwmac"; + reg = <0x37200000 0x200000>; + interrupts = ; + interrupt-names = "macirq"; +@@ -668,7 +695,7 @@ + + gmac2: ethernet@37400000 { + device_type = "network"; +- compatible = "qcom,ipq806x-gmac"; ++ compatible = "qcom,ipq806x-gmac", "snps,dwmac"; + reg = <0x37400000 0x200000>; + interrupts = ; + interrupt-names = "macirq"; +@@ -691,7 +718,7 @@ + + gmac3: ethernet@37600000 { + device_type = "network"; +- compatible = "qcom,ipq806x-gmac"; ++ compatible = "qcom,ipq806x-gmac", "snps,dwmac"; + reg = <0x37600000 0x200000>; + interrupts = ; + interrupt-names = "macirq"; @@ -740,13 +767,13 @@ qcom,ee = <0>; }; diff --git a/target/linux/ipq806x/patches-5.10/101-dwmac-ipq806x-qsgmii-pcs-all-ch-ctl.patch b/target/linux/ipq806x/patches-5.10/101-dwmac-ipq806x-qsgmii-pcs-all-ch-ctl.patch new file mode 100644 index 0000000000..3c497ead6a --- /dev/null +++ b/target/linux/ipq806x/patches-5.10/101-dwmac-ipq806x-qsgmii-pcs-all-ch-ctl.patch @@ -0,0 +1,83 @@ +--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c ++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c +@@ -64,6 +64,17 @@ + #define NSS_COMMON_CLK_DIV_SGMII_100 4 + #define NSS_COMMON_CLK_DIV_SGMII_10 49 + ++#define QSGMII_PCS_ALL_CH_CTL 0x80 ++#define QSGMII_PCS_CH_SPEED_FORCE 0x2 ++#define QSGMII_PCS_CH_SPEED_10 0x0 ++#define QSGMII_PCS_CH_SPEED_100 0x4 ++#define QSGMII_PCS_CH_SPEED_1000 0x8 ++#define QSGMII_PCS_CH_SPEED_MASK (QSGMII_PCS_CH_SPEED_FORCE | \ ++ QSGMII_PCS_CH_SPEED_10 | \ ++ QSGMII_PCS_CH_SPEED_100 | \ ++ QSGMII_PCS_CH_SPEED_1000) ++#define QSGMII_PCS_CH_SPEED_SHIFT(x) (x * 4) ++ + #define QSGMII_PCS_CAL_LCKDT_CTL 0x120 + #define QSGMII_PCS_CAL_LCKDT_CTL_RST BIT(19) + +@@ -241,6 +252,36 @@ static void ipq806x_gmac_fix_mac_speed(v + ipq806x_gmac_set_speed(gmac, speed); + } + ++static int ++ipq806x_gmac_get_qsgmii_pcs_speed_val(struct platform_device *pdev) { ++ struct device_node *fixed_link_node; ++ int rv; ++ int fixed_link_speed; ++ ++ if (!of_phy_is_fixed_link(pdev->dev.of_node)) ++ return 0; ++ ++ fixed_link_node = of_get_child_by_name(pdev->dev.of_node, "fixed-link"); ++ if (!fixed_link_node) ++ return -1; ++ ++ rv = of_property_read_u32(fixed_link_node, "speed", &fixed_link_speed); ++ of_node_put(fixed_link_node); ++ if (rv) ++ return -1; ++ ++ switch (fixed_link_speed) { ++ case SPEED_1000: ++ return QSGMII_PCS_CH_SPEED_FORCE | QSGMII_PCS_CH_SPEED_1000; ++ case SPEED_100: ++ return QSGMII_PCS_CH_SPEED_FORCE | QSGMII_PCS_CH_SPEED_100; ++ case SPEED_10: ++ return QSGMII_PCS_CH_SPEED_FORCE | QSGMII_PCS_CH_SPEED_10; ++ } ++ ++ return -1; ++} ++ + static int ipq806x_gmac_probe(struct platform_device *pdev) + { + struct plat_stmmacenet_data *plat_dat; +@@ -249,6 +290,7 @@ static int ipq806x_gmac_probe(struct pla + struct ipq806x_gmac *gmac; + int val; + int err; ++ int qsgmii_pcs_speed; + + val = stmmac_get_platform_resources(pdev, &stmmac_res); + if (val) +@@ -345,6 +387,17 @@ static int ipq806x_gmac_probe(struct pla + 0x1ul << QSGMII_PHY_RX_INPUT_EQU_OFFSET | + 0x2ul << QSGMII_PHY_CDR_PI_SLEW_OFFSET | + 0xCul << QSGMII_PHY_TX_DRV_AMP_OFFSET); ++ ++ qsgmii_pcs_speed = ipq806x_gmac_get_qsgmii_pcs_speed_val(pdev); ++ if (qsgmii_pcs_speed != -1) { ++ regmap_update_bits( ++ gmac->qsgmii_csr, ++ QSGMII_PCS_ALL_CH_CTL, ++ QSGMII_PCS_CH_SPEED_MASK << ++ QSGMII_PCS_CH_SPEED_SHIFT(gmac->id), ++ qsgmii_pcs_speed << ++ QSGMII_PCS_CH_SPEED_SHIFT(gmac->id)); ++ } + } + + plat_dat->has_gmac = true; From 89b99e9c1a3c89602beed813830efc95784b20d5 Mon Sep 17 00:00:00 2001 From: Ilya Lipnitskiy Date: Fri, 23 Apr 2021 17:20:11 -0700 Subject: [PATCH 58/62] treewide: consolidate named GPIO patch into hack-5.10 ath79, lantiq, ipq40xx, ramips all use the OpenWrt-specific gpio-export functionality. Consolidate the patch that adds it under hack-5.10 since this logic is obviously not target-specific. For those who want to disable it, unsetting CONFIG_GPIO_SYSFS symbol will disable this code. Signed-off-by: Ilya Lipnitskiy --- .../0036-GPIO-add-named-gpio-exports.patch | 165 ----------------- .../800-GPIO-add-named-gpio-exports.patch | 81 ++++----- .../0030-GPIO-add-named-gpio-exports.patch | 169 ------------------ 3 files changed, 39 insertions(+), 376 deletions(-) delete mode 100644 target/linux/ath79/patches-5.10/0036-GPIO-add-named-gpio-exports.patch rename target/linux/{ramips/patches-5.10 => generic/hack-5.10}/800-GPIO-add-named-gpio-exports.patch (90%) delete mode 100644 target/linux/lantiq/patches-5.10/0030-GPIO-add-named-gpio-exports.patch diff --git a/target/linux/ath79/patches-5.10/0036-GPIO-add-named-gpio-exports.patch b/target/linux/ath79/patches-5.10/0036-GPIO-add-named-gpio-exports.patch deleted file mode 100644 index c7899cc711..0000000000 --- a/target/linux/ath79/patches-5.10/0036-GPIO-add-named-gpio-exports.patch +++ /dev/null @@ -1,165 +0,0 @@ -From 4267880319bc1a2270d352e0ded6d6386242a7ef Mon Sep 17 00:00:00 2001 -From: John Crispin -Date: Tue, 12 Aug 2014 20:49:27 +0200 -Subject: [PATCH 24/53] GPIO: add named gpio exports - -Signed-off-by: John Crispin ---- - drivers/gpio/gpiolib-of.c | 68 +++++++++++++++++++++++++++++++++++++++++ - drivers/gpio/gpiolib-sysfs.c | 10 +++++- - include/asm-generic/gpio.h | 6 ++++ - include/linux/gpio/consumer.h | 8 +++++ - 4 files changed, 91 insertions(+), 1 deletion(-) - ---- a/drivers/gpio/gpiolib-of.c -+++ b/drivers/gpio/gpiolib-of.c -@@ -19,6 +19,8 @@ - #include - #include - #include -+#include -+#include - - #include "gpiolib.h" - #include "gpiolib-of.h" -@@ -1039,3 +1041,68 @@ void of_gpiochip_remove(struct gpio_chip - { - of_node_put(chip->of_node); - } -+ -+static struct of_device_id gpio_export_ids[] = { -+ { .compatible = "gpio-export" }, -+ { /* sentinel */ } -+}; -+ -+static int of_gpio_export_probe(struct platform_device *pdev) -+{ -+ struct device_node *np = pdev->dev.of_node; -+ struct device_node *cnp; -+ u32 val; -+ int nb = 0; -+ -+ for_each_child_of_node(np, cnp) { -+ const char *name = NULL; -+ int gpio; -+ bool dmc; -+ int max_gpio = 1; -+ int i; -+ -+ of_property_read_string(cnp, "gpio-export,name", &name); -+ -+ if (!name) -+ max_gpio = of_gpio_count(cnp); -+ -+ for (i = 0; i < max_gpio; i++) { -+ unsigned flags = 0; -+ enum of_gpio_flags of_flags; -+ -+ gpio = of_get_gpio_flags(cnp, i, &of_flags); -+ if (!gpio_is_valid(gpio)) -+ return gpio; -+ -+ if (of_flags == OF_GPIO_ACTIVE_LOW) -+ flags |= GPIOF_ACTIVE_LOW; -+ -+ if (!of_property_read_u32(cnp, "gpio-export,output", &val)) -+ flags |= val ? GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW; -+ else -+ flags |= GPIOF_IN; -+ -+ if (devm_gpio_request_one(&pdev->dev, gpio, flags, name ? name : of_node_full_name(np))) -+ continue; -+ -+ dmc = of_property_read_bool(cnp, "gpio-export,direction_may_change"); -+ gpio_export_with_name(gpio, dmc, name); -+ nb++; -+ } -+ } -+ -+ dev_info(&pdev->dev, "%d gpio(s) exported\n", nb); -+ -+ return 0; -+} -+ -+static struct platform_driver gpio_export_driver = { -+ .driver = { -+ .name = "gpio-export", -+ .owner = THIS_MODULE, -+ .of_match_table = of_match_ptr(gpio_export_ids), -+ }, -+ .probe = of_gpio_export_probe, -+}; -+ -+module_platform_driver(gpio_export_driver); ---- a/drivers/gpio/gpiolib-sysfs.c -+++ b/drivers/gpio/gpiolib-sysfs.c -@@ -572,7 +572,7 @@ static struct class gpio_class = { - * - * Returns zero on success, else an error. - */ --int gpiod_export(struct gpio_desc *desc, bool direction_may_change) -+int __gpiod_export(struct gpio_desc *desc, bool direction_may_change, const char *name) - { - struct gpio_chip *chip; - struct gpio_device *gdev; -@@ -634,6 +634,8 @@ int gpiod_export(struct gpio_desc *desc, - offset = gpio_chip_hwgpio(desc); - if (chip->names && chip->names[offset]) - ioname = chip->names[offset]; -+ if (name) -+ ioname = name; - - dev = device_create_with_groups(&gpio_class, &gdev->dev, - MKDEV(0, 0), data, gpio_groups, -@@ -655,6 +657,12 @@ err_unlock: - gpiod_dbg(desc, "%s: status %d\n", __func__, status); - return status; - } -+EXPORT_SYMBOL_GPL(__gpiod_export); -+ -+int gpiod_export(struct gpio_desc *desc, bool direction_may_change) -+{ -+ return __gpiod_export(desc, direction_may_change, NULL); -+} - EXPORT_SYMBOL_GPL(gpiod_export); - - static int match_export(struct device *dev, const void *desc) ---- a/include/asm-generic/gpio.h -+++ b/include/asm-generic/gpio.h -@@ -125,6 +125,12 @@ static inline int gpio_export(unsigned g - return gpiod_export(gpio_to_desc(gpio), direction_may_change); - } - -+int __gpiod_export(struct gpio_desc *desc, bool direction_may_change, const char *name); -+static inline int gpio_export_with_name(unsigned gpio, bool direction_may_change, const char *name) -+{ -+ return __gpiod_export(gpio_to_desc(gpio), direction_may_change, name); -+} -+ - static inline int gpio_export_link(struct device *dev, const char *name, - unsigned gpio) - { ---- a/include/linux/gpio/consumer.h -+++ b/include/linux/gpio/consumer.h -@@ -715,6 +715,7 @@ static inline void devm_acpi_dev_remove_ - - #if IS_ENABLED(CONFIG_GPIOLIB) && IS_ENABLED(CONFIG_GPIO_SYSFS) - -+int _gpiod_export(struct gpio_desc *desc, bool direction_may_change, const char *name); - int gpiod_export(struct gpio_desc *desc, bool direction_may_change); - int gpiod_export_link(struct device *dev, const char *name, - struct gpio_desc *desc); -@@ -722,6 +723,13 @@ void gpiod_unexport(struct gpio_desc *de - - #else /* CONFIG_GPIOLIB && CONFIG_GPIO_SYSFS */ - -+static inline int _gpiod_export(struct gpio_desc *desc, -+ bool direction_may_change, -+ const char *name) -+{ -+ return -ENOSYS; -+} -+ - static inline int gpiod_export(struct gpio_desc *desc, - bool direction_may_change) - { diff --git a/target/linux/ramips/patches-5.10/800-GPIO-add-named-gpio-exports.patch b/target/linux/generic/hack-5.10/800-GPIO-add-named-gpio-exports.patch similarity index 90% rename from target/linux/ramips/patches-5.10/800-GPIO-add-named-gpio-exports.patch rename to target/linux/generic/hack-5.10/800-GPIO-add-named-gpio-exports.patch index c7899cc711..76f89acdcd 100644 --- a/target/linux/ramips/patches-5.10/800-GPIO-add-named-gpio-exports.patch +++ b/target/linux/generic/hack-5.10/800-GPIO-add-named-gpio-exports.patch @@ -1,16 +1,9 @@ -From 4267880319bc1a2270d352e0ded6d6386242a7ef Mon Sep 17 00:00:00 2001 +From cc809a441d8f2924f785eb863dfa6aef47a25b0b Mon Sep 17 00:00:00 2001 From: John Crispin Date: Tue, 12 Aug 2014 20:49:27 +0200 -Subject: [PATCH 24/53] GPIO: add named gpio exports +Subject: [PATCH 30/36] GPIO: add named gpio exports Signed-off-by: John Crispin ---- - drivers/gpio/gpiolib-of.c | 68 +++++++++++++++++++++++++++++++++++++++++ - drivers/gpio/gpiolib-sysfs.c | 10 +++++- - include/asm-generic/gpio.h | 6 ++++ - include/linux/gpio/consumer.h | 8 +++++ - 4 files changed, 91 insertions(+), 1 deletion(-) - --- a/drivers/gpio/gpiolib-of.c +++ b/drivers/gpio/gpiolib-of.c @@ -19,6 +19,8 @@ @@ -22,11 +15,13 @@ Signed-off-by: John Crispin #include "gpiolib.h" #include "gpiolib-of.h" -@@ -1039,3 +1041,68 @@ void of_gpiochip_remove(struct gpio_chip +@@ -1039,3 +1041,72 @@ void of_gpiochip_remove(struct gpio_chip { of_node_put(chip->of_node); } + ++#ifdef CONFIG_GPIO_SYSFS ++ +static struct of_device_id gpio_export_ids[] = { + { .compatible = "gpio-export" }, + { /* sentinel */ } @@ -91,39 +86,8 @@ Signed-off-by: John Crispin +}; + +module_platform_driver(gpio_export_driver); ---- a/drivers/gpio/gpiolib-sysfs.c -+++ b/drivers/gpio/gpiolib-sysfs.c -@@ -572,7 +572,7 @@ static struct class gpio_class = { - * - * Returns zero on success, else an error. - */ --int gpiod_export(struct gpio_desc *desc, bool direction_may_change) -+int __gpiod_export(struct gpio_desc *desc, bool direction_may_change, const char *name) - { - struct gpio_chip *chip; - struct gpio_device *gdev; -@@ -634,6 +634,8 @@ int gpiod_export(struct gpio_desc *desc, - offset = gpio_chip_hwgpio(desc); - if (chip->names && chip->names[offset]) - ioname = chip->names[offset]; -+ if (name) -+ ioname = name; - - dev = device_create_with_groups(&gpio_class, &gdev->dev, - MKDEV(0, 0), data, gpio_groups, -@@ -655,6 +657,12 @@ err_unlock: - gpiod_dbg(desc, "%s: status %d\n", __func__, status); - return status; - } -+EXPORT_SYMBOL_GPL(__gpiod_export); + -+int gpiod_export(struct gpio_desc *desc, bool direction_may_change) -+{ -+ return __gpiod_export(desc, direction_may_change, NULL); -+} - EXPORT_SYMBOL_GPL(gpiod_export); - - static int match_export(struct device *dev, const void *desc) ++#endif --- a/include/asm-generic/gpio.h +++ b/include/asm-generic/gpio.h @@ -125,6 +125,12 @@ static inline int gpio_export(unsigned g @@ -163,3 +127,36 @@ Signed-off-by: John Crispin static inline int gpiod_export(struct gpio_desc *desc, bool direction_may_change) { +--- a/drivers/gpio/gpiolib-sysfs.c ++++ b/drivers/gpio/gpiolib-sysfs.c +@@ -572,7 +572,7 @@ static struct class gpio_class = { + * + * Returns zero on success, else an error. + */ +-int gpiod_export(struct gpio_desc *desc, bool direction_may_change) ++int __gpiod_export(struct gpio_desc *desc, bool direction_may_change, const char *name) + { + struct gpio_chip *chip; + struct gpio_device *gdev; +@@ -634,6 +634,8 @@ int gpiod_export(struct gpio_desc *desc, + offset = gpio_chip_hwgpio(desc); + if (chip->names && chip->names[offset]) + ioname = chip->names[offset]; ++ if (name) ++ ioname = name; + + dev = device_create_with_groups(&gpio_class, &gdev->dev, + MKDEV(0, 0), data, gpio_groups, +@@ -655,6 +657,12 @@ err_unlock: + gpiod_dbg(desc, "%s: status %d\n", __func__, status); + return status; + } ++EXPORT_SYMBOL_GPL(__gpiod_export); ++ ++int gpiod_export(struct gpio_desc *desc, bool direction_may_change) ++{ ++ return __gpiod_export(desc, direction_may_change, NULL); ++} + EXPORT_SYMBOL_GPL(gpiod_export); + + static int match_export(struct device *dev, const void *desc) diff --git a/target/linux/lantiq/patches-5.10/0030-GPIO-add-named-gpio-exports.patch b/target/linux/lantiq/patches-5.10/0030-GPIO-add-named-gpio-exports.patch deleted file mode 100644 index 23dde675b5..0000000000 --- a/target/linux/lantiq/patches-5.10/0030-GPIO-add-named-gpio-exports.patch +++ /dev/null @@ -1,169 +0,0 @@ -From cc809a441d8f2924f785eb863dfa6aef47a25b0b Mon Sep 17 00:00:00 2001 -From: John Crispin -Date: Tue, 12 Aug 2014 20:49:27 +0200 -Subject: [PATCH 30/36] GPIO: add named gpio exports - -Signed-off-by: John Crispin ---- - drivers/gpio/gpiolib-of.c | 68 +++++++++++++++++++++++++++++++++++++++++ - drivers/gpio/gpiolib.c | 11 +++++-- - include/asm-generic/gpio.h | 5 +++ - include/linux/gpio/consumer.h | 8 +++++ - 4 files changed, 90 insertions(+), 2 deletions(-) - ---- a/drivers/gpio/gpiolib-of.c -+++ b/drivers/gpio/gpiolib-of.c -@@ -19,6 +19,8 @@ - #include - #include - #include -+#include -+#include - - #include "gpiolib.h" - #include "gpiolib-of.h" -@@ -1039,3 +1041,72 @@ void of_gpiochip_remove(struct gpio_chip - { - of_node_put(chip->of_node); - } -+ -+#ifdef CONFIG_GPIO_SYSFS -+ -+static struct of_device_id gpio_export_ids[] = { -+ { .compatible = "gpio-export" }, -+ { /* sentinel */ } -+}; -+ -+static int of_gpio_export_probe(struct platform_device *pdev) -+{ -+ struct device_node *np = pdev->dev.of_node; -+ struct device_node *cnp; -+ u32 val; -+ int nb = 0; -+ -+ for_each_child_of_node(np, cnp) { -+ const char *name = NULL; -+ int gpio; -+ bool dmc; -+ int max_gpio = 1; -+ int i; -+ -+ of_property_read_string(cnp, "gpio-export,name", &name); -+ -+ if (!name) -+ max_gpio = of_gpio_count(cnp); -+ -+ for (i = 0; i < max_gpio; i++) { -+ unsigned flags = 0; -+ enum of_gpio_flags of_flags; -+ -+ gpio = of_get_gpio_flags(cnp, i, &of_flags); -+ if (!gpio_is_valid(gpio)) -+ return gpio; -+ -+ if (of_flags == OF_GPIO_ACTIVE_LOW) -+ flags |= GPIOF_ACTIVE_LOW; -+ -+ if (!of_property_read_u32(cnp, "gpio-export,output", &val)) -+ flags |= val ? GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW; -+ else -+ flags |= GPIOF_IN; -+ -+ if (devm_gpio_request_one(&pdev->dev, gpio, flags, name ? name : of_node_full_name(np))) -+ continue; -+ -+ dmc = of_property_read_bool(cnp, "gpio-export,direction_may_change"); -+ gpio_export_with_name(gpio, dmc, name); -+ nb++; -+ } -+ } -+ -+ dev_info(&pdev->dev, "%d gpio(s) exported\n", nb); -+ -+ return 0; -+} -+ -+static struct platform_driver gpio_export_driver = { -+ .driver = { -+ .name = "gpio-export", -+ .owner = THIS_MODULE, -+ .of_match_table = of_match_ptr(gpio_export_ids), -+ }, -+ .probe = of_gpio_export_probe, -+}; -+ -+module_platform_driver(gpio_export_driver); -+ -+#endif ---- a/include/asm-generic/gpio.h -+++ b/include/asm-generic/gpio.h -@@ -125,6 +125,12 @@ static inline int gpio_export(unsigned g - return gpiod_export(gpio_to_desc(gpio), direction_may_change); - } - -+int __gpiod_export(struct gpio_desc *desc, bool direction_may_change, const char *name); -+static inline int gpio_export_with_name(unsigned gpio, bool direction_may_change, const char *name) -+{ -+ return __gpiod_export(gpio_to_desc(gpio), direction_may_change, name); -+} -+ - static inline int gpio_export_link(struct device *dev, const char *name, - unsigned gpio) - { ---- a/include/linux/gpio/consumer.h -+++ b/include/linux/gpio/consumer.h -@@ -715,6 +715,7 @@ static inline void devm_acpi_dev_remove_ - - #if IS_ENABLED(CONFIG_GPIOLIB) && IS_ENABLED(CONFIG_GPIO_SYSFS) - -+int _gpiod_export(struct gpio_desc *desc, bool direction_may_change, const char *name); - int gpiod_export(struct gpio_desc *desc, bool direction_may_change); - int gpiod_export_link(struct device *dev, const char *name, - struct gpio_desc *desc); -@@ -722,6 +723,13 @@ void gpiod_unexport(struct gpio_desc *de - - #else /* CONFIG_GPIOLIB && CONFIG_GPIO_SYSFS */ - -+static inline int _gpiod_export(struct gpio_desc *desc, -+ bool direction_may_change, -+ const char *name) -+{ -+ return -ENOSYS; -+} -+ - static inline int gpiod_export(struct gpio_desc *desc, - bool direction_may_change) - { ---- a/drivers/gpio/gpiolib-sysfs.c -+++ b/drivers/gpio/gpiolib-sysfs.c -@@ -572,7 +572,7 @@ static struct class gpio_class = { - * - * Returns zero on success, else an error. - */ --int gpiod_export(struct gpio_desc *desc, bool direction_may_change) -+int __gpiod_export(struct gpio_desc *desc, bool direction_may_change, const char *name) - { - struct gpio_chip *chip; - struct gpio_device *gdev; -@@ -634,6 +634,8 @@ int gpiod_export(struct gpio_desc *desc, - offset = gpio_chip_hwgpio(desc); - if (chip->names && chip->names[offset]) - ioname = chip->names[offset]; -+ if (name) -+ ioname = name; - - dev = device_create_with_groups(&gpio_class, &gdev->dev, - MKDEV(0, 0), data, gpio_groups, -@@ -655,6 +657,12 @@ err_unlock: - gpiod_dbg(desc, "%s: status %d\n", __func__, status); - return status; - } -+EXPORT_SYMBOL_GPL(__gpiod_export); -+ -+int gpiod_export(struct gpio_desc *desc, bool direction_may_change) -+{ -+ return __gpiod_export(desc, direction_may_change, NULL); -+} - EXPORT_SYMBOL_GPL(gpiod_export); - - static int match_export(struct device *dev, const void *desc) From 48cad07a55246317d66fee4ced25cb62a2bae3d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Mork?= Date: Mon, 19 Apr 2021 13:00:55 +0200 Subject: [PATCH 59/62] firmware-utils: zytrx: Add util for ZyXEL specific header MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The ZyXEL NR7101 prepend an additional header to U-Boot images. This header use the TRX magic 0x30524448 (HDR0), but is incompatible with TRX images. This code is reverse-engineered based on matching 32 bit numbers found in the header with lengths and different checksum calculations of the vendor images found on the device. The result was matched against the validation output produced by the bootloader to name the associated header fields. Example bootloader validation output: Zyxel TRX Image 1 --> Found! Header Checksum OK ============ZyXEL header information================== chipId : MT7621A boardId : NR7101 modelId : 07 01 00 01 kernel_len : (14177560) kernelChksum : (0x8DD31F69) swVersionInt : 1.00(ABUV.0)D1 swVersionExt : 1.00(ABUV.0)D1 Zyxel TRX Image 2 --> Found! Header Checksum OK ============ZyXEL header information================== chipId : MT7621A boardId : NR7101 modelId : 07 01 00 01 kernel_len : (14176660) kernelChksum : (0x951A7637) swVersionInt : 1.00(ABUV.0)D0 swVersionExt : 1.00(ABUV.0)D0 ================================================= Check image validation: Image1 Header Magic Number --> OK Image2 Header Magic Number --> OK Image1 Header Checksum --> OK Image2 Header Checksum --> OK Image1 Data Checksum --> OK Image2 Data Checksum --> OK Image1 Stable Flag --> Stable Image1 Try Counter --> 0 Image1: OK Image2: OK The coverage and algorithm for the kernelChksum field is unknown. This field is not validated by the bootloader or the OEM firmware upgrade tool. It is therefore set to a static value for now. The swVersion fields contain free form string values. The OEM firmware use ZyXEL structured version numbers as shown above. The strings are not interpreted or validated on boot, so they can be repurposed for anything we want the bootloader to display to the user. But the OEM web GUI fails to flash images with freeform strings. The purpose of the other strings in the header is not known. The values appear to be static. We assume they are fixed for now, until we have other examples. One of these strings is the platform name, which is taken as an input parameter for support other members of the device family. Signed-off-by: Bjørn Mork --- tools/firmware-utils/Makefile | 1 + tools/firmware-utils/src/zytrx.c | 226 +++++++++++++++++++++++++++++++ 2 files changed, 227 insertions(+) create mode 100644 tools/firmware-utils/src/zytrx.c diff --git a/tools/firmware-utils/Makefile b/tools/firmware-utils/Makefile index 285722c3c2..72cd513a45 100644 --- a/tools/firmware-utils/Makefile +++ b/tools/firmware-utils/Makefile @@ -97,6 +97,7 @@ define Host/Compile $(call cc,wrt400n cyg_crc32,-Wall) $(call cc,xorimage,-Wall) $(call cc,zyimage,-Wall) + $(call cc,zytrx,-Wall) $(call cc,zyxbcm,-Wall) endef diff --git a/tools/firmware-utils/src/zytrx.c b/tools/firmware-utils/src/zytrx.c new file mode 100644 index 0000000000..302efc6010 --- /dev/null +++ b/tools/firmware-utils/src/zytrx.c @@ -0,0 +1,226 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * zytrx - add header to images for ZyXEL NR7101 + * + * Based on add_header.c - partially based on OpenWrt's + * motorola-bin.c + * + * Copyright (C) 2008 Imre Kaloz + * Gabor Juhos + * Copyright (C) 2021 Bjørn Mork + + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License, + * version 2 as published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define BPB 8 /* bits/byte */ + +static uint32_t crc32[1<> 1)) : (crc >> 1); + crc32[n] = crc; + } +} + +static uint32_t crc32buf(const unsigned char *buf, size_t len) +{ + uint32_t crc = 0xFFFFFFFF; + + for (; len; len--, buf++) + crc = crc32[(uint8_t)crc ^ *buf] ^ (crc >> BPB); + return ~crc; +} + +/* HDR0 reversed, to be stored as BE */ +#define MAGIC 0x30524448 /* HDR0 reversed, to be stored as BE */ + +/* All numbers are stored as BE */ +struct zytrx_t { + uint32_t magic; + uint32_t len_h; /* Length of this header */ + uint32_t len_t; /* Total length of file */ + uint32_t crc32_p; /* Bit inverted 32-bit CRC of image payload */ + uint8_t verInt[32]; /* String "5.0.0.0\n" zero padded */ + uint8_t verExt[32]; /* String "\n" zero padded */ + uint32_t len_p; /* Length of image payload */ + uint8_t pad1[12]; /* zero padding(?) */ + uint8_t code[164]; /* string "3 6035 122 0\n" zero padded */ + uint8_t chipid[8]; /* string "MT7621A" zero padded */ + uint8_t boardid[16]; /* string "NR7101" zero padded */ + uint32_t modelid; /* modelid as 4 BCD digits: 0x07010001 */ + uint8_t pad2[8]; /* zero padding(?) */ + uint8_t swVersionInt[32]; /* ZyXEL version string: "1.00(ABUV.0)D0" zero padded */ + uint8_t swVersionExt[32]; /* identical to swVersionInt */ + uint8_t pad4[4]; /* zero padding(?) */ + uint32_t kernelChksum; /* no idea how this is computed - reported but not validated */ + uint8_t pad5[4]; /* zero padding(?) */ + uint32_t crc32_h; /* Bit inverted 32-bit CRC of this header payload */ + uint8_t pad6[4]; /* zero padding(?) */ +}; + +/* static?() field values of unknown meaning - maybe ove to board + * table when we know the significance + */ +#define VER_INT "5.0.0.0\n" +#define VER_EXT "\n" +#define CODE "3 6035 122 0\n" +#define KERNELCHKSUM 0x12345678 + +/* table of supported devices using this header format */ +static struct board_t { + uint8_t chipid[8]; + uint8_t boardid[16]; + uint32_t modelid; +} boards[] = { + { "MT7621A", "NR7101", 0x07010001 }, + {} +}; + +static int find_board(struct zytrx_t *h, char *board) +{ + struct board_t *p; + + for (p = boards; p->modelid; p++) { + if (strncmp((const char *)p->boardid, board, sizeof(p->boardid))) + continue; + memcpy(h->chipid, p->chipid, sizeof(h->chipid)); + memcpy(h->boardid, p->boardid, sizeof(h->boardid)); + h->modelid = htonl(p->modelid); + return 0; + } + return -1; +} + +static void usage(const char *name) +{ + struct board_t *p; + + fprintf(stderr, "Usage:\n"); + fprintf(stderr, " %s -B -v -i [-o ]\n\n", name); + fprintf(stderr, "Supported values:\n"); + for (p = boards; p->modelid; p++) + fprintf(stderr, "\t%-12s\n", p->boardid); + fprintf(stderr, "\nExample:\n"); + fprintf(stderr, " %s -B %s -v foobar-1.0 -i my.img -o out.img\n\n", name, + boards[0].boardid); + exit(EXIT_FAILURE); +} + +static void errexit(const char *msg) +{ + fprintf(stderr, "ERR: %s: %s\n", msg, errno ? strerror(errno) : "unknown"); + exit(EXIT_FAILURE); +} + +static void *map_input(const char *name, size_t *len) +{ + struct stat stat; + void *mapped; + int fd; + + fd = open(name, O_RDONLY); + if (fd < 0) + return NULL; + if (fstat(fd, &stat) < 0) { + close(fd); + return NULL; + } + *len = stat.st_size; + mapped = mmap(NULL, stat.st_size, PROT_READ, MAP_SHARED, fd, 0); + if (close(fd) < 0) + return NULL; + return mapped; +} + +int main(int argc, char **argv) +{ + int c, fdout = STDOUT_FILENO; + void *input_file = NULL; + size_t file_len, len; + uint32_t crc; + struct zytrx_t h = { + .magic = htonl(MAGIC), + .len_h = htonl(sizeof(h)), + .verInt = VER_INT, + .verExt = VER_EXT, + .code = CODE, + .kernelChksum = htonl(KERNELCHKSUM), + }; + + while ((c = getopt(argc, argv, "B:v:i:o:")) != -1) { + switch (c) { + case 'B': + if (find_board(&h, optarg) < 0) + errexit("unsupported board"); + break; + case 'v': + len = strlen(optarg); + if (len > sizeof(h.swVersionInt)) + errexit("version string too long"); + memcpy(h.swVersionInt, optarg, len); + memcpy(h.swVersionExt, optarg, len); + break; + case 'i': + input_file = map_input(optarg, &file_len); + if (!input_file) + errexit(optarg); + break; + case 'o': + fdout = open(optarg, O_WRONLY | O_CREAT, 0644); + if (fdout < 0) + errexit(optarg); + break; + default: + usage(argv[0]); + } + } + + /* required paremeters */ + if (!input_file || !h.modelid || !h.swVersionInt[0]) + usage(argv[0]); + + /* length fields */ + h.len_t = htonl(sizeof(h) + file_len); + h.len_p = htonl(file_len); + + /* crc fields */ + init_crc32(); + crc = crc32buf(input_file, file_len); + h.crc32_p = htonl(~crc); + crc = crc32buf((unsigned char *)&h, sizeof(h)); + h.crc32_h = htonl(~crc); + + /* dump new image */ + write(fdout, &h, sizeof(h)); + write(fdout, input_file, file_len); + + /* close files */ + munmap(input_file, file_len); + if (fdout != STDOUT_FILENO) + close(fdout); + + return EXIT_SUCCESS; +} From 2449a632084b29632605e5a79ce5d73028eb15dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Mork?= Date: Mon, 19 Apr 2021 13:00:56 +0200 Subject: [PATCH 60/62] ramips: mt7621: Add support for ZyXEL NR7101 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The ZyXEL NR7101 is an 802.3at PoE powered 5G outdoor (IP68) CPE with integrated directional 5G/LTE antennas. Specifications: - SoC: MediaTek MT7621AT - RAM: 256 MB - Flash: 128 MB MB NAND (MX30LF1G18AC) - WiFi: MediaTek MT7603E - Switch: 1 LAN port (Gigabiti) - 5G/LTE: Quectel RG502Q-EA connected by USB3 to SoC - SIM: 2 micro-SIM slots under transparent cover - Buttons: Reset, WLAN under same cover - LEDs: Multicolour green/red/yellow under same cover (visible) - Power: 802.3at PoE via LAN port The device is built as an outdoor ethernet to 5G/LTE bridge or router. The Wifi interface is intended for installation and/or temporary management purposes only. UART Serial: 57600N1 Located on populated 5 pin header J5: [o] GND [ ] key - no pin [o] RX [o] TX [o] 3.3V Vcc Remove the SIM/button/LED cover, the WLAN button and 12 screws holding the back plate and antenna cover together. The GPS antenna is fixed to the cover, so be careful with the cable. Remove 4 screws fixing the antenna board to the main board, again being careful with the cables. A bluetooth TTL adapter is recommended for permanent console access, to keep the router water and dustproof. The 3.3V pin is able to power such an adapter. MAC addresses: OpenWrt OEM Address Found as lan eth2 08:26:97:*:*:BC Factory 0xe000 (hex), label wlan0 ra0 08:26:97:*:*:BD Factory 0x4 (hex) wwan0 usb0 random WARNING!! ISP managed firmware might at any time update itself to a version where all known workarounds have been disabled. Never boot an ISP managed firmware with a SIM in any of the slots if you intend to use the router with OpenWrt. The bootloader lock can only be disabled with root access to running firmware. The flash chip is physically inaccessible without soldering. Installation from OEM web GUI: - Log in as "supervisor" on https://172.17.1.1/ - Upload OpenWrt initramfs-recovery.bin image on the Maintenance -> Firmware page - Wait for OpenWrt to boot and ssh to root@192.168.1.1 - (optional) Copy OpenWrt to the recovery partition. See below - Sysupgrade to the OpenWrt sysupgrade image and reboot Installation from OEM ssh: - Log in as "root" on 172.17.1.1 port 22022 - scp OpenWrt initramfs-recovery.bin image to 172.17.1.1:/tmp - Prepare bootloader config by running: nvram setro uboot DebugFlag 0x1 nvram setro uboot CheckBypass 0 nvram commit - Run "mtd_write -w write initramfs-recovery.bin Kernel" and reboot - Wait for OpenWrt to boot and ssh to root@192.168.1.1 - (optional) Copy OpenWrt to the recovery partition. See below - Sysupgrade to the OpenWrt sysupgrade image and reboot Copying OpenWrt to the recovery partition: - Verify that you are running a working OpenWrt recovery image from flash - ssh to root@192.168.1.1 and run: fw_setenv CheckBypass 0 mtd -r erase Kernel2 - Wait while the bootloader mirrors Image1 to Image2 NOTE: This should only be done after successfully booting the OpenWrt recovery image from the primary partition during installation. Do not do this after having sysupgraded OpenWrt! Reinstalling the recovery image on normal upgrades is not required or recommended. Installation from Z-Loader: - Halt boot by pressing Escape on console - Set up a tftp server to serve the OpenWrt initramfs-recovery.bin image at 10.10.10.3 - Type "ATNR 1,initramfs-recovery.bin" at the "ZLB>" prompt - Wait for OpenWrt to boot and ssh to root@192.168.1.1 - Sysupgrade to the OpenWrt sysupgrade image NOTE: ATNR will write the recovery image to both primary and recovery partitions in one go. Booting from RAM: - Halt boot by pressing Escape on console - Type "ATGU" at the "ZLB>" prompt to enter the U-Boot menu - Press "4" to select "4: Entr boot command line interface." - Set up a tftp server to serve the OpenWrt initramfs-recovery.bin image at 10.10.10.3 - Load it using "tftpboot 0x88000000 initramfs-recovery.bin" - Boot with "bootm 0x8800017C" to skip the 380 (0x17C) bytes ZyXEL header This method can also be used to RAM boot OEM firmware. The warning regarding OEM applies! Never boot an unknown OEM firmware, or any OEM firmware with a SIM in any slot. NOTE: U-Boot configuration is incomplete (on some devices?). You may have to configure a working mac address before running tftp using "setenv eth0addr " Unlocking the bootloader: If you are unebale to halt boot, then the bootloader is locked. The OEM firmware locks the bootloader on every boot by setting DebugFlag to 0. Setting it to 1 is therefore only temporary when OEM firmware is installed. - Run "nvram setro uboot DebugFlag 0x1; nvram commit" in OEM firmware - Run "fw_setenv DebugFlag 0x1" in OpenWrt NOTE: OpenWrt does this automatically on first boot if necessary NOTE2: Setting the flag to 0x1 avoids the reset to 0 in known OEM versions, but this might change. WARNING: Writing anything to flash while the bootloader is locked is considered extremely risky. Errors might cause a permanent brick! Enabling management access from LAN: Temporary workaround to allow installing OpenWrt if OEM firmware has disabled LAN management: - Connect to console - Log in as "root" - Run "iptables -I INPUT -i br0 -j ACCEPT" Notes on the OEM/bootloader dual partition scheme The dual partition scheme on this device uses Image2 as a recovery image only. The device will always boot from Image1, but the bootloader might copy Image2 to Image1 under specific conditions. This scheme prevents repurposing of the space occupied by Image2 in any useful way. Validation of primary and recovery images is controlled by the variables CheckBypass, Image1Stable, and Image1Try. The bootloader sets CheckBypass to 0 and reboots if Image1 fails validation. If CheckBypass is 0 and Image1 is invalid then Image2 is copied to Image1. If CheckBypass is 0 and Image2 is invalid, then Image1 is copied to Image2. If CheckBypass is 1 then all tests are skipped and Image1 is booted unconditionally. CheckBypass is set to 1 after each successful validation of Image1. Image1Try is incremented if Image1Stable is 0, and Image2 is copied to Image1 if Image1Try is 3 or larger. But the bootloader only tests Image1Try if CheckBypass is 0, which is impossible unless the booted image sets it to 0 before failing. The system is therefore not resilient against runtime errors like failure to mount the rootfs, unless the kernel image sets CheckBypass to 0 before failing. This is not yet implemented in OpenWrt. Setting Image1Stable to 1 prevents the bootloader from updating Image1Try on every boot, saving unnecessary writes to the environment partition. Keeping an OpenWrt initramfs recovery as Image2 is recommended primarily to avoid unwanted OEM firmware boots on failure. Ref the warning above. It enables console-less recovery in case of some failures to boot from Image1. Signed-off-by: Bjørn Mork --- package/boot/uboot-envtools/files/ramips | 5 + .../linux/ramips/dts/mt7621_zyxel_nr7101.dts | 164 ++++++++++++++++++ target/linux/ramips/image/mt7621.mk | 22 +++ .../mt7621/base-files/etc/board.d/02_network | 3 + .../base-files/etc/board.d/03_gpio_switches | 3 + .../mt7621/base-files/etc/init.d/bootcount | 5 + .../mt7621/base-files/lib/upgrade/platform.sh | 6 + 7 files changed, 208 insertions(+) create mode 100644 target/linux/ramips/dts/mt7621_zyxel_nr7101.dts diff --git a/package/boot/uboot-envtools/files/ramips b/package/boot/uboot-envtools/files/ramips index a16c88d8bd..bce2e5f0fb 100644 --- a/package/boot/uboot-envtools/files/ramips +++ b/package/boot/uboot-envtools/files/ramips @@ -53,6 +53,11 @@ xiaomi,mi-router-ac2100|\ xiaomi,redmi-router-ac2100) ubootenv_add_uci_config "/dev/mtd1" "0x0" "0x1000" "0x20000" ;; +zyxel,nr7101) + idx="$(find_mtd_index Config)" + [ -n "$idx" ] && \ + ubootenv_add_uci_config "/dev/mtd$idx" "0x0" "0x1000" "0x80000" + ;; esac config_load ubootenv diff --git a/target/linux/ramips/dts/mt7621_zyxel_nr7101.dts b/target/linux/ramips/dts/mt7621_zyxel_nr7101.dts new file mode 100644 index 0000000000..f6a42286f1 --- /dev/null +++ b/target/linux/ramips/dts/mt7621_zyxel_nr7101.dts @@ -0,0 +1,164 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT + +#include "mt7621.dtsi" + +#include +#include + +/ { + compatible = "zyxel,nr7101", "mediatek,mt7621-soc"; + model = "ZyXEL NR7101"; + + aliases { + led-boot = &power; + led-failsafe = &power; + led-running = &power; + led-upgrade = &power; + label-mac-device = &gmac0; + }; + + leds { + compatible = "gpio-leds"; + + led@13 { + label = "yellow:system"; + gpios = <&gpio 13 GPIO_ACTIVE_HIGH>; + }; + + power: led@14 { + label = "green:system"; + gpios = <&gpio 14 GPIO_ACTIVE_HIGH>; + }; + + led@15 { + label = "red:system"; + gpios = <&gpio 15 GPIO_ACTIVE_HIGH>; + }; + }; + + keys { + compatible = "gpio-keys"; + + wps { + label = "wlan"; + gpios = <&gpio 8 GPIO_ACTIVE_LOW>; + linux,code = ; + }; + + reset { + label = "reset"; + gpios = <&gpio 6 GPIO_ACTIVE_LOW>; + linux,code = ; + }; + }; +}; + +&gpio { + lte_pwrkey { + gpio-hog; + gpios = <4 GPIO_ACTIVE_HIGH>; + output-high; + line-name = "lte-pwrkey"; + }; + + lte_power { + gpio-hog; + gpios = <18 GPIO_ACTIVE_HIGH>; + output-high; + line-name = "lte-power"; + }; +}; + +&nand { + status = "okay"; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "Bootloader"; + reg = <0x0 0x80000>; + read-only; + }; + + partition@80000 { + label = "Config"; + reg = <0x80000 0x80000>; + }; + + factory: partition@100000 { + label = "Factory"; + reg = <0x100000 0x40000>; + read-only; + }; + + partition@140000 { + label = "Kernel"; + reg = <0x140000 0x1ec0000>; + }; + + partition@540000 { + label = "ubi"; + reg = <0x540000 0x1ac0000>; + }; + + partition@2140000 { + label = "Kernel2"; + reg = <0x2140000 0x1ec0000>; + }; + + partition@4000000 { + label = "wwan"; + reg = <0x4000000 0x100000>; + }; + + partition@4100000 { + label = "data"; + reg = <0x4100000 0x1000000>; + }; + + partition@5100000 { + label = "rom-d"; + reg = <0x5100000 0x100000>; + read-only; + }; + + partition@5200000 { + label = "reserve"; + reg = <0x5200000 0x80000>; + }; + }; +}; + +&pcie { + status = "okay"; +}; + +&pcie0 { + mt76@0,0 { + reg = <0x0000 0 0 0 0>; + mediatek,mtd-eeprom = <&factory 0x0>; + }; +}; + +&gmac0 { + mtd-mac-address = <&factory 0xe000>; +}; + +&switch0 { + ports { + port@2 { + status = "okay"; + label = "lan"; + }; + }; +}; + +&state_default { + gpio { + groups = "i2c", "rgmii2", "uart3", "jtag", "wdt"; + function = "gpio"; + }; +}; diff --git a/target/linux/ramips/image/mt7621.mk b/target/linux/ramips/image/mt7621.mk index 45a58dace9..2c7aa80505 100644 --- a/target/linux/ramips/image/mt7621.mk +++ b/target/linux/ramips/image/mt7621.mk @@ -79,6 +79,13 @@ define Build/ubnt-erx-factory-image fi endef +define Build/zytrx-header + $(eval board=$(word 1,$(1))) + $(eval version=$(word 2,$(1))) + $(STAGING_DIR_HOST)/bin/zytrx -B '$(board)' -v '$(version)' -i $@ -o $@.new + mv $@.new $@ +endef + define Device/dsa-migration DEVICE_COMPAT_VERSION := 1.1 DEVICE_COMPAT_MESSAGE := Config cannot be migrated from swconfig to DSA @@ -1504,6 +1511,21 @@ define Device/zio_freezio endef TARGET_DEVICES += zio_freezio +define Device/zyxel_nr7101 + $(Device/dsa-migration) + BLOCKSIZE := 128k + PAGESIZE := 2048 + UBINIZE_OPTS := -E 5 + DEVICE_VENDOR := ZyXEL + DEVICE_MODEL := NR7101 + DEVICE_PACKAGES := kmod-mt7603 kmod-usb3 uboot-envtools kmod-usb-net-qmi-wwan kmod-usb-serial-option uqmi + KERNEL := $(KERNEL_DTB) | uImage lzma | zytrx-header $$(DEVICE_MODEL) $$(VERSION_DIST)-$$(REVISION) + KERNEL_INITRAMFS := $(KERNEL_DTB) | uImage lzma | zytrx-header $$(DEVICE_MODEL) 9.99(ABUV.9)$$(VERSION_DIST)-recovery + KERNEL_INITRAMFS_SUFFIX := -recovery.bin + IMAGE/sysupgrade.bin := sysupgrade-tar | append-metadata +endef +TARGET_DEVICES += zyxel_nr7101 + define Device/zyxel_wap6805 $(Device/dsa-migration) BLOCKSIZE := 128k diff --git a/target/linux/ramips/mt7621/base-files/etc/board.d/02_network b/target/linux/ramips/mt7621/base-files/etc/board.d/02_network index 934276a042..cde3cba9bc 100644 --- a/target/linux/ramips/mt7621/base-files/etc/board.d/02_network +++ b/target/linux/ramips/mt7621/base-files/etc/board.d/02_network @@ -63,6 +63,9 @@ ramips_setup_interfaces() ubnt,edgerouter-x-sfp) ucidef_set_interfaces_lan_wan "eth1 eth2 eth3 eth4 eth5" "eth0" ;; + zyxel,nr7101) + ucidef_set_interfaces_lan_wan "lan" "wan" + ;; zyxel,wap6805) ucidef_set_interface_lan "lan1 lan2 lan3 lan4" ucidef_set_interface "qtn" ifname "eth1" protocol "static" ipaddr "1.1.1.1" netmask "255.255.255.0" diff --git a/target/linux/ramips/mt7621/base-files/etc/board.d/03_gpio_switches b/target/linux/ramips/mt7621/base-files/etc/board.d/03_gpio_switches index 8a96e93226..ed728b07c4 100644 --- a/target/linux/ramips/mt7621/base-files/etc/board.d/03_gpio_switches +++ b/target/linux/ramips/mt7621/base-files/etc/board.d/03_gpio_switches @@ -22,6 +22,9 @@ ubnt,edgerouter-x-sfp) ucidef_add_gpio_switch "poe_power_port3" "PoE Power Port3" "403" ucidef_add_gpio_switch "poe_power_port4" "PoE Power Port4" "404" ;; +zyxel,nr7101) + ucidef_add_gpio_switch "lte_reset" "Reset LTE/5G modem" "483" + ;; zyxel,wap6805) ucidef_add_gpio_switch "qtn_power" "Quantenna Module Power" "496" "1" ;; diff --git a/target/linux/ramips/mt7621/base-files/etc/init.d/bootcount b/target/linux/ramips/mt7621/base-files/etc/init.d/bootcount index 7ef0053e67..a155458d3f 100755 --- a/target/linux/ramips/mt7621/base-files/etc/init.d/bootcount +++ b/target/linux/ramips/mt7621/base-files/etc/init.d/bootcount @@ -16,5 +16,10 @@ boot() { samknows,whitebox-v8) fw_setenv bootcount 0 ;; + zyxel,nr7101) + [ $(printf %d $(fw_printenv -n DebugFlag)) -gt 0 ] || fw_setenv DebugFlag 0x1 + [ $(printf %d $(fw_printenv -n Image1Stable)) -gt 0 ] || fw_setenv Image1Stable 1 + [ $(printf %d $(fw_printenv -n Image1Try)) -gt 0 ] && fw_setenv Image1Try 0 + ;; esac } diff --git a/target/linux/ramips/mt7621/base-files/lib/upgrade/platform.sh b/target/linux/ramips/mt7621/base-files/lib/upgrade/platform.sh index c9152c5cf4..d30bc3db2e 100755 --- a/target/linux/ramips/mt7621/base-files/lib/upgrade/platform.sh +++ b/target/linux/ramips/mt7621/base-files/lib/upgrade/platform.sh @@ -82,6 +82,12 @@ platform_do_upgrade() { ubnt,edgerouter-x-sfp) platform_upgrade_ubnt_erx "$1" ;; + zyxel,nr7101) + fw_setenv CheckBypass 0 + fw_setenv Image1Stable 0 + CI_KERNPART="Kernel" + nand_do_upgrade "$1" + ;; zyxel,wap6805) local kernel2_mtd="$(find_mtd_part Kernel2)" [ "$(hexdump -n 4 -e '"%x"' $kernel2_mtd)" = "56190527" ] &&\ From 976e65933bf52cc1244e6536c25c558ef15d2cd0 Mon Sep 17 00:00:00 2001 From: Kevin Darbyshire-Bryant Date: Mon, 3 May 2021 09:59:55 +0100 Subject: [PATCH 61/62] kernel: bump 5.10 to 5.10.34 Nothing required refreshing, simplest kernel bump you've ever seen. Signed-off-by: Kevin Darbyshire-Bryant --- include/kernel-version.mk | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/kernel-version.mk b/include/kernel-version.mk index f343716e01..0a39e42f93 100644 --- a/include/kernel-version.mk +++ b/include/kernel-version.mk @@ -7,10 +7,10 @@ ifdef CONFIG_TESTING_KERNEL endif LINUX_VERSION-5.4 = .117 -LINUX_VERSION-5.10 = .33 +LINUX_VERSION-5.10 = .34 LINUX_KERNEL_HASH-5.4.117 = 4e989b5775830092e5c76b5cca65ebff862ad0c87d0b58c3a20d415c3d4ec770 -LINUX_KERNEL_HASH-5.10.33 = 933fdbc36371c0f830b7a6a957a559fca2dad1cc0eaa852ef42fb168185b4315 +LINUX_KERNEL_HASH-5.10.34 = 6eeeb7e005bd1d4eb8b10382a35f8cd54ee6692c244ab1362590fa539f3d6582 remove_uri_prefix=$(subst git://,,$(subst http://,,$(subst https://,,$(1)))) sanitize_uri=$(call qstrip,$(subst @,_,$(subst :,_,$(subst .,_,$(subst -,_,$(subst /,_,$(1))))))) From f35dbef6d2aca7aa852aa5cc4160de6dc17abbae Mon Sep 17 00:00:00 2001 From: Kevin Darbyshire-Bryant Date: Fri, 7 May 2021 19:32:18 +0100 Subject: [PATCH 62/62] kernel: bump 5.10 to 5.10.35 Refresh kernel patches. Built under MacOS Run tested: x86_64 (apu2) Signed-off-by: Kevin Darbyshire-Bryant --- include/kernel-version.mk | 4 +-- ...Mangle-bootloader-s-kernel-arguments.patch | 22 +++++++------- .../083-ipq8064-dtsi-additions.patch | 4 +-- ....12-mtd-parsers-Add-Qcom-SMEM-parser.patch | 4 +-- ...hermal-tsens-Add-VER_0-tsens-version.patch | 29 +++++++------------ ...al-tsens-Don-t-hardcode-sensor-slope.patch | 7 +---- ...l-tsens-Convert-msm8960-to-reg_field.patch | 9 ++---- ...al-tsens-Use-init_common-for-msm8960.patch | 9 ++---- ...tsens-Fix-bug-in-sensor-enable-for-m.patch | 7 +---- ...tsens-Replace-custom-8960-apis-with-.patch | 11 ++----- ...tsens-Drop-unused-define-for-msm8960.patch | 5 ---- ...-tsens-Add-support-for-ipq8064-tsens.patch | 7 +---- ...rmal-tsens-Document-ipq8064-bindings.patch | 17 +++++------ ...al-tsens-Fix-wrong-slope-on-msm-8960.patch | 5 ---- ...et-stmmac-Set-FIFO-sizes-for-ipq806x.patch | 4 +-- 15 files changed, 46 insertions(+), 98 deletions(-) diff --git a/include/kernel-version.mk b/include/kernel-version.mk index 0a39e42f93..3560165e35 100644 --- a/include/kernel-version.mk +++ b/include/kernel-version.mk @@ -7,10 +7,10 @@ ifdef CONFIG_TESTING_KERNEL endif LINUX_VERSION-5.4 = .117 -LINUX_VERSION-5.10 = .34 +LINUX_VERSION-5.10 = .35 LINUX_KERNEL_HASH-5.4.117 = 4e989b5775830092e5c76b5cca65ebff862ad0c87d0b58c3a20d415c3d4ec770 -LINUX_KERNEL_HASH-5.10.34 = 6eeeb7e005bd1d4eb8b10382a35f8cd54ee6692c244ab1362590fa539f3d6582 +LINUX_KERNEL_HASH-5.10.35 = ac37a19d45b77a87e58e3aae8b127a6e7eb85ed7467fc8e58474b387bfd498fd remove_uri_prefix=$(subst git://,,$(subst http://,,$(subst https://,,$(1)))) sanitize_uri=$(call qstrip,$(subst @,_,$(subst :,_,$(subst .,_,$(subst -,_,$(subst /,_,$(1))))))) diff --git a/target/linux/ipq806x/patches-5.10/0067-generic-Mangle-bootloader-s-kernel-arguments.patch b/target/linux/ipq806x/patches-5.10/0067-generic-Mangle-bootloader-s-kernel-arguments.patch index 751ac10a19..c38e0a4669 100644 --- a/target/linux/ipq806x/patches-5.10/0067-generic-Mangle-bootloader-s-kernel-arguments.patch +++ b/target/linux/ipq806x/patches-5.10/0067-generic-Mangle-bootloader-s-kernel-arguments.patch @@ -22,7 +22,7 @@ Signed-off-by: Adrian Panella --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig -@@ -1827,6 +1827,17 @@ config ARM_ATAG_DTB_COMPAT_CMDLINE_EXTEN +@@ -1780,6 +1780,17 @@ config ARM_ATAG_DTB_COMPAT_CMDLINE_EXTEN The command-line arguments provided by the boot loader will be appended to the the device tree bootargs property. @@ -42,7 +42,7 @@ Signed-off-by: Adrian Panella config CMDLINE --- a/arch/arm/boot/compressed/atags_to_fdt.c +++ b/arch/arm/boot/compressed/atags_to_fdt.c -@@ -4,6 +4,8 @@ +@@ -5,6 +5,8 @@ #if defined(CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_EXTEND) #define do_extend_cmdline 1 @@ -51,7 +51,7 @@ Signed-off-by: Adrian Panella #else #define do_extend_cmdline 0 #endif -@@ -67,6 +69,80 @@ static uint32_t get_cell_size(const void +@@ -69,6 +71,80 @@ static uint32_t get_cell_size(const void return cell_size; } @@ -132,7 +132,7 @@ Signed-off-by: Adrian Panella static void merge_fdt_bootargs(void *fdt, const char *fdt_cmdline) { char cmdline[COMMAND_LINE_SIZE]; -@@ -86,12 +162,21 @@ static void merge_fdt_bootargs(void *fdt +@@ -88,12 +164,21 @@ static void merge_fdt_bootargs(void *fdt /* and append the ATAG_CMDLINE */ if (fdt_cmdline) { @@ -154,7 +154,7 @@ Signed-off-by: Adrian Panella } *ptr = '\0'; -@@ -166,7 +251,9 @@ int atags_to_fdt(void *atag_list, void * +@@ -168,7 +253,9 @@ int atags_to_fdt(void *atag_list, void * else setprop_string(fdt, "/chosen", "bootargs", atag->u.cmdline.cmdline); @@ -165,7 +165,7 @@ Signed-off-by: Adrian Panella if (memcount >= sizeof(mem_reg_property)/4) continue; if (!atag->u.mem.size) -@@ -210,6 +297,10 @@ int atags_to_fdt(void *atag_list, void * +@@ -212,6 +299,10 @@ int atags_to_fdt(void *atag_list, void * setprop(fdt, "/memory", "reg", mem_reg_property, 4 * memcount * memsize); } @@ -178,9 +178,9 @@ Signed-off-by: Adrian Panella } --- a/init/main.c +++ b/init/main.c -@@ -104,6 +104,10 @@ - #define CREATE_TRACE_POINTS - #include +@@ -110,6 +110,10 @@ + + #include +#if defined(CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_MANGLE) +#include @@ -189,8 +189,8 @@ Signed-off-by: Adrian Panella static int kernel_init(void *); extern void init_IRQ(void); -@@ -633,6 +637,18 @@ asmlinkage __visible void __init start_k - pr_notice("Kernel command line: %s\n", boot_command_line); +@@ -905,6 +909,18 @@ asmlinkage __visible void __init __no_sa + pr_notice("Kernel command line: %s\n", saved_command_line); /* parameters may set static keys */ jump_label_init(); + diff --git a/target/linux/ipq806x/patches-5.10/083-ipq8064-dtsi-additions.patch b/target/linux/ipq806x/patches-5.10/083-ipq8064-dtsi-additions.patch index 5d1ae2ae3d..fac8b174d4 100644 --- a/target/linux/ipq806x/patches-5.10/083-ipq8064-dtsi-additions.patch +++ b/target/linux/ipq806x/patches-5.10/083-ipq8064-dtsi-additions.patch @@ -674,7 +674,7 @@ pcie0: pci@1b500000 { compatible = "qcom,pcie-ipq8064"; reg = <0x1b500000 0x1000 -@@ -751,6 +1344,59 @@ +@@ -739,6 +1332,59 @@ status = "disabled"; }; @@ -734,7 +734,7 @@ vsdcc_fixed: vsdcc-regulator { compatible = "regulator-fixed"; regulator-name = "SDCC Power"; -@@ -826,4 +1472,17 @@ +@@ -814,4 +1460,17 @@ }; }; }; diff --git a/target/linux/ipq806x/patches-5.10/101-5.12-mtd-parsers-Add-Qcom-SMEM-parser.patch b/target/linux/ipq806x/patches-5.10/101-5.12-mtd-parsers-Add-Qcom-SMEM-parser.patch index d93f338c74..a78dc82a47 100644 --- a/target/linux/ipq806x/patches-5.10/101-5.12-mtd-parsers-Add-Qcom-SMEM-parser.patch +++ b/target/linux/ipq806x/patches-5.10/101-5.12-mtd-parsers-Add-Qcom-SMEM-parser.patch @@ -19,7 +19,7 @@ Link: https://lore.kernel.org/linux-mtd/20210104041137.113075-3-manivannan.sadha --- a/drivers/mtd/parsers/Kconfig +++ b/drivers/mtd/parsers/Kconfig -@@ -186,6 +186,14 @@ config MTD_REDBOOT_PARTS_READONLY +@@ -196,6 +196,14 @@ config MTD_REDBOOT_PARTS_READONLY endif # MTD_REDBOOT_PARTS @@ -36,7 +36,7 @@ Link: https://lore.kernel.org/linux-mtd/20210104041137.113075-3-manivannan.sadha depends on MTD && OF --- a/drivers/mtd/parsers/Makefile +++ b/drivers/mtd/parsers/Makefile -@@ -12,4 +12,5 @@ obj-$(CONFIG_MTD_AFS_PARTS) += afs.o +@@ -13,4 +13,5 @@ obj-$(CONFIG_MTD_AFS_PARTS) += afs.o obj-$(CONFIG_MTD_PARSER_TRX) += parser_trx.o obj-$(CONFIG_MTD_SHARPSL_PARTS) += sharpslpart.o obj-$(CONFIG_MTD_REDBOOT_PARTS) += redboot.o diff --git a/target/linux/ipq806x/patches-5.10/104-1-drivers-thermal-tsens-Add-VER_0-tsens-version.patch b/target/linux/ipq806x/patches-5.10/104-1-drivers-thermal-tsens-Add-VER_0-tsens-version.patch index d4c85a06a5..cf8fd7cf61 100644 --- a/target/linux/ipq806x/patches-5.10/104-1-drivers-thermal-tsens-Add-VER_0-tsens-version.patch +++ b/target/linux/ipq806x/patches-5.10/104-1-drivers-thermal-tsens-Add-VER_0-tsens-version.patch @@ -16,8 +16,6 @@ Reported-by: Dan Carpenter drivers/thermal/qcom/tsens.h | 4 +- 2 files changed, 124 insertions(+), 30 deletions(-) -diff --git a/drivers/thermal/qcom/tsens.c b/drivers/thermal/qcom/tsens.c -index d8ce3a687b80..9a7e991d4bd2 100644 --- a/drivers/thermal/qcom/tsens.c +++ b/drivers/thermal/qcom/tsens.c @@ -12,6 +12,7 @@ @@ -28,7 +26,7 @@ index d8ce3a687b80..9a7e991d4bd2 100644 #include #include #include -@@ -515,6 +516,15 @@ static irqreturn_t tsens_irq_thread(int irq, void *data) +@@ -515,6 +516,15 @@ static irqreturn_t tsens_irq_thread(int dev_dbg(priv->dev, "[%u] %s: no violation: %d\n", hw_id, __func__, temp); } @@ -44,7 +42,7 @@ index d8ce3a687b80..9a7e991d4bd2 100644 } return IRQ_HANDLED; -@@ -530,6 +540,13 @@ static int tsens_set_trips(void *_sensor, int low, int high) +@@ -530,6 +540,13 @@ static int tsens_set_trips(void *_sensor int high_val, low_val, cl_high, cl_low; u32 hw_id = s->hw_id; @@ -58,7 +56,7 @@ index d8ce3a687b80..9a7e991d4bd2 100644 dev_dbg(dev, "[%u] %s: proposed thresholds: (%d:%d)\n", hw_id, __func__, low, high); -@@ -584,18 +601,21 @@ int get_temp_tsens_valid(const struct tsens_sensor *s, int *temp) +@@ -584,18 +601,21 @@ int get_temp_tsens_valid(const struct ts u32 valid; int ret; @@ -89,7 +87,7 @@ index d8ce3a687b80..9a7e991d4bd2 100644 } /* Valid bit is set, OK to read the temperature */ -@@ -608,15 +628,29 @@ int get_temp_common(const struct tsens_sensor *s, int *temp) +@@ -608,15 +628,29 @@ int get_temp_common(const struct tsens_s { struct tsens_priv *priv = s->priv; int hw_id = s->hw_id; @@ -125,7 +123,7 @@ index d8ce3a687b80..9a7e991d4bd2 100644 } #ifdef CONFIG_DEBUG_FS -@@ -738,19 +772,34 @@ int __init init_common(struct tsens_priv *priv) +@@ -738,19 +772,34 @@ int __init init_common(struct tsens_priv priv->tm_offset = 0x1000; } @@ -168,7 +166,7 @@ index d8ce3a687b80..9a7e991d4bd2 100644 if (tsens_version(priv) > VER_0_1) { for (i = VER_MAJOR; i <= VER_STEP; i++) { priv->rf[i] = devm_regmap_field_alloc(dev, priv->srot_map, -@@ -769,6 +818,10 @@ int __init init_common(struct tsens_priv *priv) +@@ -769,6 +818,10 @@ int __init init_common(struct tsens_priv ret = PTR_ERR(priv->rf[TSENS_EN]); goto err_put_device; } @@ -179,7 +177,7 @@ index d8ce3a687b80..9a7e991d4bd2 100644 ret = regmap_field_read(priv->rf[TSENS_EN], &enabled); if (ret) goto err_put_device; -@@ -791,6 +844,19 @@ int __init init_common(struct tsens_priv *priv) +@@ -791,6 +844,19 @@ int __init init_common(struct tsens_priv goto err_put_device; } @@ -199,7 +197,7 @@ index d8ce3a687b80..9a7e991d4bd2 100644 /* This loop might need changes if enum regfield_ids is reordered */ for (j = LAST_TEMP_0; j <= UP_THRESH_15; j += 16) { for (i = 0; i < priv->feat->max_sensors; i++) { -@@ -806,7 +872,7 @@ int __init init_common(struct tsens_priv *priv) +@@ -806,7 +872,7 @@ int __init init_common(struct tsens_priv } } @@ -208,7 +206,7 @@ index d8ce3a687b80..9a7e991d4bd2 100644 /* Loop might need changes if enum regfield_ids is reordered */ for (j = CRITICAL_STATUS_0; j <= CRIT_THRESH_15; j += 16) { for (i = 0; i < priv->feat->max_sensors; i++) { -@@ -844,7 +910,11 @@ int __init init_common(struct tsens_priv *priv) +@@ -844,7 +910,11 @@ int __init init_common(struct tsens_priv } spin_lock_init(&priv->ul_lock); @@ -221,7 +219,7 @@ index d8ce3a687b80..9a7e991d4bd2 100644 tsens_debug_init(op); err_put_device: -@@ -943,10 +1013,19 @@ static int tsens_register_irq(struct tsens_priv *priv, char *irqname, +@@ -943,10 +1013,19 @@ static int tsens_register_irq(struct tse if (irq == -ENXIO) ret = 0; } else { @@ -245,7 +243,7 @@ index d8ce3a687b80..9a7e991d4bd2 100644 if (ret) dev_err(&pdev->dev, "%s: failed to get irq\n", __func__); -@@ -975,6 +1054,19 @@ static int tsens_register(struct tsens_priv *priv) +@@ -975,6 +1054,19 @@ static int tsens_register(struct tsens_p priv->ops->enable(priv, i); } @@ -265,8 +263,6 @@ index d8ce3a687b80..9a7e991d4bd2 100644 ret = tsens_register_irq(priv, "uplow", tsens_irq_thread); if (ret < 0) return ret; -diff --git a/drivers/thermal/qcom/tsens.h b/drivers/thermal/qcom/tsens.h -index f40b625f897e..8e6c1fd3ccf5 100644 --- a/drivers/thermal/qcom/tsens.h +++ b/drivers/thermal/qcom/tsens.h @@ -13,6 +13,7 @@ @@ -287,6 +283,3 @@ index f40b625f897e..8e6c1fd3ccf5 100644 VER_1_X, VER_2_X, }; --- -2.30.2 - diff --git a/target/linux/ipq806x/patches-5.10/104-2-drivers-thermal-tsens-Don-t-hardcode-sensor-slope.patch b/target/linux/ipq806x/patches-5.10/104-2-drivers-thermal-tsens-Don-t-hardcode-sensor-slope.patch index 44de19b7a8..109f524bbd 100644 --- a/target/linux/ipq806x/patches-5.10/104-2-drivers-thermal-tsens-Don-t-hardcode-sensor-slope.patch +++ b/target/linux/ipq806x/patches-5.10/104-2-drivers-thermal-tsens-Don-t-hardcode-sensor-slope.patch @@ -14,11 +14,9 @@ Reviewed-by: Thara Gopinath drivers/thermal/qcom/tsens.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) -diff --git a/drivers/thermal/qcom/tsens.c b/drivers/thermal/qcom/tsens.c -index 9a7e991d4bd2..38b9936def1a 100644 --- a/drivers/thermal/qcom/tsens.c +++ b/drivers/thermal/qcom/tsens.c -@@ -86,7 +86,8 @@ void compute_intercept_slope(struct tsens_priv *priv, u32 *p1, +@@ -86,7 +86,8 @@ void compute_intercept_slope(struct tsen "%s: sensor%d - data_point1:%#x data_point2:%#x\n", __func__, i, p1[i], p2[i]); @@ -28,6 +26,3 @@ index 9a7e991d4bd2..38b9936def1a 100644 if (mode == TWO_PT_CALIB) { /* * slope (m) = adc_code2 - adc_code1 (y2 - y1)/ --- -2.30.2 - diff --git a/target/linux/ipq806x/patches-5.10/104-3-drivers-thermal-tsens-Convert-msm8960-to-reg_field.patch b/target/linux/ipq806x/patches-5.10/104-3-drivers-thermal-tsens-Convert-msm8960-to-reg_field.patch index d8779c689a..bf378107c6 100644 --- a/target/linux/ipq806x/patches-5.10/104-3-drivers-thermal-tsens-Convert-msm8960-to-reg_field.patch +++ b/target/linux/ipq806x/patches-5.10/104-3-drivers-thermal-tsens-Convert-msm8960-to-reg_field.patch @@ -12,8 +12,6 @@ Acked-by: Thara Gopinath drivers/thermal/qcom/tsens-8960.c | 80 ++++++++++++++++++++++++++++++- 1 file changed, 79 insertions(+), 1 deletion(-) -diff --git a/drivers/thermal/qcom/tsens-8960.c b/drivers/thermal/qcom/tsens-8960.c -index 2a28a5af209e..3f4fc1ffe679 100644 --- a/drivers/thermal/qcom/tsens-8960.c +++ b/drivers/thermal/qcom/tsens-8960.c @@ -51,11 +51,22 @@ @@ -40,7 +38,7 @@ index 2a28a5af209e..3f4fc1ffe679 100644 static int suspend_8960(struct tsens_priv *priv) { int ret; -@@ -269,6 +280,71 @@ static int get_temp_8960(const struct tsens_sensor *s, int *temp) +@@ -269,6 +280,71 @@ static int get_temp_8960(const struct ts return -ETIMEDOUT; } @@ -112,13 +110,10 @@ index 2a28a5af209e..3f4fc1ffe679 100644 static const struct tsens_ops ops_8960 = { .init = init_8960, .calibrate = calibrate_8960, -@@ -282,4 +358,6 @@ static const struct tsens_ops ops_8960 = { +@@ -282,4 +358,6 @@ static const struct tsens_ops ops_8960 = struct tsens_plat_data data_8960 = { .num_sensors = 11, .ops = &ops_8960, + .feat = &tsens_8960_feat, + .fields = tsens_8960_regfields, }; --- -2.30.2 - diff --git a/target/linux/ipq806x/patches-5.10/104-4-drivers-thermal-tsens-Use-init_common-for-msm8960.patch b/target/linux/ipq806x/patches-5.10/104-4-drivers-thermal-tsens-Use-init_common-for-msm8960.patch index 4b12609e96..ae8a52c100 100644 --- a/target/linux/ipq806x/patches-5.10/104-4-drivers-thermal-tsens-Use-init_common-for-msm8960.patch +++ b/target/linux/ipq806x/patches-5.10/104-4-drivers-thermal-tsens-Use-init_common-for-msm8960.patch @@ -11,11 +11,9 @@ Reviewed-by: Thara Gopinath drivers/thermal/qcom/tsens-8960.c | 52 +------------------------------ 1 file changed, 1 insertion(+), 51 deletions(-) -diff --git a/drivers/thermal/qcom/tsens-8960.c b/drivers/thermal/qcom/tsens-8960.c -index 3f4fc1ffe679..86585f439985 100644 --- a/drivers/thermal/qcom/tsens-8960.c +++ b/drivers/thermal/qcom/tsens-8960.c -@@ -173,56 +173,6 @@ static void disable_8960(struct tsens_priv *priv) +@@ -173,56 +173,6 @@ static void disable_8960(struct tsens_pr regmap_write(priv->tm_map, CNTL_ADDR, reg_cntl); } @@ -72,7 +70,7 @@ index 3f4fc1ffe679..86585f439985 100644 static int calibrate_8960(struct tsens_priv *priv) { int i; -@@ -346,7 +296,7 @@ static const struct reg_field tsens_8960_regfields[MAX_REGFIELDS] = { +@@ -346,7 +296,7 @@ static const struct reg_field tsens_8960 }; static const struct tsens_ops ops_8960 = { @@ -81,6 +79,3 @@ index 3f4fc1ffe679..86585f439985 100644 .calibrate = calibrate_8960, .get_temp = get_temp_8960, .enable = enable_8960, --- -2.30.2 - diff --git a/target/linux/ipq806x/patches-5.10/104-5-drivers-thermal-tsens-Fix-bug-in-sensor-enable-for-m.patch b/target/linux/ipq806x/patches-5.10/104-5-drivers-thermal-tsens-Fix-bug-in-sensor-enable-for-m.patch index 4f8a6769a0..7b01a67d90 100644 --- a/target/linux/ipq806x/patches-5.10/104-5-drivers-thermal-tsens-Fix-bug-in-sensor-enable-for-m.patch +++ b/target/linux/ipq806x/patches-5.10/104-5-drivers-thermal-tsens-Fix-bug-in-sensor-enable-for-m.patch @@ -14,8 +14,6 @@ Acked-by: Thara Gopinath drivers/thermal/qcom/tsens-8960.c | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) -diff --git a/drivers/thermal/qcom/tsens-8960.c b/drivers/thermal/qcom/tsens-8960.c -index 86585f439985..95fcccafae14 100644 --- a/drivers/thermal/qcom/tsens-8960.c +++ b/drivers/thermal/qcom/tsens-8960.c @@ -27,9 +27,9 @@ @@ -29,7 +27,7 @@ index 86585f439985..95fcccafae14 100644 #define SENSOR0_SHIFT 3 /* INT_STATUS_ADDR bitmasks */ -@@ -126,17 +126,34 @@ static int resume_8960(struct tsens_priv *priv) +@@ -126,17 +126,34 @@ static int resume_8960(struct tsens_priv static int enable_8960(struct tsens_priv *priv, int id) { int ret; @@ -66,6 +64,3 @@ index 86585f439985..95fcccafae14 100644 if (priv->num_sensors > 1) reg |= mask | SLP_CLK_ENA | EN; else --- -2.30.2 - diff --git a/target/linux/ipq806x/patches-5.10/104-6-drivers-thermal-tsens-Replace-custom-8960-apis-with-.patch b/target/linux/ipq806x/patches-5.10/104-6-drivers-thermal-tsens-Replace-custom-8960-apis-with-.patch index 657f8b801b..a82f596954 100644 --- a/target/linux/ipq806x/patches-5.10/104-6-drivers-thermal-tsens-Replace-custom-8960-apis-with-.patch +++ b/target/linux/ipq806x/patches-5.10/104-6-drivers-thermal-tsens-Replace-custom-8960-apis-with-.patch @@ -15,8 +15,6 @@ Acked-by: Thara Gopinath drivers/thermal/qcom/tsens-8960.c | 56 +++++++++---------------------- 1 file changed, 15 insertions(+), 41 deletions(-) -diff --git a/drivers/thermal/qcom/tsens-8960.c b/drivers/thermal/qcom/tsens-8960.c -index 95fcccafae14..9cc8a7dd23ae 100644 --- a/drivers/thermal/qcom/tsens-8960.c +++ b/drivers/thermal/qcom/tsens-8960.c @@ -67,6 +67,13 @@ @@ -33,7 +31,7 @@ index 95fcccafae14..9cc8a7dd23ae 100644 static int suspend_8960(struct tsens_priv *priv) { int ret; -@@ -194,9 +201,7 @@ static int calibrate_8960(struct tsens_priv *priv) +@@ -194,9 +201,7 @@ static int calibrate_8960(struct tsens_p { int i; char *data; @@ -44,7 +42,7 @@ index 95fcccafae14..9cc8a7dd23ae 100644 data = qfprom_read(priv->dev, "calib"); if (IS_ERR(data)) -@@ -204,49 +209,18 @@ static int calibrate_8960(struct tsens_priv *priv) +@@ -204,49 +209,18 @@ static int calibrate_8960(struct tsens_p if (IS_ERR(data)) return PTR_ERR(data); @@ -100,7 +98,7 @@ index 95fcccafae14..9cc8a7dd23ae 100644 static struct tsens_features tsens_8960_feat = { .ver_major = VER_0, .crit_int = 0, -@@ -315,7 +289,7 @@ static const struct reg_field tsens_8960_regfields[MAX_REGFIELDS] = { +@@ -315,7 +289,7 @@ static const struct reg_field tsens_8960 static const struct tsens_ops ops_8960 = { .init = init_common, .calibrate = calibrate_8960, @@ -109,6 +107,3 @@ index 95fcccafae14..9cc8a7dd23ae 100644 .enable = enable_8960, .disable = disable_8960, .suspend = suspend_8960, --- -2.30.2 - diff --git a/target/linux/ipq806x/patches-5.10/104-7-drivers-thermal-tsens-Drop-unused-define-for-msm8960.patch b/target/linux/ipq806x/patches-5.10/104-7-drivers-thermal-tsens-Drop-unused-define-for-msm8960.patch index d0e383d035..77ca3cfe45 100644 --- a/target/linux/ipq806x/patches-5.10/104-7-drivers-thermal-tsens-Drop-unused-define-for-msm8960.patch +++ b/target/linux/ipq806x/patches-5.10/104-7-drivers-thermal-tsens-Drop-unused-define-for-msm8960.patch @@ -11,8 +11,6 @@ Reviewed-by: Thara Gopinath drivers/thermal/qcom/tsens-8960.c | 24 +----------------------- 1 file changed, 1 insertion(+), 23 deletions(-) -diff --git a/drivers/thermal/qcom/tsens-8960.c b/drivers/thermal/qcom/tsens-8960.c -index 9cc8a7dd23ae..58d09e927383 100644 --- a/drivers/thermal/qcom/tsens-8960.c +++ b/drivers/thermal/qcom/tsens-8960.c @@ -10,8 +10,6 @@ @@ -65,6 +63,3 @@ index 9cc8a7dd23ae..58d09e927383 100644 #define S0_STATUS_OFF 0x3628 #define S1_STATUS_OFF 0x362c --- -2.30.2 - diff --git a/target/linux/ipq806x/patches-5.10/104-8-drivers-thermal-tsens-Add-support-for-ipq8064-tsens.patch b/target/linux/ipq806x/patches-5.10/104-8-drivers-thermal-tsens-Add-support-for-ipq8064-tsens.patch index 928e8fd695..a6ecac1cae 100644 --- a/target/linux/ipq806x/patches-5.10/104-8-drivers-thermal-tsens-Add-support-for-ipq8064-tsens.patch +++ b/target/linux/ipq806x/patches-5.10/104-8-drivers-thermal-tsens-Add-support-for-ipq8064-tsens.patch @@ -12,11 +12,9 @@ Reviewed-by: Thara Gopinath drivers/thermal/qcom/tsens.c | 3 +++ 1 file changed, 3 insertions(+) -diff --git a/drivers/thermal/qcom/tsens.c b/drivers/thermal/qcom/tsens.c -index 38b9936def1a..58073dc5d30b 100644 --- a/drivers/thermal/qcom/tsens.c +++ b/drivers/thermal/qcom/tsens.c -@@ -966,6 +966,9 @@ static SIMPLE_DEV_PM_OPS(tsens_pm_ops, tsens_suspend, tsens_resume); +@@ -966,6 +966,9 @@ static SIMPLE_DEV_PM_OPS(tsens_pm_ops, t static const struct of_device_id tsens_table[] = { { @@ -26,6 +24,3 @@ index 38b9936def1a..58073dc5d30b 100644 .compatible = "qcom,msm8916-tsens", .data = &data_8916, }, { --- -2.30.2 - diff --git a/target/linux/ipq806x/patches-5.10/104-9-dt-bindings-thermal-tsens-Document-ipq8064-bindings.patch b/target/linux/ipq806x/patches-5.10/104-9-dt-bindings-thermal-tsens-Document-ipq8064-bindings.patch index 121f857182..382106863f 100644 --- a/target/linux/ipq806x/patches-5.10/104-9-dt-bindings-thermal-tsens-Document-ipq8064-bindings.patch +++ b/target/linux/ipq806x/patches-5.10/104-9-dt-bindings-thermal-tsens-Document-ipq8064-bindings.patch @@ -12,8 +12,6 @@ Reviewed-by: Rob Herring .../bindings/thermal/qcom-tsens.yaml | 56 ++++++++++++++++--- 1 file changed, 48 insertions(+), 8 deletions(-) -diff --git a/Documentation/devicetree/bindings/thermal/qcom-tsens.yaml b/Documentation/devicetree/bindings/thermal/qcom-tsens.yaml -index 95462e071ab4..1785b1c75a3c 100644 --- a/Documentation/devicetree/bindings/thermal/qcom-tsens.yaml +++ b/Documentation/devicetree/bindings/thermal/qcom-tsens.yaml @@ -19,6 +19,11 @@ description: | @@ -60,7 +58,7 @@ index 95462e071ab4..1785b1c75a3c 100644 - qcom,msm8916-tsens - qcom,msm8974-tsens - qcom,msm8976-tsens -@@ -114,17 +129,42 @@ allOf: +@@ -114,19 +129,44 @@ allOf: interrupt-names: minItems: 2 @@ -87,8 +85,8 @@ index 95462e071ab4..1785b1c75a3c 100644 additionalProperties: false examples: -+ - | -+ #include + - | + #include + // Example msm9860 based SoC (ipq8064): + gcc: clock-controller { + @@ -107,9 +105,8 @@ index 95462e071ab4..1785b1c75a3c 100644 + }; + }; + - - | - #include ++ - | ++ #include // Example 1 (legacy: for pre v1 IP): --- -2.30.2 - + tsens1: thermal-sensor@900000 { + compatible = "qcom,msm8916-tsens", "qcom,tsens-v0_1"; diff --git a/target/linux/ipq806x/patches-5.10/105-10-drivers-thermal-tsens-Fix-wrong-slope-on-msm-8960.patch b/target/linux/ipq806x/patches-5.10/105-10-drivers-thermal-tsens-Fix-wrong-slope-on-msm-8960.patch index 2212d41caf..6cdc0b263f 100644 --- a/target/linux/ipq806x/patches-5.10/105-10-drivers-thermal-tsens-Fix-wrong-slope-on-msm-8960.patch +++ b/target/linux/ipq806x/patches-5.10/105-10-drivers-thermal-tsens-Fix-wrong-slope-on-msm-8960.patch @@ -12,8 +12,6 @@ Signed-off-by: Ansuel Smith drivers/thermal/qcom/tsens-8960.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) -diff --git a/drivers/thermal/qcom/tsens-8960.c b/drivers/thermal/qcom/tsens-8960.c -index 58d09e927383..5cc5b3527f1f 100644 --- a/drivers/thermal/qcom/tsens-8960.c +++ b/drivers/thermal/qcom/tsens-8960.c @@ -45,11 +45,11 @@ @@ -32,6 +30,3 @@ index 58d09e927383..5cc5b3527f1f 100644 }; static int suspend_8960(struct tsens_priv *priv) --- -2.30.2 - diff --git a/target/linux/ipq806x/patches-5.10/106-5.13-net-stmmac-Set-FIFO-sizes-for-ipq806x.patch b/target/linux/ipq806x/patches-5.10/106-5.13-net-stmmac-Set-FIFO-sizes-for-ipq806x.patch index 1da9e7e2b3..de28edbb9f 100644 --- a/target/linux/ipq806x/patches-5.10/106-5.13-net-stmmac-Set-FIFO-sizes-for-ipq806x.patch +++ b/target/linux/ipq806x/patches-5.10/106-5.13-net-stmmac-Set-FIFO-sizes-for-ipq806x.patch @@ -86,11 +86,9 @@ Signed-off-by: Jonathan McDowell drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c | 2 ++ 1 file changed, 2 insertions(+) -diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c -index bf3250e0e59c..749585fe6fc9 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c -@@ -352,6 +352,8 @@ static int ipq806x_gmac_probe(struct platform_device *pdev) +@@ -352,6 +352,8 @@ static int ipq806x_gmac_probe(struct pla plat_dat->bsp_priv = gmac; plat_dat->fix_mac_speed = ipq806x_gmac_fix_mac_speed; plat_dat->multicast_filter_bins = 0;